Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2012-06-27 04:58:52 +0000
committerEike Stepper2012-06-27 04:58:52 +0000
commitcb0b9e117562afd34dbb50470a5da87f1983bea1 (patch)
tree8d0933a9f01cfff460e783013d2a76076e676a6d /plugins
parent79ee2993d0aa71e97973103ce6689e9134ec1c88 (diff)
downloadcdo-cb0b9e117562afd34dbb50470a5da87f1983bea1.tar.gz
cdo-cb0b9e117562afd34dbb50470a5da87f1983bea1.tar.xz
cdo-cb0b9e117562afd34dbb50470a5da87f1983bea1.zip
[383602] Branch with base after the last finished commit can be created
https://bugs.eclipse.org/bugs/show_bug.cgi?id=383602
Diffstat (limited to 'plugins')
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java3018
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java2905
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerBrowser.java39
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java215
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java3371
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_314264_Test.java318
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java5
8 files changed, 4984 insertions, 4892 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java
index fc91648d11..607f60eb69 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java
@@ -1,1502 +1,1516 @@
-/*
- * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Stefan Winkler - initial API and implementation taken from AuditFeatureMapTableMappingWithRanges
- * Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
- */
-package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
-import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
-import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
-import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
-import org.eclipse.emf.cdo.server.IStoreChunkReader;
-import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
-import org.eclipse.emf.cdo.server.db.IDBStore;
-import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
-import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
-import org.eclipse.emf.cdo.server.db.IIDHandler;
-import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
-import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
-import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
-import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
-import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
-import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import org.eclipse.net4j.db.DBException;
-import org.eclipse.net4j.db.DBType;
-import org.eclipse.net4j.db.DBUtil;
-import org.eclipse.net4j.db.ddl.IDBField;
-import org.eclipse.net4j.db.ddl.IDBIndex.Type;
-import org.eclipse.net4j.db.ddl.IDBTable;
-import org.eclipse.net4j.util.ImplementationError;
-import org.eclipse.net4j.util.collection.MoveableList;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.util.FeatureMap;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This is a featuremap-table mapping for audit mode. It is optimized for frequent insert operations at the list's end,
- * which causes just 1 DB row to be changed. This is achieved by introducing a version range (columns
- * {@link CDODBSchema#LIST_REVISION_VERSION_ADDED cdo_version_added} and
- * {@link CDODBSchema#LIST_REVISION_VERSION_REMOVED cdo_version_removed}) which records for which revisions a particular
- * entry existed. Also, this mapping is mainly optimized for potentially very large lists: the need for having the
- * complete list stored in memory to do in-the-middle-moved and inserts is traded in for a few more DB access
- * operations.
- *
- * @author Eike Stepper
- * @author Stefan Winkler
- * @author Lothar Werzinger
- * @since 3.0
- */
-public class BranchingFeatureMapTableMappingWithRanges extends BasicAbstractListTableMapping implements
- IListMappingDeltaSupport
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG,
- BranchingFeatureMapTableMappingWithRanges.class);
-
- /**
- * Used to clean up lists for detached objects.
- */
- private static final int FINAL_VERSION = Integer.MAX_VALUE;
-
- /**
- * The table of this mapping.
- */
- private IDBTable table;
-
- /**
- * The tags mapped to column names
- */
- private HashMap<CDOID, String> tagMap;
-
- /**
- * Column name Set
- */
- private List<String> columnNames;
-
- /**
- * The type mappings for the value fields.
- */
- private Map<CDOID, ITypeMapping> typeMappings;
-
- private List<DBType> dbTypes;
-
- // --------- SQL strings - see initSQLStrings() -----------------
- private String sqlSelectChunksPrefix;
-
- private String sqlOrderByIndex;
-
- private String sqlInsert;
-
- private String sqlRemoveEntry;
-
- private String sqlDeleteEntry;
-
- private String sqlUpdateIndex;
-
- private String sqlGetValue;
-
- private String sqlClearList;
-
- public BranchingFeatureMapTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass,
- EStructuralFeature feature)
- {
- super(mappingStrategy, eClass, feature);
- initDBTypes();
- initTable();
- initSQLStrings();
- }
-
- private void initDBTypes()
- {
- // TODO add annotation processing here ...
- ITypeMapping.Registry registry = ITypeMapping.Registry.INSTANCE;
- dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
- }
-
- private void initTable()
- {
- IDBStore store = getMappingStrategy().getStore();
- String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
- table = store.getDBSchema().addTable(tableName);
-
- // add fields for CDOID
- IDBField idField = table.addField(CDODBSchema.FEATUREMAP_REVISION_ID, store.getIDHandler().getDBType());
-
- IDBField branchField = table.addField(CDODBSchema.LIST_REVISION_BRANCH, DBType.INTEGER);
-
- // add fields for version range
- IDBField versionAddedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_ADDED, DBType.INTEGER);
- IDBField versionRemovedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_REMOVED, DBType.INTEGER);
-
- // add field for list index
- IDBField idxField = table.addField(CDODBSchema.FEATUREMAP_IDX, DBType.INTEGER);
-
- // add field for FeatureMap tag (MetaID for Feature in CDO registry)
- IDBField tagField = table.addField(CDODBSchema.FEATUREMAP_TAG, store.getIDHandler().getDBType());
-
- tagMap = new HashMap<CDOID, String>();
- typeMappings = new HashMap<CDOID, ITypeMapping>();
- columnNames = new ArrayList<String>();
-
- // create columns for all DBTypes
- for (DBType type : getDBTypes())
- {
- String column = CDODBSchema.FEATUREMAP_VALUE + "_" + type.name();
- table.addField(column, type);
- columnNames.add(column);
- }
-
- table.addIndex(Type.NON_UNIQUE, idField);
- table.addIndex(Type.NON_UNIQUE, branchField);
- table.addIndex(Type.NON_UNIQUE, versionAddedField);
- table.addIndex(Type.NON_UNIQUE, versionRemovedField);
- table.addIndex(Type.NON_UNIQUE, idxField);
- table.addIndex(Type.NON_UNIQUE, tagField);
- }
-
- public Collection<IDBTable> getDBTables()
- {
- return Arrays.asList(table);
- }
-
- private void initSQLStrings()
- {
- String tableName = getTable().getName();
-
- // ---------------- SELECT to read chunks ----------------------------
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT "); //$NON-NLS-1$
-
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_TAG);
- builder.append(", "); //$NON-NLS-1$
-
- Iterator<String> iter = columnNames.iterator();
- while (iter.hasNext())
- {
- builder.append(iter.next());
- if (iter.hasNext())
- {
- builder.append(", "); //$NON-NLS-1$
- }
- }
-
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
- builder.append("<=? AND ("); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(" IS NULL OR "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(">?)"); //$NON-NLS-1$
- sqlSelectChunksPrefix = builder.toString();
-
- sqlOrderByIndex = " ORDER BY " + CDODBSchema.FEATUREMAP_IDX; //$NON-NLS-1$
-
- // ----------------- INSERT - prefix -----------------
- builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append("("); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_TAG);
-
- for (int i = 0; i < columnNames.size(); i++)
- {
- builder.append(", "); //$NON-NLS-1$
- builder.append(columnNames.get(i));
- }
-
- builder.append(") VALUES (?, ?, ?, ?, ?, ?"); //$NON-NLS-1$
- for (int i = 0; i < columnNames.size(); i++)
- {
- builder.append(", ?"); //$NON-NLS-1$
- }
-
- builder.append(")"); //$NON-NLS-1$
- sqlInsert = builder.toString();
-
- // ----------------- remove current entry -----------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append("=? "); //$NON-NLS-1$
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlRemoveEntry = builder.toString();
-
- // ----------------- delete temporary entry -----------------
- builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
- builder.append("=?"); //$NON-NLS-1$
- sqlDeleteEntry = builder.toString();
-
- // ----------------- update index -----------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append("=? WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append("=?"); //$NON-NLS-1$
- sqlUpdateIndex = builder.toString();
-
- // ----------------- get current value -----------------
- builder = new StringBuilder("SELECT "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_TAG);
- builder.append(", "); //$NON-NLS-1$
-
- iter = columnNames.iterator();
- while (iter.hasNext())
- {
- builder.append(iter.next());
- if (iter.hasNext())
- {
- builder.append(", "); //$NON-NLS-1$
- }
- }
-
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlGetValue = builder.toString();
-
- // ----------- clear list items -------------------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append("=? "); //$NON-NLS-1$
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlClearList = builder.toString();
- }
-
- protected List<DBType> getDBTypes()
- {
- return dbTypes;
- }
-
- protected final IDBTable getTable()
- {
- return table;
- }
-
- protected final List<String> getColumnNames()
- {
- return columnNames;
- }
-
- protected final Map<CDOID, ITypeMapping> getTypeMappings()
- {
- return typeMappings;
- }
-
- protected final Map<CDOID, String> getTagMap()
- {
- return tagMap;
- }
-
- public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
- {
- MoveableList<Object> list = revision.getList(getFeature());
- int valuesToRead = list.size();
-
- if (listChunk != CDORevision.UNCHUNKED && listChunk < valuesToRead)
- {
- valuesToRead = listChunk;
- }
-
- if (valuesToRead == 0)
- {
- // nothing to read take shortcut
- return;
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list values for feature {0}.{1} of {2}", getContainingClass().getName(), getFeature() //$NON-NLS-1$
- .getName(), revision);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
- ResultSet resultSet = null;
-
- IStoreChunkReader baseReader = null;
-
- try
- {
- String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
-
- CDOID id = revision.getID();
- int branchID = revision.getBranch().getID();
-
- stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
- idHandler.setCDOID(stmt, 1, id);
- stmt.setInt(2, branchID);
- stmt.setInt(3, revision.getVersion());
- stmt.setInt(4, revision.getVersion());
-
- stmt.setMaxRows(valuesToRead); // optimization - don't read unneeded rows.
-
- resultSet = stmt.executeQuery();
-
- int currentIndex = 0;
-
- while (valuesToRead > 0 && resultSet.next())
- {
- int index = resultSet.getInt(1);
- if (index > currentIndex)
- {
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(accessor, id, branchID);
- }
-
- baseReader.addRangedChunk(currentIndex, index);
- if (TRACER.isEnabled())
- {
- TRACER.format("Scheduling range {0}-{1} to be read from base revision", currentIndex, index); //$NON-NLS-1$
- }
-
- valuesToRead -= index - currentIndex;
- currentIndex = index;
- }
-
- CDOID tag = idHandler.getCDOID(resultSet, 2);
- Object value = getTypeMapping(tag).readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("Read value for index {0} from result set: {1}", currentIndex, value); //$NON-NLS-1$
- }
-
- list.set(currentIndex++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
- valuesToRead--;
- }
-
- if (valuesToRead > 0)
- {
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(accessor, id, branchID);
- }
-
- baseReader.addRangedChunk(currentIndex, currentIndex + valuesToRead);
- }
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- statementCache.releasePreparedStatement(stmt);
- }
-
- if (baseReader != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading base revision chunks for featureMap {0}.{1} of {2} from base revision {3}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), revision, baseReader.getRevision());
- }
-
- List<Chunk> baseChunks = baseReader.executeRead();
- for (Chunk chunk : baseChunks)
- {
- int startIndex = chunk.getStartIndex();
- for (int i = 0; i < chunk.size(); i++)
- {
- list.set(startIndex + i, chunk.get(i));
- }
- }
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list values done for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
- getFeature().getName(), revision);
- }
- }
-
- private void addFeature(CDOID tag)
- {
- EStructuralFeature modelFeature = getFeatureByTag(tag);
-
- ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
- String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType(); //$NON-NLS-1$
-
- tagMap.put(tag, column);
- typeMapping.setDBField(table, column);
- typeMappings.put(tag, typeMapping);
- }
-
- public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
- {
- CDORevision revision = chunkReader.getRevision();
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list chunk values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
- getFeature().getName(), revision);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
- PreparedStatement stmt = null;
- ResultSet resultSet = null;
-
- IStoreChunkReader baseReader = null;
-
- try
- {
- StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
- if (where != null)
- {
- builder.append(" AND "); //$NON-NLS-1$
- builder.append(where);
- }
-
- builder.append(sqlOrderByIndex);
-
- String sql = builder.toString();
- stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
- idHandler.setCDOID(stmt, 1, revision.getID());
- stmt.setInt(2, revision.getBranch().getID());
- stmt.setInt(3, revision.getVersion());
- stmt.setInt(4, revision.getVersion());
-
- resultSet = stmt.executeQuery();
-
- int nextDBIndex = Integer.MAX_VALUE; // next available DB index
- if (resultSet.next())
- {
- nextDBIndex = resultSet.getInt(1);
- }
-
- for (Chunk chunk : chunks)
- {
- int startIndex = chunk.getStartIndex();
- int missingValueStartIndex = -1;
-
- for (int i = 0; i < chunk.size(); i++)
- {
- int nextListIndex = startIndex + i; // next expected list index
-
- if (nextDBIndex == nextListIndex)
- {
- // DB value is available. check first if missing indexes were present before.
- if (missingValueStartIndex != -1)
- {
- // read missing indexes from missingValueStartIndex to currentIndex
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
- chunkReader.getRevision().getBranch().getID());
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, nextListIndex); //$NON-NLS-1$
- }
-
- baseReader.addRangedChunk(missingValueStartIndex, nextListIndex);
-
- // reset missingValueStartIndex
- missingValueStartIndex = -1;
- }
-
- // now read value and set to chunk
- CDOID tag = idHandler.getCDOID(resultSet, 2);
- Object value = getTypeMapping(tag).readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("ChunkReader read value for index {0} from result set: {1}", nextDBIndex, value); //$NON-NLS-1$
- }
-
- chunk.add(i, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
-
- // advance DB cursor and read next available index
- if (resultSet.next())
- {
- nextDBIndex = resultSet.getInt(1);
- }
- else
- {
- // no more DB indexes available, but we have to continue checking for gaps, therefore set to MAX_VALUE
- nextDBIndex = Integer.MAX_VALUE;
- }
- }
- else
- {
- // gap between next DB index and next list index detected.
- // skip until end of chunk or until DB value becomes available
- if (missingValueStartIndex == -1)
- {
- missingValueStartIndex = nextListIndex;
- }
- }
- }
-
- // chunk complete. check for missing values at the end of the chunk.
- if (missingValueStartIndex != -1)
- {
- // read missing indexes from missingValueStartIndex to last chunk index
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
- chunkReader.getRevision().getBranch().getID());
- }
- baseReader.addRangedChunk(missingValueStartIndex, chunk.getStartIndex() + chunk.size());
- }
- }
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- statementCache.releasePreparedStatement(stmt);
- }
-
- // now read missing values from base revision.
- if (baseReader != null)
- {
- List<Chunk> baseChunks = baseReader.executeRead();
-
- Iterator<Chunk> thisIterator = chunks.iterator();
- Chunk thisChunk = thisIterator.next();
-
- for (Chunk baseChunk : baseChunks)
- {
- int baseStartIndex = baseChunk.getStartIndex();
-
- while (baseStartIndex > thisChunk.getStartIndex() + thisChunk.size())
- {
- // advance thisChunk, because it does not match baseChunk
- thisChunk = thisIterator.next();
- }
-
- // baseChunk now corresponds to this chunk, but startIndex of baseChunk may be higher.
- // therefore calculate offset
- int offset = thisChunk.getStartIndex() - baseStartIndex;
-
- // and copy values.
- for (int i = 0; i < baseChunk.size(); i++)
- {
- thisChunk.add(i + offset, baseChunk.get(i));
- }
- } // finally, continue with the next baseChunk
-
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
- getFeature(), revision);
- }
- }
-
- public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
- {
- CDOList values = revision.getList(getFeature());
-
- int idx = 0;
- for (Object element : values)
- {
- writeValue(accessor, revision, idx++, element);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing done"); //$NON-NLS-1$
- }
- }
-
- protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
- {
- if (TRACER.isEnabled())
- {
- TRACER
- .format(
- "Writing value for feature {0}.{1} index {2} of {3} : {4}", getContainingClass().getName(), getFeature(), idx, revision, value); //$NON-NLS-1$
- }
-
- addEntry(accessor, revision.getID(), revision.getBranch().getID(), revision.getVersion(), idx, value,
- revision.getTimeStamp());
- }
-
- /**
- * Get column name (lazy).
- *
- * @param tag
- * The feature's MetaID in CDO
- * @return the column name where the values are stored
- */
- protected String getColumnName(CDOID tag)
- {
- String column = tagMap.get(tag);
- if (column == null)
- {
- addFeature(tag);
- column = tagMap.get(tag);
- }
-
- return column;
- }
-
- /**
- * Get type mapping (lazy).
- *
- * @param tag
- * The feature's MetaID in CDO
- * @return the corresponding type mapping
- */
- protected ITypeMapping getTypeMapping(CDOID tag)
- {
- ITypeMapping typeMapping = typeMappings.get(tag);
- if (typeMapping == null)
- {
- addFeature(tag);
- typeMapping = typeMappings.get(tag);
- }
-
- return typeMapping;
- }
-
- /**
- * @param metaID
- * @return the column name where the values are stored
- */
- private EStructuralFeature getFeatureByTag(CDOID tag)
- {
- return (EStructuralFeature)getMappingStrategy().getStore().getMetaDataManager().getMetaInstance(tag);
- }
-
- /**
- * @param feature
- * The EStructuralFeature
- * @return The feature's MetaID in CDO
- */
- protected CDOID getTagByFeature(EStructuralFeature feature, long created)
- {
- return getMappingStrategy().getStore().getMetaDataManager().getMetaID(feature, created);
- }
-
- /**
- * Clear a list of a given revision.
- *
- * @param accessor
- * the accessor to use
- * @param id
- * the id of the revision from which to remove all items
- */
- public void clearList(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int lastIndex, long timestamp)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmtDeleteTemp = null;
- PreparedStatement stmtClear = null;
-
- try
- {
- // check for each index if the value exists in the current branch
- for (int i = 0; i <= lastIndex; i++)
- {
- if (getValue(accessor, id, branchId, i, false) == null)
- {
- // if not, add a historic entry for missing ones.
- addHistoricEntry(accessor, id, branchId, 0, newVersion, i, getValueFromBase(accessor, id, branchId, i),
- timestamp);
- }
- }
-
- // clear rest of the list
- stmtClear = statementCache.getPreparedStatement(sqlClearList, ReuseProbability.HIGH);
- stmtClear.setInt(1, newVersion);
- idHandler.setCDOID(stmtClear, 2, id);
- stmtClear.setInt(3, branchId);
-
- int result = DBUtil.update(stmtClear, false);
- if (TRACER.isEnabled())
- {
- TRACER.format("ClearList result: {0}", result); //$NON-NLS-1$
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmtDeleteTemp);
- statementCache.releasePreparedStatement(stmtClear);
- }
- }
-
- public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
- {
- InternalCDORevision revision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
- int branchId = accessor.getTransaction().getBranch().getID();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("objectDetached {1}", revision); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchId, revision.getVersion(), FINAL_VERSION, revision.getList(getFeature()).size() - 1,
- revised);
- }
-
- public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion,
- final int newVersion, long created, CDOListFeatureDelta delta)
- {
- List<CDOFeatureDelta> listChanges = delta.getListChanges();
- if (listChanges.size() == 0)
- {
- // nothing to do.
- return;
- }
-
- InternalCDORevision originalRevision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
- int oldListSize = originalRevision.getList(getFeature()).size();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("ListTableMapping.processDelta for revision {0} - previous list size: {1}", originalRevision, //$NON-NLS-1$
- oldListSize);
- }
-
- // let the visitor collect the changes
- ListDeltaVisitor visitor = new ListDeltaVisitor(accessor, originalRevision, branchId, oldVersion, newVersion,
- created);
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Processing deltas..."); //$NON-NLS-1$
- }
-
- // optimization: it's only necessary to process deltas
- // starting with the last feature delta which clears the list
- // (any operation before the clear is cascaded by it anyway)
- int index = listChanges.size() - 1;
- while (index > 0)
- {
- CDOFeatureDelta listDelta = listChanges.get(index);
- if (listDelta instanceof CDOClearFeatureDelta || listDelta instanceof CDOUnsetFeatureDelta)
- {
- break;
- }
- index--;
- }
- while (index < listChanges.size())
- {
- listChanges.get(index++).accept(visitor);
- }
- }
-
- private class ListDeltaVisitor implements CDOFeatureDeltaVisitor
- {
- private IDBStoreAccessor accessor;
-
- private InternalCDORevision originalRevision;
-
- private CDOID id;
-
- private int branchID;
-
- private int oldVersion;
-
- private int newVersion;
-
- private int lastIndex;
-
- private long timestamp;
-
- public ListDeltaVisitor(IDBStoreAccessor accessor, InternalCDORevision originalRevision, int targetBranchID,
- int oldVersion, int newVersion, long timestamp)
- {
- this.accessor = accessor;
- this.originalRevision = originalRevision;
- id = this.originalRevision.getID();
- branchID = targetBranchID;
- this.oldVersion = oldVersion;
- this.newVersion = newVersion;
- lastIndex = originalRevision.getList(getFeature()).size() - 1;
- this.timestamp = timestamp;
- }
-
- public void visit(CDOMoveFeatureDelta delta)
- {
- int fromIdx = delta.getOldPosition();
- int toIdx = delta.getNewPosition();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Moving: {0} to {1}", fromIdx, toIdx); //$NON-NLS-1$
- }
-
- Object value = getValue(accessor, id, branchID, fromIdx, true);
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, fromIdx, timestamp);
-
- // adjust indexes and shift either up or down
- if (fromIdx < toIdx)
- {
- moveOneUp(accessor, id, branchID, oldVersion, newVersion, fromIdx + 1, toIdx);
- }
- else
- { // fromIdx > toIdx here
- moveOneDown(accessor, id, branchID, oldVersion, newVersion, toIdx, fromIdx - 1);
- }
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, toIdx, value, timestamp);
- }
-
- public void visit(CDOAddFeatureDelta delta)
- {
- int startIndex = delta.getIndex();
- int endIndex = lastIndex;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Adding at: {0}", startIndex); //$NON-NLS-1$
- }
-
- if (startIndex <= endIndex)
- {
- // make room for the new item
- moveOneDown(accessor, id, branchID, oldVersion, newVersion, startIndex, endIndex);
- }
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, startIndex, delta.getValue(), timestamp);
-
- ++lastIndex;
- }
-
- public void visit(CDORemoveFeatureDelta delta)
- {
- int startIndex = delta.getIndex();
- int endIndex = lastIndex;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Removing at: {0}", startIndex); //$NON-NLS-1$
- }
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, startIndex, timestamp);
-
- // make room for the new item
- moveOneUp(accessor, id, branchID, oldVersion, newVersion, startIndex + 1, endIndex);
-
- --lastIndex;
- }
-
- public void visit(CDOSetFeatureDelta delta)
- {
- int index = delta.getIndex();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Setting at: {0}", index); //$NON-NLS-1$
- }
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, index, timestamp);
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, index, delta.getValue(), timestamp);
- }
-
- public void visit(CDOUnsetFeatureDelta delta)
- {
- if (delta.getFeature().isUnsettable())
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Unsetting"); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex, timestamp);
- lastIndex = -1;
- }
-
- public void visit(CDOListFeatureDelta delta)
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- public void visit(CDOClearFeatureDelta delta)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Clearing"); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex, timestamp);
- lastIndex = -1;
- }
-
- public void visit(CDOContainerFeatureDelta delta)
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- private void moveOneUp(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int startIndex, int endIndex)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
-
- for (int index = startIndex; index <= endIndex; ++index)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp moving: {0} -> {1}", index, index - 1); //$NON-NLS-1$
- }
-
- int column = 1;
- stmt.setInt(column++, index - 1);
- idHandler.setCDOID(stmt, startIndex++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, newVersion);
- stmt.setInt(column++, index);
-
- int result = DBUtil.update(stmt, false);
- switch (result)
- {
- case 1:
- // entry for current revision was already present.
- // index update succeeded.
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp updated: {0} -> {1}", index, index - 1); //$NON-NLS-1$
- }
-
- break;
- case 0:
- Object value = getValue(accessor, id, branchId, index, false);
-
- if (value != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp remove: {0}", index); //$NON-NLS-1$
- }
-
- removeEntry(accessor, id, branchId, oldVersion, newVersion, index, timestamp);
- }
- else
- {
- value = getValueFromBase(accessor, id, branchId, index);
- {
- TRACER.format("moveOneUp add historic entry at: {0}", index); //$NON-NLS-1$
- }
-
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp add: {0}", index - 1); //$NON-NLS-1$
- }
-
- addEntry(accessor, id, branchId, newVersion, index - 1, value, timestamp);
- break;
- default:
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void moveOneDown(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int startIndex, int endIndex)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
- for (int index = endIndex; index >= startIndex; --index)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown moving: {0} -> {1}", index, index + 1); //$NON-NLS-1$
- }
-
- int column = 1;
- stmt.setInt(column++, index + 1);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, newVersion);
- stmt.setInt(column++, index);
-
- int result = DBUtil.update(stmt, false);
- switch (result)
- {
- case 1:
- // entry for current revision was already present.
- // index update succeeded.
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown updated: {0} -> {1}", index, index + 1); //$NON-NLS-1$
- }
-
- break;
- case 0:
- Object value = getValue(accessor, id, branchId, index, false);
- if (value != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown remove: {0}", index); //$NON-NLS-1$
- }
-
- removeEntry(accessor, id, branchId, oldVersion, newVersion, index, timestamp);
- }
- else
- {
- value = getValueFromBase(accessor, id, branchId, index);
- {
- TRACER.format("moveOneDown add historic entry at: {0}", index); //$NON-NLS-1$
- }
-
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
- }
-
- addEntry(accessor, id, branchId, newVersion, index + 1, value, timestamp);
- break;
- default:
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
- }
-
- private void addEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int version, int index, Object value,
- long timestamp)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, version, value);
- }
-
- try
- {
- FeatureMap.Entry entry = (FeatureMap.Entry)value;
- EStructuralFeature entryFeature = entry.getEStructuralFeature();
- CDOID tag = getTagByFeature(entryFeature, timestamp);
- String columnName = getColumnName(tag);
-
- stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, version);
- stmt.setNull(column++, DBType.INTEGER.getCode()); // versionRemoved
- stmt.setInt(column++, index);
- idHandler.setCDOID(stmt, column++, tag);
-
- for (int i = 0; i < columnNames.size(); i++)
- {
- if (columnNames.get(i).equals(columnName))
- {
- getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
- }
- else
- {
- stmt.setNull(column++, getDBTypes().get(i).getCode());
- }
- }
-
- DBUtil.update(stmt, true);
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void addHistoricEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int versionAdded,
- int versionRemoved, int index, Object value, long timestamp)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "Adding historic value for feature {0}.{1} index {2} of {3}:{4}v{5}-v{6} : {7}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, versionAdded, versionRemoved,
- value);
- }
-
- try
- {
- FeatureMap.Entry entry = (FeatureMap.Entry)value;
- EStructuralFeature entryFeature = entry.getEStructuralFeature();
- CDOID tag = getTagByFeature(entryFeature, timestamp);
- String columnName = getColumnName(tag);
-
- stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, versionAdded);
- stmt.setNull(column++, versionRemoved);
- stmt.setInt(column++, index);
- idHandler.setCDOID(stmt, column++, tag);
-
- for (int i = 0; i < columnNames.size(); i++)
- {
- if (columnNames.get(i).equals(columnName))
- {
- getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
- }
- else
- {
- stmt.setNull(column++, getDBTypes().get(i).getCode());
- }
- }
-
- DBUtil.update(stmt, true);
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void removeEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int index, long timestamp)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion);
- }
-
- try
- {
- // try to delete a temporary entry first
- stmt = statementCache.getPreparedStatement(sqlDeleteEntry, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
- stmt.setInt(column++, newVersion);
-
- int result = DBUtil.update(stmt, false);
- if (result == 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
- }
- }
- else if (result > 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- else
- {
- // no temporary entry found, so mark the entry as removed
- statementCache.releasePreparedStatement(stmt);
- stmt = statementCache.getPreparedStatement(sqlRemoveEntry, ReuseProbability.HIGH);
-
- column = 1;
- stmt.setInt(column++, newVersion);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
- result = DBUtil.update(stmt, false);
-
- if (result == 0)
- {
- // no entry removed -> this means that we are in a branch and
- // the entry has not been modified since the branch fork.
- // therefore, we have to copy the base value and mark it as removed
- Object value = getValueFromBase(accessor, id, branchId, index);
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
- }
- }
- }
- catch (SQLException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private FeatureMap.Entry getValue(IDBStoreAccessor accessor, CDOID id, int branchId, int index, boolean getFromBase)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
- FeatureMap.Entry result = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlGetValue, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
-
- ResultSet resultSet = stmt.executeQuery();
- if (resultSet.next())
- {
- CDOID tag = idHandler.getCDOID(resultSet, 1);
- Object value = getTypeMapping(tag).readValue(resultSet);
- result = CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value);
- }
- else
- {
- // value is not in this branch.
- // -> read from base revision
- if (getFromBase)
- {
- result = getValueFromBase(accessor, id, branchId, index);
- } // else: result remains null
- }
- if (TRACER.isEnabled())
- {
- TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
-
- return result;
- }
-
- /**
- * Read a single value (at a given index) from the base revision
- *
- * @param accessor
- * the DBStoreAccessor
- * @param id
- * the ID of the revision
- * @param branchID
- * the ID of the current (child) branch
- * @param index
- * the index to read the value from
- * @return the value which is at index <code>index</code> in revision with ID <code>id</code> in the parent branch at
- * the base of this branch (indicated by <code>branchID</code>).
- */
- private FeatureMap.Entry getValueFromBase(IDBStoreAccessor accessor, CDOID id, int branchID, int index)
- {
- IStoreChunkReader chunkReader = createBaseChunkReader(accessor, id, branchID);
- chunkReader.addSimpleChunk(index);
- List<Chunk> chunks = chunkReader.executeRead();
- return (FeatureMap.Entry)chunks.get(0).get(0);
- }
-
- private IStoreChunkReader createBaseChunkReader(IDBStoreAccessor accessor, CDOID id, int branchID)
- {
- CDOBranchPoint base = accessor.getStore().getRepository().getBranchManager().getBranch(branchID).getBase();
- InternalCDORevision baseRevision = (InternalCDORevision)accessor.getStore().getRepository().getRevisionManager()
- .getRevision(id, base, /* referenceChunk = */0, /* prefetchDepth = */CDORevision.DEPTH_NONE, true);
- IStoreChunkReader chunkReader = accessor.createChunkReader(baseRevision, getFeature());
- return chunkReader;
- }
-
- public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
- QueryXRefsContext context, String idString)
- {
- // must never be called (a feature map is not associated with an EReference feature, so XRefs are nor supported
- // here)
- throw new ImplementationError("Should never be called!");
- }
-}
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Winkler - initial API and implementation taken from AuditFeatureMapTableMappingWithRanges
+ * Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This is a featuremap-table mapping for audit mode. It is optimized for frequent insert operations at the list's end,
+ * which causes just 1 DB row to be changed. This is achieved by introducing a version range (columns
+ * {@link CDODBSchema#LIST_REVISION_VERSION_ADDED cdo_version_added} and
+ * {@link CDODBSchema#LIST_REVISION_VERSION_REMOVED cdo_version_removed}) which records for which revisions a particular
+ * entry existed. Also, this mapping is mainly optimized for potentially very large lists: the need for having the
+ * complete list stored in memory to do in-the-middle-moved and inserts is traded in for a few more DB access
+ * operations.
+ *
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @author Lothar Werzinger
+ * @since 3.0
+ */
+public class BranchingFeatureMapTableMappingWithRanges extends BasicAbstractListTableMapping implements
+ IListMappingDeltaSupport
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG,
+ BranchingFeatureMapTableMappingWithRanges.class);
+
+ /**
+ * Used to clean up lists for detached objects.
+ */
+ private static final int FINAL_VERSION = Integer.MAX_VALUE;
+
+ /**
+ * The table of this mapping.
+ */
+ private IDBTable table;
+
+ /**
+ * The tags mapped to column names
+ */
+ private HashMap<CDOID, String> tagMap;
+
+ /**
+ * Column name Set
+ */
+ private List<String> columnNames;
+
+ /**
+ * The type mappings for the value fields.
+ */
+ private Map<CDOID, ITypeMapping> typeMappings;
+
+ private List<DBType> dbTypes;
+
+ // --------- SQL strings - see initSQLStrings() -----------------
+ private String sqlSelectChunksPrefix;
+
+ private String sqlOrderByIndex;
+
+ private String sqlInsert;
+
+ private String sqlRemoveEntry;
+
+ private String sqlDeleteEntry;
+
+ private String sqlUpdateIndex;
+
+ private String sqlGetValue;
+
+ private String sqlClearList;
+
+ public BranchingFeatureMapTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass,
+ EStructuralFeature feature)
+ {
+ super(mappingStrategy, eClass, feature);
+ initDBTypes();
+ initTable();
+ initSQLStrings();
+ }
+
+ private void initDBTypes()
+ {
+ // TODO add annotation processing here ...
+ ITypeMapping.Registry registry = ITypeMapping.Registry.INSTANCE;
+ dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes());
+ }
+
+ private void initTable()
+ {
+ IDBStore store = getMappingStrategy().getStore();
+ String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+ table = store.getDBSchema().addTable(tableName);
+
+ // add fields for CDOID
+ IDBField idField = table.addField(CDODBSchema.FEATUREMAP_REVISION_ID, store.getIDHandler().getDBType());
+
+ IDBField branchField = table.addField(CDODBSchema.LIST_REVISION_BRANCH, DBType.INTEGER);
+
+ // add fields for version range
+ IDBField versionAddedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_ADDED, DBType.INTEGER);
+ IDBField versionRemovedField = table.addField(CDODBSchema.FEATUREMAP_VERSION_REMOVED, DBType.INTEGER);
+
+ // add field for list index
+ IDBField idxField = table.addField(CDODBSchema.FEATUREMAP_IDX, DBType.INTEGER);
+
+ // add field for FeatureMap tag (MetaID for Feature in CDO registry)
+ IDBField tagField = table.addField(CDODBSchema.FEATUREMAP_TAG, store.getIDHandler().getDBType());
+
+ tagMap = new HashMap<CDOID, String>();
+ typeMappings = new HashMap<CDOID, ITypeMapping>();
+ columnNames = new ArrayList<String>();
+
+ // create columns for all DBTypes
+ for (DBType type : getDBTypes())
+ {
+ String column = CDODBSchema.FEATUREMAP_VALUE + "_" + type.name();
+ table.addField(column, type);
+ columnNames.add(column);
+ }
+
+ table.addIndex(Type.NON_UNIQUE, idField);
+ table.addIndex(Type.NON_UNIQUE, branchField);
+ table.addIndex(Type.NON_UNIQUE, versionAddedField);
+ table.addIndex(Type.NON_UNIQUE, versionRemovedField);
+ table.addIndex(Type.NON_UNIQUE, idxField);
+ table.addIndex(Type.NON_UNIQUE, tagField);
+ }
+
+ public Collection<IDBTable> getDBTables()
+ {
+ return Arrays.asList(table);
+ }
+
+ private void initSQLStrings()
+ {
+ String tableName = getTable().getName();
+
+ // ---------------- SELECT to read chunks ----------------------------
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT "); //$NON-NLS-1$
+
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append(", "); //$NON-NLS-1$
+
+ Iterator<String> iter = columnNames.iterator();
+ while (iter.hasNext())
+ {
+ builder.append(iter.next());
+ if (iter.hasNext())
+ {
+ builder.append(", "); //$NON-NLS-1$
+ }
+ }
+
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append("<=? AND ("); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL OR "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(">?)"); //$NON-NLS-1$
+ sqlSelectChunksPrefix = builder.toString();
+
+ sqlOrderByIndex = " ORDER BY " + CDODBSchema.FEATUREMAP_IDX; //$NON-NLS-1$
+
+ // ----------------- INSERT - prefix -----------------
+ builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append("("); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(columnNames.get(i));
+ }
+
+ builder.append(") VALUES (?, ?, ?, ?, ?, ?"); //$NON-NLS-1$
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ builder.append(", ?"); //$NON-NLS-1$
+ }
+
+ builder.append(")"); //$NON-NLS-1$
+ sqlInsert = builder.toString();
+
+ // ----------------- remove current entry -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append("=? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlRemoveEntry = builder.toString();
+
+ // ----------------- delete temporary entry -----------------
+ builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append("=?"); //$NON-NLS-1$
+ sqlDeleteEntry = builder.toString();
+
+ // ----------------- update index -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_ADDED);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=?"); //$NON-NLS-1$
+ sqlUpdateIndex = builder.toString();
+
+ // ----------------- get current value -----------------
+ builder = new StringBuilder("SELECT "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append(", "); //$NON-NLS-1$
+
+ iter = columnNames.iterator();
+ while (iter.hasNext())
+ {
+ builder.append(iter.next());
+ if (iter.hasNext())
+ {
+ builder.append(", "); //$NON-NLS-1$
+ }
+ }
+
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlGetValue = builder.toString();
+
+ // ----------- clear list items -------------------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append("=? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlClearList = builder.toString();
+ }
+
+ protected List<DBType> getDBTypes()
+ {
+ return dbTypes;
+ }
+
+ protected final IDBTable getTable()
+ {
+ return table;
+ }
+
+ protected final List<String> getColumnNames()
+ {
+ return columnNames;
+ }
+
+ protected final Map<CDOID, ITypeMapping> getTypeMappings()
+ {
+ return typeMappings;
+ }
+
+ protected final Map<CDOID, String> getTagMap()
+ {
+ return tagMap;
+ }
+
+ public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
+ {
+ MoveableList<Object> list = revision.getList(getFeature());
+ int valuesToRead = list.size();
+
+ if (listChunk != CDORevision.UNCHUNKED && listChunk < valuesToRead)
+ {
+ valuesToRead = listChunk;
+ }
+
+ if (valuesToRead == 0)
+ {
+ // nothing to read take shortcut
+ return;
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list values for feature {0}.{1} of {2}", getContainingClass().getName(), getFeature() //$NON-NLS-1$
+ .getName(), revision);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+ ResultSet resultSet = null;
+
+ IStoreChunkReader baseReader = null;
+
+ try
+ {
+ String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+
+ CDOID id = revision.getID();
+ int branchID = revision.getBranch().getID();
+
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, branchID);
+ stmt.setInt(3, revision.getVersion());
+ stmt.setInt(4, revision.getVersion());
+
+ stmt.setMaxRows(valuesToRead); // optimization - don't read unneeded rows.
+
+ resultSet = stmt.executeQuery();
+
+ int currentIndex = 0;
+
+ while (valuesToRead > 0 && resultSet.next())
+ {
+ int index = resultSet.getInt(1);
+ if (index > currentIndex)
+ {
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(accessor, id, branchID);
+ }
+
+ baseReader.addRangedChunk(currentIndex, index);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Scheduling range {0}-{1} to be read from base revision", currentIndex, index); //$NON-NLS-1$
+ }
+
+ valuesToRead -= index - currentIndex;
+ currentIndex = index;
+ }
+
+ CDOID tag = idHandler.getCDOID(resultSet, 2);
+ Object value = getTypeMapping(tag).readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Read value for index {0} from result set: {1}", currentIndex, value); //$NON-NLS-1$
+ }
+
+ list.set(currentIndex++, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+ valuesToRead--;
+ }
+
+ if (valuesToRead > 0)
+ {
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(accessor, id, branchID);
+ }
+
+ baseReader.addRangedChunk(currentIndex, currentIndex + valuesToRead);
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ if (baseReader != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading base revision chunks for featureMap {0}.{1} of {2} from base revision {3}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), revision, baseReader.getRevision());
+ }
+
+ List<Chunk> baseChunks = baseReader.executeRead();
+ for (Chunk chunk : baseChunks)
+ {
+ int startIndex = chunk.getStartIndex();
+ for (int i = 0; i < chunk.size(); i++)
+ {
+ list.set(startIndex + i, chunk.get(i));
+ }
+ }
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list values done for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision);
+ }
+ }
+
+ private void addFeature(CDOID tag)
+ {
+ EStructuralFeature modelFeature = getFeatureByTag(tag);
+
+ ITypeMapping typeMapping = getMappingStrategy().createValueMapping(modelFeature);
+ String column = CDODBSchema.FEATUREMAP_VALUE + "_" + typeMapping.getDBType(); //$NON-NLS-1$
+
+ tagMap.put(tag, column);
+ typeMapping.setDBField(table, column);
+ typeMappings.put(tag, typeMapping);
+ }
+
+ public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
+ {
+ CDORevision revision = chunkReader.getRevision();
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list chunk values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
+ PreparedStatement stmt = null;
+ ResultSet resultSet = null;
+
+ IStoreChunkReader baseReader = null;
+
+ try
+ {
+ StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
+ if (where != null)
+ {
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(where);
+ }
+
+ builder.append(sqlOrderByIndex);
+
+ String sql = builder.toString();
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
+ idHandler.setCDOID(stmt, 1, revision.getID());
+ stmt.setInt(2, revision.getBranch().getID());
+ stmt.setInt(3, revision.getVersion());
+ stmt.setInt(4, revision.getVersion());
+
+ resultSet = stmt.executeQuery();
+
+ int nextDBIndex = Integer.MAX_VALUE; // next available DB index
+ if (resultSet.next())
+ {
+ nextDBIndex = resultSet.getInt(1);
+ }
+
+ for (Chunk chunk : chunks)
+ {
+ int startIndex = chunk.getStartIndex();
+ int missingValueStartIndex = -1;
+
+ for (int i = 0; i < chunk.size(); i++)
+ {
+ int nextListIndex = startIndex + i; // next expected list index
+
+ if (nextDBIndex == nextListIndex)
+ {
+ // DB value is available. check first if missing indexes were present before.
+ if (missingValueStartIndex != -1)
+ {
+ // read missing indexes from missingValueStartIndex to currentIndex
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
+ chunkReader.getRevision().getBranch().getID());
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, nextListIndex); //$NON-NLS-1$
+ }
+
+ baseReader.addRangedChunk(missingValueStartIndex, nextListIndex);
+
+ // reset missingValueStartIndex
+ missingValueStartIndex = -1;
+ }
+
+ // now read value and set to chunk
+ CDOID tag = idHandler.getCDOID(resultSet, 2);
+ Object value = getTypeMapping(tag).readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ChunkReader read value for index {0} from result set: {1}", nextDBIndex, value); //$NON-NLS-1$
+ }
+
+ chunk.add(i, CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value));
+
+ // advance DB cursor and read next available index
+ if (resultSet.next())
+ {
+ nextDBIndex = resultSet.getInt(1);
+ }
+ else
+ {
+ // no more DB indexes available, but we have to continue checking for gaps, therefore set to MAX_VALUE
+ nextDBIndex = Integer.MAX_VALUE;
+ }
+ }
+ else
+ {
+ // gap between next DB index and next list index detected.
+ // skip until end of chunk or until DB value becomes available
+ if (missingValueStartIndex == -1)
+ {
+ missingValueStartIndex = nextListIndex;
+ }
+ }
+ }
+
+ // chunk complete. check for missing values at the end of the chunk.
+ if (missingValueStartIndex != -1)
+ {
+ // read missing indexes from missingValueStartIndex to last chunk index
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
+ chunkReader.getRevision().getBranch().getID());
+ }
+ baseReader.addRangedChunk(missingValueStartIndex, chunk.getStartIndex() + chunk.size());
+ }
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ // now read missing values from base revision.
+ if (baseReader != null)
+ {
+ List<Chunk> baseChunks = baseReader.executeRead();
+
+ Iterator<Chunk> thisIterator = chunks.iterator();
+ Chunk thisChunk = thisIterator.next();
+
+ for (Chunk baseChunk : baseChunks)
+ {
+ int baseStartIndex = baseChunk.getStartIndex();
+
+ while (baseStartIndex > thisChunk.getStartIndex() + thisChunk.size())
+ {
+ // advance thisChunk, because it does not match baseChunk
+ thisChunk = thisIterator.next();
+ }
+
+ // baseChunk now corresponds to this chunk, but startIndex of baseChunk may be higher.
+ // therefore calculate offset
+ int offset = thisChunk.getStartIndex() - baseStartIndex;
+
+ // and copy values.
+ for (int i = 0; i < baseChunk.size(); i++)
+ {
+ thisChunk.add(i + offset, baseChunk.get(i));
+ }
+ } // finally, continue with the next baseChunk
+
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature(), revision);
+ }
+ }
+
+ public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
+ {
+ CDOList values = revision.getList(getFeature());
+
+ int idx = 0;
+ for (Object element : values)
+ {
+ writeValue(accessor, revision, idx++, element);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Writing done"); //$NON-NLS-1$
+ }
+ }
+
+ protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER
+ .format(
+ "Writing value for feature {0}.{1} index {2} of {3} : {4}", getContainingClass().getName(), getFeature(), idx, revision, value); //$NON-NLS-1$
+ }
+
+ addEntry(accessor, revision.getID(), revision.getBranch().getID(), revision.getVersion(), idx, value,
+ revision.getTimeStamp());
+ }
+
+ /**
+ * Get column name (lazy).
+ *
+ * @param tag
+ * The feature's MetaID in CDO
+ * @return the column name where the values are stored
+ */
+ protected String getColumnName(CDOID tag)
+ {
+ String column = tagMap.get(tag);
+ if (column == null)
+ {
+ addFeature(tag);
+ column = tagMap.get(tag);
+ }
+
+ return column;
+ }
+
+ /**
+ * Get type mapping (lazy).
+ *
+ * @param tag
+ * The feature's MetaID in CDO
+ * @return the corresponding type mapping
+ */
+ protected ITypeMapping getTypeMapping(CDOID tag)
+ {
+ ITypeMapping typeMapping = typeMappings.get(tag);
+ if (typeMapping == null)
+ {
+ addFeature(tag);
+ typeMapping = typeMappings.get(tag);
+ }
+
+ return typeMapping;
+ }
+
+ /**
+ * @param metaID
+ * @return the column name where the values are stored
+ */
+ private EStructuralFeature getFeatureByTag(CDOID tag)
+ {
+ return (EStructuralFeature)getMappingStrategy().getStore().getMetaDataManager().getMetaInstance(tag);
+ }
+
+ /**
+ * @param feature
+ * The EStructuralFeature
+ * @return The feature's MetaID in CDO
+ */
+ protected CDOID getTagByFeature(EStructuralFeature feature, long created)
+ {
+ return getMappingStrategy().getStore().getMetaDataManager().getMetaID(feature, created);
+ }
+
+ /**
+ * Clear a list of a given revision.
+ *
+ * @param accessor
+ * the accessor to use
+ * @param id
+ * the id of the revision from which to remove all items
+ */
+ public void clearList(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int lastIndex, long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmtDeleteTemp = null;
+ PreparedStatement stmtClear = null;
+
+ try
+ {
+ // check for each index if the value exists in the current branch
+ for (int i = 0; i <= lastIndex; i++)
+ {
+ if (getValue(accessor, id, branchId, i, false) == null)
+ {
+ // if not, add a historic entry for missing ones.
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, i, getValueFromBase(accessor, id, branchId, i),
+ timestamp);
+ }
+ }
+
+ // clear rest of the list
+ stmtClear = statementCache.getPreparedStatement(sqlClearList, ReuseProbability.HIGH);
+ stmtClear.setInt(1, newVersion);
+ idHandler.setCDOID(stmtClear, 2, id);
+ stmtClear.setInt(3, branchId);
+
+ int result = DBUtil.update(stmtClear, false);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ClearList result: {0}", result); //$NON-NLS-1$
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmtDeleteTemp);
+ statementCache.releasePreparedStatement(stmtClear);
+ }
+ }
+
+ public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
+ {
+ InternalCDORevision revision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
+ int branchId = accessor.getTransaction().getBranch().getID();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("objectDetached {1}", revision); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchId, revision.getVersion(), FINAL_VERSION, revision.getList(getFeature()).size() - 1,
+ revised);
+ }
+
+ public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion,
+ final int newVersion, long created, CDOListFeatureDelta delta)
+ {
+ List<CDOFeatureDelta> listChanges = delta.getListChanges();
+ if (listChanges.size() == 0)
+ {
+ // nothing to do.
+ return;
+ }
+
+ InternalCDORevision originalRevision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
+ int oldListSize = originalRevision.getList(getFeature()).size();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ListTableMapping.processDelta for revision {0} - previous list size: {1}", originalRevision, //$NON-NLS-1$
+ oldListSize);
+ }
+
+ // let the visitor collect the changes
+ ListDeltaVisitor visitor = new ListDeltaVisitor(accessor, originalRevision, branchId, oldVersion, newVersion,
+ created);
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Processing deltas..."); //$NON-NLS-1$
+ }
+
+ // optimization: it's only necessary to process deltas
+ // starting with the last feature delta which clears the list
+ // (any operation before the clear is cascaded by it anyway)
+ int index = listChanges.size() - 1;
+ while (index > 0)
+ {
+ CDOFeatureDelta listDelta = listChanges.get(index);
+ if (listDelta instanceof CDOClearFeatureDelta || listDelta instanceof CDOUnsetFeatureDelta)
+ {
+ break;
+ }
+ index--;
+ }
+ while (index < listChanges.size())
+ {
+ listChanges.get(index++).accept(visitor);
+ }
+ }
+
+ private class ListDeltaVisitor implements CDOFeatureDeltaVisitor
+ {
+ private IDBStoreAccessor accessor;
+
+ private InternalCDORevision originalRevision;
+
+ private CDOID id;
+
+ private int branchID;
+
+ private int oldVersion;
+
+ private int newVersion;
+
+ private int lastIndex;
+
+ private long timestamp;
+
+ public ListDeltaVisitor(IDBStoreAccessor accessor, InternalCDORevision originalRevision, int targetBranchID,
+ int oldVersion, int newVersion, long timestamp)
+ {
+ this.accessor = accessor;
+ this.originalRevision = originalRevision;
+ id = this.originalRevision.getID();
+ branchID = targetBranchID;
+ this.oldVersion = oldVersion;
+ this.newVersion = newVersion;
+ lastIndex = originalRevision.getList(getFeature()).size() - 1;
+ this.timestamp = timestamp;
+ }
+
+ public void visit(CDOMoveFeatureDelta delta)
+ {
+ int fromIdx = delta.getOldPosition();
+ int toIdx = delta.getNewPosition();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Moving: {0} to {1}", fromIdx, toIdx); //$NON-NLS-1$
+ }
+
+ Object value = getValue(accessor, id, branchID, fromIdx, true);
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, fromIdx, timestamp);
+
+ // adjust indexes and shift either up or down
+ if (fromIdx < toIdx)
+ {
+ moveOneUp(accessor, id, branchID, oldVersion, newVersion, fromIdx + 1, toIdx);
+ }
+ else
+ { // fromIdx > toIdx here
+ moveOneDown(accessor, id, branchID, oldVersion, newVersion, toIdx, fromIdx - 1);
+ }
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, toIdx, value, timestamp);
+ }
+
+ public void visit(CDOAddFeatureDelta delta)
+ {
+ int startIndex = delta.getIndex();
+ int endIndex = lastIndex;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Adding at: {0}", startIndex); //$NON-NLS-1$
+ }
+
+ if (startIndex <= endIndex)
+ {
+ // make room for the new item
+ moveOneDown(accessor, id, branchID, oldVersion, newVersion, startIndex, endIndex);
+ }
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, startIndex, delta.getValue(), timestamp);
+
+ ++lastIndex;
+ }
+
+ public void visit(CDORemoveFeatureDelta delta)
+ {
+ int startIndex = delta.getIndex();
+ int endIndex = lastIndex;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Removing at: {0}", startIndex); //$NON-NLS-1$
+ }
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, startIndex, timestamp);
+
+ // make room for the new item
+ moveOneUp(accessor, id, branchID, oldVersion, newVersion, startIndex + 1, endIndex);
+
+ --lastIndex;
+ }
+
+ public void visit(CDOSetFeatureDelta delta)
+ {
+ int index = delta.getIndex();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Setting at: {0}", index); //$NON-NLS-1$
+ }
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, index, timestamp);
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, index, delta.getValue(), timestamp);
+ }
+
+ public void visit(CDOUnsetFeatureDelta delta)
+ {
+ if (delta.getFeature().isUnsettable())
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Unsetting"); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex, timestamp);
+ lastIndex = -1;
+ }
+
+ public void visit(CDOListFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ public void visit(CDOClearFeatureDelta delta)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Clearing"); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex, timestamp);
+ lastIndex = -1;
+ }
+
+ public void visit(CDOContainerFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ private void moveOneUp(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int startIndex, int endIndex)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
+
+ for (int index = startIndex; index <= endIndex; ++index)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp moving: {0} -> {1}", index, index - 1); //$NON-NLS-1$
+ }
+
+ int column = 1;
+ stmt.setInt(column++, index - 1);
+ idHandler.setCDOID(stmt, startIndex++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, newVersion);
+ stmt.setInt(column++, index);
+
+ int result = DBUtil.update(stmt, false);
+ switch (result)
+ {
+ case 1:
+ // entry for current revision was already present.
+ // index update succeeded.
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp updated: {0} -> {1}", index, index - 1); //$NON-NLS-1$
+ }
+
+ break;
+ case 0:
+ Object value = getValue(accessor, id, branchId, index, false);
+
+ if (value != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp remove: {0}", index); //$NON-NLS-1$
+ }
+
+ removeEntry(accessor, id, branchId, oldVersion, newVersion, index, timestamp);
+ }
+ else
+ {
+ value = getValueFromBase(accessor, id, branchId, index);
+ {
+ TRACER.format("moveOneUp add historic entry at: {0}", index); //$NON-NLS-1$
+ }
+
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp add: {0}", index - 1); //$NON-NLS-1$
+ }
+
+ addEntry(accessor, id, branchId, newVersion, index - 1, value, timestamp);
+ break;
+ default:
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void moveOneDown(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int startIndex, int endIndex)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
+ for (int index = endIndex; index >= startIndex; --index)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown moving: {0} -> {1}", index, index + 1); //$NON-NLS-1$
+ }
+
+ int column = 1;
+ stmt.setInt(column++, index + 1);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, newVersion);
+ stmt.setInt(column++, index);
+
+ int result = DBUtil.update(stmt, false);
+ switch (result)
+ {
+ case 1:
+ // entry for current revision was already present.
+ // index update succeeded.
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown updated: {0} -> {1}", index, index + 1); //$NON-NLS-1$
+ }
+
+ break;
+ case 0:
+ Object value = getValue(accessor, id, branchId, index, false);
+ if (value != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown remove: {0}", index); //$NON-NLS-1$
+ }
+
+ removeEntry(accessor, id, branchId, oldVersion, newVersion, index, timestamp);
+ }
+ else
+ {
+ value = getValueFromBase(accessor, id, branchId, index);
+ {
+ TRACER.format("moveOneDown add historic entry at: {0}", index); //$NON-NLS-1$
+ }
+
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
+ }
+
+ addEntry(accessor, id, branchId, newVersion, index + 1, value, timestamp);
+ break;
+ default:
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+ }
+
+ private void addEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int version, int index, Object value,
+ long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, version, value);
+ }
+
+ try
+ {
+ FeatureMap.Entry entry = (FeatureMap.Entry)value;
+ EStructuralFeature entryFeature = entry.getEStructuralFeature();
+ CDOID tag = getTagByFeature(entryFeature, timestamp);
+ String columnName = getColumnName(tag);
+
+ stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, version);
+ stmt.setNull(column++, DBType.INTEGER.getCode()); // versionRemoved
+ stmt.setInt(column++, index);
+ idHandler.setCDOID(stmt, column++, tag);
+
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ if (columnNames.get(i).equals(columnName))
+ {
+ getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
+ }
+ else
+ {
+ stmt.setNull(column++, getDBTypes().get(i).getCode());
+ }
+ }
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void addHistoricEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int versionAdded,
+ int versionRemoved, int index, Object value, long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "Adding historic value for feature {0}.{1} index {2} of {3}:{4}v{5}-v{6} : {7}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, versionAdded, versionRemoved,
+ value);
+ }
+
+ try
+ {
+ FeatureMap.Entry entry = (FeatureMap.Entry)value;
+ EStructuralFeature entryFeature = entry.getEStructuralFeature();
+ CDOID tag = getTagByFeature(entryFeature, timestamp);
+ String columnName = getColumnName(tag);
+
+ stmt = statementCache.getPreparedStatement(sqlInsert, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, versionAdded);
+ stmt.setNull(column++, versionRemoved);
+ stmt.setInt(column++, index);
+ idHandler.setCDOID(stmt, column++, tag);
+
+ for (int i = 0; i < columnNames.size(); i++)
+ {
+ if (columnNames.get(i).equals(columnName))
+ {
+ getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
+ }
+ else
+ {
+ stmt.setNull(column++, getDBTypes().get(i).getCode());
+ }
+ }
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void removeEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int index, long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion);
+ }
+
+ try
+ {
+ // try to delete a temporary entry first
+ stmt = statementCache.getPreparedStatement(sqlDeleteEntry, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+ stmt.setInt(column++, newVersion);
+
+ int result = DBUtil.update(stmt, false);
+ if (result == 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
+ }
+ }
+ else if (result > 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ else
+ {
+ // no temporary entry found, so mark the entry as removed
+ statementCache.releasePreparedStatement(stmt);
+ stmt = statementCache.getPreparedStatement(sqlRemoveEntry, ReuseProbability.HIGH);
+
+ column = 1;
+ stmt.setInt(column++, newVersion);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+ result = DBUtil.update(stmt, false);
+
+ if (result == 0)
+ {
+ // no entry removed -> this means that we are in a branch and
+ // the entry has not been modified since the branch fork.
+ // therefore, we have to copy the base value and mark it as removed
+ Object value = getValueFromBase(accessor, id, branchId, index);
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value, timestamp);
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private FeatureMap.Entry getValue(IDBStoreAccessor accessor, CDOID id, int branchId, int index, boolean getFromBase)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+ FeatureMap.Entry result = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlGetValue, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+
+ ResultSet resultSet = stmt.executeQuery();
+ if (resultSet.next())
+ {
+ CDOID tag = idHandler.getCDOID(resultSet, 1);
+ Object value = getTypeMapping(tag).readValue(resultSet);
+ result = CDORevisionUtil.createFeatureMapEntry(getFeatureByTag(tag), value);
+ }
+ else
+ {
+ // value is not in this branch.
+ // -> read from base revision
+ if (getFromBase)
+ {
+ result = getValueFromBase(accessor, id, branchId, index);
+ } // else: result remains null
+ }
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a single value (at a given index) from the base revision
+ *
+ * @param accessor
+ * the DBStoreAccessor
+ * @param id
+ * the ID of the revision
+ * @param branchID
+ * the ID of the current (child) branch
+ * @param index
+ * the index to read the value from
+ * @return the value which is at index <code>index</code> in revision with ID <code>id</code> in the parent branch at
+ * the base of this branch (indicated by <code>branchID</code>).
+ */
+ private FeatureMap.Entry getValueFromBase(IDBStoreAccessor accessor, CDOID id, int branchID, int index)
+ {
+ IStoreChunkReader chunkReader = createBaseChunkReader(accessor, id, branchID);
+ chunkReader.addSimpleChunk(index);
+ List<Chunk> chunks = chunkReader.executeRead();
+ return (FeatureMap.Entry)chunks.get(0).get(0);
+ }
+
+ private IStoreChunkReader createBaseChunkReader(IDBStoreAccessor accessor, CDOID id, int branchID)
+ {
+ InternalRepository repository = (InternalRepository)accessor.getStore().getRepository();
+
+ CDOBranchManager branchManager = repository.getBranchManager();
+ CDOBranch branch = branchManager.getBranch(branchID);
+ CDOBranchPoint base = branch.getBase();
+ if (base.getBranch() == null)
+ {
+ // Branch is main branch!
+ throw new IllegalArgumentException("Base of main branch is null");
+ }
+
+ InternalCDORevisionManager revisionManager = repository.getRevisionManager();
+ InternalCDORevision baseRevision = revisionManager.getRevision(id, base, 0, CDORevision.DEPTH_NONE, true);
+
+ return accessor.createChunkReader(baseRevision, getFeature());
+ }
+
+ public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+ QueryXRefsContext context, String idString)
+ {
+ // must never be called (a feature map is not associated with an EReference feature, so XRefs are nor supported
+ // here)
+ throw new ImplementationError("Should never be called!");
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java
index 96079b3298..f9a584affd 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java
@@ -1,1447 +1,1458 @@
-/*
- * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * This class has been derived from AbstractListTableMapping
- *
- * Contributors:
- * Stefan Winkler - initial API and implementation taken from AuditListTableMappingWithRanges
- * Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
- */
-package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
-import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
-import org.eclipse.emf.cdo.server.IRepository;
-import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
-import org.eclipse.emf.cdo.server.IStoreChunkReader;
-import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
-import org.eclipse.emf.cdo.server.ITransaction;
-import org.eclipse.emf.cdo.server.db.IDBStore;
-import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
-import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
-import org.eclipse.emf.cdo.server.db.IIDHandler;
-import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
-import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
-import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
-import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
-import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
-import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
-import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import org.eclipse.net4j.db.DBException;
-import org.eclipse.net4j.db.DBType;
-import org.eclipse.net4j.db.DBUtil;
-import org.eclipse.net4j.db.ddl.IDBField;
-import org.eclipse.net4j.db.ddl.IDBIndex.Type;
-import org.eclipse.net4j.db.ddl.IDBTable;
-import org.eclipse.net4j.util.ImplementationError;
-import org.eclipse.net4j.util.collection.MoveableList;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * This is a list-table mapping for audit mode. It is optimized for frequent insert operations at the list's end, which
- * causes just 1 DB row to be changed. This is achieved by introducing a version range (columns cdo_version_added and
- * cdo_version_removed) which records for which revisions a particular entry existed. Also, this mapping is mainly
- * optimized for potentially very large lists: the need for having the complete list stored in memopy to do
- * in-the-middle-moved and inserts is traded in for a few more DB access operations.
- *
- * @author Eike Stepper
- * @author Stefan Winkler
- * @author Lothar Werzinger
- */
-public class BranchingListTableMappingWithRanges extends BasicAbstractListTableMapping implements
- IListMappingDeltaSupport
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, BranchingListTableMappingWithRanges.class);
-
- /**
- * Used to clean up lists for detached objects.
- */
- private static final int FINAL_VERSION = Integer.MAX_VALUE;
-
- /**
- * The table of this mapping.
- */
- private IDBTable table;
-
- /**
- * The type mapping for the value field.
- */
- private ITypeMapping typeMapping;
-
- // --------- SQL strings - see initSQLStrings() -----------------
- private String sqlSelectChunksPrefix;
-
- private String sqlOrderByIndex;
-
- private String sqlInsertEntry;
-
- private String sqlDeleteEntry;
-
- private String sqlRemoveEntry;
-
- private String sqlUpdateIndex;
-
- private String sqlGetValue;
-
- private String sqlClearList;
-
- public BranchingListTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
- {
- super(mappingStrategy, eClass, feature);
- initTable();
- initSQLStrings();
- }
-
- private void initTable()
- {
- IDBStore store = getMappingStrategy().getStore();
- String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
- table = store.getDBSchema().addTable(tableName);
-
- IDBField[] dbFields = new IDBField[5];
-
- dbFields[0] = table.addField(CDODBSchema.LIST_REVISION_ID, store.getIDHandler().getDBType());
- dbFields[1] = table.addField(CDODBSchema.LIST_REVISION_BRANCH, DBType.INTEGER);
- dbFields[2] = table.addField(CDODBSchema.LIST_REVISION_VERSION_ADDED, DBType.INTEGER);
- dbFields[3] = table.addField(CDODBSchema.LIST_REVISION_VERSION_REMOVED, DBType.INTEGER);
- dbFields[4] = table.addField(CDODBSchema.LIST_IDX, DBType.INTEGER);
-
- // add field for value
- typeMapping = getMappingStrategy().createValueMapping(getFeature());
- typeMapping.createDBField(table, CDODBSchema.LIST_VALUE);
-
- // add table indexes
- for (IDBField dbField : dbFields)
- {
- table.addIndex(Type.NON_UNIQUE, dbField);
- }
- }
-
- public Collection<IDBTable> getDBTables()
- {
- return Arrays.asList(table);
- }
-
- private void initSQLStrings()
- {
- String tableName = getTable().getName();
-
- // ---------------- read chunks ----------------------------
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append(", "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_VALUE);
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
- builder.append("<=? AND ("); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(" IS NULL OR "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(">?)"); //$NON-NLS-1$
- sqlSelectChunksPrefix = builder.toString();
-
- sqlOrderByIndex = " ORDER BY " + CDODBSchema.LIST_IDX; //$NON-NLS-1$
-
- // ----------------- insert entry -----------------
- builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append("("); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append(","); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append(","); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
- builder.append(","); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(","); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append(","); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_VALUE);
- builder.append(") VALUES (?, ?, ?, ?, ?, ?)"); //$NON-NLS-1$
- sqlInsertEntry = builder.toString();
-
- // ----------------- remove current entry -----------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append("=? "); //$NON-NLS-1$
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlRemoveEntry = builder.toString();
-
- // ----------------- delete temporary entry -----------------
- builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
- builder.append("=?"); //$NON-NLS-1$
- sqlDeleteEntry = builder.toString();
-
- // ----------------- update index -----------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append("=? WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append("=?"); //$NON-NLS-1$
- sqlUpdateIndex = builder.toString();
-
- // ----------------- get current value -----------------
- builder = new StringBuilder("SELECT "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_VALUE);
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlGetValue = builder.toString();
-
- // ----------- clear list items -------------------------
- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" SET "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append("=? "); //$NON-NLS-1$
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_BRANCH);
- builder.append("=? AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
- builder.append(" IS NULL"); //$NON-NLS-1$
- sqlClearList = builder.toString();
- }
-
- protected final IDBTable getTable()
- {
- return table;
- }
-
- protected final ITypeMapping getTypeMapping()
- {
- return typeMapping;
- }
-
- public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, final int listChunk)
- {
- MoveableList<Object> list = revision.getList(getFeature());
- int valuesToRead = list.size();
- if (listChunk != CDORevision.UNCHUNKED && listChunk < valuesToRead)
- {
- valuesToRead = listChunk;
- }
-
- if (valuesToRead == 0)
- {
- // nothing to read take shortcut
- return;
- }
-
- CDOID id = revision.getID();
- int branchID = revision.getBranch().getID();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
- getFeature().getName(), revision);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
- ResultSet resultSet = null;
-
- IStoreChunkReader baseReader = null;
- try
- {
- String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
- stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
- idHandler.setCDOID(stmt, 1, id);
- stmt.setInt(2, branchID);
- stmt.setInt(3, revision.getVersion());
- stmt.setInt(4, revision.getVersion());
- stmt.setMaxRows(valuesToRead); // optimization - don't read unneeded rows.
-
- resultSet = stmt.executeQuery();
-
- int currentIndex = 0;
-
- while (valuesToRead > 0 && resultSet.next())
- {
- int index = resultSet.getInt(1);
- if (index > currentIndex)
- {
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(accessor, id, branchID);
- }
-
- baseReader.addRangedChunk(currentIndex, index);
- if (TRACER.isEnabled())
- {
- TRACER.format("Scheduling range {0}-{1} to be read from base revision", currentIndex, index); //$NON-NLS-1$
- }
-
- valuesToRead -= index - currentIndex;
- currentIndex = index;
- }
-
- Object value = typeMapping.readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("Read value for index {0} from result set: {1}", currentIndex, value); //$NON-NLS-1$
- }
-
- list.set(currentIndex++, value);
- valuesToRead--;
- }
-
- if (valuesToRead > 0)
- {
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(accessor, id, branchID);
- }
-
- baseReader.addRangedChunk(currentIndex, currentIndex + valuesToRead);
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "Scheduling range {0}-{1} to be read from base revision", currentIndex, currentIndex + valuesToRead); //$NON-NLS-1$
- }
- }
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- statementCache.releasePreparedStatement(stmt);
- }
-
- if (baseReader != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading base revision chunks for feature {0}.{1} of {2} from base revision {3}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), revision, baseReader.getRevision());
- }
-
- List<Chunk> baseChunks = baseReader.executeRead();
- for (Chunk chunk : baseChunks)
- {
- int startIndex = chunk.getStartIndex();
- for (int i = 0; i < chunk.size(); i++)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Copying value {0} at chunk index {1}+{2} to index {3}", //$NON-NLS-1$
- chunk.get(i), startIndex, i, startIndex + i);
- }
-
- list.set(startIndex + i, chunk.get(i));
- }
- }
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading {3} list values done for feature {0}.{1} of {2}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), revision, list.size());
- }
- }
-
- public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list chunk values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
- getFeature().getName(), chunkReader.getRevision());
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
- PreparedStatement stmt = null;
- ResultSet resultSet = null;
-
- IStoreChunkReader baseReader = null;
-
- try
- {
- StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
- if (where != null)
- {
- builder.append(" AND "); //$NON-NLS-1$
- builder.append(where);
- }
-
- builder.append(sqlOrderByIndex);
-
- String sql = builder.toString();
- stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
- idHandler.setCDOID(stmt, 1, chunkReader.getRevision().getID());
- stmt.setInt(2, chunkReader.getRevision().getBranch().getID());
- stmt.setInt(3, chunkReader.getRevision().getVersion());
- stmt.setInt(4, chunkReader.getRevision().getVersion());
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Readung Chunks: {0}", stmt); //$NON-NLS-1$
- }
-
- resultSet = stmt.executeQuery();
-
- int nextDBIndex = Integer.MAX_VALUE; // next available DB index
- if (resultSet.next())
- {
- nextDBIndex = resultSet.getInt(1);
- }
-
- for (Chunk chunk : chunks)
- {
- int startIndex = chunk.getStartIndex();
- int missingValueStartIndex = -1;
-
- for (int i = 0; i < chunk.size(); i++)
- {
- int nextListIndex = startIndex + i; // next expected list index
-
- if (nextDBIndex == nextListIndex)
- {
- // DB value is available. check first if missing indexes were present before.
- if (missingValueStartIndex != -1)
- {
- // read missing indexes from missingValueStartIndex to currentIndex
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
- chunkReader.getRevision().getBranch().getID());
- }
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, nextListIndex); //$NON-NLS-1$
- }
-
- baseReader.addRangedChunk(missingValueStartIndex, nextListIndex);
-
- // reset missingValueStartIndex
- missingValueStartIndex = -1;
- }
-
- // now read value and set to chunk
- Object value = typeMapping.readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("ChunkReader read value for index {0} from result set: {1}", nextDBIndex, value); //$NON-NLS-1$
- }
- chunk.add(i, value);
-
- // advance DB cursor and read next available index
- if (resultSet.next())
- {
- nextDBIndex = resultSet.getInt(1);
- }
- else
- {
- // no more DB indexes available, but we have to continue checking for gaps, therefore set to MAX_VALUE
- nextDBIndex = Integer.MAX_VALUE;
- }
- }
- else
- {
- // gap between next DB index and next list index detected.
- // skip until end of chunk or until DB value becomes available
- if (missingValueStartIndex == -1)
- {
- missingValueStartIndex = nextListIndex;
- }
- }
- }
-
- // chunk complete. check for missing values at the end of the chunk.
- if (missingValueStartIndex != -1)
- {
- // read missing indexes from missingValueStartIndex to last chunk index
- if (baseReader == null)
- {
- baseReader = createBaseChunkReader(chunkReader.getAccessor(), chunkReader.getRevision().getID(),
- chunkReader.getRevision().getBranch().getID());
- }
-
- if (TRACER.isEnabled())
- {
- TRACER
- .format(
- "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, chunk.getStartIndex() + chunk.size()); //$NON-NLS-1$
- }
- baseReader.addRangedChunk(missingValueStartIndex, chunk.getStartIndex() + chunk.size());
- }
- }
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- statementCache.releasePreparedStatement(stmt);
- }
-
- // now read missing values from base revision.
- if (baseReader != null)
- {
- List<Chunk> baseChunks = baseReader.executeRead();
-
- Iterator<Chunk> thisIterator = chunks.iterator();
- Chunk thisChunk = thisIterator.next();
-
- for (Chunk baseChunk : baseChunks)
- {
- int baseStartIndex = baseChunk.getStartIndex();
-
- while (baseStartIndex > thisChunk.getStartIndex() + thisChunk.size())
- {
- // advance thisChunk, because it does not match baseChunk
- thisChunk = thisIterator.next();
- }
-
- // baseChunk now corresponds to thisChunk, but startIndex of baseChunk may be higher.
- // therefore calculate offset
- int offset = baseStartIndex - thisChunk.getStartIndex();
-
- // and copy values.
- for (int i = 0; i < baseChunk.size(); i++)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Copying base chunk reader value {0} at index {1} to current chunk reader at index {2}.",
- baseChunk.get(i), baseChunk.getStartIndex() + i, thisChunk.getStartIndex() + i + offset);
- }
-
- thisChunk.add(i + offset, baseChunk.get(i));
- } // finally, continue with the next baseChunk
- }
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), chunkReader.getRevision());
- }
- }
-
- public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
- {
- CDOList values = revision.getList(getFeature());
-
- int idx = 0;
- for (Object element : values)
- {
- writeValue(accessor, revision, idx++, element);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing done"); //$NON-NLS-1$
- }
- }
-
- protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int index, Object value)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing value for feature {0}.{1} index {2} of {3} : {4}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, revision, value);
- }
-
- addEntry(accessor, revision.getID(), revision.getBranch().getID(), revision.getVersion(), index, value);
- }
-
- /**
- * Clear a list of a given revision.
- *
- * @param accessor
- * the accessor to use
- * @param id
- * the id of the revision from which to remove all items
- * @param lastIndex
- */
- public void clearList(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion, int lastIndex)
- {
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- try
- {
- // check for each index if the value exists in the current branch
- for (int i = 0; i <= lastIndex; i++)
- {
- if (getValue(accessor, id, branchId, i, false) == null)
- {
- // if not, add a historic entry for missing ones.
- addHistoricEntry(accessor, id, branchId, 0, newVersion, i, getValueFromBase(accessor, id, branchId, i));
- }
- }
-
- // clear rest of the list
- stmt = statementCache.getPreparedStatement(sqlClearList, ReuseProbability.HIGH);
- stmt.setInt(1, newVersion);
- getMappingStrategy().getStore().getIDHandler().setCDOID(stmt, 2, id);
- stmt.setInt(3, branchId);
-
- int result = DBUtil.update(stmt, false);
- if (TRACER.isEnabled())
- {
- TRACER.format("ClearList result: {0}", result); //$NON-NLS-1$
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
- {
- ITransaction transaction = accessor.getTransaction();
- InternalCDORevision revision = (InternalCDORevision)transaction.getRevision(id);
- int branchID = transaction.getBranch().getID();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("objectDetached {1}", revision); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchID, revision.getVersion(), FINAL_VERSION, revision.getList(getFeature()).size() - 1);
- }
-
- public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, final int oldVersion,
- final int newVersion, long created, CDOListFeatureDelta delta)
- {
- List<CDOFeatureDelta> listChanges = delta.getListChanges();
- if (listChanges.size() == 0)
- {
- // nothing to do.
- return;
- }
-
- InternalCDORevision originalRevision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
- int oldListSize = originalRevision.getList(getFeature()).size();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("ListTableMapping.processDelta for revision {0} - previous list size: {1}", originalRevision, //$NON-NLS-1$
- oldListSize);
- }
-
- // let the visitor collect the changes
- ListDeltaVisitor visitor = new ListDeltaVisitor(accessor, originalRevision, branchId, oldVersion, newVersion);
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Processing deltas..."); //$NON-NLS-1$
- }
-
- // optimization: it's only necessary to process deltas
- // starting with the last feature delta which clears the list
- // (any operation before the clear is cascaded by it anyway)
- int index = listChanges.size() - 1;
- while (index > 0)
- {
- CDOFeatureDelta listDelta = listChanges.get(index);
- if (listDelta instanceof CDOClearFeatureDelta || listDelta instanceof CDOUnsetFeatureDelta)
- {
- break;
- }
- index--;
- }
- while (index < listChanges.size())
- {
- listChanges.get(index++).accept(visitor);
- }
-
- visitor.finishPendingRemove();
- }
-
- /**
- * @author Stefan Winkler
- * @author Andras Peteri
- */
- private class ListDeltaVisitor implements CDOFeatureDeltaVisitor
- {
- private IDBStoreAccessor accessor;
-
- private CDOID id;
-
- private int branchID;
-
- private int oldVersion;
-
- private int newVersion;
-
- private int lastIndex;
-
- private int lastRemovedIndex;
-
- public ListDeltaVisitor(IDBStoreAccessor accessor, InternalCDORevision originalRevision, int targetBranchID,
- int oldVersion, int newVersion)
- {
- this.accessor = accessor;
- id = originalRevision.getID();
- branchID = targetBranchID;
- this.oldVersion = oldVersion;
- this.newVersion = newVersion;
- lastIndex = originalRevision.getList(getFeature()).size() - 1;
- lastRemovedIndex = -1;
- }
-
- public void visit(CDOAddFeatureDelta delta)
- {
- finishPendingRemove();
- int startIndex = delta.getIndex();
- int endIndex = lastIndex;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Adding at: {0}", startIndex); //$NON-NLS-1$
- }
-
- if (startIndex <= endIndex)
- {
- // make room for the new item
- moveOneDown(accessor, id, branchID, oldVersion, newVersion, startIndex, endIndex);
- }
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, startIndex, delta.getValue());
-
- ++lastIndex;
- }
-
- public void visit(CDORemoveFeatureDelta delta)
- {
- finishPendingRemove();
- lastRemovedIndex = delta.getIndex();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Removing at: {0}", lastRemovedIndex); //$NON-NLS-1$
- }
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, lastRemovedIndex);
- }
-
- public void visit(CDOSetFeatureDelta delta)
- {
- finishPendingRemove();
- int index = delta.getIndex();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Setting at: {0}", index); //$NON-NLS-1$
- }
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, index);
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, index, delta.getValue());
- }
-
- public void visit(CDOUnsetFeatureDelta delta)
- {
- if (delta.getFeature().isUnsettable())
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Unsetting"); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex);
- lastIndex = -1;
- lastRemovedIndex = -1;
- }
-
- public void visit(CDOClearFeatureDelta delta)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Clearing"); //$NON-NLS-1$
- }
-
- clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex);
- lastIndex = -1;
- lastRemovedIndex = -1;
- }
-
- public void visit(CDOMoveFeatureDelta delta)
- {
- int fromIdx = delta.getOldPosition();
- int toIdx = delta.getNewPosition();
-
- // optimization: a move from the end of the list to an index that was just removed requires no shifting
- boolean optimizeMove = lastRemovedIndex != -1 && fromIdx == lastIndex - 1 && toIdx == lastRemovedIndex;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Delta Moving: {0} to {1}", fromIdx, toIdx); //$NON-NLS-1$
- }
-
- // items after a pending remove have an index offset by one
- if (optimizeMove)
- {
- fromIdx++;
- }
- else
- {
- finishPendingRemove();
- }
-
- Object value = getValue(accessor, id, branchID, fromIdx, true);
-
- // remove the item
- removeEntry(accessor, id, branchID, oldVersion, newVersion, fromIdx);
-
- // adjust indexes and shift either up or down for regular moves
- if (!optimizeMove)
- {
- if (fromIdx < toIdx)
- {
- moveOneUp(accessor, id, branchID, oldVersion, newVersion, fromIdx + 1, toIdx);
- }
- else
- { // fromIdx > toIdx here
- moveOneDown(accessor, id, branchID, oldVersion, newVersion, toIdx, fromIdx - 1);
- }
- }
-
- // create the item
- addEntry(accessor, id, branchID, newVersion, toIdx, value);
- }
-
- public void visit(CDOListFeatureDelta delta)
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- public void visit(CDOContainerFeatureDelta delta)
- {
- throw new ImplementationError("Should not be called"); //$NON-NLS-1$
- }
-
- public void finishPendingRemove()
- {
- if (lastRemovedIndex != -1)
- {
- int startIndex = lastRemovedIndex;
- int endIndex = lastIndex;
-
- // make room for the new item
- moveOneUp(accessor, id, branchID, oldVersion, newVersion, startIndex + 1, endIndex);
-
- --lastIndex;
- lastRemovedIndex = -1;
- }
- }
-
- private void moveOneUp(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int startIndex, int endIndex)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
-
- for (int index = startIndex; index <= endIndex; ++index)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp moving: {0} -> {1}", index, index - 1); //$NON-NLS-1$
- }
-
- int column = 1;
- stmt.setInt(column++, index - 1);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, newVersion);
- stmt.setInt(column++, index);
-
- int result = DBUtil.update(stmt, false);
- switch (result)
- {
- case 1:
- // entry for current revision was already present.
- // index update succeeded.
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp updated: {0} -> {1}", index, index - 1); //$NON-NLS-1$
- }
-
- break;
- // no entry for current revision there.
- case 0:
- Object value = getValue(accessor, id, branchId, index, false);
-
- if (value != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp remove: {0}", index); //$NON-NLS-1$
- }
-
- removeEntry(accessor, id, branchId, oldVersion, newVersion, index);
- }
- else
- {
- value = getValueFromBase(accessor, id, branchId, index);
- {
- TRACER.format("moveOneUp add historic entry at: {0}", index); //$NON-NLS-1$
- }
-
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp add: {0}", index - 1); //$NON-NLS-1$
- }
-
- addEntry(accessor, id, branchId, newVersion, index - 1, value);
- break;
- default:
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneUp Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void moveOneDown(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
- int startIndex, int endIndex)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
-
- for (int index = endIndex; index >= startIndex; --index)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown moving: {0} -> {1}", index, index + 1); //$NON-NLS-1$
- }
-
- int column = 1;
- stmt.setInt(column++, index + 1);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, newVersion);
- stmt.setInt(column++, index);
-
- int result = DBUtil.update(stmt, false);
- switch (result)
- {
- case 1:
- // entry for current revision was already present.
- // index update succeeded.
-
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown updated: {0} -> {1}", index, index + 1); //$NON-NLS-1$
- }
-
- break;
- case 0:
- Object value = getValue(accessor, id, branchId, index, false);
-
- if (value != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown remove: {0}", index); //$NON-NLS-1$
- }
-
- removeEntry(accessor, id, branchId, oldVersion, newVersion, index);
- }
- else
- {
- value = getValueFromBase(accessor, id, branchId, index);
- {
- TRACER.format("moveOneDown add historic entry at: {0}", index); //$NON-NLS-1$
- }
-
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown add: {0}", index + 1); //$NON-NLS-1$
- }
-
- addEntry(accessor, id, branchId, newVersion, index + 1, value);
- break;
- default:
- if (TRACER.isEnabled())
- {
- TRACER.format("moveOneDown Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
- }
-
- private void addEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int version, int index, Object value)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Adding value for feature {0}.{1} index {2} of {3}:{4}v{5} : {6}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, version, value);
- }
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, version); // versionAdded
- stmt.setNull(column++, DBType.INTEGER.getCode()); // versionRemoved
- stmt.setInt(column++, index);
- typeMapping.setValue(stmt, column++, value);
-
- DBUtil.update(stmt, true);
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void addHistoricEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int versionAdded,
- int versionRemoved, int index, Object value)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format(
- "Adding historic value for feature {0}.{1} index {2} of {3}:{4}v{5}-v{6} : {7}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, versionAdded, versionRemoved,
- value);
- }
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, versionAdded); // versionAdded
- stmt.setInt(column++, versionRemoved); // versionRemoved
- stmt.setInt(column++, index);
- typeMapping.setValue(stmt, column++, value);
-
- DBUtil.update(stmt, true);
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- private void removeEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion, int index)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion);
- }
-
- try
- {
- // Try to delete a temporary entry first
- stmt = statementCache.getPreparedStatement(sqlDeleteEntry, ReuseProbability.HIGH);
-
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
- stmt.setInt(column++, newVersion);
-
- int result = DBUtil.update(stmt, false);
- if (result == 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
- }
- }
- else if (result > 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- else
- {
- // no temporary entry found, so mark the entry as removed
- statementCache.releasePreparedStatement(stmt);
- stmt = statementCache.getPreparedStatement(sqlRemoveEntry, ReuseProbability.HIGH);
-
- column = 1;
- stmt.setInt(column++, newVersion);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
-
- result = DBUtil.update(stmt, false);
-
- if (result == 0)
- {
- // no entry removed -> this means that we are in a branch and
- // the entry has not been modified since the branch fork.
- // therefore, we have to copy the base value and mark it as removed
- Object value = getValueFromBase(accessor, id, branchId, index);
- addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
- }
- }
- }
- catch (SQLException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5} FAILED {6}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5} FAILED {6}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
- }
-
- /**
- * Read a single value from the current revision's list.
- *
- * @param accessor
- * the store accessor
- * @param id
- * the revision's ID
- * @param branchId
- * the revision's branch ID
- * @param index
- * the index from which to get the value
- * @param getFromBase
- * if <code>true</code>, the value is recursively loaded from the base revision of a branch, if it is not
- * present in the current branch (because it has not been changed since the branch fork). If
- * <code>false</code>, <code>null</code> is returned in the former case.
- */
- private Object getValue(IDBStoreAccessor accessor, CDOID id, int branchId, int index, boolean getFromBase)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IPreparedStatementCache statementCache = accessor.getStatementCache();
- PreparedStatement stmt = null;
- Object result = null;
-
- try
- {
- stmt = statementCache.getPreparedStatement(sqlGetValue, ReuseProbability.HIGH);
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, branchId);
- stmt.setInt(column++, index);
-
- ResultSet resultSet = stmt.executeQuery();
- if (resultSet.next())
- {
- result = typeMapping.readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
- }
- }
- else
- {
- // value is not in this branch.
- // -> read from base revision
- if (getFromBase)
- {
- result = getValueFromBase(accessor, id, branchId, index);
- } // else: result remains null
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- statementCache.releasePreparedStatement(stmt);
- }
-
- return result;
- }
-
- /**
- * Read a single value (at a given index) from the base revision
- *
- * @param accessor
- * the DBStoreAccessor
- * @param id
- * the ID of the revision
- * @param branchID
- * the ID of the current (child) branch
- * @param index
- * the index to read the value from
- * @return the value which is at index <code>index</code> in revision with ID <code>id</code> in the parent branch at
- * the base of this branch (indicated by <code>branchID</code>).
- */
- private Object getValueFromBase(IDBStoreAccessor accessor, CDOID id, int branchID, int index)
- {
- IStoreChunkReader chunkReader = createBaseChunkReader(accessor, id, branchID);
- chunkReader.addSimpleChunk(index);
- List<Chunk> chunks = chunkReader.executeRead();
- return chunks.get(0).get(0);
- }
-
- private IStoreChunkReader createBaseChunkReader(IDBStoreAccessor accessor, CDOID id, int branchID)
- {
- IRepository repository = accessor.getStore().getRepository();
- CDOBranchPoint base = repository.getBranchManager().getBranch(branchID).getBase();
- InternalCDORevision baseRevision = (InternalCDORevision)repository.getRevisionManager().getRevision(id, base, /*
- * referenceChunk
- * =
- */0, /*
- * prefetchDepth
- * =
- */
- CDORevision.DEPTH_NONE, true);
- IStoreChunkReader chunkReader = accessor.createChunkReader(baseRevision, getFeature());
- return chunkReader;
- }
-
- public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
- QueryXRefsContext context, String idString)
- {
-
- String tableName = getTable().getName();
- String listJoin = getMappingStrategy().getListJoin("a_t", "l_t");
-
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT l_t."); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_REVISION_ID);
- builder.append(", l_t."); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_VALUE);
- builder.append(", l_t."); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_IDX);
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" AS l_t, ");//$NON-NLS-1$
- builder.append(mainTableName);
- builder.append(" AS a_t WHERE ");//$NON-NLS-1$
- builder.append("a_t." + mainTableWhere);//$NON-NLS-1$
- builder.append(listJoin);
- builder.append(" AND "); //$NON-NLS-1$
- builder.append(CDODBSchema.LIST_VALUE);
- builder.append(" IN "); //$NON-NLS-1$
- builder.append(idString);
- String sql = builder.toString();
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- ResultSet resultSet = null;
- Statement stmt = null;
-
- try
- {
- stmt = accessor.getConnection().createStatement();
- if (TRACER.isEnabled())
- {
- TRACER.format("Query XRefs (list): {0}", sql);
- }
-
- resultSet = stmt.executeQuery(sql);
- while (resultSet.next())
- {
- CDOID sourceID = idHandler.getCDOID(resultSet, 1);
- CDOID targetID = idHandler.getCDOID(resultSet, 2);
- int idx = resultSet.getInt(3);
-
- boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx);
- if (TRACER.isEnabled())
- {
- TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx);
- }
-
- if (!more)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format(" result limit reached. Ignoring further results.");
- }
-
- return false;
- }
- }
-
- return true;
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- DBUtil.close(stmt);
- }
- }
-}
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This class has been derived from AbstractListTableMapping
+ *
+ * Contributors:
+ * Stefan Winkler - initial API and implementation taken from AuditListTableMappingWithRanges
+ * Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.IStoreChunkReader;
+import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
+import org.eclipse.net4j.db.ddl.IDBIndex.Type;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a list-table mapping for audit mode. It is optimized for frequent insert operations at the list's end, which
+ * causes just 1 DB row to be changed. This is achieved by introducing a version range (columns cdo_version_added and
+ * cdo_version_removed) which records for which revisions a particular entry existed. Also, this mapping is mainly
+ * optimized for potentially very large lists: the need for having the complete list stored in memopy to do
+ * in-the-middle-moved and inserts is traded in for a few more DB access operations.
+ *
+ * @author Eike Stepper
+ * @author Stefan Winkler
+ * @author Lothar Werzinger
+ */
+public class BranchingListTableMappingWithRanges extends BasicAbstractListTableMapping implements
+ IListMappingDeltaSupport
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, BranchingListTableMappingWithRanges.class);
+
+ /**
+ * Used to clean up lists for detached objects.
+ */
+ private static final int FINAL_VERSION = Integer.MAX_VALUE;
+
+ /**
+ * The table of this mapping.
+ */
+ private IDBTable table;
+
+ /**
+ * The type mapping for the value field.
+ */
+ private ITypeMapping typeMapping;
+
+ // --------- SQL strings - see initSQLStrings() -----------------
+ private String sqlSelectChunksPrefix;
+
+ private String sqlOrderByIndex;
+
+ private String sqlInsertEntry;
+
+ private String sqlDeleteEntry;
+
+ private String sqlRemoveEntry;
+
+ private String sqlUpdateIndex;
+
+ private String sqlGetValue;
+
+ private String sqlClearList;
+
+ public BranchingListTableMappingWithRanges(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
+ {
+ super(mappingStrategy, eClass, feature);
+ initTable();
+ initSQLStrings();
+ }
+
+ private void initTable()
+ {
+ IDBStore store = getMappingStrategy().getStore();
+ String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature());
+ table = store.getDBSchema().addTable(tableName);
+
+ IDBField[] dbFields = new IDBField[5];
+
+ dbFields[0] = table.addField(CDODBSchema.LIST_REVISION_ID, store.getIDHandler().getDBType());
+ dbFields[1] = table.addField(CDODBSchema.LIST_REVISION_BRANCH, DBType.INTEGER);
+ dbFields[2] = table.addField(CDODBSchema.LIST_REVISION_VERSION_ADDED, DBType.INTEGER);
+ dbFields[3] = table.addField(CDODBSchema.LIST_REVISION_VERSION_REMOVED, DBType.INTEGER);
+ dbFields[4] = table.addField(CDODBSchema.LIST_IDX, DBType.INTEGER);
+
+ // add field for value
+ typeMapping = getMappingStrategy().createValueMapping(getFeature());
+ typeMapping.createDBField(table, CDODBSchema.LIST_VALUE);
+
+ // add table indexes
+ for (IDBField dbField : dbFields)
+ {
+ table.addIndex(Type.NON_UNIQUE, dbField);
+ }
+ }
+
+ public Collection<IDBTable> getDBTables()
+ {
+ return Arrays.asList(table);
+ }
+
+ private void initSQLStrings()
+ {
+ String tableName = getTable().getName();
+
+ // ---------------- read chunks ----------------------------
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_VALUE);
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
+ builder.append("<=? AND ("); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(" IS NULL OR "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(">?)"); //$NON-NLS-1$
+ sqlSelectChunksPrefix = builder.toString();
+
+ sqlOrderByIndex = " ORDER BY " + CDODBSchema.LIST_IDX; //$NON-NLS-1$
+
+ // ----------------- insert entry -----------------
+ builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append("("); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append(","); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append(","); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
+ builder.append(","); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(","); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append(","); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_VALUE);
+ builder.append(") VALUES (?, ?, ?, ?, ?, ?)"); //$NON-NLS-1$
+ sqlInsertEntry = builder.toString();
+
+ // ----------------- remove current entry -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append("=? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlRemoveEntry = builder.toString();
+
+ // ----------------- delete temporary entry -----------------
+ builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
+ builder.append("=?"); //$NON-NLS-1$
+ sqlDeleteEntry = builder.toString();
+
+ // ----------------- update index -----------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append("=? WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_ADDED);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append("=?"); //$NON-NLS-1$
+ sqlUpdateIndex = builder.toString();
+
+ // ----------------- get current value -----------------
+ builder = new StringBuilder("SELECT "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_VALUE);
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlGetValue = builder.toString();
+
+ // ----------- clear list items -------------------------
+ builder = new StringBuilder("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append("=? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_BRANCH);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_VERSION_REMOVED);
+ builder.append(" IS NULL"); //$NON-NLS-1$
+ sqlClearList = builder.toString();
+ }
+
+ protected final IDBTable getTable()
+ {
+ return table;
+ }
+
+ protected final ITypeMapping getTypeMapping()
+ {
+ return typeMapping;
+ }
+
+ public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, final int listChunk)
+ {
+ MoveableList<Object> list = revision.getList(getFeature());
+ int valuesToRead = list.size();
+ if (listChunk != CDORevision.UNCHUNKED && listChunk < valuesToRead)
+ {
+ valuesToRead = listChunk;
+ }
+
+ if (valuesToRead == 0)
+ {
+ // nothing to read take shortcut
+ return;
+ }
+
+ CDOID id = revision.getID();
+ int branchID = revision.getBranch().getID();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+ ResultSet resultSet = null;
+
+ IStoreChunkReader baseReader = null;
+ try
+ {
+ String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, branchID);
+ stmt.setInt(3, revision.getVersion());
+ stmt.setInt(4, revision.getVersion());
+ stmt.setMaxRows(valuesToRead); // optimization - don't read unneeded rows.
+
+ resultSet = stmt.executeQuery();
+
+ int currentIndex = 0;
+
+ while (valuesToRead > 0 && resultSet.next())
+ {
+ int index = resultSet.getInt(1);
+ if (index > currentIndex)
+ {
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(accessor, id, branchID);
+ }
+
+ baseReader.addRangedChunk(currentIndex, index);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Scheduling range {0}-{1} to be read from base revision", currentIndex, index); //$NON-NLS-1$
+ }
+
+ valuesToRead -= index - currentIndex;
+ currentIndex = index;
+ }
+
+ Object value = typeMapping.readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Read value for index {0} from result set: {1}", currentIndex, value); //$NON-NLS-1$
+ }
+
+ list.set(currentIndex++, value);
+ valuesToRead--;
+ }
+
+ if (valuesToRead > 0)
+ {
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(accessor, id, branchID);
+ }
+
+ baseReader.addRangedChunk(currentIndex, currentIndex + valuesToRead);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "Scheduling range {0}-{1} to be read from base revision", currentIndex, currentIndex + valuesToRead); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ if (baseReader != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading base revision chunks for feature {0}.{1} of {2} from base revision {3}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), revision, baseReader.getRevision());
+ }
+
+ List<Chunk> baseChunks = baseReader.executeRead();
+ for (Chunk chunk : baseChunks)
+ {
+ int startIndex = chunk.getStartIndex();
+ for (int i = 0; i < chunk.size(); i++)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Copying value {0} at chunk index {1}+{2} to index {3}", //$NON-NLS-1$
+ chunk.get(i), startIndex, i, startIndex + i);
+ }
+
+ list.set(startIndex + i, chunk.get(i));
+ }
+ }
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading {3} list values done for feature {0}.{1} of {2}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), revision, list.size());
+ }
+ }
+
+ public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where)
+ {
+ CDORevision revision = chunkReader.getRevision();
+ CDOID id = revision.getID();
+ int branchID = revision.getBranch().getID();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list chunk values for feature {0}.{1} of {2}", getContainingClass().getName(), //$NON-NLS-1$
+ getFeature().getName(), revision);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = chunkReader.getAccessor().getStatementCache();
+ PreparedStatement stmt = null;
+ ResultSet resultSet = null;
+
+ IStoreChunkReader baseReader = null;
+
+ try
+ {
+ StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix);
+ if (where != null)
+ {
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(where);
+ }
+
+ builder.append(sqlOrderByIndex);
+
+ String sql = builder.toString();
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.LOW);
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, branchID);
+ stmt.setInt(3, revision.getVersion());
+ stmt.setInt(4, revision.getVersion());
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Readung Chunks: {0}", stmt); //$NON-NLS-1$
+ }
+
+ resultSet = stmt.executeQuery();
+
+ int nextDBIndex = Integer.MAX_VALUE; // next available DB index
+ if (resultSet.next())
+ {
+ nextDBIndex = resultSet.getInt(1);
+ }
+
+ for (Chunk chunk : chunks)
+ {
+ int startIndex = chunk.getStartIndex();
+ int missingValueStartIndex = -1;
+
+ for (int i = 0; i < chunk.size(); i++)
+ {
+ int nextListIndex = startIndex + i; // next expected list index
+
+ if (nextDBIndex == nextListIndex)
+ {
+ // DB value is available. check first if missing indexes were present before.
+ if (missingValueStartIndex != -1)
+ {
+ // read missing indexes from missingValueStartIndex to currentIndex
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(chunkReader.getAccessor(), id, branchID);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, nextListIndex); //$NON-NLS-1$
+ }
+
+ baseReader.addRangedChunk(missingValueStartIndex, nextListIndex);
+
+ // reset missingValueStartIndex
+ missingValueStartIndex = -1;
+ }
+
+ // now read value and set to chunk
+ Object value = typeMapping.readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ChunkReader read value for index {0} from result set: {1}", nextDBIndex, value); //$NON-NLS-1$
+ }
+
+ chunk.add(i, value);
+
+ // advance DB cursor and read next available index
+ if (resultSet.next())
+ {
+ nextDBIndex = resultSet.getInt(1);
+ }
+ else
+ {
+ // no more DB indexes available, but we have to continue checking for gaps, therefore set to MAX_VALUE
+ nextDBIndex = Integer.MAX_VALUE;
+ }
+ }
+ else
+ {
+ // gap between next DB index and next list index detected.
+ // skip until end of chunk or until DB value becomes available
+ if (missingValueStartIndex == -1)
+ {
+ missingValueStartIndex = nextListIndex;
+ }
+ }
+ }
+
+ // chunk complete. check for missing values at the end of the chunk.
+ if (missingValueStartIndex != -1)
+ {
+ // read missing indexes from missingValueStartIndex to last chunk index
+ if (baseReader == null)
+ {
+ baseReader = createBaseChunkReader(chunkReader.getAccessor(), id, branchID);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER
+ .format(
+ "Scheduling range {0}-{1} to be read from base revision", missingValueStartIndex, chunk.getStartIndex() + chunk.size()); //$NON-NLS-1$
+ }
+
+ baseReader.addRangedChunk(missingValueStartIndex, chunk.getStartIndex() + chunk.size());
+ }
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ // now read missing values from base revision.
+ if (baseReader != null)
+ {
+ List<Chunk> baseChunks = baseReader.executeRead();
+
+ Iterator<Chunk> thisIterator = chunks.iterator();
+ Chunk thisChunk = thisIterator.next();
+
+ for (Chunk baseChunk : baseChunks)
+ {
+ int baseStartIndex = baseChunk.getStartIndex();
+
+ while (baseStartIndex > thisChunk.getStartIndex() + thisChunk.size())
+ {
+ // advance thisChunk, because it does not match baseChunk
+ thisChunk = thisIterator.next();
+ }
+
+ // baseChunk now corresponds to thisChunk, but startIndex of baseChunk may be higher.
+ // therefore calculate offset
+ int offset = baseStartIndex - thisChunk.getStartIndex();
+
+ // and copy values.
+ for (int i = 0; i < baseChunk.size(); i++)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Copying base chunk reader value {0} at index {1} to current chunk reader at index {2}.",
+ baseChunk.get(i), baseChunk.getStartIndex() + i, thisChunk.getStartIndex() + i + offset);
+ }
+
+ thisChunk.add(i + offset, baseChunk.get(i));
+ } // finally, continue with the next baseChunk
+ }
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), revision);
+ }
+ }
+
+ public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision)
+ {
+ CDOList values = revision.getList(getFeature());
+
+ int idx = 0;
+ for (Object element : values)
+ {
+ writeValue(accessor, revision, idx++, element);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Writing done"); //$NON-NLS-1$
+ }
+ }
+
+ protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int index, Object value)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Writing value for feature {0}.{1} index {2} of {3} : {4}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, revision, value);
+ }
+
+ addEntry(accessor, revision.getID(), revision.getBranch().getID(), revision.getVersion(), index, value);
+ }
+
+ /**
+ * Clear a list of a given revision.
+ *
+ * @param accessor
+ * the accessor to use
+ * @param id
+ * the id of the revision from which to remove all items
+ * @param lastIndex
+ */
+ public void clearList(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion, int lastIndex)
+ {
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ // check for each index if the value exists in the current branch
+ for (int i = 0; i <= lastIndex; i++)
+ {
+ if (getValue(accessor, id, branchId, i, false) == null)
+ {
+ // if not, add a historic entry for missing ones.
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, i, getValueFromBase(accessor, id, branchId, i));
+ }
+ }
+
+ // clear rest of the list
+ stmt = statementCache.getPreparedStatement(sqlClearList, ReuseProbability.HIGH);
+ stmt.setInt(1, newVersion);
+ getMappingStrategy().getStore().getIDHandler().setCDOID(stmt, 2, id);
+ stmt.setInt(3, branchId);
+
+ int result = DBUtil.update(stmt, false);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ClearList result: {0}", result); //$NON-NLS-1$
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ public void objectDetached(IDBStoreAccessor accessor, CDOID id, long revised)
+ {
+ ITransaction transaction = accessor.getTransaction();
+ InternalCDORevision revision = (InternalCDORevision)transaction.getRevision(id);
+ int branchID = transaction.getBranch().getID();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("objectDetached {1}", revision); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchID, revision.getVersion(), FINAL_VERSION, revision.getList(getFeature()).size() - 1);
+ }
+
+ public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, final int oldVersion,
+ final int newVersion, long created, CDOListFeatureDelta delta)
+ {
+ List<CDOFeatureDelta> listChanges = delta.getListChanges();
+ if (listChanges.size() == 0)
+ {
+ // nothing to do.
+ return;
+ }
+
+ InternalCDORevision originalRevision = (InternalCDORevision)accessor.getTransaction().getRevision(id);
+ int oldListSize = originalRevision.getList(getFeature()).size();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ListTableMapping.processDelta for revision {0} - previous list size: {1}", originalRevision, //$NON-NLS-1$
+ oldListSize);
+ }
+
+ // let the visitor collect the changes
+ ListDeltaVisitor visitor = new ListDeltaVisitor(accessor, originalRevision, branchId, oldVersion, newVersion);
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Processing deltas..."); //$NON-NLS-1$
+ }
+
+ // optimization: it's only necessary to process deltas
+ // starting with the last feature delta which clears the list
+ // (any operation before the clear is cascaded by it anyway)
+ int index = listChanges.size() - 1;
+ while (index > 0)
+ {
+ CDOFeatureDelta listDelta = listChanges.get(index);
+ if (listDelta instanceof CDOClearFeatureDelta || listDelta instanceof CDOUnsetFeatureDelta)
+ {
+ break;
+ }
+ index--;
+ }
+ while (index < listChanges.size())
+ {
+ listChanges.get(index++).accept(visitor);
+ }
+
+ visitor.finishPendingRemove();
+ }
+
+ /**
+ * @author Stefan Winkler
+ * @author Andras Peteri
+ */
+ private class ListDeltaVisitor implements CDOFeatureDeltaVisitor
+ {
+ private IDBStoreAccessor accessor;
+
+ private CDOID id;
+
+ private int branchID;
+
+ private int oldVersion;
+
+ private int newVersion;
+
+ private int lastIndex;
+
+ private int lastRemovedIndex;
+
+ public ListDeltaVisitor(IDBStoreAccessor accessor, InternalCDORevision originalRevision, int targetBranchID,
+ int oldVersion, int newVersion)
+ {
+ this.accessor = accessor;
+ id = originalRevision.getID();
+ branchID = targetBranchID;
+ this.oldVersion = oldVersion;
+ this.newVersion = newVersion;
+ lastIndex = originalRevision.getList(getFeature()).size() - 1;
+ lastRemovedIndex = -1;
+ }
+
+ public void visit(CDOAddFeatureDelta delta)
+ {
+ finishPendingRemove();
+ int startIndex = delta.getIndex();
+ int endIndex = lastIndex;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Adding at: {0}", startIndex); //$NON-NLS-1$
+ }
+
+ if (startIndex <= endIndex)
+ {
+ // make room for the new item
+ moveOneDown(accessor, id, branchID, oldVersion, newVersion, startIndex, endIndex);
+ }
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, startIndex, delta.getValue());
+
+ ++lastIndex;
+ }
+
+ public void visit(CDORemoveFeatureDelta delta)
+ {
+ finishPendingRemove();
+ lastRemovedIndex = delta.getIndex();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Removing at: {0}", lastRemovedIndex); //$NON-NLS-1$
+ }
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, lastRemovedIndex);
+ }
+
+ public void visit(CDOSetFeatureDelta delta)
+ {
+ finishPendingRemove();
+ int index = delta.getIndex();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Setting at: {0}", index); //$NON-NLS-1$
+ }
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, index);
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, index, delta.getValue());
+ }
+
+ public void visit(CDOUnsetFeatureDelta delta)
+ {
+ if (delta.getFeature().isUnsettable())
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Unsetting"); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex);
+ lastIndex = -1;
+ lastRemovedIndex = -1;
+ }
+
+ public void visit(CDOClearFeatureDelta delta)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Clearing"); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id, branchID, oldVersion, newVersion, lastIndex);
+ lastIndex = -1;
+ lastRemovedIndex = -1;
+ }
+
+ public void visit(CDOMoveFeatureDelta delta)
+ {
+ int fromIdx = delta.getOldPosition();
+ int toIdx = delta.getNewPosition();
+
+ // optimization: a move from the end of the list to an index that was just removed requires no shifting
+ boolean optimizeMove = lastRemovedIndex != -1 && fromIdx == lastIndex - 1 && toIdx == lastRemovedIndex;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Delta Moving: {0} to {1}", fromIdx, toIdx); //$NON-NLS-1$
+ }
+
+ // items after a pending remove have an index offset by one
+ if (optimizeMove)
+ {
+ fromIdx++;
+ }
+ else
+ {
+ finishPendingRemove();
+ }
+
+ Object value = getValue(accessor, id, branchID, fromIdx, true);
+
+ // remove the item
+ removeEntry(accessor, id, branchID, oldVersion, newVersion, fromIdx);
+
+ // adjust indexes and shift either up or down for regular moves
+ if (!optimizeMove)
+ {
+ if (fromIdx < toIdx)
+ {
+ moveOneUp(accessor, id, branchID, oldVersion, newVersion, fromIdx + 1, toIdx);
+ }
+ else
+ { // fromIdx > toIdx here
+ moveOneDown(accessor, id, branchID, oldVersion, newVersion, toIdx, fromIdx - 1);
+ }
+ }
+
+ // create the item
+ addEntry(accessor, id, branchID, newVersion, toIdx, value);
+ }
+
+ public void visit(CDOListFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ public void visit(CDOContainerFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ public void finishPendingRemove()
+ {
+ if (lastRemovedIndex != -1)
+ {
+ int startIndex = lastRemovedIndex;
+ int endIndex = lastIndex;
+
+ // make room for the new item
+ moveOneUp(accessor, id, branchID, oldVersion, newVersion, startIndex + 1, endIndex);
+
+ --lastIndex;
+ lastRemovedIndex = -1;
+ }
+ }
+
+ private void moveOneUp(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int startIndex, int endIndex)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
+
+ for (int index = startIndex; index <= endIndex; ++index)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp moving: {0} -> {1}", index, index - 1); //$NON-NLS-1$
+ }
+
+ int column = 1;
+ stmt.setInt(column++, index - 1);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, newVersion);
+ stmt.setInt(column++, index);
+
+ int result = DBUtil.update(stmt, false);
+ switch (result)
+ {
+ case 1:
+ // entry for current revision was already present.
+ // index update succeeded.
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp updated: {0} -> {1}", index, index - 1); //$NON-NLS-1$
+ }
+
+ break;
+ // no entry for current revision there.
+ case 0:
+ Object value = getValue(accessor, id, branchId, index, false);
+
+ if (value != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp remove: {0}", index); //$NON-NLS-1$
+ }
+
+ removeEntry(accessor, id, branchId, oldVersion, newVersion, index);
+ }
+ else
+ {
+ value = getValueFromBase(accessor, id, branchId, index);
+ {
+ TRACER.format("moveOneUp add historic entry at: {0}", index); //$NON-NLS-1$
+ }
+
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp add: {0}", index - 1); //$NON-NLS-1$
+ }
+
+ addEntry(accessor, id, branchId, newVersion, index - 1, value);
+ break;
+ default:
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneUp Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void moveOneDown(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion,
+ int startIndex, int endIndex)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
+
+ for (int index = endIndex; index >= startIndex; --index)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown moving: {0} -> {1}", index, index + 1); //$NON-NLS-1$
+ }
+
+ int column = 1;
+ stmt.setInt(column++, index + 1);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, newVersion);
+ stmt.setInt(column++, index);
+
+ int result = DBUtil.update(stmt, false);
+ switch (result)
+ {
+ case 1:
+ // entry for current revision was already present.
+ // index update succeeded.
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown updated: {0} -> {1}", index, index + 1); //$NON-NLS-1$
+ }
+
+ break;
+ case 0:
+ Object value = getValue(accessor, id, branchId, index, false);
+
+ if (value != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown remove: {0}", index); //$NON-NLS-1$
+ }
+
+ removeEntry(accessor, id, branchId, oldVersion, newVersion, index);
+ }
+ else
+ {
+ value = getValueFromBase(accessor, id, branchId, index);
+ {
+ TRACER.format("moveOneDown add historic entry at: {0}", index); //$NON-NLS-1$
+ }
+
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown add: {0}", index + 1); //$NON-NLS-1$
+ }
+
+ addEntry(accessor, id, branchId, newVersion, index + 1, value);
+ break;
+ default:
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("moveOneDown Too many results: {0} -> {1}: {2}", index, index + 1, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+ }
+
+ private void addEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int version, int index, Object value)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Adding value for feature {0}.{1} index {2} of {3}:{4}v{5} : {6}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, version, value);
+ }
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, version); // versionAdded
+ stmt.setNull(column++, DBType.INTEGER.getCode()); // versionRemoved
+ stmt.setInt(column++, index);
+ typeMapping.setValue(stmt, column++, value);
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void addHistoricEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int versionAdded,
+ int versionRemoved, int index, Object value)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(
+ "Adding historic value for feature {0}.{1} index {2} of {3}:{4}v{5}-v{6} : {7}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, versionAdded, versionRemoved,
+ value);
+ }
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, versionAdded); // versionAdded
+ stmt.setInt(column++, versionRemoved); // versionRemoved
+ stmt.setInt(column++, index);
+ typeMapping.setValue(stmt, column++, value);
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void removeEntry(IDBStoreAccessor accessor, CDOID id, int branchId, int oldVersion, int newVersion, int index)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion);
+ }
+
+ try
+ {
+ // Try to delete a temporary entry first
+ stmt = statementCache.getPreparedStatement(sqlDeleteEntry, ReuseProbability.HIGH);
+
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+ stmt.setInt(column++, newVersion);
+
+ int result = DBUtil.update(stmt, false);
+ if (result == 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
+ }
+ }
+ else if (result > 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ else
+ {
+ // no temporary entry found, so mark the entry as removed
+ statementCache.releasePreparedStatement(stmt);
+ stmt = statementCache.getPreparedStatement(sqlRemoveEntry, ReuseProbability.HIGH);
+
+ column = 1;
+ stmt.setInt(column++, newVersion);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+
+ result = DBUtil.update(stmt, false);
+
+ if (result == 0)
+ {
+ // no entry removed -> this means that we are in a branch and
+ // the entry has not been modified since the branch fork.
+ // therefore, we have to copy the base value and mark it as removed
+ Object value = getValueFromBase(accessor, id, branchId, index);
+ addHistoricEntry(accessor, id, branchId, 0, newVersion, index, value);
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5} FAILED {6}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature {0}.{1} index {2} of {3}:{4}v{5} FAILED {6}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, branchId, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ /**
+ * Read a single value from the current revision's list.
+ *
+ * @param accessor
+ * the store accessor
+ * @param id
+ * the revision's ID
+ * @param branchId
+ * the revision's branch ID
+ * @param index
+ * the index from which to get the value
+ * @param getFromBase
+ * if <code>true</code>, the value is recursively loaded from the base revision of a branch, if it is not
+ * present in the current branch (because it has not been changed since the branch fork). If
+ * <code>false</code>, <code>null</code> is returned in the former case.
+ */
+ private Object getValue(IDBStoreAccessor accessor, CDOID id, int branchId, int index, boolean getFromBase)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+ Object result = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlGetValue, ReuseProbability.HIGH);
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, branchId);
+ stmt.setInt(column++, index);
+
+ ResultSet resultSet = stmt.executeQuery();
+ if (resultSet.next())
+ {
+ result = typeMapping.readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
+ }
+ }
+ else
+ {
+ // value is not in this branch.
+ // -> read from base revision
+ if (getFromBase)
+ {
+ result = getValueFromBase(accessor, id, branchId, index);
+ } // else: result remains null
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a single value (at a given index) from the base revision
+ *
+ * @param accessor
+ * the DBStoreAccessor
+ * @param id
+ * the ID of the revision
+ * @param branchID
+ * the ID of the current (child) branch
+ * @param index
+ * the index to read the value from
+ * @return the value which is at index <code>index</code> in revision with ID <code>id</code> in the parent branch at
+ * the base of this branch (indicated by <code>branchID</code>).
+ */
+ private Object getValueFromBase(IDBStoreAccessor accessor, CDOID id, int branchID, int index)
+ {
+ IStoreChunkReader chunkReader = createBaseChunkReader(accessor, id, branchID);
+ chunkReader.addSimpleChunk(index);
+ List<Chunk> chunks = chunkReader.executeRead();
+ return chunks.get(0).get(0);
+ }
+
+ private IStoreChunkReader createBaseChunkReader(IDBStoreAccessor accessor, CDOID id, int branchID)
+ {
+ InternalRepository repository = (InternalRepository)accessor.getStore().getRepository();
+
+ CDOBranchManager branchManager = repository.getBranchManager();
+ CDOBranch branch = branchManager.getBranch(branchID);
+ CDOBranchPoint base = branch.getBase();
+ if (base.getBranch() == null)
+ {
+ // Branch is main branch!
+ throw new IllegalArgumentException("Base of main branch is null");
+ }
+
+ InternalCDORevisionManager revisionManager = repository.getRevisionManager();
+ InternalCDORevision baseRevision = revisionManager.getRevision(id, base, 0, CDORevision.DEPTH_NONE, true);
+
+ return accessor.createChunkReader(baseRevision, getFeature());
+ }
+
+ public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+ QueryXRefsContext context, String idString)
+ {
+
+ String tableName = getTable().getName();
+ String listJoin = getMappingStrategy().getListJoin("a_t", "l_t");
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT l_t."); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_REVISION_ID);
+ builder.append(", l_t."); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_VALUE);
+ builder.append(", l_t."); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_IDX);
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" AS l_t, ");//$NON-NLS-1$
+ builder.append(mainTableName);
+ builder.append(" AS a_t WHERE ");//$NON-NLS-1$
+ builder.append("a_t." + mainTableWhere);//$NON-NLS-1$
+ builder.append(listJoin);
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.LIST_VALUE);
+ builder.append(" IN "); //$NON-NLS-1$
+ builder.append(idString);
+ String sql = builder.toString();
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ ResultSet resultSet = null;
+ Statement stmt = null;
+
+ try
+ {
+ stmt = accessor.getConnection().createStatement();
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Query XRefs (list): {0}", sql);
+ }
+
+ resultSet = stmt.executeQuery(sql);
+ while (resultSet.next())
+ {
+ CDOID sourceID = idHandler.getCDOID(resultSet, 1);
+ CDOID targetID = idHandler.getCDOID(resultSet, 2);
+ int idx = resultSet.getInt(3);
+
+ boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx);
+ }
+
+ if (!more)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(" result limit reached. Ignoring further results.");
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ DBUtil.close(stmt);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
index 8347f99acc..aec0598956 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
@@ -368,10 +368,11 @@ public class Repository extends Container<Object> implements InternalRepository
throw new IllegalStateException("Branching is not supported by " + this);
}
+ long lastFinishedTimeStamp = timeStampAuthority.getLastFinishedTimeStamp();
long baseTimeStamp = branchInfo.getBaseTimeStamp();
- if (baseTimeStamp == CDOBranchPoint.UNSPECIFIED_DATE)
+ if (baseTimeStamp == CDOBranchPoint.UNSPECIFIED_DATE || baseTimeStamp > lastFinishedTimeStamp)
{
- baseTimeStamp = getTimeStamp();
+ baseTimeStamp = lastFinishedTimeStamp;
branchInfo = new BranchInfo(branchInfo.getName(), branchInfo.getBaseBranchID(), baseTimeStamp);
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerBrowser.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerBrowser.java
index 52d3ab1f3e..965e895a5f 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerBrowser.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerBrowser.java
@@ -11,6 +11,7 @@
package org.eclipse.emf.cdo.server;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
import org.eclipse.emf.cdo.common.id.CDOID;
@@ -806,7 +807,22 @@ public class CDOServerBrowser extends Worker
showKeyValue(pout, true, "version", revision.getVersion());
showKeyValue(pout, true, "created", commitInfo);
showKeyValue(pout, true, "revised", CDOCommonUtil.formatTimeStamp(revision.getRevised()));
- if (!(revision instanceof SyntheticCDORevision))
+ if (revision instanceof SyntheticCDORevision)
+ {
+ if (revision instanceof PointerCDORevision)
+ {
+ PointerCDORevision pointer = (PointerCDORevision)revision;
+ CDOBranchVersion target = pointer.getTarget();
+ CDOBranch branch = target.getBranch();
+ int version = target.getVersion();
+
+ String label = getVersionLabel("v", version, branch);
+ CDORevisionKey targetKey = CDORevisionUtil.createRevisionKey(pointer.getID(), branch, version);
+ String value = CDORevisionUtil.formatRevisionKey(targetKey);
+ showKeyValue(pout, true, "target", browser.href(label, getName(), "revision", value));
+ }
+ }
+ else
{
showKeyValue(pout, true, "resource", getRevisionValue(revision.getResourceID(), browser, ids, revision));
showKeyValue(pout, true, "container", getRevisionValue(revision.getContainerID(), browser, ids, revision));
@@ -841,12 +857,10 @@ public class CDOServerBrowser extends Worker
builder.append("&nbsp;&nbsp;");
for (CDORevision revision : revisions)
{
- String label = getVersionPrefix(revision) + revision.getVersion();
- String branchName = revision.getBranch().getName();
- if (!CDOBranch.MAIN_BRANCH_NAME.equals(branchName))
- {
- label += "[" + branchName + "]";
- }
+ String versionPrefix = getVersionPrefix(revision);
+ int version = revision.getVersion();
+ CDOBranch branch = revision.getBranch();
+ String label = getVersionLabel(versionPrefix, version, branch);
builder.append(" ");
if (revision == context)
@@ -879,6 +893,17 @@ public class CDOServerBrowser extends Worker
return value;
}
+ private String getVersionLabel(String versionPrefix, int version, CDOBranch branch)
+ {
+ String label = versionPrefix + version;
+ String branchName = branch.getName();
+ if (!CDOBranch.MAIN_BRANCH_NAME.equals(branchName))
+ {
+ label += "[" + branchName + "]";
+ }
+ return label;
+ }
+
private String getVersionPrefix(CDORevision revision)
{
if (revision instanceof PointerCDORevision)
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
index 69b668b9d1..baf512d12a 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
@@ -1,105 +1,110 @@
-/*
- * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Eike Stepper - initial API and implementation
- */
-package org.eclipse.emf.cdo.tests;
-
-import org.eclipse.emf.cdo.tests.bundle.OM;
-import org.eclipse.emf.cdo.tests.config.IScenario;
-import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
-import org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite;
-
-import java.util.List;
-
-/**
- * @author Eike Stepper
- */
-public abstract class AllConfigs extends ConfigTestSuite
-{
- @Override
- protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses, IScenario scenario)
- {
- // General
- testClasses.add(InitialTest.class);
- testClasses.add(CDOIDTest.class);
- testClasses.add(ComplexTest.class);
- testClasses.add(AttributeTest.class);
- testClasses.add(EnumTest.class);
- testClasses.add(EMapTest.class);
- testClasses.add(UnsetTest.class);
- testClasses.add(StateMachineTest.class);
- testClasses.add(SessionTest.class);
- testClasses.add(RevisionManagerTest.class);
- testClasses.add(RevisionManagerClientSideTest.class);
- testClasses.add(BranchingTest.class);
- testClasses.add(BranchingSameSessionTest.class);
- testClasses.add(BranchingWithCacheClearTest.class);
- testClasses.add(MergingTest.class);
- testClasses.add(ViewTest.class);
- testClasses.add(TransactionTest.class);
- testClasses.add(PushTransactionTest.class);
- testClasses.add(PushTransactionWithoutReconstructSavepointsTest.class);
- testClasses.add(CommitInfoTest.class);
- testClasses.add(AuditTest.class);
- testClasses.add(AuditSameSessionTest.class);
- testClasses.add(ResourceTest.class);
- testClasses.add(ContainmentTest.class);
- testClasses.add(InvalidationTest.class);
- testClasses.add(RollbackTest.class);
- testClasses.add(CrossReferenceTest.class);
- testClasses.add(ChunkingTest.class);
- testClasses.add(ChunkingWithMEMTest.class);
- testClasses.add(MEMStoreQueryTest.class);
- testClasses.add(PackageRegistryTest.class);
- testClasses.add(PartialCommitTest.class);
- testClasses.add(MetaTest.class);
- testClasses.add(RevisionDeltaTest.class);
- testClasses.add(RevisionDeltaInBranchTest.class);
- testClasses.add(RevisionDeltaCascadingBranchesTest.class);
- testClasses.add(IndexReconstructionTest.class);
- testClasses.add(AutoAttacherTest.class);
- testClasses.add(SavePointTest.class);
- testClasses.add(ChangeSubscriptionTest.class);
- testClasses.add(DetachTest.class);
- testClasses.add(ExternalReferenceTest.class);
- testClasses.add(XATransactionTest.class);
- testClasses.add(TransactionHandlerTest.class);
- testClasses.add(RepositoryTest.class);
- testClasses.add(LockingManagerTest.class);
- testClasses.add(LockingManagerRestartTransactionTest.class);
- testClasses.add(LockingManagerRestartSessionTest.class);
- testClasses.add(LockingManagerRestartRepositoryTest.class);
- testClasses.add(LockingNotificationsTest.class);
- testClasses.add(MultiValuedOfAttributeTest.class);
- testClasses.add(MapTest.class);
- testClasses.add(FeatureMapTest.class);
- testClasses.add(AdapterManagerTest.class);
- testClasses.add(ConflictResolverTest.class);
- testClasses.add(DynamicXSDTest.class);
- testClasses.add(SetFeatureTest.class);
- testClasses.add(DynamicPackageTest.class);
- testClasses.add(LegacyTest.class);
- testClasses.add(XRefTest.class);
- testClasses.add(StickyViewsTest.class);
- testClasses.add(LobTest.class);
- testClasses.add(OCLQueryTest.class);
- testClasses.add(ViewProviderTest.class);
- testClasses.add(WorkspaceTest.class);
- testClasses.add(BackupTest.class);
- testClasses.add(ResourceModificationTrackingTest.class);
-
- // TODO testClasses.add(RemoteSessionManagerTest.class);
- // TODO testClasses.add(ConflictResolverMergingTest.class);
- // TODO testClasses.add(NonCDOResourceTest.class);
- // TODO testClasses.add(GeneratedEcoreTest.class);
-
- // Bugzilla verifications
- testClasses.addAll(getTestClasses(OM.BUNDLE, "org.eclipse.emf.cdo.tests.bugzilla"));
- }
-}
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests;
+
+import org.eclipse.emf.cdo.tests.bundle.OM;
+import org.eclipse.emf.cdo.tests.config.IScenario;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite;
+
+import java.util.List;
+
+/**
+ * @author Eike Stepper
+ */
+public abstract class AllConfigs extends ConfigTestSuite
+{
+ public List<Class<? extends ConfigTest>> getBugzillaTests()
+ {
+ return getTestClasses(OM.BUNDLE, "org.eclipse.emf.cdo.tests.bugzilla");
+ }
+
+ @Override
+ protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses, IScenario scenario)
+ {
+ // General
+ testClasses.add(InitialTest.class);
+ testClasses.add(CDOIDTest.class);
+ testClasses.add(ComplexTest.class);
+ testClasses.add(AttributeTest.class);
+ testClasses.add(EnumTest.class);
+ testClasses.add(EMapTest.class);
+ testClasses.add(UnsetTest.class);
+ testClasses.add(StateMachineTest.class);
+ testClasses.add(SessionTest.class);
+ testClasses.add(RevisionManagerTest.class);
+ testClasses.add(RevisionManagerClientSideTest.class);
+ testClasses.add(BranchingTest.class);
+ testClasses.add(BranchingSameSessionTest.class);
+ testClasses.add(BranchingWithCacheClearTest.class);
+ testClasses.add(MergingTest.class);
+ testClasses.add(ViewTest.class);
+ testClasses.add(TransactionTest.class);
+ testClasses.add(PushTransactionTest.class);
+ testClasses.add(PushTransactionWithoutReconstructSavepointsTest.class);
+ testClasses.add(CommitInfoTest.class);
+ testClasses.add(AuditTest.class);
+ testClasses.add(AuditSameSessionTest.class);
+ testClasses.add(ResourceTest.class);
+ testClasses.add(ContainmentTest.class);
+ testClasses.add(InvalidationTest.class);
+ testClasses.add(RollbackTest.class);
+ testClasses.add(CrossReferenceTest.class);
+ testClasses.add(ChunkingTest.class);
+ testClasses.add(ChunkingWithMEMTest.class);
+ testClasses.add(MEMStoreQueryTest.class);
+ testClasses.add(PackageRegistryTest.class);
+ testClasses.add(PartialCommitTest.class);
+ testClasses.add(MetaTest.class);
+ testClasses.add(RevisionDeltaTest.class);
+ testClasses.add(RevisionDeltaInBranchTest.class);
+ testClasses.add(RevisionDeltaCascadingBranchesTest.class);
+ testClasses.add(IndexReconstructionTest.class);
+ testClasses.add(AutoAttacherTest.class);
+ testClasses.add(SavePointTest.class);
+ testClasses.add(ChangeSubscriptionTest.class);
+ testClasses.add(DetachTest.class);
+ testClasses.add(ExternalReferenceTest.class);
+ testClasses.add(XATransactionTest.class);
+ testClasses.add(TransactionHandlerTest.class);
+ testClasses.add(RepositoryTest.class);
+ testClasses.add(LockingManagerTest.class);
+ testClasses.add(LockingManagerRestartTransactionTest.class);
+ testClasses.add(LockingManagerRestartSessionTest.class);
+ testClasses.add(LockingManagerRestartRepositoryTest.class);
+ testClasses.add(LockingNotificationsTest.class);
+ testClasses.add(MultiValuedOfAttributeTest.class);
+ testClasses.add(MapTest.class);
+ testClasses.add(FeatureMapTest.class);
+ testClasses.add(AdapterManagerTest.class);
+ testClasses.add(ConflictResolverTest.class);
+ testClasses.add(DynamicXSDTest.class);
+ testClasses.add(SetFeatureTest.class);
+ testClasses.add(DynamicPackageTest.class);
+ testClasses.add(LegacyTest.class);
+ testClasses.add(XRefTest.class);
+ testClasses.add(StickyViewsTest.class);
+ testClasses.add(LobTest.class);
+ testClasses.add(OCLQueryTest.class);
+ testClasses.add(ViewProviderTest.class);
+ testClasses.add(WorkspaceTest.class);
+ testClasses.add(BackupTest.class);
+ testClasses.add(ResourceModificationTrackingTest.class);
+
+ // TODO testClasses.add(RemoteSessionManagerTest.class);
+ // TODO testClasses.add(ConflictResolverMergingTest.class);
+ // TODO testClasses.add(NonCDOResourceTest.class);
+ // TODO testClasses.add(GeneratedEcoreTest.class);
+
+ // Bugzilla verifications
+ testClasses.addAll(getBugzillaTests());
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java
index c504f9c3ab..416182c50e 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ResourceTest.java
@@ -1,1680 +1,1691 @@
-/*
- * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Simon McDuff - initial API and implementation
- * Eike Stepper - maintenance
- */
-package org.eclipse.emf.cdo.tests;
-
-import org.eclipse.emf.cdo.CDOObject;
-import org.eclipse.emf.cdo.CDOState;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.eresource.CDOResource;
-import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
-import org.eclipse.emf.cdo.eresource.CDOResourceNode;
-import org.eclipse.emf.cdo.session.CDOSession;
-import org.eclipse.emf.cdo.tests.model1.Category;
-import org.eclipse.emf.cdo.tests.model1.Company;
-import org.eclipse.emf.cdo.tests.model1.Order;
-import org.eclipse.emf.cdo.tests.model1.OrderDetail;
-import org.eclipse.emf.cdo.tests.model1.Product1;
-import org.eclipse.emf.cdo.tests.model1.VAT;
-import org.eclipse.emf.cdo.transaction.CDOTransaction;
-import org.eclipse.emf.cdo.util.CDOURIUtil;
-import org.eclipse.emf.cdo.util.CDOUtil;
-import org.eclipse.emf.cdo.util.CommitException;
-import org.eclipse.emf.cdo.util.ObjectNotFoundException;
-import org.eclipse.emf.cdo.view.CDOView;
-
-import org.eclipse.emf.common.notify.Notification;
-import org.eclipse.emf.common.notify.Notifier;
-import org.eclipse.emf.common.notify.impl.AdapterImpl;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.emf.ecore.xmi.XMIResource;
-import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Eike Stepper
- */
-public class ResourceTest extends AbstractCDOTest
-{
- /**
- * Test logic not up to date with the new xmi:id format.
- */
- public void _testSaveXMI() throws Exception
- {
- ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- transaction.commit();
- resource.save(cdoOUT, null);
- }
-
- ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
- {
- XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- resource.save(xmiOUT, null);
- }
-
- String xmiString = xmiOUT.toString();
- msg("XMI:\n\n" + xmiString);
-
- String cdoString = cdoOUT.toString();
- msg("CDO:\n\n" + cdoString);
-
- assertEquals(xmiString, cdoString);
- }
-
- public void testSaveXMI_WithXRef() throws Exception
- {
- ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- OrderDetail orderDetail = getModel1Factory().createOrderDetail();
- orderDetail.setPrice(147.111f);
- orderDetail.setProduct(category.getProducts().get(0));
- resource.getContents().add(orderDetail);
-
- transaction.commit();
- resource.save(cdoOUT, null);
- }
-
- ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
- {
- XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- OrderDetail orderDetail = getModel1Factory().createOrderDetail();
- orderDetail.setPrice(147.111f);
- orderDetail.setProduct(category.getProducts().get(0));
- resource.getContents().add(orderDetail);
-
- resource.save(xmiOUT, null);
- }
-
- String xmiString = xmiOUT.toString();
- msg("XMI:\n\n" + xmiString);
-
- String cdoString = cdoOUT.toString();
- msg("CDO:\n\n" + cdoString);
-
- // TODO assertEquals(xmiString, cdoString);
- }
-
- public void testSaveXMI_WithXRef_OtherResource() throws Exception
- {
- ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
- CDOResource resource2 = transaction.createResource(getResourcePath("/folder/res2"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- OrderDetail orderDetail = getModel1Factory().createOrderDetail();
- orderDetail.setPrice(147.111f);
- orderDetail.setProduct(category.getProducts().get(0));
- resource2.getContents().add(orderDetail);
-
- transaction.commit();
- resource.save(cdoOUT, null);
- resource2.save(cdoOUT, null);
- }
-
- ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
- {
- XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
- XMIResource resource2 = new XMIResourceImpl(URI.createFileURI("/folder/res2"));
-
- counter = 0;
- Category category = createCategoryTree(3);
- resource.getContents().add(category);
-
- OrderDetail orderDetail = getModel1Factory().createOrderDetail();
- orderDetail.setPrice(147.111f);
- orderDetail.setProduct(category.getProducts().get(0));
- resource2.getContents().add(orderDetail);
-
- resource.save(xmiOUT, null);
- resource2.save(xmiOUT, null);
- }
-
- String xmiString = xmiOUT.toString();
- msg("XMI:\n\n" + xmiString);
-
- String cdoString = cdoOUT.toString();
- msg("CDO:\n\n" + cdoString);
-
- // TODO assertEquals(xmiString, cdoString);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth1_Delete() throws Exception
- {
- attachDetachResourceDepth1(1, true, 0);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth1_Remove() throws Exception
- {
- attachDetachResourceDepth1(1, false, 0);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth2_Delete() throws Exception
- {
- attachDetachResourceDepth1(2, true, 1);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth2_Remove() throws Exception
- {
- attachDetachResourceDepth1(2, false, 1);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth3_Delete() throws Exception
- {
- attachDetachResourceDepth1(3, true, 2);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth3_Remove() throws Exception
- {
- attachDetachResourceDepth1(3, false, 2);
- }
-
- @CleanRepositoriesBefore
- public void testAttachDetachResourceDepth3_Remove_Tree() throws Exception
- {
- attachDetachResourceDepth1(3, false, 1);
- }
-
- public void testRootResourceFromURI() throws Exception
- {
- URI rootResourceURI = null;
- URI resourceURI = null;
- String resourcePath = getResourcePath("/test1");
- {
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
-
- resourceURI = URI.createURI("cdo:" + resourcePath);
- Resource res1 = resourceSet.createResource(resourceURI);
-
- transaction.commit();
- rootResourceURI = EcoreUtil.getURI(transaction.getRootResource());
- resourceURI = EcoreUtil.getURI((EObject)res1);
- }
-
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
- CDOResource rootResource = (CDOResource)resourceSet.getEObject(rootResourceURI, true);
- assertProxy(rootResource);
- assertSame(rootResource, transaction.getRootResource());
-
- CDOResource resource = (CDOResource)resourceSet.getEObject(resourceURI, true);
- assertClean(resource, transaction);
- assertSame(resource, transaction.getResource(resourcePath));
-
- transaction.close();
- session.close();
- }
-
- @CleanRepositoriesBefore
- public void testCreateResource_FromResourceSet() throws Exception
- {
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
-
- final URI uri = URI.createURI("cdo:/test1");
- CDOResource resource = (CDOResource)resourceSet.createResource(uri);
- assertActive(resource);
- assertNew(resource, transaction);
- assertEquals(transaction.getResourceSet(), resource.getResourceSet());
- assertEquals(CDOURIUtil.createResourceURI(session, "test1"), resource.getURI());
- assertEquals("test1", resource.getName());
- assertEquals(null, resource.getFolder());
-
- transaction.getRootResource().getContents().contains(resource);
- transaction.commit();
-
- CDOObject cdoResource = resource;
- CDOObject cdoRootResource = transaction.getRootResource();
- assertClean(cdoResource, transaction);
- assertClean(cdoRootResource, transaction);
- assertEquals(CDOID.NULL, cdoResource.cdoRevision().data().getContainerID());
- assertEquals(cdoRootResource.cdoID(), cdoResource.cdoRevision().data().getResourceID());
- assertEquals(cdoRootResource.cdoID(), cdoRootResource.cdoRevision().data().getResourceID());
- assertEquals(true, transaction.getResourceSet().getResources().contains(resource));
- assertEquals(false, transaction.getResourceSet().getResources().contains(transaction.getRootResource()));// Bug
- // 346636
-
- transaction.getRootResource().getContents().remove(resource);
- assertEquals(false, transaction.getResourceSet().getResources().contains(resource));
- assertEquals(false, transaction.getResourceSet().getResources().contains(transaction.getRootResource()));// Bug
- // 346636
- }
-
- public void testCreateNestedResource_FromResourceSet() throws Exception
- {
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
-
- final URI uri = URI.createURI("cdo:/folder/test1");
- CDOResource resource = (CDOResource)resourceSet.createResource(uri);
- assertActive(resource);
- assertNew(resource, transaction);
- assertEquals(transaction.getResourceSet(), resource.getResourceSet());
- assertEquals(CDOURIUtil.createResourceURI(session, "folder/test1"), resource.getURI());
- assertEquals("test1", resource.getName());
-
- CDOResourceFolder folder = resource.getFolder();
- assertNotNull(folder);
- assertEquals("folder", folder.getName());
- assertEquals(null, folder.getFolder());
- }
-
- public void testCreateResource_FromTransaction() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- // Test if Resource is well-formed after CDOResourceFactoryImpl.
- // Adapter will be called right after and could be used!
- transaction.getResourceSet().eAdapters().add(new TestAdapter());
-
- CDOResource resource = transaction.createResource(getResourcePath("/test1"));
- assertActive(resource);
-
- CDOResource resourceCopy = transaction.getOrCreateResource(getResourcePath("/test1"));
- assertEquals(resource, resourceCopy);
- assertNew(resource, transaction);
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("test1")), resource.getURI());
- assertEquals(transaction.getResourceSet(), resource.getResourceSet());
- }
-
- public void testCreateResource_WithDeepPath() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- transaction.createResource(getResourcePath("/org/eclipse/net4j/core"));
- transaction.commit();
- session.close();
- }
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.getResource(getResourcePath("/org/eclipse/net4j/core"));
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/org/eclipse/net4j/core")), resource.getURI());
- assertEquals(transaction.getResourceSet(), resource.getResourceSet());
- session.close();
- }
-
- public void testLoadAbsentResource_FromResourceSet() throws Exception
- {
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
-
- final URI uri = URI.createURI("cdo:/test1");
- CDOResource resource = (CDOResource)resourceSet.getResource(uri, false);
- assertEquals(null, resource);
-
- try
- {
- resourceSet.getResource(uri, true);
- }
- catch (Exception ignore)
- {
- }
-
- transaction.close();
- }
-
- public void testRemoveResourceWithCloseView() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- ResourceSet rset = transaction.getResourceSet();
- CDOResource resource = transaction.createResource(getResourcePath("/test1"));
- assertActive(resource);
-
- transaction.commit();
- assertEquals(1, rset.getResources().size()); // Bug 346636
- assertEquals(1, CDOUtil.getViewSet(rset).getViews().length);
-
- transaction.close();
- assertEquals(0, CDOUtil.getViewSet(rset).getViews().length);
- assertEquals(0, rset.getResources().size());
- session.close();
- }
-
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = (CDOResource)transaction.getResourceSet().getResource(
- CDOURIUtil.createResourceURI(transaction, getResourcePath("/test1")), true);
- assertNotNull(resource);
- assertEquals(transaction.getResourceSet(), resource.getResourceSet());
- assertEquals(1, transaction.getResourceSet().getResources().size());
- assertEquals(CDOState.PROXY, resource.cdoState());
- assertEquals(transaction, resource.cdoView());
- assertNull(resource.cdoRevision());
- }
- }
-
- public void testAttachResource() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- transaction.createResource(getResourcePath("/my/resource1"));
- assertEquals(1, transaction.getResourceSet().getResources().size());// Bug 346636
-
- transaction.commit();
- session.close();
- }
-
- public void testCommitMultipleResources() throws CommitException
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- transaction.createResource(getResourcePath("/level1/level2-A/level3"));
- transaction.createResource(getResourcePath("/level1/level2-B/level3"));
- transaction.commit();
- session.close();
- }
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource1 = transaction.getResource(getResourcePath("/level1/level2-A/level3"));
- CDOResource resource2 = transaction.getResource(getResourcePath("/level1/level2-B/level3"));
- assertEquals(getResourcePath("/level1/level2-A/level3"), resource1.getPath());
- assertEquals(getResourcePath("/level1/level2-B/level3"), resource2.getPath());
- session.close();
- }
-
- public void testLoadMultipleResources() throws CommitException
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- transaction.createResource(getResourcePath("/level1/level2-A/level3"));
- transaction.createResource(getResourcePath("/level1/level2-B/level3"));
- transaction.commit();
- session.close();
- }
-
- clearCache(getRepository().getRevisionManager());
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource1 = transaction.getResource(getResourcePath("/level1/level2-A/level3"));
- CDOResource resource2 = transaction.getResource(getResourcePath("/level1/level2-B/level3"));
- assertEquals(getResourcePath("/level1/level2-A/level3"), resource1.getPath());
- assertEquals(getResourcePath("/level1/level2-B/level3"), resource2.getPath());
- session.close();
- }
-
- public void testDuplicatePath() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- transaction.createResource(getResourcePath("/my/resource"));
- transaction.commit();
-
- transaction.createResource(getResourcePath("/my/resource"));
-
- try
- {
- transaction.commit();
- fail("CommitException expected");
- }
- catch (CommitException expected)
- {
- // Success
- }
- finally
- {
- session.close();
- }
- }
-
- public void testDuplicatePathAfterDetach() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
- transaction.commit();
-
- resource.delete(null);
- transaction.commit();
-
- transaction.createResource(getResourcePath("/my/resource"));
- transaction.commit();
- session.close();
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth0ToDepth0() throws Exception
- {
- changePath(0, 0);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth0ToDepth1() throws Exception
- {
- changePath(0, 1);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth0ToDepth2() throws Exception
- {
- changePath(0, 2);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth0ToDepth3() throws Exception
- {
- changePath(0, 3);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth3ToDepth3() throws Exception
- {
- changePath(3, 3);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth3ToDepth2() throws Exception
- {
- changePath(3, 2);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth3ToDepth1() throws Exception
- {
- changePath(3, 1);
- }
-
- @CleanRepositoriesBefore
- public void testChangePathFromDepth3ToDepth0() throws Exception
- {
- changePath(3, 0);
- }
-
- public void testChangeResourceURI() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
- transaction.commit();
-
- URI uri = URI.createURI("cdo://repo1/renamed");
- assertEquals(CDOURIUtil.createResourceURI(session, "/renamed"), uri);
- resource.setURI(uri);
-
- transaction.commit();
- session.close();
- }
-
- clearCache(getRepository().getRevisionManager());
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- assertEquals(false, transaction.hasResource("/my/resource"));
- assertEquals(true, transaction.hasResource("/renamed"));
- }
-
- @CleanRepositoriesBefore
- public void testChangeResourceFolderURI() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
- transaction.commit();
-
- URI uri = URI.createURI("cdo://repo1/renamed");
- assertEquals(CDOURIUtil.createResourceURI(session, "/renamed"), uri);
- resource.setURI(uri);
-
- transaction.commit();
- session.close();
- }
-
- clearCache(getRepository().getRevisionManager());
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- assertEquals(false, transaction.hasResource("/my/resource"));
- assertEquals(true, transaction.hasResource("/renamed"));
- }
-
- public void testPathNotNull() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(getResourcePath("/res1"));
- assertEquals(getResourcePath("/res1"), resource.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
-
- transaction.commit();
- assertEquals(getResourcePath("/res1"), resource.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
- session.close();
- }
-
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.getResource(getResourcePath("/res1"));
- assertEquals(getResourcePath("/res1"), resource.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
-
- CDOResource resource2 = transaction.getOrCreateResource(getResourcePath("/res2"));
- assertEquals(getResourcePath("/res2"), resource2.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
-
- transaction.commit();
- assertEquals(getResourcePath("/res2"), resource2.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
- session.close();
- }
-
- {
- CDOSession session = openSession();
- CDOView view = session.openView();
- CDOResource resource2 = view.getResource(getResourcePath("/res2"));
- assertEquals(getResourcePath("/res2"), resource2.getPath());
- assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
- session.close();
- }
- }
-
- public void testPrefetchContents() throws Exception
- {
- {
- Company company = getModel1Factory().createCompany();
- company.getCategories().add(createCategoryTree(3));
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOResource resource = transaction.createResource(getResourcePath("/res1"));
- resource.getContents().add(company);
-
- transaction.commit();
- session.close();
- }
-
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOResource resource = transaction.getResource(getResourcePath("/res1"));
- resource.cdoPrefetch(CDORevision.DEPTH_INFINITE);
-
- Company company = (Company)resource.getContents().get(0);
- System.out.println(company);
-
- session.close();
- }
-
- private static int counter;
-
- private Category createCategoryTree(int depth)
- {
- if (depth == 0)
- {
- return null;
- }
-
- Category category = getModel1Factory().createCategory();
- for (int i = 0; i < 2; i++)
- {
- Category child = createCategoryTree(depth - 1);
- if (child != null)
- {
- category.getCategories().add(child);
- }
- }
-
- for (int i = 0; i < 3; i++)
- {
- Product1 child = getModel1Factory().createProduct1();
- // generate a unique id
- String id = "test " + depth + "_" + i + "_" + ++counter;
- child.setName(id);
- category.getProducts().add(child);
- }
-
- return category;
- }
-
- /**
- * bug 208689
- */
- public void testQueryResources() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- createResource(transaction, "/aresource");
- createResource(transaction, "/aaresource");
- createResource(transaction, "/abresource");
- createResource(transaction, "/acresource");
- createResource(transaction, "/adresource");
- createResource(transaction, "/aeresource");
- createResource(transaction, "/bresource");
- createResource(transaction, "/baresource");
- createResource(transaction, "/bbresource");
- createResource(transaction, "/bcresource");
- createResource(transaction, "/bdresource");
- createResource(transaction, "/beresource");
- createResource(transaction, "/bearesource");
- createResource(transaction, "/bebresource");
- createResource(transaction, "/cresource");
- createResource(transaction, "/caresource");
- createResource(transaction, "/caresource2");
- createResource(transaction, "/caresource3");
- createResource(transaction, "/cbresource");
- createResource(transaction, "/ccresource");
- createResource(transaction, "/cdresource");
- createResource(transaction, "/ceresource");
- transaction.commit();
- session.close();
- }
-
- CDOSession session = openSession();
- CDOView view = session.openView();
- queryResources(view, "a", 6);
- queryResources(view, "b", 8);
- queryResources(view, "c", 8);
- queryResources(view, "be", 3);
- queryResources(view, "ca", 3);
- session.close();
- }
-
- /**
- * bug 208689
- */
- public void testQueryModifiedResources() throws Exception
- {
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- createResource(transaction, "/aresource");
- createResource(transaction, "/aaresource");
- createResource(transaction, "/abresource");
- createResource(transaction, "/acresource");
- createResource(transaction, "/adresource");
- createResource(transaction, "/aeresource");
- createResource(transaction, "/bresource");
- createResource(transaction, "/baresource");
- createResource(transaction, "/bbresource");
- createResource(transaction, "/bcresource");
- createResource(transaction, "/bdresource");
- createResource(transaction, "/beresource");
- createResource(transaction, "/bearesource");
- createResource(transaction, "/bebresource");
- createResource(transaction, "/cresource");
- createResource(transaction, "/caresource");
- createResource(transaction, "/caresource2");
- createResource(transaction, "/caresource3");
- createResource(transaction, "/cbresource");
- createResource(transaction, "/ccresource");
- createResource(transaction, "/cdresource");
- createResource(transaction, "/ceresource");
- transaction.commit();
- modifyResource(transaction, "/aresource");
- modifyResource(transaction, "/aaresource");
- modifyResource(transaction, "/abresource");
- modifyResource(transaction, "/acresource");
- modifyResource(transaction, "/adresource");
- modifyResource(transaction, "/aeresource");
- modifyResource(transaction, "/bresource");
- modifyResource(transaction, "/baresource");
- modifyResource(transaction, "/bbresource");
- modifyResource(transaction, "/bcresource");
- modifyResource(transaction, "/bdresource");
- modifyResource(transaction, "/beresource");
- modifyResource(transaction, "/bearesource");
- modifyResource(transaction, "/bebresource");
- modifyResource(transaction, "/cresource");
- modifyResource(transaction, "/caresource");
- modifyResource(transaction, "/caresource2");
- modifyResource(transaction, "/caresource3");
- modifyResource(transaction, "/cbresource");
- modifyResource(transaction, "/ccresource");
- modifyResource(transaction, "/cdresource");
- modifyResource(transaction, "/ceresource");
- transaction.commit();
- session.close();
- }
-
- CDOSession session = openSession();
- CDOView view = session.openView();
- queryResources(view, "a", 6);
- queryResources(view, "b", 8);
- queryResources(view, "c", 8);
- queryResources(view, "be", 3);
- queryResources(view, "ca", 3);
- session.close();
- }
-
- public void testDeleteResource() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOResource resource = createResource(transaction, "/resource1");
- CDOID resourceID = resource.cdoID();
-
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- CDOID objectID = object.cdoID();
-
- transaction.commit();
- resource.delete(null);
- transaction.commit();
- transaction.close();
-
- CDOView view = session.openView();
- assertEquals(false, view.hasResource("/resource1"));
-
- try
- {
- view.getResourceNode("/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceFresh() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOResource resource = createResource(transaction, "/resource1");
- CDOID resourceID = resource.cdoID();
-
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- CDOID objectID = object.cdoID();
-
- transaction.commit();
- resource.delete(null);
- transaction.commit();
- transaction.close();
-
- clearCache(getRepository().getRevisionManager());
- CDOView view = session.openView();
- assertEquals(false, view.hasResource("/resource1"));
-
- try
- {
- view.getResourceNode("/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceDifferentSession() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOSession session2 = openSession();
- CDOView view = session2.openView();
-
- CDOResource resource = createResource(transaction, "/resource1");
- CDOID resourceID = resource.cdoID();
-
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- CDOID objectID = object.cdoID();
-
- transaction.commit();
- assertEquals(true, view.hasResource(getResourcePath("/resource1")));
- assertEquals(resource.getURI(), view.getResource(getResourcePath("/resource1")).getURI());
-
- resource.delete(null);
- commitAndSync(transaction, view);
- transaction.close();
-
- assertEquals(false, view.hasResource("/resource1"));
-
- try
- {
- view.getResourceNode("/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceDifferentSessionFresh() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOSession session2 = openSession();
- CDOView view = session2.openView();
-
- CDOResource resource = createResource(transaction, "/resource1");
- CDOID resourceID = resource.cdoID();
-
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- CDOID objectID = object.cdoID();
-
- transaction.commit();
- assertEquals(true, view.hasResource(getResourcePath("/resource1")));
- assertEquals(resource.getURI(), view.getResource(getResourcePath("/resource1")).getURI());
-
- resource.delete(null);
- commitAndSync(transaction, view);
- transaction.close();
-
- clearCache(getRepository().getRevisionManager());
- assertEquals(false, view.hasResource("/resource1"));
-
- try
- {
- view.getResourceNode("/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- CDOResource resource1 = view.getResource(getResourcePath("/resource1"));
- assertNull(resource1);
- fail("Exception expected");
- // TODO Fails on automated build:
- // junit.framework.AssertionFailedError: Exception expected
- // at org.eclipse.emf.cdo.tests.ResourceTest.testDeleteResourceDifferentSessionFresh(ResourceTest.java:859)
- // at org.eclipse.net4j.tests.AbstractOMTest.runBare(AbstractOMTest.java:86)
- // at org.eclipse.net4j.tests.AbstractOMTest.run(AbstractOMTest.java:108)
- // at org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite$TestWrapper.runTest(ConfigTestSuite.java:126)
- // at org.eclipse.test.EclipseTestRunner.run(EclipseTestRunner.java:332)
- // at org.eclipse.test.EclipseTestRunner.run(EclipseTestRunner.java:202)
- // at org.eclipse.test.CoreTestApplication.runTests(CoreTestApplication.java:35)
- // at org.eclipse.test.CoreTestApplication.run(CoreTestApplication.java:31)
- // at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:574)
- // at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
- // at org.eclipse.equinox.internal.app.MainApplicationLauncher.run(MainApplicationLauncher.java:32)
- // at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
- // at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
- // at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
- // at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
- // at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
- // at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
- // at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
- // at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
- // at org.eclipse.core.launcher.Main.main(Main.java:34)
- }
- catch (Exception expected)
- {
- expected.printStackTrace();
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceFolder() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = createResource(transaction, "/folder/resource1");
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- transaction.commit();
-
- CDOResourceFolder folder = resource.getFolder();
- CDOID folderID = folder.cdoID();
- CDOID resourceID = resource.cdoID();
- CDOID objectID = object.cdoID();
-
- folder.delete(null);
- transaction.commit();
- transaction.close();
-
- CDOView view = session.openView();
- assertEquals(false, view.hasResource("/folder/resource1"));
-
- try
- {
- view.getResourceNode("/folder");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResourceNode("/folder/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/folder/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(folderID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceFolderFresh() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = createResource(transaction, "/folder/resource1");
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
- transaction.commit();
-
- CDOResourceFolder folder = resource.getFolder();
- CDOID folderID = folder.cdoID();
- CDOID resourceID = resource.cdoID();
- CDOID objectID = object.cdoID();
-
- folder.delete(null);
- transaction.commit();
- transaction.close();
-
- clearCache(getRepository().getRevisionManager());
- CDOView view = session.openView();
- assertEquals(false, view.hasResource("/folder/resource1"));
-
- try
- {
- view.getResourceNode("/folder");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResourceNode("/folder/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/folder/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(folderID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceFolderDifferentSession() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOSession session2 = openSession();
- CDOView view = session2.openView();
-
- CDOResource resource = createResource(transaction, "/folder/resource1");
- CDOResourceFolder folder = resource.getFolder();
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
-
- transaction.commit();
- assertEquals(true, view.hasResource(getResourcePath("/folder/resource1")));
- assertEquals(resource.getURI(), view.getResource(getResourcePath("/folder/resource1")).getURI());
-
- CDOID folderID = folder.cdoID();
- CDOID resourceID = resource.cdoID();
- CDOID objectID = object.cdoID();
-
- folder.delete(null);
- commitAndSync(transaction, view);
- transaction.close();
-
- assertEquals(false, view.hasResource("/folder/resource1"));
-
- try
- {
- view.getResourceNode("/folder");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResourceNode("/folder/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/folder/resource1"));
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(folderID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- public void testDeleteResourceFolderDifferentSessionFresh() throws Exception
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- CDOSession session2 = openSession();
- CDOView view = session2.openView();
-
- CDOResource resource = createResource(transaction, "/folder/resource1");
- CDOResourceFolder folder = resource.getFolder();
- CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
-
- transaction.commit();
- assertEquals(true, view.hasResource(getResourcePath("/folder/resource1")));
- assertEquals(resource.getURI(), view.getResource(getResourcePath("/folder/resource1")).getURI());
-
- CDOID folderID = folder.cdoID();
- CDOID resourceID = resource.cdoID();
- CDOID objectID = object.cdoID();
-
- folder.delete(null);
- commitAndSync(transaction, view);
- transaction.close();
-
- clearCache(getRepository().getRevisionManager());
- assertEquals(false, view.hasResource("/folder/resource1"));
-
- try
- {
- view.getResourceNode("/folder");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResourceNode("/folder/resource1");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getResource(getResourcePath("/folder/resource1"));
- // TODO Fails on automated build
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- }
-
- try
- {
- view.getObject(folderID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(resourceID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- try
- {
- view.getObject(objectID);
- fail("ObjectNotFoundException expected");
- }
- catch (ObjectNotFoundException expected)
- {
- }
-
- session.close();
- }
-
- /**
- * Create resource with the following pattern /test1/test2/test3 for a depth 3. <br>
- * After it will remove the resource with the following rule:<br>
- * if calldelete is true <code>resource.delete(null)</code> <br>
- * if calldelete is false it will use the depthtoRemove to call <code>object.remove(resource)</code><br>
- * deptToRemove = /0/1/2/...<br>
- * It will remove it from parent folder (depthtoRemove - 1);
- */
- private void attachDetachResourceDepth1(int depth, boolean callDelete, int depthtoRemove) throws Exception
- {
- CDOSession session = openSession();
- ResourceSet resourceSet = new ResourceSetImpl();
- CDOTransaction transaction = session.openTransaction(resourceSet);
- CDOResource rootResource = transaction.getRootResource();
- assertSame(rootResource, rootResource.eResource());
- String path = "";
- List<String> names = new ArrayList<String>();
- for (int i = 0; i < depth; i++)
- {
- String name = "test" + String.valueOf(i + 1);
- names.add(name);
- path += "/" + name;
- }
-
- final URI uri = URI.createURI("cdo:" + path);
- CDOResource resource = (CDOResource)resourceSet.createResource(uri);
- assertEquals(names.get(names.size() - 1), resource.getName());
-
- transaction.commit();
- List<CDOResourceNode> nodesList = new ArrayList<CDOResourceNode>();
- CDOResource resourceByLookup = null;
- CDOResourceNode next = null;
- for (int i = 0; i < depth; i++)
- {
- if (i == 0)
- {
- next = (CDOResourceNode)rootResource.getContents().get(0);
- }
- else
- {
- next = ((CDOResourceFolder)next).getNodes().get(0);
- }
-
- nodesList.add(next);
- }
-
- resourceByLookup = (CDOResource)next;
- assertSame(resource, resourceByLookup);
- assertClean(resourceByLookup, transaction);
- assertEquals(true, resourceSet.getResources().contains(resourceByLookup));
-
- CDOObject cdoParent = null;
- CDOObject cdoRootResource = CDOUtil.getCDOObject(rootResource);
- for (int i = 0; i < depth; i++)
- {
- CDOResourceNode resourceNode = nodesList.get(i);
- CDOObject cdoResourceNode = CDOUtil.getCDOObject(resourceNode);
-
- if (i == 0)
- {
- assertEquals(cdoRootResource.cdoID(), cdoResourceNode.cdoRevision().data().getResourceID());
- assertEquals(CDOID.NULL, cdoResourceNode.cdoRevision().data().getContainerID());
- }
- else
- {
- assertEquals(CDOID.NULL, cdoResourceNode.cdoRevision().data().getResourceID());
- assertEquals(cdoParent.cdoID(), cdoResourceNode.cdoRevision().data().getContainerID());
- }
-
- cdoParent = cdoResourceNode;
- }
-
- if (callDelete)
- {
- resource.delete(null);
- depthtoRemove = depth;
- }
- else
- {
- CDOResourceNode node = nodesList.get(depthtoRemove);
- if (depthtoRemove == 0)
- {
- rootResource.getContents().remove(node);
- }
- else
- {
- CDOResourceFolder parentFolder = (CDOResourceFolder)nodesList.get(depthtoRemove - 1);
- assertEquals(parentFolder, node.getFolder());
- parentFolder.getNodes().remove(node);
- }
- }
-
- for (int i = depthtoRemove; i < depth; i++)
- {
- CDOResourceNode transientNode = nodesList.get(i);
- assertTransient(transientNode);
- if (transientNode instanceof CDOResource)
- {
- assertEquals(false, resourceSet.getResources().contains(transientNode));
- }
-
- assertEquals(null, transientNode.eResource());
- if (i == depthtoRemove)
- {
- assertEquals(null, transientNode.eContainer());
- }
- else
- {
- assertEquals(cdoParent, transientNode.eContainer());
- }
-
- cdoParent = transientNode;
- }
-
- transaction.commit();
- }
-
- private void changePath(int depthFrom, int depthTo) throws Exception
- {
- String prefixA = "testA";
- String prefixB = "testB";
-
- String oldPath = createPath(prefixA, depthFrom, "test");
- String newPath = createPath(prefixB, depthTo, "test2");
- {
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
- CDOResource resource = transaction.createResource(oldPath);
- Order order = getModel1Factory().createPurchaseOrder();
- resource.getContents().add(order);
-
- String path = CDOURIUtil.extractResourcePath(resource.getURI());
- assertEquals(oldPath, path);
- assertEquals(depthFrom, CDOURIUtil.analyzePath(resource.getURI()).size() - 1);
-
- transaction.commit();
-
- CDOID idBeforeChangePath = CDOUtil.getCDOObject(resource).cdoID();
- CDOID idBeforeChangePathOrder = CDOUtil.getCDOObject(order).cdoID();
-
- msg("New path");
- resource.setPath(newPath);
- path = CDOURIUtil.extractResourcePath(resource.getURI());
- assertEquals(depthTo, CDOURIUtil.analyzePath(resource.getURI()).size() - 1);
- assertEquals(newPath, path);
- transaction.commit();
-
- CDOID idAfterChangePath = CDOUtil.getCDOObject(resource).cdoID();
- assertEquals(idBeforeChangePath, idAfterChangePath);
-
- CDOID idAfterChangePathOrder = CDOUtil.getCDOObject(order).cdoID();
- assertEquals(idBeforeChangePathOrder, idAfterChangePathOrder);
-
- Resource resourceRenamed = transaction.getResourceSet().getResource(
- CDOURIUtil.createResourceURI(session, newPath), false);
-
- assertEquals(resource, resourceRenamed);
- assertClean(resource, transaction);
- assertClean(order, transaction);
- session.close();
- }
-
- clearCache(getRepository().getRevisionManager());
- CDOSession session = openSession();
- CDOTransaction transaction = session.openTransaction();
-
- try
- {
- URI uri = CDOURIUtil.createResourceURI(session, oldPath);
- transaction.getResourceSet().getResource(uri, true);
- fail("Doesn't exist");
- }
- catch (Exception ex)
- {
- }
-
- Resource resource = transaction.getResourceSet().getResource(CDOURIUtil.createResourceURI(session, newPath), true);
- assertNotNull(resource);
- }
-
- private String createPath(String namePrefix, int depth, String name)
- {
- String path = "";
- for (int i = 0; i < depth; i++)
- {
- String localName = namePrefix + String.valueOf(i + 1);
- path += "/" + localName;
- }
-
- path += "/" + name;
- return path;
- }
-
- private CDOResource createResource(CDOTransaction transaction, String path)
- {
- Product1 p = getModel1Factory().createProduct1();
- p.setName("test-" + path);
- p.setVat(VAT.VAT0);
-
- CDOResource resource = transaction.createResource(getResourcePath(path));
- resource.getContents().add(p);
- return resource;
- }
-
- private CDOResource modifyResource(CDOTransaction transaction, String path)
- {
- Product1 p = getModel1Factory().createProduct1();
- p.setName("test-" + path + "-modified");
- p.setVat(VAT.VAT0);
-
- CDOResource resource = transaction.getResource(getResourcePath(path));
- resource.getContents().add(p);
- return resource;
- }
-
- private void queryResources(CDOView view, String namePrefix, int expected)
- {
- msg("Name prefix: " + namePrefix);
- CDOResourceFolder folder = (CDOResourceFolder)view.getResourceNode(getResourcePath(null));
- List<CDOResourceNode> nodes = view.queryResources(folder, namePrefix, false);
- for (CDOResourceNode node : nodes)
- {
- msg("Result: " + node.getPath());
- }
-
- assertEquals(expected, nodes.size());
- }
-
- /**
- * See bug 353249.
- */
- public void testGetResourceNodeContract()
- {
- CDOView view = openSession().openView();
-
- try
- {
- view.getResourceNode("SomePath/That/DoesntExist");
- fail("Exception expected");
- }
- catch (Exception expected)
- {
- // SUCCCESS
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private static class TestAdapter extends AdapterImpl
- {
- @Override
- public void notifyChanged(Notification msg)
- {
- super.notifyChanged(msg);
- if (msg.getNewValue() instanceof CDOResource)
- {
- ((CDOResource)msg.getNewValue()).getPath();
- }
- }
-
- @Override
- public void setTarget(Notifier newTarget)
- {
- }
-
- @Override
- public boolean isAdapterForType(Object type)
- {
- return super.isAdapterForType(type);
- }
- }
-}
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ */
+package org.eclipse.emf.cdo.tests;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
+import org.eclipse.emf.cdo.eresource.CDOResourceNode;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Order;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.VAT;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOURIUtil;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.ObjectNotFoundException;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eike Stepper
+ */
+public class ResourceTest extends AbstractCDOTest
+{
+ /**
+ * Test logic not up to date with the new xmi:id format.
+ */
+ public void _testSaveXMI() throws Exception
+ {
+ ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ transaction.commit();
+ resource.save(cdoOUT, null);
+ }
+
+ ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
+ {
+ XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ resource.save(xmiOUT, null);
+ }
+
+ String xmiString = xmiOUT.toString();
+ msg("XMI:\n\n" + xmiString);
+
+ String cdoString = cdoOUT.toString();
+ msg("CDO:\n\n" + cdoString);
+
+ assertEquals(xmiString, cdoString);
+ }
+
+ public void testSaveXMI_WithXRef() throws Exception
+ {
+ ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ orderDetail.setPrice(147.111f);
+ orderDetail.setProduct(category.getProducts().get(0));
+ resource.getContents().add(orderDetail);
+
+ transaction.commit();
+ resource.save(cdoOUT, null);
+ }
+
+ ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
+ {
+ XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ orderDetail.setPrice(147.111f);
+ orderDetail.setProduct(category.getProducts().get(0));
+ resource.getContents().add(orderDetail);
+
+ resource.save(xmiOUT, null);
+ }
+
+ String xmiString = xmiOUT.toString();
+ msg("XMI:\n\n" + xmiString);
+
+ String cdoString = cdoOUT.toString();
+ msg("CDO:\n\n" + cdoString);
+
+ // TODO assertEquals(xmiString, cdoString);
+ }
+
+ public void testSaveXMI_WithXRef_OtherResource() throws Exception
+ {
+ ByteArrayOutputStream cdoOUT = new ByteArrayOutputStream();
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/folder/res1"));
+ CDOResource resource2 = transaction.createResource(getResourcePath("/folder/res2"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ orderDetail.setPrice(147.111f);
+ orderDetail.setProduct(category.getProducts().get(0));
+ resource2.getContents().add(orderDetail);
+
+ transaction.commit();
+ resource.save(cdoOUT, null);
+ resource2.save(cdoOUT, null);
+ }
+
+ ByteArrayOutputStream xmiOUT = new ByteArrayOutputStream();
+ {
+ XMIResource resource = new XMIResourceImpl(URI.createFileURI("/folder/res1"));
+ XMIResource resource2 = new XMIResourceImpl(URI.createFileURI("/folder/res2"));
+
+ counter = 0;
+ Category category = createCategoryTree(3);
+ resource.getContents().add(category);
+
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ orderDetail.setPrice(147.111f);
+ orderDetail.setProduct(category.getProducts().get(0));
+ resource2.getContents().add(orderDetail);
+
+ resource.save(xmiOUT, null);
+ resource2.save(xmiOUT, null);
+ }
+
+ String xmiString = xmiOUT.toString();
+ msg("XMI:\n\n" + xmiString);
+
+ String cdoString = cdoOUT.toString();
+ msg("CDO:\n\n" + cdoString);
+
+ // TODO assertEquals(xmiString, cdoString);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth1_Delete() throws Exception
+ {
+ attachDetachResourceDepth1(1, true, 0);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth1_Remove() throws Exception
+ {
+ attachDetachResourceDepth1(1, false, 0);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth2_Delete() throws Exception
+ {
+ attachDetachResourceDepth1(2, true, 1);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth2_Remove() throws Exception
+ {
+ attachDetachResourceDepth1(2, false, 1);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth3_Delete() throws Exception
+ {
+ attachDetachResourceDepth1(3, true, 2);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth3_Remove() throws Exception
+ {
+ attachDetachResourceDepth1(3, false, 2);
+ }
+
+ @CleanRepositoriesBefore
+ public void testAttachDetachResourceDepth3_Remove_Tree() throws Exception
+ {
+ attachDetachResourceDepth1(3, false, 1);
+ }
+
+ public void testRootResourceFromURI() throws Exception
+ {
+ URI rootResourceURI = null;
+ URI resourceURI = null;
+ String resourcePath = getResourcePath("/test1");
+ {
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+
+ resourceURI = URI.createURI("cdo:" + resourcePath);
+ Resource res1 = resourceSet.createResource(resourceURI);
+
+ transaction.commit();
+ rootResourceURI = EcoreUtil.getURI(transaction.getRootResource());
+ resourceURI = EcoreUtil.getURI((EObject)res1);
+ }
+
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+ CDOResource rootResource = (CDOResource)resourceSet.getEObject(rootResourceURI, true);
+ assertProxy(rootResource);
+ assertSame(rootResource, transaction.getRootResource());
+
+ CDOResource resource = (CDOResource)resourceSet.getEObject(resourceURI, true);
+ assertClean(resource, transaction);
+ assertSame(resource, transaction.getResource(resourcePath));
+
+ transaction.close();
+ session.close();
+ }
+
+ // public void testRootResourceParent() throws Exception
+ // {
+ // CDOSession session = openSession();
+ // ResourceSet resourceSet = new ResourceSetImpl();
+ // CDOTransaction transaction = session.openTransaction(resourceSet);
+ // CDOResource rootResource = transaction.getRootResource();
+ // assertEquals(true, CDOIDUtil.isNull(rootResource.cdoRevision().data().getResourceID()));
+ // assertEquals(null, rootResource.eResource());
+ // assertEquals(false, transaction.getResourceSet().getResources().contains(rootResource));
+ // }
+
+ @CleanRepositoriesBefore
+ public void testCreateResource_FromResourceSet() throws Exception
+ {
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+
+ final URI uri = URI.createURI("cdo:/test1");
+ CDOResource resource = (CDOResource)resourceSet.createResource(uri);
+ assertActive(resource);
+ assertNew(resource, transaction);
+ assertEquals(transaction.getResourceSet(), resource.getResourceSet());
+ assertEquals(CDOURIUtil.createResourceURI(session, "test1"), resource.getURI());
+ assertEquals("test1", resource.getName());
+ assertEquals(null, resource.getFolder());
+
+ transaction.getRootResource().getContents().contains(resource);
+ transaction.commit();
+
+ CDOObject cdoResource = resource;
+ CDOObject cdoRootResource = transaction.getRootResource();
+ assertClean(cdoResource, transaction);
+ assertClean(cdoRootResource, transaction);
+ assertEquals(CDOID.NULL, cdoResource.cdoRevision().data().getContainerID());
+ assertEquals(cdoRootResource.cdoID(), cdoResource.cdoRevision().data().getResourceID());
+ assertEquals(cdoRootResource.cdoID(), cdoRootResource.cdoRevision().data().getResourceID());
+ assertEquals(true, transaction.getResourceSet().getResources().contains(resource));
+ assertEquals(false, transaction.getResourceSet().getResources().contains(transaction.getRootResource()));// Bug
+ // 346636
+
+ transaction.getRootResource().getContents().remove(resource);
+ assertEquals(false, transaction.getResourceSet().getResources().contains(resource));
+ assertEquals(false, transaction.getResourceSet().getResources().contains(transaction.getRootResource()));// Bug
+ // 346636
+ }
+
+ public void testCreateNestedResource_FromResourceSet() throws Exception
+ {
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+
+ final URI uri = URI.createURI("cdo:/folder/test1");
+ CDOResource resource = (CDOResource)resourceSet.createResource(uri);
+ assertActive(resource);
+ assertNew(resource, transaction);
+ assertEquals(transaction.getResourceSet(), resource.getResourceSet());
+ assertEquals(CDOURIUtil.createResourceURI(session, "folder/test1"), resource.getURI());
+ assertEquals("test1", resource.getName());
+
+ CDOResourceFolder folder = resource.getFolder();
+ assertNotNull(folder);
+ assertEquals("folder", folder.getName());
+ assertEquals(null, folder.getFolder());
+ }
+
+ public void testCreateResource_FromTransaction() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ // Test if Resource is well-formed after CDOResourceFactoryImpl.
+ // Adapter will be called right after and could be used!
+ transaction.getResourceSet().eAdapters().add(new TestAdapter());
+
+ CDOResource resource = transaction.createResource(getResourcePath("/test1"));
+ assertActive(resource);
+
+ CDOResource resourceCopy = transaction.getOrCreateResource(getResourcePath("/test1"));
+ assertEquals(resource, resourceCopy);
+ assertNew(resource, transaction);
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("test1")), resource.getURI());
+ assertEquals(transaction.getResourceSet(), resource.getResourceSet());
+ }
+
+ public void testCreateResource_WithDeepPath() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.createResource(getResourcePath("/org/eclipse/net4j/core"));
+ transaction.commit();
+ session.close();
+ }
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("/org/eclipse/net4j/core"));
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/org/eclipse/net4j/core")), resource.getURI());
+ assertEquals(transaction.getResourceSet(), resource.getResourceSet());
+ session.close();
+ }
+
+ public void testLoadAbsentResource_FromResourceSet() throws Exception
+ {
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+
+ final URI uri = URI.createURI("cdo:/test1");
+ CDOResource resource = (CDOResource)resourceSet.getResource(uri, false);
+ assertEquals(null, resource);
+
+ try
+ {
+ resourceSet.getResource(uri, true);
+ }
+ catch (Exception ignore)
+ {
+ }
+
+ transaction.close();
+ }
+
+ public void testRemoveResourceWithCloseView() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ ResourceSet rset = transaction.getResourceSet();
+ CDOResource resource = transaction.createResource(getResourcePath("/test1"));
+ assertActive(resource);
+
+ transaction.commit();
+ assertEquals(1, rset.getResources().size()); // Bug 346636
+ assertEquals(1, CDOUtil.getViewSet(rset).getViews().length);
+
+ transaction.close();
+ assertEquals(0, CDOUtil.getViewSet(rset).getViews().length);
+ assertEquals(0, rset.getResources().size());
+ session.close();
+ }
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = (CDOResource)transaction.getResourceSet().getResource(
+ CDOURIUtil.createResourceURI(transaction, getResourcePath("/test1")), true);
+ assertNotNull(resource);
+ assertEquals(transaction.getResourceSet(), resource.getResourceSet());
+ assertEquals(1, transaction.getResourceSet().getResources().size());
+ assertEquals(CDOState.PROXY, resource.cdoState());
+ assertEquals(transaction, resource.cdoView());
+ assertNull(resource.cdoRevision());
+ }
+ }
+
+ public void testAttachResource() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ transaction.createResource(getResourcePath("/my/resource1"));
+ assertEquals(1, transaction.getResourceSet().getResources().size());// Bug 346636
+
+ transaction.commit();
+ session.close();
+ }
+
+ public void testCommitMultipleResources() throws CommitException
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.createResource(getResourcePath("/level1/level2-A/level3"));
+ transaction.createResource(getResourcePath("/level1/level2-B/level3"));
+ transaction.commit();
+ session.close();
+ }
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource1 = transaction.getResource(getResourcePath("/level1/level2-A/level3"));
+ CDOResource resource2 = transaction.getResource(getResourcePath("/level1/level2-B/level3"));
+ assertEquals(getResourcePath("/level1/level2-A/level3"), resource1.getPath());
+ assertEquals(getResourcePath("/level1/level2-B/level3"), resource2.getPath());
+ session.close();
+ }
+
+ public void testLoadMultipleResources() throws CommitException
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.createResource(getResourcePath("/level1/level2-A/level3"));
+ transaction.createResource(getResourcePath("/level1/level2-B/level3"));
+ transaction.commit();
+ session.close();
+ }
+
+ clearCache(getRepository().getRevisionManager());
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource1 = transaction.getResource(getResourcePath("/level1/level2-A/level3"));
+ CDOResource resource2 = transaction.getResource(getResourcePath("/level1/level2-B/level3"));
+ assertEquals(getResourcePath("/level1/level2-A/level3"), resource1.getPath());
+ assertEquals(getResourcePath("/level1/level2-B/level3"), resource2.getPath());
+ session.close();
+ }
+
+ public void testDuplicatePath() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.createResource(getResourcePath("/my/resource"));
+ transaction.commit();
+
+ transaction.createResource(getResourcePath("/my/resource"));
+
+ try
+ {
+ transaction.commit();
+ fail("CommitException expected");
+ }
+ catch (CommitException expected)
+ {
+ // Success
+ }
+ finally
+ {
+ session.close();
+ }
+ }
+
+ public void testDuplicatePathAfterDetach() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
+ transaction.commit();
+
+ resource.delete(null);
+ transaction.commit();
+
+ transaction.createResource(getResourcePath("/my/resource"));
+ transaction.commit();
+ session.close();
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth0ToDepth0() throws Exception
+ {
+ changePath(0, 0);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth0ToDepth1() throws Exception
+ {
+ changePath(0, 1);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth0ToDepth2() throws Exception
+ {
+ changePath(0, 2);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth0ToDepth3() throws Exception
+ {
+ changePath(0, 3);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth3ToDepth3() throws Exception
+ {
+ changePath(3, 3);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth3ToDepth2() throws Exception
+ {
+ changePath(3, 2);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth3ToDepth1() throws Exception
+ {
+ changePath(3, 1);
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangePathFromDepth3ToDepth0() throws Exception
+ {
+ changePath(3, 0);
+ }
+
+ public void testChangeResourceURI() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
+ transaction.commit();
+
+ URI uri = URI.createURI("cdo://repo1/renamed");
+ assertEquals(CDOURIUtil.createResourceURI(session, "/renamed"), uri);
+ resource.setURI(uri);
+
+ transaction.commit();
+ session.close();
+ }
+
+ clearCache(getRepository().getRevisionManager());
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ assertEquals(false, transaction.hasResource("/my/resource"));
+ assertEquals(true, transaction.hasResource("/renamed"));
+ }
+
+ @CleanRepositoriesBefore
+ public void testChangeResourceFolderURI() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/my/resource"));
+ transaction.commit();
+
+ URI uri = URI.createURI("cdo://repo1/renamed");
+ assertEquals(CDOURIUtil.createResourceURI(session, "/renamed"), uri);
+ resource.setURI(uri);
+
+ transaction.commit();
+ session.close();
+ }
+
+ clearCache(getRepository().getRevisionManager());
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ assertEquals(false, transaction.hasResource("/my/resource"));
+ assertEquals(true, transaction.hasResource("/renamed"));
+ }
+
+ public void testPathNotNull() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("/res1"));
+ assertEquals(getResourcePath("/res1"), resource.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
+
+ transaction.commit();
+ assertEquals(getResourcePath("/res1"), resource.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
+ session.close();
+ }
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("/res1"));
+ assertEquals(getResourcePath("/res1"), resource.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res1")), resource.getURI());
+
+ CDOResource resource2 = transaction.getOrCreateResource(getResourcePath("/res2"));
+ assertEquals(getResourcePath("/res2"), resource2.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
+
+ transaction.commit();
+ assertEquals(getResourcePath("/res2"), resource2.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
+ session.close();
+ }
+
+ {
+ CDOSession session = openSession();
+ CDOView view = session.openView();
+ CDOResource resource2 = view.getResource(getResourcePath("/res2"));
+ assertEquals(getResourcePath("/res2"), resource2.getPath());
+ assertEquals(CDOURIUtil.createResourceURI(session, getResourcePath("/res2")), resource2.getURI());
+ session.close();
+ }
+ }
+
+ public void testPrefetchContents() throws Exception
+ {
+ {
+ Company company = getModel1Factory().createCompany();
+ company.getCategories().add(createCategoryTree(3));
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOResource resource = transaction.createResource(getResourcePath("/res1"));
+ resource.getContents().add(company);
+
+ transaction.commit();
+ session.close();
+ }
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOResource resource = transaction.getResource(getResourcePath("/res1"));
+ resource.cdoPrefetch(CDORevision.DEPTH_INFINITE);
+
+ Company company = (Company)resource.getContents().get(0);
+ System.out.println(company);
+
+ session.close();
+ }
+
+ private static int counter;
+
+ private Category createCategoryTree(int depth)
+ {
+ if (depth == 0)
+ {
+ return null;
+ }
+
+ Category category = getModel1Factory().createCategory();
+ for (int i = 0; i < 2; i++)
+ {
+ Category child = createCategoryTree(depth - 1);
+ if (child != null)
+ {
+ category.getCategories().add(child);
+ }
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ Product1 child = getModel1Factory().createProduct1();
+ // generate a unique id
+ String id = "test " + depth + "_" + i + "_" + ++counter;
+ child.setName(id);
+ category.getProducts().add(child);
+ }
+
+ return category;
+ }
+
+ /**
+ * bug 208689
+ */
+ public void testQueryResources() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ createResource(transaction, "/aresource");
+ createResource(transaction, "/aaresource");
+ createResource(transaction, "/abresource");
+ createResource(transaction, "/acresource");
+ createResource(transaction, "/adresource");
+ createResource(transaction, "/aeresource");
+ createResource(transaction, "/bresource");
+ createResource(transaction, "/baresource");
+ createResource(transaction, "/bbresource");
+ createResource(transaction, "/bcresource");
+ createResource(transaction, "/bdresource");
+ createResource(transaction, "/beresource");
+ createResource(transaction, "/bearesource");
+ createResource(transaction, "/bebresource");
+ createResource(transaction, "/cresource");
+ createResource(transaction, "/caresource");
+ createResource(transaction, "/caresource2");
+ createResource(transaction, "/caresource3");
+ createResource(transaction, "/cbresource");
+ createResource(transaction, "/ccresource");
+ createResource(transaction, "/cdresource");
+ createResource(transaction, "/ceresource");
+ transaction.commit();
+ session.close();
+ }
+
+ CDOSession session = openSession();
+ CDOView view = session.openView();
+ queryResources(view, "a", 6);
+ queryResources(view, "b", 8);
+ queryResources(view, "c", 8);
+ queryResources(view, "be", 3);
+ queryResources(view, "ca", 3);
+ session.close();
+ }
+
+ /**
+ * bug 208689
+ */
+ public void testQueryModifiedResources() throws Exception
+ {
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ createResource(transaction, "/aresource");
+ createResource(transaction, "/aaresource");
+ createResource(transaction, "/abresource");
+ createResource(transaction, "/acresource");
+ createResource(transaction, "/adresource");
+ createResource(transaction, "/aeresource");
+ createResource(transaction, "/bresource");
+ createResource(transaction, "/baresource");
+ createResource(transaction, "/bbresource");
+ createResource(transaction, "/bcresource");
+ createResource(transaction, "/bdresource");
+ createResource(transaction, "/beresource");
+ createResource(transaction, "/bearesource");
+ createResource(transaction, "/bebresource");
+ createResource(transaction, "/cresource");
+ createResource(transaction, "/caresource");
+ createResource(transaction, "/caresource2");
+ createResource(transaction, "/caresource3");
+ createResource(transaction, "/cbresource");
+ createResource(transaction, "/ccresource");
+ createResource(transaction, "/cdresource");
+ createResource(transaction, "/ceresource");
+ transaction.commit();
+ modifyResource(transaction, "/aresource");
+ modifyResource(transaction, "/aaresource");
+ modifyResource(transaction, "/abresource");
+ modifyResource(transaction, "/acresource");
+ modifyResource(transaction, "/adresource");
+ modifyResource(transaction, "/aeresource");
+ modifyResource(transaction, "/bresource");
+ modifyResource(transaction, "/baresource");
+ modifyResource(transaction, "/bbresource");
+ modifyResource(transaction, "/bcresource");
+ modifyResource(transaction, "/bdresource");
+ modifyResource(transaction, "/beresource");
+ modifyResource(transaction, "/bearesource");
+ modifyResource(transaction, "/bebresource");
+ modifyResource(transaction, "/cresource");
+ modifyResource(transaction, "/caresource");
+ modifyResource(transaction, "/caresource2");
+ modifyResource(transaction, "/caresource3");
+ modifyResource(transaction, "/cbresource");
+ modifyResource(transaction, "/ccresource");
+ modifyResource(transaction, "/cdresource");
+ modifyResource(transaction, "/ceresource");
+ transaction.commit();
+ session.close();
+ }
+
+ CDOSession session = openSession();
+ CDOView view = session.openView();
+ queryResources(view, "a", 6);
+ queryResources(view, "b", 8);
+ queryResources(view, "c", 8);
+ queryResources(view, "be", 3);
+ queryResources(view, "ca", 3);
+ session.close();
+ }
+
+ public void testDeleteResource() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOResource resource = createResource(transaction, "/resource1");
+ CDOID resourceID = resource.cdoID();
+
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ CDOID objectID = object.cdoID();
+
+ transaction.commit();
+ resource.delete(null);
+ transaction.commit();
+ transaction.close();
+
+ CDOView view = session.openView();
+ assertEquals(false, view.hasResource("/resource1"));
+
+ try
+ {
+ view.getResourceNode("/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceFresh() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOResource resource = createResource(transaction, "/resource1");
+ CDOID resourceID = resource.cdoID();
+
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ CDOID objectID = object.cdoID();
+
+ transaction.commit();
+ resource.delete(null);
+ transaction.commit();
+ transaction.close();
+
+ clearCache(getRepository().getRevisionManager());
+ CDOView view = session.openView();
+ assertEquals(false, view.hasResource("/resource1"));
+
+ try
+ {
+ view.getResourceNode("/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceDifferentSession() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOSession session2 = openSession();
+ CDOView view = session2.openView();
+
+ CDOResource resource = createResource(transaction, "/resource1");
+ CDOID resourceID = resource.cdoID();
+
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ CDOID objectID = object.cdoID();
+
+ transaction.commit();
+ assertEquals(true, view.hasResource(getResourcePath("/resource1")));
+ assertEquals(resource.getURI(), view.getResource(getResourcePath("/resource1")).getURI());
+
+ resource.delete(null);
+ commitAndSync(transaction, view);
+ transaction.close();
+
+ assertEquals(false, view.hasResource("/resource1"));
+
+ try
+ {
+ view.getResourceNode("/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceDifferentSessionFresh() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOSession session2 = openSession();
+ CDOView view = session2.openView();
+
+ CDOResource resource = createResource(transaction, "/resource1");
+ CDOID resourceID = resource.cdoID();
+
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ CDOID objectID = object.cdoID();
+
+ transaction.commit();
+ assertEquals(true, view.hasResource(getResourcePath("/resource1")));
+ assertEquals(resource.getURI(), view.getResource(getResourcePath("/resource1")).getURI());
+
+ resource.delete(null);
+ commitAndSync(transaction, view);
+ transaction.close();
+
+ clearCache(getRepository().getRevisionManager());
+ assertEquals(false, view.hasResource("/resource1"));
+
+ try
+ {
+ view.getResourceNode("/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ CDOResource resource1 = view.getResource(getResourcePath("/resource1"));
+ assertNull(resource1);
+ fail("Exception expected");
+ // TODO Fails on automated build:
+ // junit.framework.AssertionFailedError: Exception expected
+ // at org.eclipse.emf.cdo.tests.ResourceTest.testDeleteResourceDifferentSessionFresh(ResourceTest.java:859)
+ // at org.eclipse.net4j.tests.AbstractOMTest.runBare(AbstractOMTest.java:86)
+ // at org.eclipse.net4j.tests.AbstractOMTest.run(AbstractOMTest.java:108)
+ // at org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite$TestWrapper.runTest(ConfigTestSuite.java:126)
+ // at org.eclipse.test.EclipseTestRunner.run(EclipseTestRunner.java:332)
+ // at org.eclipse.test.EclipseTestRunner.run(EclipseTestRunner.java:202)
+ // at org.eclipse.test.CoreTestApplication.runTests(CoreTestApplication.java:35)
+ // at org.eclipse.test.CoreTestApplication.run(CoreTestApplication.java:31)
+ // at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:574)
+ // at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
+ // at org.eclipse.equinox.internal.app.MainApplicationLauncher.run(MainApplicationLauncher.java:32)
+ // at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
+ // at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
+ // at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
+ // at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
+ // at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
+ // at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
+ // at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
+ // at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
+ // at org.eclipse.core.launcher.Main.main(Main.java:34)
+ }
+ catch (Exception expected)
+ {
+ expected.printStackTrace();
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceFolder() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = createResource(transaction, "/folder/resource1");
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ transaction.commit();
+
+ CDOResourceFolder folder = resource.getFolder();
+ CDOID folderID = folder.cdoID();
+ CDOID resourceID = resource.cdoID();
+ CDOID objectID = object.cdoID();
+
+ folder.delete(null);
+ transaction.commit();
+ transaction.close();
+
+ CDOView view = session.openView();
+ assertEquals(false, view.hasResource("/folder/resource1"));
+
+ try
+ {
+ view.getResourceNode("/folder");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResourceNode("/folder/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/folder/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(folderID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceFolderFresh() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = createResource(transaction, "/folder/resource1");
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+ transaction.commit();
+
+ CDOResourceFolder folder = resource.getFolder();
+ CDOID folderID = folder.cdoID();
+ CDOID resourceID = resource.cdoID();
+ CDOID objectID = object.cdoID();
+
+ folder.delete(null);
+ transaction.commit();
+ transaction.close();
+
+ clearCache(getRepository().getRevisionManager());
+ CDOView view = session.openView();
+ assertEquals(false, view.hasResource("/folder/resource1"));
+
+ try
+ {
+ view.getResourceNode("/folder");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResourceNode("/folder/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/folder/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(folderID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceFolderDifferentSession() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOSession session2 = openSession();
+ CDOView view = session2.openView();
+
+ CDOResource resource = createResource(transaction, "/folder/resource1");
+ CDOResourceFolder folder = resource.getFolder();
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+
+ transaction.commit();
+ assertEquals(true, view.hasResource(getResourcePath("/folder/resource1")));
+ assertEquals(resource.getURI(), view.getResource(getResourcePath("/folder/resource1")).getURI());
+
+ CDOID folderID = folder.cdoID();
+ CDOID resourceID = resource.cdoID();
+ CDOID objectID = object.cdoID();
+
+ folder.delete(null);
+ commitAndSync(transaction, view);
+ transaction.close();
+
+ assertEquals(false, view.hasResource("/folder/resource1"));
+
+ try
+ {
+ view.getResourceNode("/folder");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResourceNode("/folder/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/folder/resource1"));
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(folderID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ public void testDeleteResourceFolderDifferentSessionFresh() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ CDOSession session2 = openSession();
+ CDOView view = session2.openView();
+
+ CDOResource resource = createResource(transaction, "/folder/resource1");
+ CDOResourceFolder folder = resource.getFolder();
+ CDOObject object = CDOUtil.getCDOObject(resource.getContents().get(0));
+
+ transaction.commit();
+ assertEquals(true, view.hasResource(getResourcePath("/folder/resource1")));
+ assertEquals(resource.getURI(), view.getResource(getResourcePath("/folder/resource1")).getURI());
+
+ CDOID folderID = folder.cdoID();
+ CDOID resourceID = resource.cdoID();
+ CDOID objectID = object.cdoID();
+
+ folder.delete(null);
+ commitAndSync(transaction, view);
+ transaction.close();
+
+ clearCache(getRepository().getRevisionManager());
+ assertEquals(false, view.hasResource("/folder/resource1"));
+
+ try
+ {
+ view.getResourceNode("/folder");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResourceNode("/folder/resource1");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getResource(getResourcePath("/folder/resource1"));
+ // TODO Fails on automated build
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(folderID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(resourceID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ try
+ {
+ view.getObject(objectID);
+ fail("ObjectNotFoundException expected");
+ }
+ catch (ObjectNotFoundException expected)
+ {
+ }
+
+ session.close();
+ }
+
+ /**
+ * Create resource with the following pattern /test1/test2/test3 for a depth 3. <br>
+ * After it will remove the resource with the following rule:<br>
+ * if calldelete is true <code>resource.delete(null)</code> <br>
+ * if calldelete is false it will use the depthtoRemove to call <code>object.remove(resource)</code><br>
+ * deptToRemove = /0/1/2/...<br>
+ * It will remove it from parent folder (depthtoRemove - 1);
+ */
+ private void attachDetachResourceDepth1(int depth, boolean callDelete, int depthtoRemove) throws Exception
+ {
+ CDOSession session = openSession();
+ ResourceSet resourceSet = new ResourceSetImpl();
+ CDOTransaction transaction = session.openTransaction(resourceSet);
+ CDOResource rootResource = transaction.getRootResource();
+ assertSame(rootResource, rootResource.eResource());
+ String path = "";
+ List<String> names = new ArrayList<String>();
+ for (int i = 0; i < depth; i++)
+ {
+ String name = "test" + String.valueOf(i + 1);
+ names.add(name);
+ path += "/" + name;
+ }
+
+ final URI uri = URI.createURI("cdo:" + path);
+ CDOResource resource = (CDOResource)resourceSet.createResource(uri);
+ assertEquals(names.get(names.size() - 1), resource.getName());
+
+ transaction.commit();
+ List<CDOResourceNode> nodesList = new ArrayList<CDOResourceNode>();
+ CDOResource resourceByLookup = null;
+ CDOResourceNode next = null;
+ for (int i = 0; i < depth; i++)
+ {
+ if (i == 0)
+ {
+ next = (CDOResourceNode)rootResource.getContents().get(0);
+ }
+ else
+ {
+ next = ((CDOResourceFolder)next).getNodes().get(0);
+ }
+
+ nodesList.add(next);
+ }
+
+ resourceByLookup = (CDOResource)next;
+ assertSame(resource, resourceByLookup);
+ assertClean(resourceByLookup, transaction);
+ assertEquals(true, resourceSet.getResources().contains(resourceByLookup));
+
+ CDOObject cdoParent = null;
+ CDOObject cdoRootResource = CDOUtil.getCDOObject(rootResource);
+ for (int i = 0; i < depth; i++)
+ {
+ CDOResourceNode resourceNode = nodesList.get(i);
+ CDOObject cdoResourceNode = CDOUtil.getCDOObject(resourceNode);
+
+ if (i == 0)
+ {
+ assertEquals(cdoRootResource.cdoID(), cdoResourceNode.cdoRevision().data().getResourceID());
+ assertEquals(CDOID.NULL, cdoResourceNode.cdoRevision().data().getContainerID());
+ }
+ else
+ {
+ assertEquals(CDOID.NULL, cdoResourceNode.cdoRevision().data().getResourceID());
+ assertEquals(cdoParent.cdoID(), cdoResourceNode.cdoRevision().data().getContainerID());
+ }
+
+ cdoParent = cdoResourceNode;
+ }
+
+ if (callDelete)
+ {
+ resource.delete(null);
+ depthtoRemove = depth;
+ }
+ else
+ {
+ CDOResourceNode node = nodesList.get(depthtoRemove);
+ if (depthtoRemove == 0)
+ {
+ rootResource.getContents().remove(node);
+ }
+ else
+ {
+ CDOResourceFolder parentFolder = (CDOResourceFolder)nodesList.get(depthtoRemove - 1);
+ assertEquals(parentFolder, node.getFolder());
+ parentFolder.getNodes().remove(node);
+ }
+ }
+
+ for (int i = depthtoRemove; i < depth; i++)
+ {
+ CDOResourceNode transientNode = nodesList.get(i);
+ assertTransient(transientNode);
+ if (transientNode instanceof CDOResource)
+ {
+ assertEquals(false, resourceSet.getResources().contains(transientNode));
+ }
+
+ assertEquals(null, transientNode.eResource());
+ if (i == depthtoRemove)
+ {
+ assertEquals(null, transientNode.eContainer());
+ }
+ else
+ {
+ assertEquals(cdoParent, transientNode.eContainer());
+ }
+
+ cdoParent = transientNode;
+ }
+
+ transaction.commit();
+ }
+
+ private void changePath(int depthFrom, int depthTo) throws Exception
+ {
+ String prefixA = "testA";
+ String prefixB = "testB";
+
+ String oldPath = createPath(prefixA, depthFrom, "test");
+ String newPath = createPath(prefixB, depthTo, "test2");
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(oldPath);
+ Order order = getModel1Factory().createPurchaseOrder();
+ resource.getContents().add(order);
+
+ String path = CDOURIUtil.extractResourcePath(resource.getURI());
+ assertEquals(oldPath, path);
+ assertEquals(depthFrom, CDOURIUtil.analyzePath(resource.getURI()).size() - 1);
+
+ transaction.commit();
+
+ CDOID idBeforeChangePath = CDOUtil.getCDOObject(resource).cdoID();
+ CDOID idBeforeChangePathOrder = CDOUtil.getCDOObject(order).cdoID();
+
+ msg("New path");
+ resource.setPath(newPath);
+ path = CDOURIUtil.extractResourcePath(resource.getURI());
+ assertEquals(depthTo, CDOURIUtil.analyzePath(resource.getURI()).size() - 1);
+ assertEquals(newPath, path);
+ transaction.commit();
+
+ CDOID idAfterChangePath = CDOUtil.getCDOObject(resource).cdoID();
+ assertEquals(idBeforeChangePath, idAfterChangePath);
+
+ CDOID idAfterChangePathOrder = CDOUtil.getCDOObject(order).cdoID();
+ assertEquals(idBeforeChangePathOrder, idAfterChangePathOrder);
+
+ Resource resourceRenamed = transaction.getResourceSet().getResource(
+ CDOURIUtil.createResourceURI(session, newPath), false);
+
+ assertEquals(resource, resourceRenamed);
+ assertClean(resource, transaction);
+ assertClean(order, transaction);
+ session.close();
+ }
+
+ clearCache(getRepository().getRevisionManager());
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+
+ try
+ {
+ URI uri = CDOURIUtil.createResourceURI(session, oldPath);
+ transaction.getResourceSet().getResource(uri, true);
+ fail("Doesn't exist");
+ }
+ catch (Exception ex)
+ {
+ }
+
+ Resource resource = transaction.getResourceSet().getResource(CDOURIUtil.createResourceURI(session, newPath), true);
+ assertNotNull(resource);
+ }
+
+ private String createPath(String namePrefix, int depth, String name)
+ {
+ String path = "";
+ for (int i = 0; i < depth; i++)
+ {
+ String localName = namePrefix + String.valueOf(i + 1);
+ path += "/" + localName;
+ }
+
+ path += "/" + name;
+ return path;
+ }
+
+ private CDOResource createResource(CDOTransaction transaction, String path)
+ {
+ Product1 p = getModel1Factory().createProduct1();
+ p.setName("test-" + path);
+ p.setVat(VAT.VAT0);
+
+ CDOResource resource = transaction.createResource(getResourcePath(path));
+ resource.getContents().add(p);
+ return resource;
+ }
+
+ private CDOResource modifyResource(CDOTransaction transaction, String path)
+ {
+ Product1 p = getModel1Factory().createProduct1();
+ p.setName("test-" + path + "-modified");
+ p.setVat(VAT.VAT0);
+
+ CDOResource resource = transaction.getResource(getResourcePath(path));
+ resource.getContents().add(p);
+ return resource;
+ }
+
+ private void queryResources(CDOView view, String namePrefix, int expected)
+ {
+ msg("Name prefix: " + namePrefix);
+ CDOResourceFolder folder = (CDOResourceFolder)view.getResourceNode(getResourcePath(null));
+ List<CDOResourceNode> nodes = view.queryResources(folder, namePrefix, false);
+ for (CDOResourceNode node : nodes)
+ {
+ msg("Result: " + node.getPath());
+ }
+
+ assertEquals(expected, nodes.size());
+ }
+
+ /**
+ * See bug 353249.
+ */
+ public void testGetResourceNodeContract()
+ {
+ CDOView view = openSession().openView();
+
+ try
+ {
+ view.getResourceNode("SomePath/That/DoesntExist");
+ fail("Exception expected");
+ }
+ catch (Exception expected)
+ {
+ // SUCCCESS
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static class TestAdapter extends AdapterImpl
+ {
+ @Override
+ public void notifyChanged(Notification msg)
+ {
+ super.notifyChanged(msg);
+ if (msg.getNewValue() instanceof CDOResource)
+ {
+ ((CDOResource)msg.getNewValue()).getPath();
+ }
+ }
+
+ @Override
+ public void setTarget(Notifier newTarget)
+ {
+ }
+
+ @Override
+ public boolean isAdapterForType(Object type)
+ {
+ return super.isAdapterForType(type);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_314264_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_314264_Test.java
index 91c50e36bf..40ae949137 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_314264_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_314264_Test.java
@@ -1,147 +1,171 @@
-/*
- * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Eike Stepper - initial API and implementation
- */
-package org.eclipse.emf.cdo.tests.bugzilla;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.eresource.CDOResource;
-import org.eclipse.emf.cdo.session.CDOSession;
-import org.eclipse.emf.cdo.tests.AbstractCDOTest;
-import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
-import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
-import org.eclipse.emf.cdo.tests.model2.TaskContainer;
-import org.eclipse.emf.cdo.tests.util.TestAdapter;
-import org.eclipse.emf.cdo.transaction.CDOTransaction;
-import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
-import org.eclipse.emf.cdo.view.CDOView;
-
-import org.eclipse.emf.common.notify.Notification;
-import org.eclipse.emf.spi.cdo.DefaultCDOMerger;
-
-/**
- * IndexOutOfBoundsException during merge.
- * <p>
- * See bug 314264
- */
-@CleanRepositoriesBefore
-public class Bugzilla_314264_Test extends AbstractCDOTest
-{
- @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
- @CleanRepositoriesBefore
- public void testMergeTest() throws Exception
- {
- // setup transaction.
- final CDOSession session = openSession();
- final CDOTransaction tr1 = session.openTransaction();
- tr1.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
-
- final CDOResource resource = tr1.createResource(getResourcePath("/test1"));
- TaskContainer container = getModel2Factory().createTaskContainer();
- resource.getContents().add(container);
-
- // add at least 2 elements to avoid getting a clear when removing one.
- container.getTasks().add(getModel2Factory().createTask());
- container.getTasks().add(getModel2Factory().createTask());
- tr1.commit();
-
- // sleep(1000);
-
- final CDOBranch otherBranch = tr1.getBranch().createBranch("other");
- final CDOTransaction tr2 = session.openTransaction(otherBranch);
-
- TaskContainer otherContainer = tr2.getObject(container);
- assertNotNull(otherContainer);
-
- // add a new element on other branch at index 0.
- otherContainer.getTasks().add(0, getModel2Factory().createTask());
-
- // remove an element on main branch at index 0.
- container.getTasks().remove(0);
-
- commitAndSync(tr1, tr2);
- commitAndSync(tr2, tr1);
-
- // merge the other branch to main.
- tr1.merge(tr2.getBranch().getHead(), new DefaultCDOMerger.PerFeature.ManyValued());
-
- tr1.commit();
- assertEquals(false, tr1.isDirty());
- }
-
- public void testNotificationBuilderTest() throws Exception
- {
- // setup transaction.
- final CDOSession session = openSession();
- final CDOTransaction tr1 = session.openTransaction();
- tr1.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
-
- final CDOResource resource = tr1.createResource(getResourcePath("/test1"));
- TaskContainer container = getModel2Factory().createTaskContainer();
- resource.getContents().add(container);
- tr1.commit();
-
- final BlockingResultContainer result = new BlockingResultContainer();
-
- // setup additional view.
- CDOView view = session.openView();
- view.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
-
- TestAdapter adapter = new TestAdapter()
- {
- private int counter;
-
- @Override
- public void notifyChanged(Notification notification)
- {
- if (counter != 0)
- {
- result.setResult(new Boolean(notification.getPosition() == 0));
- }
-
- counter++;
- }
- };
-
- TaskContainer containerObject = view.getObject(container);
- containerObject.eAdapters().add(adapter);
-
- // add elements at index 0 causing NotificationBuilder to patch indices beyond 0.
- container.getTasks().add(0, getModel2Factory().createTask());
- container.getTasks().add(0, getModel2Factory().createTask());
- tr1.commit();
-
- Boolean indexWasCorrect = (Boolean)result.getResult();
- assertEquals(true, indexWasCorrect != null && indexWasCorrect.booleanValue());
- }
-
- /**
- * @author Eike Stepper
- */
- private static class BlockingResultContainer
- {
- private Object result;
-
- public synchronized Object getResult() throws Exception
- {
- while (result == null)
- {
- wait(5000);
- }
-
- return result;
- }
-
- public synchronized void setResult(Object result)
- {
- this.result = result;
- notifyAll();
- }
- }
-}
+/*
+ * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
+import org.eclipse.emf.cdo.tests.model2.TaskContainer;
+import org.eclipse.emf.cdo.tests.util.TestAdapter;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.spi.cdo.DefaultCDOMerger;
+
+/**
+ * IndexOutOfBoundsException during merge.
+ * <p>
+ * See bug 314264
+ */
+@CleanRepositoriesBefore
+public class Bugzilla_314264_Test extends AbstractCDOTest
+{
+ @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
+ public void testMerge() throws Exception
+ {
+ // Setup transaction.
+ CDOSession session = openSession();
+ CDOTransaction tr1 = session.openTransaction();
+ tr1.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
+
+ CDOResource resource = tr1.createResource(getResourcePath("/test"));
+ TaskContainer container1 = getModel2Factory().createTaskContainer();
+ resource.getContents().add(container1);
+
+ // Add at least 2 elements to avoid getting a clear when removing one.
+ container1.getTasks().add(getModel2Factory().createTask());
+ container1.getTasks().add(getModel2Factory().createTask());
+ tr1.commit();
+
+ CDOBranch branch2 = tr1.getBranch().createBranch("branch2");
+ CDOTransaction tr2 = session.openTransaction(branch2);
+
+ TaskContainer container2 = tr2.getObject(container1);
+ assertNotNull(container2);
+
+ // Add a new element on other branch at index 0.
+ container2.getTasks().add(0, getModel2Factory().createTask());
+
+ // Remove an element on main branch at index 0.
+ container1.getTasks().remove(0);
+ commitAndSync(tr1, tr2);
+ commitAndSync(tr2, tr1);
+
+ // Merge the other branch to main.
+ tr1.merge(tr2.getBranch().getHead(), new DefaultCDOMerger.PerFeature.ManyValued());
+
+ tr1.commit();
+ assertEquals(false, tr1.isDirty());
+ }
+
+ @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
+ public void testMerge1() throws Exception
+ {
+ // Try again after some warm up. See bug 383602.
+ testMerge();
+ }
+
+ @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
+ public void testMerge2() throws Exception
+ {
+ // Try again after some warm up. See bug 383602.
+ testMerge();
+ }
+
+ @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
+ public void testMerge3() throws Exception
+ {
+ // Try again after some warm up. See bug 383602.
+ testMerge();
+ }
+
+ @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
+ public void testMerge4() throws Exception
+ {
+ // Try again after some warm up. See bug 383602.
+ testMerge();
+ }
+
+ public void testNotificationBuilderTest() throws Exception
+ {
+ // Setup transaction.
+ final CDOSession session = openSession();
+ final CDOTransaction tr1 = session.openTransaction();
+ tr1.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
+
+ final CDOResource resource = tr1.createResource(getResourcePath("/test1"));
+ TaskContainer container = getModel2Factory().createTaskContainer();
+ resource.getContents().add(container);
+ tr1.commit();
+
+ final BlockingResultContainer result = new BlockingResultContainer();
+
+ // Setup additional view.
+ CDOView view = session.openView();
+ view.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
+
+ TestAdapter adapter = new TestAdapter()
+ {
+ private int counter;
+
+ @Override
+ public void notifyChanged(Notification notification)
+ {
+ if (counter != 0)
+ {
+ result.setResult(new Boolean(notification.getPosition() == 0));
+ }
+
+ counter++;
+ }
+ };
+
+ TaskContainer containerObject = view.getObject(container);
+ containerObject.eAdapters().add(adapter);
+
+ // Add elements at index 0 causing NotificationBuilder to patch indices beyond 0.
+ container.getTasks().add(0, getModel2Factory().createTask());
+ container.getTasks().add(0, getModel2Factory().createTask());
+ tr1.commit();
+
+ Boolean indexWasCorrect = (Boolean)result.getResult();
+ assertEquals(true, indexWasCorrect != null && indexWasCorrect.booleanValue());
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static class BlockingResultContainer
+ {
+ private Object result;
+
+ public synchronized Object getResult() throws Exception
+ {
+ while (result == null)
+ {
+ wait(5000);
+ }
+
+ return result;
+ }
+
+ public synchronized void setResult(Object result)
+ {
+ this.result = result;
+ notifyAll();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
index a78d061204..ba36fe8284 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
@@ -58,6 +58,7 @@ import org.eclipse.emf.internal.cdo.messages.Messages;
import org.eclipse.emf.internal.cdo.object.CDOLegacyAdapter;
import org.eclipse.emf.internal.cdo.query.CDOQueryImpl;
+import org.eclipse.net4j.util.CheckUtil;
import org.eclipse.net4j.util.ImplementationError;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.StringUtil;
@@ -214,8 +215,8 @@ public abstract class AbstractCDOView extends Lifecycle implements InternalCDOVi
throw new IllegalStateException("RootResourceID is null; is the repository not yet initialized?");
}
- CDOResourceImpl resource = (CDOResourceImpl)getObject(rootResourceID);
- setRootResource(resource);
+ getObject(rootResourceID);
+ CheckUtil.checkState(rootResource, "rootResource");
}
return rootResource;

Back to the top