diff options
19 files changed, 1525 insertions, 11 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java index 9cba65135f..e81cc85db3 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java @@ -8,7 +8,8 @@ * Contributors: * Eike Stepper - initial API and implementation * Simon McDuff - http://bugs.eclipse.org/226778 - * Simon McDuff - http://bugs.eclipse.org/213402 + * Simon McDuff - http://bugs.eclipse.org/213402 + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.common.id; @@ -227,6 +228,29 @@ public final class CDOIDUtil builder.append("/" + id.toURIFragment()); //$NON-NLS-1$ } + /** + * Backport of 4.0's implementation of write(StringBuilder,CDOID), + * or more accurately: a limited emulation of the 4.0 behavior + */ + public static void write40(StringBuilder builder, CDOID id) + { + if (id == null) + { + id = CDOID.NULL; + } + + if (id instanceof CDOIDLongImpl) + { + builder.append('L'); + } + else + { + throw new RuntimeException("Runtime type of CDOID not supported: " + id.getClass().getName()); + } + + builder.append(id.toURIFragment()); + } + public static CDOIDMeta createMeta(long value) { return new CDOIDMetaImpl(value); diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionHandler.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionHandler.java new file mode 100644 index 0000000000..9d8c591533 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionHandler.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2004 - 2010 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.common.revision; + +/** + * Backported from 3.0/4.0 + * + * @author Eike Stepper + * @since 3.0 + */ +public interface CDORevisionHandler +{ + /** + * Handles a revision. + * + * @return <code>true</code> to indicate that the caller may pass more revisions, <code>false</code> otherwise. + * @since 4.0 + */ + public boolean handleRevision(CDORevision revision); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java new file mode 100644 index 0000000000..53b017c766 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java @@ -0,0 +1,22 @@ +package org.eclipse.emf.cdo.server.internal.db; + +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; + +/** + * @author Eike Stepper + */ +public class DBRevisionHandler implements CDORevisionHandler +{ + private CDORevisionHandler delegate; + + public DBRevisionHandler(CDORevisionHandler delegate) + { + this.delegate = delegate; + } + + public boolean handleRevision(CDORevision revision) + { + return delegate.handleRevision(revision); + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java index fd943c69b0..9a7ffe794a 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java @@ -11,12 +11,17 @@ * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 * Stefan Winkler - 249610: [DB] Support external references (Implementation) * Victor Roldan - 289237: [DB] [maintenance] Support external references + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.server.internal.db; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.server.ISession; +import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; @@ -40,6 +45,8 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.text.MessageFormat; +import java.util.LinkedList; +import java.util.List; import java.util.Set; /** @@ -65,6 +72,8 @@ public class DBStore extends LongIDStore implements InternalIDBStore private IExternalReferenceManager.Internal externalReferenceManager; + private CDOID rootResourceID; + @ExcludeFromDump private transient ProgressDistributor accessorWriteDistributor = new ProgressDistributor.Geometric() { @@ -238,8 +247,8 @@ public class DBStore extends LongIDStore implements InternalIDBStore checkNull(dbAdapter, Messages.getString("DBStore.1")); //$NON-NLS-1$ checkNull(dbConnectionProvider, Messages.getString("DBStore.0")); //$NON-NLS-1$ - checkState(getRevisionTemporality() == RevisionTemporality.AUDITING == mappingStrategy.hasAuditSupport(), Messages - .getString("DBStore.7")); //$NON-NLS-1$ + checkState(getRevisionTemporality() == RevisionTemporality.AUDITING == mappingStrategy.hasAuditSupport(), + Messages.getString("DBStore.7")); //$NON-NLS-1$ } @Override @@ -407,4 +416,56 @@ public class DBStore extends LongIDStore implements InternalIDBStore { return System.currentTimeMillis(); } + + @Override + public CDOID getRootResourceID() + { + if (rootResourceID != null) + { + return rootResourceID; + } + + IStoreAccessor accessor = StoreThreadLocal.getAccessor(); + final List<CDOID> resourceIDs = new LinkedList<CDOID>(); + accessor.queryResources(new IStoreAccessor.QueryResourcesContext() + { + public long getTimeStamp() + { + return CDORevision.UNSPECIFIED_DATE; + } + + public CDOID getFolderID() + { + return null; + } + + public String getName() + { + return null; + } + + public boolean exactMatch() + { + return true; + } + + public int getMaxResults() + { + return 2; + } + + public boolean addResource(CDOID resourceID) + { + return resourceIDs.add(resourceID); + } + }); + + if (resourceIDs.size() != 1) + { + throw new RuntimeException("Could not deduce rootResourceID"); + } + + rootResourceID = resourceIDs.get(0); + return rootResourceID; + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java index 70ce86162f..2c310f2e3c 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java @@ -9,6 +9,7 @@ * Eike Stepper - initial API and implementation * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.server.internal.db; @@ -16,6 +17,7 @@ import org.eclipse.emf.cdo.common.CDOQueryInfo; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.IRepository; @@ -30,6 +32,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport; import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; @@ -41,9 +44,9 @@ import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; import org.eclipse.net4j.util.om.monitor.ProgressDistributable; import org.eclipse.net4j.util.om.monitor.ProgressDistributor; -import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; @@ -501,6 +504,13 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce } } + @Override + public void handleRevisions(CDORevisionHandler handler) + { + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); + ((AbstractMappingStrategy)mappingStrategy).handleRevisions(this, new DBRevisionHandler(handler)); + } + private class ConnectionKeepAliveTask extends TimerTask { public static final long EXECUTION_PERIOD = 1000 * 60 * 60 * 4; // 4 hours diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java index 9e88cf380c..8eb8e79245 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java @@ -10,13 +10,18 @@ * Stefan Winkler - major refactoring * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 * Victor Roldan Betancort - 289360: [DB] [maintenance] Support FeatureMaps + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.server.internal.db.mapping; import org.eclipse.emf.cdo.common.id.CDOID; 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.EMFUtil; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; @@ -26,6 +31,7 @@ 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.ObjectIDIterator; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalClassMapping; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; @@ -41,6 +47,7 @@ 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; @@ -85,6 +92,8 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp private ConcurrentMap<EClass, IClassMapping> classMappings; + private boolean allClassMappingsCreated; + public AbstractMappingStrategy() { classMappings = new ConcurrentHashMap<EClass, IClassMapping>(); @@ -367,9 +376,49 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public final Map<EClass, IClassMapping> getClassMappings() { + return getClassMappings(true); + } + + public final Map<EClass, IClassMapping> getClassMappings(boolean createOnDemand) + { + if (createOnDemand) + { + synchronized (classMappings) + { + if (!allClassMappingsCreated) + { + createAllClassMappings(); + allClassMappingsCreated = true; + } + } + } + return classMappings; } + private void createAllClassMappings() + { + IRepository repository = getStore().getRepository(); + CDOPackageRegistry packageRegistry = repository.getPackageRegistry(); + for (CDOPackageInfo packageInfo : packageRegistry.getPackageInfos()) + { + if (!packageInfo.isSystemPackage()) + { + for (EClassifier eClassifier : packageInfo.getEPackage().getEClassifiers()) + { + if (eClassifier instanceof EClass) + { + EClass eClass = (EClass)eClassifier; + if (!eClass.isAbstract() && !eClass.isInterface()) + { + getClassMapping(eClass); // Get or create it + } + } + } + } + } + } + public final IClassMapping getClassMapping(EClass eClass) { // Try without synchronization first; this will almost always succeed, so it avoids the @@ -416,4 +465,13 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public abstract IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature); public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature); + + public void handleRevisions(IDBStoreAccessor accessor, CDORevisionHandler handler) + { + Collection<IClassMapping> values = getClassMappings().values(); + for (IClassMapping mapping : values) + { + ((AbstractHorizontalClassMapping)mapping).handleRevisions(accessor, handler); + } + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java index fa7952315c..f6e133c2a2 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java @@ -11,15 +11,22 @@ * Stefan Winkler - 249610: [DB] Support external references (Implementation) * Victor Roldan - 289237: [DB] [maintenance] Support external references * Victor Roldan Betancort - 289360: [DB] [maintenance] Support FeatureMaps + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; 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.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.eresource.EresourcePackage; +import org.eclipse.emf.cdo.server.IRepository; +import org.eclipse.emf.cdo.server.IRevisionManager; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IMetaDataManager; +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.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; @@ -71,6 +78,8 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping private List<IListMapping> listMappings; + private String sqlSelectForHandle; + public AbstractHorizontalClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass) { this.mappingStrategy = mappingStrategy; @@ -78,6 +87,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping initTable(); initFeatures(); + initSQLStrings(); } private void initTable() @@ -186,10 +196,10 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping revision.setVersion(resultSet.getInt(i++)); revision.setCreated(resultSet.getLong(i++)); revision.setRevised(resultSet.getLong(i++)); - revision.setResourceID(InternalCDODBUtil.convertLongToCDOID(getExternalReferenceManager(), accessor, resultSet - .getLong(i++))); - revision.setContainerID(InternalCDODBUtil.convertLongToCDOID(getExternalReferenceManager(), accessor, resultSet - .getLong(i++))); + revision.setResourceID(InternalCDODBUtil.convertLongToCDOID(getExternalReferenceManager(), accessor, + resultSet.getLong(i++))); + revision.setContainerID(InternalCDODBUtil.convertLongToCDOID(getExternalReferenceManager(), accessor, + resultSet.getLong(i++))); revision.setContainingFeatureID(resultSet.getInt(i++)); for (ITypeMapping mapping : valueMappings) @@ -389,4 +399,66 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping protected abstract void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision); protected abstract void reviseObject(IDBStoreAccessor accessor, CDOID id, long revised); + + public void handleRevisions(IDBStoreAccessor accessor, CDORevisionHandler handler) + { + IPreparedStatementCache statementCache = accessor.getStatementCache(); + IRepository repository = accessor.getStore().getRepository(); + IRevisionManager revisionManager = repository.getRevisionManager(); + + PreparedStatement stmt = null; + ResultSet rs = null; + + // TODO: test for timeStamp == INVALID_TIME and encode revision.isValid() as WHERE instead of fetching all revisions + // in order to increase performance + + StringBuilder builder = new StringBuilder(sqlSelectForHandle); + + int timeParameters = 0; + + try + { + stmt = statementCache.getPreparedStatement(builder.toString(), ReuseProbability.LOW); + for (int i = 0; i < timeParameters; i++) + { + stmt.setLong(i + 1, -1/* CDOBranchPoint.INVALID_DATE */); + } + + rs = stmt.executeQuery(); + while (rs.next()) + { + long id = rs.getLong(1); + int version = rs.getInt(2); + + InternalCDORevision revision = (InternalCDORevision)revisionManager.getRevisionByVersion( + CDOIDUtil.createLong(id), CDORevision.UNCHUNKED, version, true); + + if (!handler.handleRevision(revision)) + { + break; + } + } + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + DBUtil.close(rs); + statementCache.releasePreparedStatement(stmt); + } + } + + private void initSQLStrings() + { + // ----------- Select all revisions (for handleRevisions) --- + StringBuilder builder = new StringBuilder("SELECT "); //$NON-NLS-1$ + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(", "); //$NON-NLS-1$ + builder.append(CDODBSchema.ATTRIBUTES_VERSION); + builder.append(" FROM "); //$NON-NLS-1$ + builder.append(getTable()); + sqlSelectForHandle = builder.toString(); + } } 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 b2f3b0ab75..a5bf30c35f 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 @@ -11,15 +11,18 @@ * Simon McDuff - http://bugs.eclipse.org/233273 * Simon McDuff - http://bugs.eclipse.org/233490 * Stefan Winkler - changed order of determining audit and revision delta support. + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.internal.server; import org.eclipse.emf.cdo.common.CDOQueryInfo; +import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDMetaRange; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.internal.common.model.CDOPackageRegistryImpl; import org.eclipse.emf.cdo.server.IQueryHandler; @@ -32,9 +35,11 @@ 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.ContainerQueryHandlerProvider; +import org.eclipse.emf.cdo.spi.server.Store; +import org.eclipse.emf.cdo.spi.server.StoreAccessor; -import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; +import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; import org.eclipse.net4j.util.container.Container; import org.eclipse.net4j.util.container.IPluginContainer; @@ -668,6 +673,24 @@ public class Repository extends Container<Object> implements IRepository, Intern } } + public void handleRevisions(final CDORevisionHandler handler) + { + CDORevisionHandler wrapper = handler; + + IStoreAccessor accessor = StoreThreadLocal.getAccessor(); + ((StoreAccessor)accessor).handleRevisions(wrapper); + } + + public CDOID getRootResourceID() + { + return ((Store)getStore()).getRootResourceID(); + } + + public long getLastCommitTimeStamp() + { + return System.currentTimeMillis() - 1; + } + /** * @author Eike Stepper * @since 2.0 diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java index 081d30cc16..6ce02bf9a8 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java @@ -11,6 +11,7 @@ * Simon McDuff - http://bugs.eclipse.org/230832 * Simon McDuff - http://bugs.eclipse.org/233490 * Simon McDuff - http://bugs.eclipse.org/213402 + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.internal.server; @@ -38,6 +39,7 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.channel.IChannel; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.container.Container; +import org.eclipse.net4j.util.event.EventUtil; import org.eclipse.net4j.util.event.IListener; import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; @@ -96,7 +98,7 @@ public class Session extends Container<IView> implements ISession, CDOIDProvider this.protocol = protocol; this.sessionID = sessionID; this.userID = userID; - protocol.addListener(protocolListener); + EventUtil.addListener(protocol, protocolListener); try { diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOCommandProvider.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOCommandProvider.java new file mode 100644 index 0000000000..69c6dc22c3 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOCommandProvider.java @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2004 - 2010 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 + * Caspar De Groot - https://bugs.eclipse.org/333260 + */ +package org.eclipse.emf.cdo.internal.server.bundle; + +import org.eclipse.emf.cdo.server.CDOServerExporter; +import org.eclipse.emf.cdo.server.IRepository; +import org.eclipse.emf.cdo.spi.server.RepositoryFactory; + +import org.eclipse.net4j.util.container.IManagedContainer; +import org.eclipse.net4j.util.container.IPluginContainer; +import org.eclipse.net4j.util.io.IOUtil; + +import org.eclipse.osgi.framework.console.CommandInterpreter; +import org.eclipse.osgi.framework.console.CommandProvider; + +import org.osgi.framework.BundleContext; + +import java.io.FileOutputStream; +import java.io.OutputStream; + +/** + * @author Eike Stepper + */ +public class CDOCommandProvider implements CommandProvider +{ + public CDOCommandProvider(BundleContext bundleContext) + { + bundleContext.registerService(CommandProvider.class.getName(), this, null); + } + + public String getHelp() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("---CDO commands---\n"); + buffer.append("\tcdo list - list all active repositories\n"); + buffer.append("\tcdo export - export the contents of a repository to an XML file\n"); + return buffer.toString(); + } + + public Object _cdo(CommandInterpreter interpreter) + { + try + { + String cmd = interpreter.nextArgument(); + if ("list".equals(cmd)) + { + list(interpreter); + return null; + } + + if ("export".equals(cmd)) + { + exportXML(interpreter); + return null; + } + + interpreter.println(getHelp()); + } + catch (CommandException ex) + { + interpreter.println(ex.getMessage()); + } + catch (Exception ex) + { + interpreter.printStackTrace(ex); + } + + return null; + } + + protected void list(CommandInterpreter interpreter) throws Exception + { + IManagedContainer container = IPluginContainer.INSTANCE; + for (Object element : container.getElements(RepositoryFactory.PRODUCT_GROUP)) + { + if (element instanceof IRepository) + { + IRepository repository = (IRepository)element; + interpreter.println(repository.getName()); + } + } + } + + protected void exportXML(CommandInterpreter interpreter) throws Exception + { + String syntax = "Syntax: cdo export <repository-name> <export-file>"; + IRepository repository = getRepository(interpreter, syntax); + String exportFile = nextArgument(interpreter, syntax); + OutputStream out = null; + + try + { + out = new FileOutputStream(exportFile); + + CDOServerExporter.XML exporter = new CDOServerExporter.XML(repository); + exporter.exportRepository(out); + interpreter.println("Repository exported"); + } + finally + { + IOUtil.close(out); + } + } + + private String nextArgument(CommandInterpreter interpreter, String syntax) + { + String argument = interpreter.nextArgument(); + if (argument == null) + { + throw new CommandException(syntax); + } + + return argument; + } + + private IRepository getRepository(CommandInterpreter interpreter, String syntax) + { + String repositoryName = nextArgument(interpreter, syntax); + IRepository repository = getRepository(repositoryName); + if (repository == null) + { + throw new CommandException("Repository not found: " + repositoryName); + } + + return repository; + } + + private IRepository getRepository(String name) + { + IManagedContainer container = IPluginContainer.INSTANCE; + for (Object element : container.getElements(RepositoryFactory.PRODUCT_GROUP)) + { + if (element instanceof IRepository) + { + IRepository repository = (IRepository)element; + if (repository.getName().equals(name)) + { + return repository; + } + } + } + + return null; + } + + /** + * @author Eike Stepper + */ + private static final class CommandException extends RuntimeException + { + private static final long serialVersionUID = 1L; + + public CommandException(String message) + { + super(message); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/OM.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/OM.java index a5275d991c..23bd811d23 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/OM.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/OM.java @@ -7,6 +7,7 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.internal.server.bundle; @@ -56,5 +57,11 @@ public abstract class OM { super(BUNDLE); } + + @Override + protected void doStart() throws Exception + { + new CDOCommandProvider(bundleContext); + } } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java index dddedc3755..a67cc03a82 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java @@ -16,6 +16,8 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.model.CDOModelConstants; import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.IMEMStore; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.server.IStoreAccessor; @@ -28,6 +30,9 @@ import org.eclipse.emf.cdo.spi.server.StoreAccessorPool; import org.eclipse.net4j.util.ObjectUtil; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import java.util.ArrayList; @@ -49,6 +54,8 @@ public class MEMStore extends LongIDStore implements IMEMStore private int listLimit; + private CDOID rootResourceID; + /** * @param listLimit * See {@link #setListLimit(int)}. @@ -382,4 +389,54 @@ public class MEMStore extends LongIDStore implements IMEMStore list.remove(0); } } + + public synchronized void handleRevisions(CDORevisionHandler handler) + { + for (List<InternalCDORevision> list : revisions.values()) + { + for (InternalCDORevision revision : list) + { + if (!handleRevision(revision, handler)) + { + return; + } + } + } + } + + private boolean handleRevision(InternalCDORevision revision, CDORevisionHandler handler) + { + return handler.handleRevision(revision); + } + + public CDOID getRootResourceID() + { + if (rootResourceID != null) + { + return rootResourceID; + } + + EClass eResourceEClass = EresourcePackage.eINSTANCE.getCDOResource(); + EAttribute nameAttr = EresourcePackage.eINSTANCE.getCDOResourceNode_Name(); + EReference folderRef = EresourcePackage.eINSTANCE.getCDOResourceNode_Folder(); + for (List<InternalCDORevision> list : revisions.values()) + { + InternalCDORevision firstRev = list.get(0); + if (firstRev.getEClass() == eResourceEClass) + { + CDOID folderID = (CDOID)firstRev.get(folderRef, 0); + if (folderID.isNull()) + { + String name = (String)firstRev.get(nameAttr, 0); + if (name == null) + { + rootResourceID = firstRev.getID(); + return rootResourceID; + } + } + } + } + + throw new RuntimeException("Could not deduce rootResourceID"); + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java index a749905a7f..ade249bad0 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java @@ -14,6 +14,7 @@ package org.eclipse.emf.cdo.internal.server.mem; import org.eclipse.emf.cdo.common.CDOQueryInfo; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.server.IQueryContext; import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.ISession; @@ -324,4 +325,9 @@ public class MEMStoreAccessor extends LongIDStoreAccessor { // Pooling of store accessors not supported } + + public void handleRevisions(CDORevisionHandler handler) + { + getStore().handleRevisions(handler); + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerExporter.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerExporter.java new file mode 100644 index 0000000000..b571e0c379 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerExporter.java @@ -0,0 +1,570 @@ +/** + * Copyright (c) 2004 - 2010 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 + * Caspar De Groot - https://bugs.eclipse.org/333260 + */ +package org.eclipse.emf.cdo.server; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOClassInfo; +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.EMFUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; +import org.eclipse.emf.cdo.internal.server.Repository; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.util.WrappedException; +import org.eclipse.net4j.util.io.XMLOutput; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; + +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMapUtil; + +import org.xml.sax.SAXException; + +import java.io.OutputStream; +import java.util.Date; +import java.util.List; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public abstract class CDOServerExporter<OUT> +{ + private IRepository repository; + + public CDOServerExporter(IRepository repository) + { + this.repository = repository; + } + + public final IRepository getRepository() + { + return repository; + } + + public final void exportRepository(OutputStream out) throws Exception + { + boolean wasActive = LifecycleUtil.isActive(repository); + if (!wasActive) + { + LifecycleUtil.activate(repository); + } + + ISession session = repository.getSessionManager().openSession(null); + StoreThreadLocal.setSession(session); + + try + { + OUT output = createOutput(out); + exportAll(output); + } + finally + { + StoreThreadLocal.release(); + if (!wasActive) + { + LifecycleUtil.deactivate(repository); + } + + repository = null; + } + } + + protected abstract OUT createOutput(OutputStream out) throws Exception; + + protected void exportAll(final OUT out) throws Exception + { + try + { + exportPackages(out); + exportBranches(out); + exportLobs(out); + exportCommits(out); + } + catch (WrappedException ex) + { + throw WrappedException.unwrap(ex); + } + } + + protected void exportPackages(OUT out) throws Exception + { + CDOPackageRegistry packageRegistry = repository.getPackageRegistry(); + CDOPackageUnit[] packageUnits = packageRegistry.getPackageUnits(); + for (CDOPackageUnit packageUnit : packageUnits) + { + String id = packageUnit.getID(); + + // Don't export the system packages, as 4.0 does not expect these + if (CDOModelUtil.CORE_PACKAGE_URI.equals(id) || CDOModelUtil.RESOURCE_PACKAGE_URI.equals(id)) + { + continue; + } + + CDOPackageUnit.Type type = packageUnit.getOriginalType(); + long time = packageUnit.getTimeStamp(); + + EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage(); + String data = new String(EMFUtil.getEPackageBytes(ePackage, false, packageRegistry)); + + startPackageUnit(out, id, type, time, data); + for (CDOPackageInfo packageInfo : packageUnit.getPackageInfos()) + { + String packageURI = packageInfo.getPackageURI(); + exportPackageInfo(out, packageURI); + } + + endPackageUnit(out); + } + } + + protected abstract void startPackageUnit(OUT out, String id, CDOPackageUnit.Type type, long time, String data) + throws Exception; + + protected abstract void endPackageUnit(OUT out) throws Exception; + + protected abstract void exportPackageInfo(OUT out, String packageURI) throws Exception; + + protected void exportBranches(final OUT out) throws Exception + { + exportBranch(out); + } + + protected void exportBranch(OUT out) throws Exception + { + exportRevisions(out); + } + + protected void exportRevisions(final OUT out) throws Exception + { + ((Repository)repository).handleRevisions(new CDORevisionHandler() + { + public boolean handleRevision(CDORevision revision) + { + try + { + exportRevision(out, revision); + return true; + } + catch (Exception ex) + { + throw WrappedException.wrap(ex); + } + } + }); + } + + protected abstract void exportRevision(OUT out, CDORevision revision) throws Exception; + + protected void exportLobs(final OUT out) throws Exception + { + } + + protected void exportCommits(final OUT out) throws Exception + { + } + + /** + * @author Eike Stepper + */ + public static interface XMLConstants + { + public static final String REPOSITORY = "repository"; + + public static final String REPOSITORY_NAME = "name"; + + public static final String REPOSITORY_UUID = "uuid"; + + public static final String REPOSITORY_ROOT = "root"; + + public static final String REPOSITORY_CREATED = "created"; + + public static final String REPOSITORY_COMMITTED = "committed"; + + public static final String MODELS = "models"; + + public static final String PACKAGE_UNIT = "packageUnit"; + + public static final String PACKAGE_UNIT_ID = "id"; + + public static final String PACKAGE_UNIT_TYPE = "type"; + + public static final String PACKAGE_UNIT_TIME = "time"; + + public static final String PACKAGE_UNIT_DATA = "data"; + + public static final String PACKAGE_INFO = "packageInfo"; + + public static final String PACKAGE_INFO_URI = "uri"; + + public static final String INSTANCES = "instances"; + + public static final String BRANCH = "branch"; + + public static final String BRANCH_ID = "id"; + + public static final String BRANCH_NAME = "name"; + + public static final String BRANCH_TIME = "time"; + + public static final String BRANCH_PARENT = "parent"; + + public static final String REVISION = "revision"; + + public static final String REVISION_ID = "id"; + + public static final String REVISION_CLASS = "class"; + + public static final String REVISION_VERSION = "version"; + + public static final String REVISION_TIME = "time"; + + public static final String REVISION_REVISED = "revised"; + + public static final String REVISION_RESOURCE = "resource"; + + public static final String REVISION_CONTAINER = "container"; + + public static final String REVISION_FEATURE = "feature"; + + public static final String FEATURE = "feature"; + + public static final String FEATURE_NAME = "name"; + + public static final String FEATURE_TYPE = "type"; + + public static final String FEATURE_INNER_FEATURE = "innerFeature"; + + public static final String FEATURE_INNER_TYPE = "innerType"; + + public static final String FEATURE_VALUE = "value"; + + public static final String FEATURE_ID = "id"; + + public static final String FEATURE_SIZE = "size"; + + public static final String TYPE_BLOB = "Blob"; + + public static final String TYPE_CLOB = "Clob"; + + public static final String TYPE_FEATURE_MAP = "FeatureMap"; + + public static final String LOBS = "lobs"; + + public static final String LOB_ID = "id"; + + public static final String LOB_SIZE = "size"; + + public static final String BLOB = "blob"; + + public static final String CLOB = "clob"; + + public static final String COMMITS = "commits"; + + public static final String COMMIT = "commit"; + + public static final String COMMIT_TIME = "time"; + + public static final String COMMIT_PREVIOUS = "previous"; + + public static final String COMMIT_BRANCH = "branch"; + + public static final String COMMIT_USER = "user"; + + public static final String COMMIT_COMMENT = "comment"; + } + + /** + * @author Eike Stepper + */ + public static class XML extends CDOServerExporter<XMLOutput> implements XMLConstants + { + public XML(IRepository repository) + { + super(repository); + } + + @Override + protected final XMLOutput createOutput(OutputStream out) throws Exception + { + return new XMLOutput(out); + } + + @Override + protected void exportAll(XMLOutput out) throws Exception + { + out.element(REPOSITORY); + out.attribute(REPOSITORY_NAME, getRepository().getName()); + out.attribute(REPOSITORY_UUID, getRepository().getUUID()); + out.attribute(REPOSITORY_ROOT, str(((Repository)getRepository()).getRootResourceID())); + out.attribute(REPOSITORY_CREATED, getRepository().getStore().getCreationTime()); + out.attribute(REPOSITORY_COMMITTED, ((Repository)getRepository()).getLastCommitTimeStamp()); + + out.push(); + super.exportAll(out); + out.done(); + } + + @Override + protected void exportPackages(XMLOutput out) throws Exception + { + out.element(MODELS); + + out.push(); + super.exportPackages(out); + out.pop(); + } + + @Override + protected void startPackageUnit(XMLOutput out, String id, CDOPackageUnit.Type type, long time, String data) + throws Exception + { + out.element(PACKAGE_UNIT); + out.attribute(PACKAGE_UNIT_ID, id); + out.attribute(PACKAGE_UNIT_TYPE, type); + out.attribute(PACKAGE_UNIT_TIME, time); + out.attribute(PACKAGE_UNIT_DATA, data); + out.push(); + } + + @Override + protected void endPackageUnit(XMLOutput out) throws Exception + { + out.pop(); + } + + @Override + protected void exportPackageInfo(XMLOutput out, String uri) throws Exception + { + out.element(PACKAGE_INFO); + out.attribute(PACKAGE_INFO_URI, uri); + } + + @Override + protected void exportBranches(XMLOutput out) throws Exception + { + out.element(INSTANCES); + + out.push(); + super.exportBranches(out); + out.pop(); + } + + @Override + protected void exportBranch(XMLOutput out) throws Exception + { + out.element(BRANCH); + out.attribute(BRANCH_ID, 0); + out.attribute(BRANCH_NAME, "MAIN"); + out.attribute(BRANCH_TIME, getRepository().getStore().getCreationTime()); + + out.push(); + super.exportBranch(out); + out.pop(); + } + + private String getURI(CDOClassifierRef ref) + { + return ref.getPackageURI() + CDOClassifierRef.URI_SEPARATOR + ref.getClassifierName(); + } + + @Override + protected void exportRevision(XMLOutput out, CDORevision revision) throws Exception + { + InternalCDORevision rev = (InternalCDORevision)revision; + + out.element(REVISION); + out.attribute(REVISION_ID, str(rev.getID())); + out.attribute(REVISION_CLASS, getURI(new CDOClassifierRef(rev.getEClass()))); + out.attribute(REVISION_VERSION, rev.getVersion()); + out.attribute(REVISION_TIME, rev.getCreated()); + + long revised = rev.getRevised(); + if (revised != 0 /* CDOBranchPoint.UNSPECIFIED_DATE */) + { + out.attribute(REVISION_REVISED, revised); + } + + CDOID resourceID = rev.getResourceID(); + if (!CDOIDUtil.isNull(resourceID)) + { + out.attribute(REVISION_RESOURCE, str(resourceID)); + } + + CDOID containerID = (CDOID)rev.getContainerID(); + if (!CDOIDUtil.isNull(containerID)) + { + out.attribute(REVISION_CONTAINER, str(containerID)); + } + + int containingFeatureID = rev.getContainingFeatureID(); + if (containingFeatureID != 0) + { + out.attribute(REVISION_FEATURE, containingFeatureID); + } + + out.push(); + CDOClassInfo classInfo = CDOModelUtil.getClassInfo(rev.getEClass()); + for (EStructuralFeature feature : classInfo.getAllPersistentFeatures()) + { + if (feature.isMany()) + { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)rev.getValue(feature); + if (list != null) + { + for (Object value : list) + { + exportFeature(out, feature, value); + } + } + } + else + { + Object value = rev.getValue(feature); + if (value != null && !(value instanceof CDOID && CDOIDUtil.isNull((CDOID)value))) + { + exportFeature(out, feature, value); + } + } + } + + out.pop(); + } + + protected void exportFeature(XMLOutput out, EStructuralFeature feature, Object value) throws Exception + { + out.element(FEATURE); + out.attribute(FEATURE_NAME, feature.getName()); + exportFeature(out, feature, FEATURE_TYPE, value); + } + + protected void exportFeature(XMLOutput out, EStructuralFeature feature, String featureType, Object value) + throws SAXException + { + if (value instanceof CDOID) + { + out.attribute(featureType, Object.class.getSimpleName()); + out.attribute(FEATURE_VALUE, str((CDOID)value)); + } + else if (value instanceof Date) + { + Date date = (Date)value; + out.attribute(featureType, Date.class.getSimpleName()); + out.attribute(FEATURE_VALUE, date.getTime()); + } + else if (FeatureMapUtil.isFeatureMap(feature)) + { + FeatureMap.Entry entry = (FeatureMap.Entry)value; + EStructuralFeature innerFeature = entry.getEStructuralFeature(); + Object innerValue = entry.getValue(); + + out.attribute(featureType, TYPE_FEATURE_MAP); + out.attribute(FEATURE_INNER_FEATURE, innerFeature.getName()); + exportFeature(out, innerFeature, FEATURE_INNER_TYPE, innerValue); + } + else + { + if (!(value instanceof String)) + { + out.attribute(featureType, type(value)); + } + + out.attributeOrNull(FEATURE_VALUE, value); + } + } + + @Override + protected void exportLobs(XMLOutput out) throws Exception + { + out.element(LOBS); + + out.push(); + super.exportLobs(out); + out.pop(); + } + + @Override + protected void exportCommits(XMLOutput out) throws Exception + { + out.element(COMMITS); + + out.push(); + super.exportCommits(out); + out.pop(); + } + + protected final String str(CDOID id) + { + StringBuilder builder = new StringBuilder(); + CDOIDUtil.write40(builder, id); + return builder.toString(); + } + + protected String type(Object value) + { + if (value instanceof Boolean) + { + return Boolean.class.getSimpleName(); + } + + if (value instanceof Character) + { + return Character.class.getSimpleName(); + } + + if (value instanceof Byte) + { + return Byte.class.getSimpleName(); + } + + if (value instanceof Short) + { + return Short.class.getSimpleName(); + } + + if (value instanceof Integer) + { + return Integer.class.getSimpleName(); + } + + if (value instanceof Long) + { + return Long.class.getSimpleName(); + } + + if (value instanceof Float) + { + return Float.class.getSimpleName(); + } + + if (value instanceof Double) + { + return Double.class.getSimpleName(); + } + + if (value instanceof String) + { + return String.class.getSimpleName(); + } + + throw new IllegalArgumentException("Invalid type: " + value.getClass().getName()); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java index c8f8b97fcd..ffb25c4126 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java @@ -7,6 +7,7 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.spi.server; @@ -22,8 +23,8 @@ import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.server.IView; -import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; +import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.container.IContainerDelta; import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; @@ -363,4 +364,9 @@ public abstract class Store extends Lifecycle implements IStore { return Collections.unmodifiableSet(new HashSet<T>(Arrays.asList(elements))); } + + public CDOID getRootResourceID() + { + throw new RuntimeException("Method getRootResourceID not supported"); + } } diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java index 97b6644a58..189ab87a5b 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java @@ -9,11 +9,13 @@ * Eike Stepper - initial API and implementation * Simon McDuff - http://bugs.eclipse.org/201266 * Simon McDuff - http://bugs.eclipse.org/213402 + * Caspar De Groot - https://bugs.eclipse.org/333260 */ package org.eclipse.emf.cdo.spi.server; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDTemp; +import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.internal.server.bundle.OM; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.server.IStoreAccessor; @@ -203,4 +205,9 @@ public abstract class StoreAccessor extends Lifecycle implements IStoreAccessor protected abstract void doPassivate() throws Exception; protected abstract void doUnpassivate() throws Exception; + + public void handleRevisions(CDORevisionHandler handler) + { + throw new RuntimeException("handleRevisions not supported"); + } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java index 1a56903b88..0c80ba74d6 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java @@ -115,6 +115,7 @@ public abstract class AllTestsAllConfigs extends ConfigTestSuite testClasses.add(MultiValuedOfAttributeTest.class); testClasses.add(AdapterManagerTest.class); testClasses.add(ConflictResolverTest.class); + testClasses.add(BackupTest.class); // Specific for MEMStore testClasses.add(MEMStoreQueryTest.class); diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/BackupTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/BackupTest.java new file mode 100644 index 0000000000..19aeef011c --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/BackupTest.java @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2004 - 2010 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 + * Caspar De Groot - https://bugs.eclipse.org/333260 + */ +package org.eclipse.emf.cdo.tests; + +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.server.CDOServerExporter; +import org.eclipse.emf.cdo.server.IRepository; +import org.eclipse.emf.cdo.session.CDOSession; +import org.eclipse.emf.cdo.tests.model1.Customer; +import org.eclipse.emf.cdo.tests.model1.PurchaseOrder; +import org.eclipse.emf.cdo.transaction.CDOTransaction; + +import java.io.ByteArrayOutputStream; +import java.util.Date; + +/** + * @author Eike Stepper + */ +public class BackupTest extends AbstractCDOTest +{ + @Override + protected void doSetUp() throws Exception + { + disableConsole(); + super.doSetUp(); + } + + @Override + protected void doTearDown() throws Exception + { + disableConsole(); + super.doTearDown(); + } + + public void testExport() throws Exception + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource("/res1"); + resource.getContents().add(createCustomer("Eike")); + transaction.commit(); + session.close(); + + IRepository repo1 = getRepository(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CDOServerExporter.XML exporter = new CDOServerExporter.XML(repo1); + exporter.exportRepository(baos); + System.out.println(baos.toString()); + } + + public void testExportDate() throws Exception + { + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.createResource("/res1"); + PurchaseOrder purchaseOrder = getModel1Factory().createPurchaseOrder(); + purchaseOrder.setDate(new Date(1234567)); + resource.getContents().add(purchaseOrder); + transaction.commit(); + session.close(); + + IRepository repo1 = getRepository(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CDOServerExporter.XML exporter = new CDOServerExporter.XML(repo1); + exporter.exportRepository(baos); + System.out.println(baos.toString()); + } + + private Customer createCustomer(String name) + { + Customer customer = getModel1Factory().createCustomer(); + customer.setName(name); + return customer; + } +} diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/XMLOutput.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/XMLOutput.java new file mode 100644 index 0000000000..ed8aa97eb5 --- /dev/null +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/XMLOutput.java @@ -0,0 +1,307 @@ +package org.eclipse.net4j.util.io; + +import org.eclipse.net4j.util.HexUtil; +import org.eclipse.net4j.util.WrappedException; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.util.LinkedList; + +/** + * @author Eike Stepper + * @since 3.1 + */ +public class XMLOutput +{ + private static final AttributesImpl NO_ATTRIBUTES = new AttributesImpl(); + + private TransformerHandler xmlHandler; + + private char[] newLine; + + private char[] indentation; + + private LinkedList<Element> stack = new LinkedList<Element>(); + + private Element element; + + public XMLOutput(OutputStream out) throws TransformerConfigurationException, SAXException + { + setNewLine("\n"); + setIndentation(" "); + SAXTransformerFactory factory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + xmlHandler = factory.newTransformerHandler(); + + Transformer transformer = xmlHandler.getTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.VERSION, "1.0"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + + xmlHandler.setResult(new StreamResult(out)); + xmlHandler.startDocument(); + } + + public void setNewLine(String newLine) + { + this.newLine = newLine.toCharArray(); + } + + public void setIndentation(String indentation) + { + this.indentation = indentation.toCharArray(); + } + + public XMLOutput element(String name) throws SAXException + { + flush(); + element = new Element(name); + return this; + } + + public XMLOutput attribute(String name, Object value) throws SAXException + { + if (value != null) + { + return attributeOrNull(name, value); + } + + return this; + } + + public XMLOutput attributeOrNull(String name, Object value) throws SAXException + { + checkElement(); + element.addAttribute(name, value); + return this; + } + + public Writer characters() throws SAXException + { + checkElement(); + newLine(); + element.start(); + xmlHandler.startCDATA(); + + return new Writer() + { + @Override + public void write(char[] cbuf, int off, int len) throws IOException + { + try + { + xmlHandler.characters(cbuf, off, len); + } + catch (SAXException ex) + { + throw WrappedException.wrap(ex); + } + } + + @Override + public void flush() throws IOException + { + // Do nothing + } + + @Override + public void close() throws IOException + { + try + { + xmlHandler.endCDATA(); + element.end(); + } + catch (SAXException ex) + { + throw WrappedException.wrap(ex); + } + finally + { + element = null; + } + } + }; + } + + public OutputStream bytes() throws SAXException + { + checkElement(); + newLine(); + element.start(); + xmlHandler.startCDATA(); + + return new OutputStream() + { + @Override + public void write(byte[] b, int off, int len) throws IOException + { + try + { + char[] cbuf = HexUtil.bytesToHex(b, off, len).toCharArray(); + xmlHandler.characters(cbuf, 0, cbuf.length); + } + catch (SAXException ex) + { + throw WrappedException.wrap(ex); + } + } + + @Override + public void write(int i) throws IOException + { + byte b = (byte)((i & 0xff) + Byte.MIN_VALUE); + byte[] bs = { b }; + write(bs, 0, 1); + } + + @Override + public void close() throws IOException + { + try + { + xmlHandler.endCDATA(); + element.end(); + } + catch (SAXException ex) + { + throw WrappedException.wrap(ex); + } + finally + { + element = null; + } + } + }; + } + + public XMLOutput push() throws SAXException + { + newLine(); + element.start(); + + stack.add(element); + element = null; + return this; + } + + public XMLOutput pop() throws SAXException + { + flush(); + Element element = stack.removeLast(); + + if (element.hasChildren()) + { + newLine(); + } + + element.end(); + return this; + } + + public void done() throws SAXException + { + while (!stack.isEmpty()) + { + pop(); + } + + xmlHandler.endDocument(); + } + + private void flush() throws SAXException + { + if (element != null) + { + newLine(); + element.start(); + element.end(); + element = null; + } + } + + private void newLine() throws SAXException + { + xmlHandler.ignorableWhitespace(newLine, 0, newLine.length); + for (int i = 0; i < stack.size(); i++) + { + xmlHandler.ignorableWhitespace(indentation, 0, indentation.length); + } + } + + private void checkElement() + { + if (element == null) + { + throw new IllegalStateException("No element"); + } + } + + /** + * @author Eike Stepper + */ + private final class Element + { + private String name; + + private AttributesImpl attributes; + + private boolean children; + + public Element(String name) + { + this.name = name; + } + + public boolean hasChildren() + { + return children; + } + + public void addChild() + { + children = true; + } + + public void addAttribute(String name, Object value) + { + if (attributes == null) + { + attributes = new AttributesImpl(); + } + + if (value == null) + { + value = ""; + } + + attributes.addAttribute("", "", name, "", value.toString()); + } + + public void start() throws SAXException + { + if (!stack.isEmpty()) + { + stack.getLast().addChild(); + } + + xmlHandler.startElement("", "", name, attributes == null ? NO_ATTRIBUTES : attributes); + } + + public void end() throws SAXException + { + xmlHandler.endElement("", "", name); + } + } +} |