| /* |
| * Copyright (c) 2009-2014 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 |
| * Stefan Winkler - major refactoring |
| * Stefan Winkler - Bug 271444: [DB] Multiple refactorings bug 271444 |
| * Stefan Winkler - Bug 282976: [DB] Influence Mappings through EAnnotations |
| * Kai Schlamp - Bug 284680 - [DB] Provide annotation to bypass ClassMapping |
| * Stefan Winkler - maintenance |
| * Stefan Winkler - Bug 285426: [DB] Implement user-defined typeMapping support |
| */ |
| package org.eclipse.emf.cdo.server.internal.db.mapping; |
| |
| import org.eclipse.emf.cdo.common.branch.CDOBranch; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; |
| import org.eclipse.emf.cdo.common.id.CDOID; |
| import org.eclipse.emf.cdo.common.id.CDOIDUtil; |
| import org.eclipse.emf.cdo.common.model.CDOModelUtil; |
| import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; |
| import org.eclipse.emf.cdo.common.model.CDOPackageUnit; |
| import org.eclipse.emf.cdo.common.model.EMFUtil; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; |
| import org.eclipse.emf.cdo.eresource.EresourcePackage; |
| import org.eclipse.emf.cdo.etypes.EtypesPackage; |
| import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; |
| import org.eclipse.emf.cdo.server.StoreThreadLocal; |
| import org.eclipse.emf.cdo.server.db.IDBStore; |
| import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; |
| import org.eclipse.emf.cdo.server.db.IMetaDataManager; |
| import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; |
| import org.eclipse.emf.cdo.server.db.mapping.IListMapping; |
| 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.DBAnnotation; |
| import org.eclipse.emf.cdo.server.internal.db.ObjectIDIterator; |
| import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; |
| import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; |
| import org.eclipse.emf.cdo.spi.server.InternalRepository; |
| |
| import org.eclipse.net4j.db.DBException; |
| import org.eclipse.net4j.db.DBUtil; |
| import org.eclipse.net4j.db.IDBSchemaTransaction; |
| import org.eclipse.net4j.db.ddl.IDBSchema; |
| import org.eclipse.net4j.db.ddl.IDBTable; |
| import org.eclipse.net4j.util.ImplementationError; |
| import org.eclipse.net4j.util.StringUtil; |
| import org.eclipse.net4j.util.WrappedException; |
| import org.eclipse.net4j.util.collection.CloseableIterator; |
| import org.eclipse.net4j.util.lifecycle.Lifecycle; |
| import org.eclipse.net4j.util.om.monitor.OMMonitor; |
| import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.ENamedElement; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.util.FeatureMapUtil; |
| |
| import java.sql.Connection; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.concurrent.Semaphore; |
| |
| /** |
| * This abstract base class implements those methods which are most likely common to most mapping strategies. It can be |
| * used to derive custom mapping strategy implementation. |
| * |
| * @author Eike Stepper |
| * @since 2.0 |
| */ |
| public abstract class AbstractMappingStrategy extends Lifecycle implements IMappingStrategy |
| { |
| // --------- database name generation strings -------------- |
| protected static final String NAME_SEPARATOR = "_"; //$NON-NLS-1$ |
| |
| protected static final String TYPE_PREFIX_FEATURE = "F"; //$NON-NLS-1$ |
| |
| protected static final String TYPE_PREFIX_CLASS = "C"; //$NON-NLS-1$ |
| |
| protected static final String TYPE_PREFIX_PACKAGE = "P"; //$NON-NLS-1$ |
| |
| protected static final String GENERAL_PREFIX = "X"; //$NON-NLS-1$ |
| |
| protected static final String GENERAL_SUFFIX = "0"; //$NON-NLS-1$ |
| |
| /** |
| * Prefix for unsettable feature helper columns |
| */ |
| protected static final String CDO_SET_PREFIX = "cdo_set_"; //$NON-NLS-1$ |
| |
| protected static final String FEATURE_TABLE_SUFFIX = "_list"; //$NON-NLS-1$ |
| |
| private IDBStore store; |
| |
| private Map<String, String> properties; |
| |
| private ConcurrentMap<EClass, IClassMapping> classMappings; |
| |
| private boolean allClassMappingsCreated; |
| |
| private SystemPackageMappingInfo systemPackageMappingInfo; |
| |
| public AbstractMappingStrategy() |
| { |
| classMappings = new ConcurrentHashMap<EClass, IClassMapping>(); |
| } |
| |
| // -- property related methods ----------------------------------------- |
| |
| public synchronized Map<String, String> getProperties() |
| { |
| if (properties == null) |
| { |
| properties = new HashMap<String, String>(); |
| } |
| |
| return properties; |
| } |
| |
| public synchronized void setProperties(Map<String, String> properties) |
| { |
| this.properties = properties; |
| } |
| |
| private int getMaxTableNameLength() |
| { |
| String value = getProperties().get(PROP_MAX_TABLE_NAME_LENGTH); |
| return value == null ? store.getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value); |
| } |
| |
| private int getMaxFieldNameLength() |
| { |
| String value = getProperties().get(PROP_MAX_FIELD_NAME_LENGTH); |
| return value == null ? store.getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value); |
| } |
| |
| private boolean isQualifiedNames() |
| { |
| String value = getProperties().get(PROP_QUALIFIED_NAMES); |
| return value == null ? false : Boolean.valueOf(value); |
| } |
| |
| private boolean isForceNamesWithID() |
| { |
| String value = getProperties().get(PROP_FORCE_NAMES_WITH_ID); |
| return value == null ? false : Boolean.valueOf(value); |
| } |
| |
| private String getTableNamePrefix() |
| { |
| String value = getProperties().get(PROP_TABLE_NAME_PREFIX); |
| return StringUtil.safe(value); |
| } |
| |
| // -- getters and setters ---------------------------------------------- |
| |
| public final IDBStore getStore() |
| { |
| return store; |
| } |
| |
| public final void setStore(IDBStore dbStore) |
| { |
| checkInactive(); |
| store = dbStore; |
| } |
| |
| protected final IMetaDataManager getMetaDataManager() |
| { |
| return getStore().getMetaDataManager(); |
| } |
| |
| // -- object id related methods ---------------------------------------- |
| |
| public void handleRevisions(IDBStoreAccessor accessor, EClass eClass, CDOBranch branch, long timeStamp, |
| boolean exactTime, CDORevisionHandler handler) |
| { |
| if (eClass == null) |
| { |
| Collection<IClassMapping> values = getClassMappings().values(); |
| for (IClassMapping mapping : values) |
| { |
| mapping.handleRevisions(accessor, branch, timeStamp, exactTime, handler); |
| } |
| } |
| else |
| { |
| EPackage ePackage = eClass.getEPackage(); |
| if (CDOModelUtil.isCorePackage(ePackage)) |
| { |
| initSystemPackageMappingInfo(); |
| if (!systemPackageMappingInfo.ecoreMapped) |
| { |
| return; |
| } |
| } |
| |
| if (CDOModelUtil.isTypesPackage(ePackage)) |
| { |
| initSystemPackageMappingInfo(); |
| if (!systemPackageMappingInfo.etypesMapped) |
| { |
| return; |
| } |
| } |
| |
| IClassMapping classMapping = getClassMapping(eClass); |
| classMapping.handleRevisions(accessor, branch, timeStamp, exactTime, handler); |
| } |
| } |
| |
| public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, OMMonitor monitor, CDOChangeSetSegment[] segments) |
| { |
| Set<CDOID> result = new HashSet<CDOID>(); |
| Collection<IClassMapping> classMappings = getClassMappings().values(); |
| |
| monitor.begin(classMappings.size()); |
| |
| try |
| { |
| for (IClassMapping mapping : classMappings) |
| { |
| Async async = monitor.forkAsync(); |
| |
| try |
| { |
| Set<CDOID> ids = mapping.readChangeSet(accessor, segments); |
| result.addAll(ids); |
| } |
| finally |
| { |
| async.stop(); |
| } |
| } |
| |
| return result; |
| } |
| finally |
| { |
| monitor.done(); |
| } |
| } |
| |
| public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor accessor) |
| { |
| Collection<EClass> classes = getClassesWithObjectInfo(); |
| final Iterator<EClass> classIt = classes.iterator(); |
| |
| return new ObjectIDIterator(this, accessor) |
| { |
| private PreparedStatement currentStatement; |
| |
| @Override |
| protected ResultSet getNextResultSet() |
| { |
| while (classIt.hasNext()) |
| { |
| EClass eClass = classIt.next(); |
| IClassMapping mapping = getClassMapping(eClass); |
| currentStatement = mapping.createObjectIDStatement(getAccessor()); |
| |
| ResultSet resultSet = null; |
| |
| try |
| { |
| resultSet = currentStatement.executeQuery(); |
| return resultSet; |
| } |
| catch (Exception ex) |
| { |
| DBUtil.close(resultSet); // only on error |
| releaseCurrentStatement(); |
| throw new DBException(ex); |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| protected void closeCurrentResultSet() |
| { |
| super.closeCurrentResultSet(); |
| releaseCurrentStatement(); |
| } |
| |
| private void releaseCurrentStatement() |
| { |
| DBUtil.close(currentStatement); |
| currentStatement = null; |
| } |
| }; |
| } |
| |
| protected abstract Collection<EClass> getClassesWithObjectInfo(); |
| |
| // -- database name demangling methods --------------------------------- |
| |
| public String getTableName(ENamedElement element) |
| { |
| String name = null; |
| String typePrefix = null; |
| |
| if (element instanceof EClass) |
| { |
| typePrefix = TYPE_PREFIX_CLASS; |
| name = DBAnnotation.TABLE_NAME.getValue(element); |
| if (name == null) |
| { |
| name = isQualifiedNames() ? EMFUtil.getQualifiedName((EClass)element, NAME_SEPARATOR) : element.getName(); |
| } |
| } |
| else if (element instanceof EPackage) |
| { |
| typePrefix = TYPE_PREFIX_PACKAGE; |
| name = DBAnnotation.TABLE_NAME.getValue(element); |
| if (name == null) |
| { |
| name = isQualifiedNames() ? EMFUtil.getQualifiedName((EPackage)element, NAME_SEPARATOR) : element.getName(); |
| } |
| } |
| else |
| { |
| throw new ImplementationError("Unknown element: " + element); //$NON-NLS-1$ |
| } |
| |
| String prefix = getTableNamePrefix(); |
| if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) |
| { |
| prefix += NAME_SEPARATOR; |
| } |
| |
| String suffix = typePrefix + getUniqueID(element); |
| int maxTableNameLength = getMaxTableNameLength(); |
| |
| return getName(prefix + name, suffix, maxTableNameLength); |
| } |
| |
| public String getTableName(EClass eClass, EStructuralFeature feature) |
| { |
| String name = DBAnnotation.TABLE_NAME.getValue(eClass); |
| if (name == null) |
| { |
| name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); |
| } |
| |
| name += NAME_SEPARATOR; |
| name += feature.getName(); |
| name += FEATURE_TABLE_SUFFIX; |
| |
| String prefix = getTableNamePrefix(); |
| if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) |
| { |
| prefix += NAME_SEPARATOR; |
| } |
| |
| String suffix = TYPE_PREFIX_FEATURE + getUniqueID(feature); |
| int maxTableNameLength = getMaxTableNameLength(); |
| |
| return getName(prefix + name, suffix, maxTableNameLength); |
| } |
| |
| public String getFieldName(EStructuralFeature feature) |
| { |
| String name = DBAnnotation.COLUMN_NAME.getValue(feature); |
| if (name == null) |
| { |
| name = getName(feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength()); |
| } |
| |
| return name; |
| } |
| |
| public String getUnsettableFieldName(EStructuralFeature feature) |
| { |
| String name = DBAnnotation.COLUMN_NAME.getValue(feature); |
| if (name != null) |
| { |
| return CDO_SET_PREFIX + name; |
| } |
| |
| return getName(CDO_SET_PREFIX + feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), |
| getMaxFieldNameLength()); |
| } |
| |
| private String getName(String name, String suffix, int maxLength) |
| { |
| if (!store.getDBAdapter().isValidFirstChar(name.charAt(0))) |
| { |
| name = GENERAL_PREFIX + name; |
| } |
| |
| boolean forceNamesWithID = isForceNamesWithID(); |
| if (!forceNamesWithID && store.getDBAdapter().isReservedWord(name)) |
| { |
| name = name + GENERAL_SUFFIX; |
| } |
| |
| if (name.length() > maxLength || forceNamesWithID) |
| { |
| suffix = NAME_SEPARATOR + suffix.replace('-', 'S'); |
| int length = Math.min(name.length(), maxLength - suffix.length()); |
| if (length < 0) |
| { |
| // Most likely CDOIDs are client side-assigned, i.e., meta IDs are extrefs. See getUniqueID() |
| throw new IllegalStateException("Suffix is too long: " + suffix); |
| } |
| |
| name = name.substring(0, length) + suffix; |
| } |
| |
| return name; |
| } |
| |
| private String getUniqueID(ENamedElement element) |
| { |
| long timeStamp; |
| CommitContext commitContext = StoreThreadLocal.getCommitContext(); |
| if (commitContext != null) |
| { |
| timeStamp = commitContext.getBranchPoint().getTimeStamp(); |
| } |
| else |
| { |
| // This happens outside a commit, i.e. at system init time. |
| // Ensure that resulting ext refs are not replicated! |
| timeStamp = CDOBranchPoint.INVALID_DATE; |
| // timeStamp = getStore().getRepository().getTimeStamp(); |
| } |
| |
| IMetaDataManager metaDataManager = getMetaDataManager(); |
| CDOID result = metaDataManager.getMetaID(element, timeStamp); |
| |
| StringBuilder builder = new StringBuilder(); |
| CDOIDUtil.write(builder, result); |
| return builder.toString(); |
| } |
| |
| // -- factories for mapping of classes, values, lists ------------------ |
| |
| public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) |
| { |
| boolean passedPackageUnits = packageUnits != null && packageUnits.length != 0; |
| Semaphore packageRegistryCommitLock = null; |
| boolean ecoreNew = false; |
| boolean etypesNew = false; |
| |
| Async async = null; |
| monitor.begin(); |
| |
| try |
| { |
| async = monitor.forkAsync(); |
| |
| boolean isInitialCommit = passedPackageUnits && contains(packageUnits, EresourcePackage.eINSTANCE.getNsURI()); |
| if (isInitialCommit) |
| { |
| systemPackageMappingInfo = new SystemPackageMappingInfo(); |
| } |
| else |
| { |
| CommitContext commitContext = StoreThreadLocal.getCommitContext(); |
| if (commitContext != null && (commitContext.isUsingEcore() || commitContext.isUsingEtypes())) |
| { |
| InternalRepository repository = (InternalRepository)store.getRepository(); |
| if (!passedPackageUnits) |
| { |
| try |
| { |
| packageRegistryCommitLock = repository.getPackageRegistryCommitLock(); |
| packageRegistryCommitLock.acquire(); |
| } |
| catch (InterruptedException ex) |
| { |
| throw WrappedException.wrap(ex); |
| } |
| } |
| |
| initSystemPackageMappingInfo(); |
| |
| if (!systemPackageMappingInfo.ecoreMapped || !systemPackageMappingInfo.etypesMapped) |
| { |
| CDOPackageRegistry packageRegistry = repository.getPackageRegistry(); |
| List<InternalCDOPackageUnit> extendedPackageUnits = new ArrayList<InternalCDOPackageUnit>(); |
| if (passedPackageUnits) |
| { |
| extendedPackageUnits.addAll(Arrays.asList(packageUnits)); |
| } |
| |
| if (!systemPackageMappingInfo.ecoreMapped && commitContext.isUsingEcore()) |
| { |
| CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(EcorePackage.eINSTANCE); |
| extendedPackageUnits.add((InternalCDOPackageUnit)packageUnit); |
| ecoreNew = true; |
| } |
| |
| if (!systemPackageMappingInfo.etypesMapped && commitContext.isUsingEtypes()) |
| { |
| CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(EtypesPackage.eINSTANCE); |
| extendedPackageUnits.add((InternalCDOPackageUnit)packageUnit); |
| etypesNew = true; |
| } |
| |
| if (ecoreNew || etypesNew) |
| { |
| packageUnits = extendedPackageUnits.toArray(new InternalCDOPackageUnit[extendedPackageUnits.size()]); |
| } |
| } |
| } |
| } |
| |
| if (packageUnits != null && packageUnits.length != 0) |
| { |
| IDBSchemaTransaction schemaTransaction = store.getDatabase().openSchemaTransaction(); |
| |
| try |
| { |
| mapPackageUnits(packageUnits, connection, false); |
| schemaTransaction.commit(); |
| } |
| finally |
| { |
| schemaTransaction.close(); |
| } |
| } |
| } |
| finally |
| { |
| if (async != null) |
| { |
| async.stop(); |
| } |
| |
| if (packageRegistryCommitLock != null) |
| { |
| systemPackageMappingInfo.ecoreMapped |= ecoreNew; |
| systemPackageMappingInfo.etypesMapped |= etypesNew; |
| packageRegistryCommitLock.release(); |
| } |
| |
| monitor.done(); |
| } |
| } |
| |
| private void initSystemPackageMappingInfo() |
| { |
| if (systemPackageMappingInfo == null) |
| { |
| systemPackageMappingInfo = new SystemPackageMappingInfo(); |
| systemPackageMappingInfo.ecoreMapped = hasTableFor(EcorePackage.eINSTANCE.getEPackage()); |
| systemPackageMappingInfo.etypesMapped = hasTableFor(EtypesPackage.eINSTANCE.getAnnotation()); |
| } |
| } |
| |
| public void removeMapping(Connection connection, InternalCDOPackageUnit[] packageUnits) |
| { |
| IDBSchemaTransaction schemaTransaction = store.getDatabase().openSchemaTransaction(); |
| |
| try |
| { |
| mapPackageUnits(packageUnits, connection, true); |
| schemaTransaction.commit(); |
| } |
| finally |
| { |
| schemaTransaction.close(); |
| } |
| } |
| |
| private boolean hasTableFor(EClass eClass) |
| { |
| String tableName = getTableName(eClass); |
| return store.getDBSchema().getTable(tableName) != null; |
| } |
| |
| private boolean contains(InternalCDOPackageUnit[] packageUnits, String packageUnitID) |
| { |
| for (InternalCDOPackageUnit packageUnit : packageUnits) |
| { |
| if (packageUnit.getID().equals(packageUnitID)) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private void mapPackageUnits(InternalCDOPackageUnit[] packageUnits, Connection connection, boolean unmap) |
| { |
| if (packageUnits != null && packageUnits.length != 0) |
| { |
| for (InternalCDOPackageUnit packageUnit : packageUnits) |
| { |
| InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); |
| mapPackageInfos(packageInfos, connection, unmap); |
| } |
| } |
| } |
| |
| private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Connection connection, boolean unmap) |
| { |
| for (InternalCDOPackageInfo packageInfo : packageInfos) |
| { |
| EPackage ePackage = packageInfo.getEPackage(); |
| EClass[] persistentClasses = EMFUtil.getPersistentClasses(ePackage); |
| mapClasses(connection, unmap, persistentClasses); |
| } |
| } |
| |
| private void mapClasses(Connection connection, boolean unmap, EClass... eClasses) |
| { |
| for (EClass eClass : eClasses) |
| { |
| if (!(eClass.isInterface() || eClass.isAbstract())) |
| { |
| String mappingAnnotation = DBAnnotation.TABLE_MAPPING.getValue(eClass); |
| |
| // TODO Maybe we should explicitly report unknown values of the annotation |
| if (mappingAnnotation != null && mappingAnnotation.equalsIgnoreCase(DBAnnotation.TABLE_MAPPING_NONE)) |
| { |
| continue; |
| } |
| |
| if (unmap) |
| { |
| removeClassMapping(eClass); |
| } |
| else |
| { |
| createClassMapping(eClass); |
| } |
| } |
| } |
| } |
| |
| private IClassMapping createClassMapping(EClass eClass) |
| { |
| IClassMapping mapping = doCreateClassMapping(eClass); |
| if (mapping != null) |
| { |
| classMappings.put(eClass, mapping); |
| } |
| |
| return mapping; |
| } |
| |
| private IClassMapping removeClassMapping(EClass eClass) |
| { |
| IClassMapping mapping = classMappings.get(eClass); |
| if (mapping != null) |
| { |
| IDBSchema schema = getStore().getDBSchema(); |
| for (IDBTable table : mapping.getDBTables()) |
| { |
| schema.removeTable(table.getName()); |
| } |
| |
| classMappings.remove(eClass); |
| } |
| return mapping; |
| } |
| |
| protected abstract IClassMapping doCreateClassMapping(EClass eClass); |
| |
| public final IClassMapping getClassMapping(EClass eClass) |
| { |
| if (!isMapped(eClass)) |
| { |
| throw new IllegalArgumentException("Class is not mapped: " + eClass); |
| } |
| |
| // Try without synchronization first; this will almost always succeed, so it avoids the |
| // performance penalty of syncing in the majority of cases |
| IClassMapping result = classMappings.get(eClass); |
| if (result == null) |
| { |
| // Synchronize on the classMappings to prevent concurrent invocations of createClassMapping |
| // (Synchronizing on the eClass allows for more concurrency, but is risky because application |
| // code may be syncing on the eClass also.) |
| synchronized (classMappings) |
| { |
| // Check again, because other thread may have just added the mapping |
| result = classMappings.get(eClass); |
| if (result == null) |
| { |
| result = createClassMapping(eClass); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| public final Map<EClass, IClassMapping> getClassMappings() |
| { |
| return getClassMappings(true); |
| } |
| |
| public final Map<EClass, IClassMapping> getClassMappings(boolean createOnDemand) |
| { |
| return doGetClassMappings(createOnDemand); |
| } |
| |
| public final Map<EClass, IClassMapping> doGetClassMappings(boolean createOnDemand) |
| { |
| if (createOnDemand) |
| { |
| synchronized (classMappings) |
| { |
| if (!allClassMappingsCreated) |
| { |
| createAllClassMappings(); |
| allClassMappingsCreated = true; |
| } |
| } |
| } |
| |
| return classMappings; |
| } |
| |
| private void createAllClassMappings() |
| { |
| InternalRepository repository = (InternalRepository)getStore().getRepository(); |
| InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false); |
| for (InternalCDOPackageInfo packageInfo : packageRegistry.getPackageInfos()) |
| { |
| if (!packageInfo.isSystemPackage()) |
| { |
| for (EClassifier eClassifier : packageInfo.getEPackage().getEClassifiers()) |
| { |
| if (eClassifier instanceof EClass) |
| { |
| EClass eClass = (EClass)eClassifier; |
| if (isMapped(eClass)) |
| { |
| getClassMapping(eClass); // Get or create it |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| protected abstract boolean isMapped(EClass eClass); |
| |
| public ITypeMapping createValueMapping(EStructuralFeature feature) |
| { |
| ITypeMapping.Provider provider = getTypeMappingProvider(); |
| return provider.createTypeMapping(this, feature); |
| } |
| |
| protected ITypeMapping.Provider getTypeMappingProvider() |
| { |
| return ITypeMapping.Provider.INSTANCE; |
| } |
| |
| public final IListMapping createListMapping(EClass containingClass, EStructuralFeature feature) |
| { |
| checkArg(feature.isMany(), "Only many-valued features allowed"); //$NON-NLS-1$ |
| return doCreateListMapping(containingClass, feature); |
| } |
| |
| public final IListMapping createFeatureMapMapping(EClass containingClass, EStructuralFeature feature) |
| { |
| checkArg(FeatureMapUtil.isFeatureMap(feature), "Only FeatureMaps allowed"); //$NON-NLS-1$ |
| return doCreateFeatureMapMapping(containingClass, feature); |
| } |
| |
| public abstract IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature); |
| |
| public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature); |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class SystemPackageMappingInfo |
| { |
| public boolean ecoreMapped; |
| |
| public boolean etypesMapped; |
| } |
| } |