/* * Copyright (c) 2012-2016 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 * Simon McDuff - bug 213402 */ package org.eclipse.emf.cdo.spi.common.protocol; 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.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; import org.eclipse.emf.cdo.common.commit.CDOCommitData; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDReference; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.lob.CDOLob; import org.eclipse.emf.cdo.common.lob.CDOLobStore; import org.eclipse.emf.cdo.common.lob.CDOLobUtil; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; import org.eclipse.emf.cdo.common.lock.CDOLockOwner; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.lock.CDOLockUtil; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.CDOPackageInfo; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.model.CDOType; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; import org.eclipse.emf.cdo.common.revision.CDOList; import org.eclipse.emf.cdo.common.revision.CDOListFactory; import org.eclipse.emf.cdo.common.revision.CDORevisable; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; import org.eclipse.emf.cdo.common.util.CDOClassNotFoundException; import org.eclipse.emf.cdo.internal.common.bundle.OM; import org.eclipse.emf.cdo.internal.common.commit.CDOChangeSetDataImpl; import org.eclipse.emf.cdo.internal.common.commit.FailureCommitInfo; import org.eclipse.emf.cdo.internal.common.lock.CDOLockAreaImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl; import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl; import org.eclipse.emf.cdo.internal.common.messages.Messages; import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndBranchImpl; import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndVersionImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOListFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl; import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl; import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; import org.eclipse.emf.cdo.spi.common.commit.CDOCommitInfoUtil; import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager; import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState; 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.common.revision.InternalCDOList; import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList.ConfigurableEquality; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.io.ExtendedDataInput; import org.eclipse.net4j.util.io.StringIO; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.FeatureMapUtil; import org.eclipse.emf.ecore.xml.type.XMLTypePackage; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * If the meaning of this type isn't clear, there really should be more of a description here... * * @author Eike Stepper * @since 4.2 */ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating implements CDODataInput { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, CDODataInputImpl.class); public CDODataInputImpl(ExtendedDataInput delegate) { super(delegate); } public CDOPackageUnit readCDOPackageUnit(ResourceSet resourceSet) throws IOException { InternalCDOPackageUnit packageUnit = (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); packageUnit.read(this, resourceSet); return packageUnit; } public CDOPackageUnit[] readCDOPackageUnits(ResourceSet resourceSet) throws IOException { int size = readInt(); if (TRACER.isEnabled()) { TRACER.format("Reading {0} package units", size); //$NON-NLS-1$ } CDOPackageUnit[] packageUnits = new CDOPackageUnit[size]; for (int i = 0; i < size; i++) { packageUnits[i] = readCDOPackageUnit(resourceSet); } return packageUnits; } public CDOPackageUnit.Type readCDOPackageUnitType() throws IOException { return CDOPackageUnit.Type.values()[readByte()]; } public CDOPackageInfo readCDOPackageInfo() throws IOException { InternalCDOPackageInfo packageInfo = (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); packageInfo.read(this); return packageInfo; } public String readCDOPackageURI() throws IOException { return getPackageURICompressor().read(this); } public CDOClassifierRef readCDOClassifierRef() throws IOException { return new CDOClassifierRef(this); } public EClassifier readCDOClassifierRefAndResolve() throws IOException { CDOClassifierRef classifierRef = readCDOClassifierRef(); EClassifier classifier = classifierRef.resolve(getPackageRegistry()); if (classifier == null) { throw new CDOClassNotFoundException(classifierRef.getPackageURI(), classifierRef.getClassifierName()); } return classifier; } public CDOType readCDOType() throws IOException { byte typeID = readByte(); return CDOModelUtil.getType(typeID); } public CDOBranch readCDOBranch() throws IOException { int branchID = readInt(); CDOBranch branch = getBranchManager().getBranch(branchID); if (branch == null) { throw new IOException("Branch not found: " + branchID); } return branch; } public CDOBranchPoint readCDOBranchPoint() throws IOException { CDOBranch branch = readCDOBranch(); long timeStamp = readLong(); return branch.getPoint(timeStamp); } public CDOBranchVersion readCDOBranchVersion() throws IOException { CDOBranch branch = readCDOBranch(); int version = readInt(); return branch.getVersion(version); } public CDOChangeSetData readCDOChangeSetData() throws IOException { int size1 = readInt(); List<CDOIDAndVersion> newObjects = new ArrayList<CDOIDAndVersion>(size1); for (int i = 0; i < size1; i++) { boolean revision = readBoolean(); CDOIDAndVersion data = revision ? readCDORevision() : readCDOIDAndVersion(); newObjects.add(data); } int size2 = readInt(); List<CDORevisionKey> changedObjects = new ArrayList<CDORevisionKey>(size2); for (int i = 0; i < size2; i++) { boolean delta = readBoolean(); CDORevisionKey data = delta ? readCDORevisionDelta() : readCDORevisionKey(); changedObjects.add(data); } int size3 = readInt(); List<CDOIDAndVersion> detachedObjects = new ArrayList<CDOIDAndVersion>(size3); for (int i = 0; i < size3; i++) { CDOID id = readCDOID(); int version = readInt(); boolean isCDORevisionKey = readBoolean(); CDOIDAndVersion data; if (isCDORevisionKey) { CDOBranch branch = readCDOBranch(); data = CDORevisionUtil.createRevisionKey(id, branch, version); } else { data = new CDOIDAndVersionImpl(id, version); } detachedObjects.add(data); } return new CDOChangeSetDataImpl(newObjects, changedObjects, detachedObjects); } public CDOCommitData readCDOCommitData() throws IOException { InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getPackageRegistry(); ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.setPackageRegistry(packageRegistry); int size = readInt(); List<CDOPackageUnit> newPackageUnits = new ArrayList<CDOPackageUnit>(size); for (int i = 0; i < size; i++) { CDOPackageUnit data = readCDOPackageUnit(resourceSet); newPackageUnits.add(data); packageRegistry.putPackageUnit((InternalCDOPackageUnit)data); } CDOChangeSetData data = readCDOChangeSetData(); return CDOCommitInfoUtil.createCommitData(newPackageUnits, data.getNewObjects(), data.getChangedObjects(), data.getDetachedObjects()); } public CDOCommitInfo readCDOCommitInfo() throws IOException { InternalCDOCommitInfoManager commitInfoManager = (InternalCDOCommitInfoManager)getCommitInfoManager(); long timeStamp = readLong(); long previousTimeStamp = readLong(); if (readBoolean()) { CDOBranch branch = readCDOBranch(); String userID = readString(); String comment = readString(); CDOBranchPoint mergeSource = CDOBranchUtil.readBranchPointOrNull(this); CDOCommitData commitData = readCDOCommitData(); return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, mergeSource, commitData); } return new FailureCommitInfo(commitInfoManager, timeStamp, previousTimeStamp); } public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException { boolean isInvalidateAll = readBoolean(); if (isInvalidateAll) { return CDOLockUtil.createLockChangeInfo(); } CDOBranchPoint branchPoint = readCDOBranchPoint(); CDOLockOwner lockOwner = readCDOLockOwner(); Operation operation = readEnum(Operation.class); LockType lockType = readCDOLockType(); int n = readInt(); CDOLockState[] lockStates = new CDOLockState[n]; for (int i = 0; i < n; i++) { lockStates[i] = readCDOLockState(); } return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation, lockType); } public LockArea readCDOLockArea() throws IOException { String durableLockingID = readString(); CDOBranch branch = readCDOBranch(); long timestamp = readLong(); String userID = readString(); boolean readOnly = readBoolean(); int nLockStates = readInt(); Map<CDOID, LockGrade> locks = CDOIDUtil.createMap(); for (int i = 0; i < nLockStates; i++) { CDOID key = readCDOID(); LockGrade value = readEnum(LockGrade.class); locks.put(key, value); } return new CDOLockAreaImpl(durableLockingID, userID, branch.getPoint(timestamp), readOnly, locks); } public CDOLockOwner readCDOLockOwner() throws IOException { int session = readInt(); int view = readInt(); String lockAreaID = readString(); boolean isDurableView = readBoolean(); return new CDOLockOwnerImpl(session, view, lockAreaID, isDurableView); } public CDOLockState readCDOLockState() throws IOException { Object target; boolean sendingBranchWithID = readBoolean(); if (!sendingBranchWithID) { target = readCDOID(); } else { target = readCDOIDAndBranch(); } InternalCDOLockState lockState = new CDOLockStateImpl(target); int nReadLockOwners = readInt(); for (int i = 0; i < nReadLockOwners; i++) { CDOLockOwner lockOwner = readCDOLockOwner(); lockState.addReadLockOwner(lockOwner); } boolean hasWriteLock = readBoolean(); if (hasWriteLock) { CDOLockOwner lockOwner = readCDOLockOwner(); lockState.setWriteLockOwner(lockOwner); } boolean hasWriteOption = readBoolean(); if (hasWriteOption) { CDOLockOwner lockOwner = readCDOLockOwner(); lockState.setWriteOptionOwner(lockOwner); } return lockState; } public LockType readCDOLockType() throws IOException { return readEnum(LockType.class); } public CDOID readCDOID() throws IOException { return CDOIDUtil.read(this); } public CDOIDReference readCDOIDReference() throws IOException { return new CDOIDReference(this); } public CDOIDAndVersion readCDOIDAndVersion() throws IOException { CDOID id = readCDOID(); int version = readInt(); return new CDOIDAndVersionImpl(id, version); } public CDOIDAndBranch readCDOIDAndBranch() throws IOException { CDOID id = readCDOID(); CDOBranch branch = readCDOBranch(); return new CDOIDAndBranchImpl(id, branch); } public CDORevisionKey readCDORevisionKey() throws IOException { CDOID id = readCDOID(); CDOBranch branch = readCDOBranch(); int version = readInt(); return CDORevisionUtil.createRevisionKey(id, branch, version); } public CDORevision readCDORevision() throws IOException { return readCDORevision(true); } public CDORevision readCDORevision(boolean freeze) throws IOException { boolean notNull = readBoolean(); if (notNull) { InternalCDORevision revision = (InternalCDORevision)getRevisionFactory().createRevision(null); revision.read(this); if (freeze) { revision.freeze(); } return revision; } return null; } public CDORevisable readCDORevisable() throws IOException { CDOBranch branch = readCDOBranch(); int version = readInt(); long timeStamp = readLong(); long revised = readLong(); return CDORevisionUtil.createRevisable(branch, version, timeStamp, revised); } public CDOList readCDOList(EClass owner, EStructuralFeature feature) throws IOException { int referenceChunk; int size = readInt(); if (size < 0) { size = -size; referenceChunk = readInt(); if (TRACER.isEnabled()) { TRACER.format("Read feature {0}: size={1}, referenceChunk={2}", feature.getName(), size, referenceChunk); //$NON-NLS-1$ } } else { referenceChunk = size; if (TRACER.isEnabled()) { TRACER.format("Read feature {0}: size={1}", feature.getName(), size); //$NON-NLS-1$ } } Object value = null; CDOType type = null; boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); if (!isFeatureMap) { type = CDOModelUtil.getType(feature.getEType()); } InternalCDOList list = (InternalCDOList)getListFactory().createList(size, size, referenceChunk); if (feature instanceof EReference && list instanceof ConfigurableEquality) { ((ConfigurableEquality)list).setUseEquals(false); } for (int j = 0; j < referenceChunk; j++) { if (isFeatureMap) { EStructuralFeature innerFeature; boolean demandCreated = readBoolean(); if (demandCreated) { EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage(); ePackage.setNsURI(readString()); EClass eClass = EcoreFactory.eINSTANCE.createEClass(); eClass.setName(readString()); ePackage.getEClassifiers().add(eClass); if (readBoolean()) { EReference eReference = EcoreFactory.eINSTANCE.createEReference(); eReference.setEType(EcorePackage.Literals.EOBJECT); // if (isElement) // { // eReference.setContainment(true); // eReference.setResolveProxies(false); // } innerFeature = eReference; } else { EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute(); eAttribute.setEType(XMLTypePackage.eINSTANCE.getAnySimpleType()); innerFeature = eAttribute; } innerFeature.setName(readString()); innerFeature.setDerived(true); innerFeature.setTransient(true); innerFeature.setVolatile(true); // if (isElement) // { // innerFeature.setUpperBound(ETypedElement.UNSPECIFIED_MULTIPLICITY); // } eClass.getEStructuralFeatures().add(innerFeature); } else { EClass eClass = (EClass)readCDOClassifierRefAndResolve(); innerFeature = eClass.getEStructuralFeature(readInt()); } type = CDOModelUtil.getType(innerFeature.getEType()); value = type.readValue(this); value = CDORevisionUtil.createFeatureMapEntry(innerFeature, value); } else { value = type.readValue(this); } list.set(j, value); if (TRACER.isEnabled()) { TRACER.trace(" " + value); //$NON-NLS-1$ } } return list; } public Object readCDOFeatureValue(EStructuralFeature feature) throws IOException { CDOType type = CDOModelUtil.getType(feature); Object value = type.readValue(this); if (value instanceof CDOLob<?>) { CDOLob<?> lob = (CDOLob<?>)value; CDOLobUtil.setStore(getLobStore(), lob); } return value; } public CDORevisionDelta readCDORevisionDelta() throws IOException { return new CDORevisionDeltaImpl(this); } public CDOFeatureDelta readCDOFeatureDelta(EClass owner) throws IOException { int typeOrdinal = readInt(); CDOFeatureDelta.Type type = CDOFeatureDelta.Type.values()[typeOrdinal]; switch (type) { case ADD: return new CDOAddFeatureDeltaImpl(this, owner); case SET: return new CDOSetFeatureDeltaImpl(this, owner); case LIST: return new CDOListFeatureDeltaImpl(this, owner); case MOVE: return new CDOMoveFeatureDeltaImpl(this, owner); case CLEAR: return new CDOClearFeatureDeltaImpl(this, owner); case REMOVE: return new CDORemoveFeatureDeltaImpl(this, owner); case CONTAINER: return new CDOContainerFeatureDeltaImpl(this, owner); case UNSET: return new CDOUnsetFeatureDeltaImpl(this, owner); default: throw new IOException(MessageFormat.format(Messages.getString("CDODataInputImpl.5"), typeOrdinal)); //$NON-NLS-1$ } } public Object readCDORevisionOrPrimitive() throws IOException { CDOType type = readCDOType(); return type.readValue(this); } public Object readCDORevisionOrPrimitiveOrClassifier() throws IOException { boolean isClassifier = readBoolean(); if (isClassifier) { return readCDOClassifierRefAndResolve(); } return readCDORevisionOrPrimitive(); } protected StringIO getPackageURICompressor() { return StringIO.DIRECT; } protected abstract CDOBranchManager getBranchManager(); protected abstract CDOCommitInfoManager getCommitInfoManager(); protected abstract CDORevisionFactory getRevisionFactory(); protected abstract CDOListFactory getListFactory(); protected abstract CDOLobStore getLobStore(); /** * A concrete subclass of {@link CDODataInputImpl}. * * @author Eike Stepper */ public static final class Default extends CDODataInputImpl { public Default(ExtendedDataInput delegate) { super(delegate); } @Override protected CDORevisionFactory getRevisionFactory() { throw new UnsupportedOperationException(); } public CDOPackageRegistry getPackageRegistry() { throw new UnsupportedOperationException(); } @Override protected CDOLobStore getLobStore() { throw new UnsupportedOperationException(); } @Override protected CDOListFactory getListFactory() { throw new UnsupportedOperationException(); } @Override protected CDOCommitInfoManager getCommitInfoManager() { throw new UnsupportedOperationException(); } @Override protected CDOBranchManager getBranchManager() { throw new UnsupportedOperationException(); } } }