summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2011-01-03 22:33:11 (EST)
committerCaspar De Groot2011-01-03 22:33:11 (EST)
commit5e29ebd61b5a09b150e3c1222dc569e9d0e0a0cd (patch)
tree81b6c4111b1628d9bf2ae44fb46bd6bc90e3676f
parent40c997a1687886c4db2797fc53c8e48096ce4dca (diff)
downloadcdo-5e29ebd61b5a09b150e3c1222dc569e9d0e0a0cd.zip
cdo-5e29ebd61b5a09b150e3c1222dc569e9d0e0a0cd.tar.gz
cdo-5e29ebd61b5a09b150e3c1222dc569e9d0e0a0cd.tar.bz2
[333260] Backport repo export featurestreams/2.0-maintenance
https://bugs.eclipse.org/bugs/show_bug.cgi?id=333260
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java26
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionHandler.java28
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBRevisionHandler.java22
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java65
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java12
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java58
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java80
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java25
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOCommandProvider.java167
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/OM.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStore.java57
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/mem/MEMStoreAccessor.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/CDOServerExporter.java570
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/BackupTest.java86
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/io/XMLOutput.java307
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 9cba651..e81cc85 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 0000000..9d8c591
--- /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 0000000..53b017c
--- /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 fd943c6..9a7ffe7 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 70ce861..2c310f2 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 9e88cf3..8eb8e79 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 fa79523..f6e133c 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 b2f3b0a..a5bf30c 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 081d30c..6ce02bf 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 0000000..69c6dc2
--- /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 a5275d9..23bd811 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 dddedc3..a67cc03 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 a749905..ade249b 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 0000000..b571e0c
--- /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 c8f8b97..ffb25c4 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 97b6644..189ab87 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 1a56903..0c80ba7 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 0000000..19aeef0
--- /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 0000000..ed8aa97
--- /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);
+ }
+ }
+}