Bug 369103 - Enable Edapt Migrator
* Created AbstractOperationEmitter
* Created SerializedOperationEmitter for being able to iterate over a
FileBasedChangePackage without having to deserialize the operations
Change-Id: I9cd6068e949ac0ee68a7f1b5ac14553285e9c47f
Signed-off-by: Johannes Faltermeier <jfaltermeier@eclipsesource.com>
diff --git a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/FileBasedChangePackageImpl.java b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/FileBasedChangePackageImpl.java
index a943276..fe8f274 100644
--- a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/FileBasedChangePackageImpl.java
+++ b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/FileBasedChangePackageImpl.java
@@ -102,9 +102,11 @@
private static final String TEMP_FILE_PREFIX = "temp-"; //$NON-NLS-1$
/**
+ * Suffix for temporary operation files.
+ *
* @generated NOT
*/
- private static final String TEMP_SUFFIX = ".temp"; //$NON-NLS-1$
+ public static final String TEMP_SUFFIX = ".temp"; //$NON-NLS-1$
// FIXME we also have a constant for this on the client side
private static final String OPERATION_FILE_SUFFIX = ".eoc"; //$NON-NLS-1$
diff --git a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/AbstractOperationEmitter.java b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/AbstractOperationEmitter.java
new file mode 100644
index 0000000..0e07075
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/AbstractOperationEmitter.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Edgar Mueller - initial API and implementation
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.internal.server.model.versioning.impl.persistent;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PipedOutputStream;
+import java.io.RandomAccessFile;
+import java.nio.channels.Channels;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.input.ReversedLinesFileReader;
+import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil;
+
+/**
+ * Abstract super class for implementing types which emit operations when given an {@link ReadLineCapable} type.
+ *
+ */
+public abstract class AbstractOperationEmitter implements Closeable {
+
+ private final Direction direction;
+
+ private final File operationsFile;
+
+ private ReadLineCapable reader;
+ private final List<Long> forwardOffsets = new ArrayList<Long>();
+ private final List<Long> backwardsOffsets = new ArrayList<Long>();
+ private int currentOpIndex;
+ private long startOffset;
+
+ /**
+ * Constructor.
+ *
+ * @param direction
+ * the {@link Direction} that is used for reading
+ * @param file
+ * the operation file
+ */
+ public AbstractOperationEmitter(Direction direction, File file) {
+ this.direction = direction;
+ operationsFile = file;
+ determineOperationOffsets();
+ currentOpIndex = direction == Direction.Forward ? 0 : backwardsOffsets.size() - 1;
+ initReader();
+ }
+
+ /**
+ * @return the direction the {@link Direction}
+ */
+ protected final Direction getDirection() {
+ return direction;
+ }
+
+ private void determineOperationOffsets() {
+ try {
+ final RandomAccessFile randomAccessFile = new RandomAccessFile(operationsFile, "r"); //$NON-NLS-1$
+ final InputStream inputStream = Channels.newInputStream(randomAccessFile.getChannel());
+ final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+ final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+
+ long filePointer = 0;
+ try {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ filePointer += line.getBytes().length;
+ final long filePointerAfterReadline = randomAccessFile.getFilePointer();
+ randomAccessFile.seek(filePointer);
+ int byteAfterLine = randomAccessFile.read();
+ /*
+ * Line is terminated by either:
+ * \r\n
+ * \r
+ * \n
+ */
+ if (byteAfterLine == '\r') {
+ filePointer += 1;
+ byteAfterLine = randomAccessFile.read();
+ }
+ if (byteAfterLine == '\n') {
+ filePointer += 1;
+ }
+ randomAccessFile.seek(filePointerAfterReadline);
+
+ if (line.contains(XmlTags.CHANGE_PACKAGE_START)) {
+ startOffset = filePointer;
+ } else if (line.contains(XmlTags.OPERATIONS_START_TAG)) {
+ forwardOffsets.add(filePointer);
+ } else if (line.contains(XmlTags.OPERATIONS_END_TAG)) {
+ backwardsOffsets.add(filePointer);
+ }
+ }
+ } finally {
+ bufferedReader.close();
+ randomAccessFile.close();
+ }
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+
+ private void initReader() {
+ try {
+ if (getDirection() == Direction.Forward) {
+ reader = ReadLineCapable.INSTANCE.create(new BufferedReader(new FileReader(operationsFile)));
+ } else {
+ reader = ReadLineCapable.INSTANCE.create(new ReversedLinesFileReader(operationsFile));
+ }
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+
+ /**
+ * Returns the current offset.
+ *
+ * @return the current offset
+ */
+ public long getOffset() {
+ if (currentOpIndex < 0) {
+ return startOffset;
+ }
+ return backwardsOffsets.get(currentOpIndex);
+ }
+
+ /**
+ * Since an XML Resource needs exactly one root object, we have to write a dummy object to the stream.
+ *
+ * @param pos the {@link PipedOutputStream}
+ * @throws IOException in case there is a problem during write
+ */
+ private static void writeDummyResourceToStream(PipedOutputStream pos) throws IOException {
+ pos.write(XmlTags.XML_RESOURCE_WITH_EOBJECT.getBytes());
+ }
+
+ /**
+ * Reads the file in forward direction and writes read lines to the given stream.
+ *
+ * @param pos the output stream
+ */
+ protected final void readForward(PipedOutputStream pos) {
+ try {
+ boolean operationsFound = false;
+ boolean withinOperationsElement = false;
+ final boolean isForwardDir = getDirection() == Direction.Forward;
+ final String closingTag = getClosingTag(isForwardDir);
+ String line = reader.readLine();
+ while (line != null && !line.contains(closingTag)) {
+ if (line.contains(getOpeningTag(isForwardDir))) {
+ withinOperationsElement = true;
+ } else if (withinOperationsElement) {
+ operationsFound = true;
+ pos.write(line.getBytes());
+ }
+ line = reader.readLine();
+ }
+ if (line != null) {
+ withinOperationsElement = false;
+ }
+ if (!operationsFound) {
+ writeDummyResourceToStream(pos);
+ }
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ } finally {
+ try {
+ pos.close();
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+ }
+
+ private void readForward(DataInput reader, PipedOutputStream pos) {
+ try {
+ boolean operationsFound = false;
+ boolean withinOperationsElement = true;
+ final String closingTag = getClosingTag(true);
+ String line = reader.readLine();
+ while (line != null && !line.contains(closingTag)) {
+ if (line.contains(getOpeningTag(true))) {
+ withinOperationsElement = true;
+ } else if (withinOperationsElement && line.length() > 0) {
+ operationsFound = true;
+ pos.write(line.getBytes());
+ }
+ line = reader.readLine();
+ }
+
+ if (!operationsFound) {
+ writeDummyResourceToStream(pos);
+ }
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ } finally {
+ try {
+ pos.close();
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+ }
+
+ /**
+ * Reads the file in backward direction and writes read lines to the given stream.
+ *
+ * @param pos the output strea,
+ */
+ protected final void readBackward(PipedOutputStream pos) {
+
+ if (currentOpIndex < 0) {
+ try {
+ writeDummyResourceToStream(pos);
+ pos.close();
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ return;
+ }
+
+ final long offset = forwardOffsets.get(currentOpIndex);
+ currentOpIndex -= 1;
+
+ RandomAccessFile raf = null;
+ try {
+ raf = new RandomAccessFile(operationsFile, "r"); //$NON-NLS-1$
+ raf.skipBytes((int) offset);
+ readForward(raf, pos);
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ } finally {
+ try {
+ raf.close();
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+ }
+
+ private String getClosingTag(boolean isForward) {
+ return isForward ? XmlTags.OPERATIONS_END_TAG : XmlTags.OPERATIONS_START_TAG;
+ }
+
+ private String getOpeningTag(boolean isForward) {
+ return isForward ? XmlTags.OPERATIONS_START_TAG : XmlTags.OPERATIONS_END_TAG;
+ }
+
+ /**
+ * Closes the emitter.
+ */
+ public void close() {
+ try {
+ reader.close();
+ } catch (final IOException ex) {
+ ModelUtil.logException(ex);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/OperationEmitter.java b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/OperationEmitter.java
index 36136bd..5acdf25 100644
--- a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/OperationEmitter.java
+++ b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/OperationEmitter.java
@@ -11,22 +11,11 @@
******************************************************************************/
package org.eclipse.emf.emfstore.internal.server.model.versioning.impl.persistent;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.DataInput;
import java.io.File;
-import java.io.FileReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
-import java.io.RandomAccessFile;
-import java.nio.channels.Channels;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.io.input.ReversedLinesFileReader;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
@@ -48,17 +37,7 @@
* @author emueller
*
*/
-public class OperationEmitter implements Closeable {
-
- private final Direction direction;
-
- private final File operationsFile;
-
- private ReadLineCapable reader;
- private final List<Long> forwardOffsets = new ArrayList<Long>();
- private final List<Long> backwardsOffsets = new ArrayList<Long>();
- private int currentOpIndex;
- private long startOffset;
+public class OperationEmitter extends AbstractOperationEmitter {
/**
* Constructor.
@@ -69,186 +48,7 @@
* the operation file
*/
public OperationEmitter(Direction direction, File file) {
- this.direction = direction;
- operationsFile = file;
- determineOperationOffsets();
- currentOpIndex = direction == Direction.Forward ? 0 : backwardsOffsets.size() - 1;
- initReader();
- }
-
- private void determineOperationOffsets() {
- try {
- final RandomAccessFile randomAccessFile = new RandomAccessFile(operationsFile, "r"); //$NON-NLS-1$
- final InputStream inputStream = Channels.newInputStream(randomAccessFile.getChannel());
- final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
- final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
-
- long filePointer = 0;
- try {
- String line;
- while ((line = bufferedReader.readLine()) != null) {
- filePointer += line.getBytes().length;
- final long filePointerAfterReadline = randomAccessFile.getFilePointer();
- randomAccessFile.seek(filePointer);
- int byteAfterLine = randomAccessFile.read();
- /*
- * Line is terminated by either:
- * \r\n
- * \r
- * \n
- */
- if (byteAfterLine == '\r') {
- filePointer += 1;
- byteAfterLine = randomAccessFile.read();
- }
- if (byteAfterLine == '\n') {
- filePointer += 1;
- }
- randomAccessFile.seek(filePointerAfterReadline);
-
- if (line.contains(XmlTags.CHANGE_PACKAGE_START)) {
- startOffset = filePointer;
- } else if (line.contains(XmlTags.OPERATIONS_START_TAG)) {
- forwardOffsets.add(filePointer);
- } else if (line.contains(XmlTags.OPERATIONS_END_TAG)) {
- backwardsOffsets.add(filePointer);
- }
- }
- } finally {
- bufferedReader.close();
- randomAccessFile.close();
- }
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
-
- private void initReader() {
- try {
- if (direction == Direction.Forward) {
- reader = ReadLineCapable.INSTANCE.create(new BufferedReader(new FileReader(operationsFile)));
- } else {
- reader = ReadLineCapable.INSTANCE.create(new ReversedLinesFileReader(operationsFile));
- }
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
-
- /**
- * Returns the current offset.
- *
- * @return the current offset
- */
- public long getOffset() {
- if (currentOpIndex < 0) {
- return startOffset;
- }
- return backwardsOffsets.get(currentOpIndex);
- }
-
- /**
- * Since an XML Resource needs exactly one root object, we have to write a dummy object to the stream.
- *
- * @param pos the {@link PipedOutputStream}
- * @throws IOException in case there is a problem during write
- */
- private static void writeDummyResourceToStream(PipedOutputStream pos) throws IOException {
- pos.write(XmlTags.XML_RESOURCE_WITH_EOBJECT.getBytes());
- }
-
- private void readForward(PipedOutputStream pos) {
- try {
- boolean operationsFound = false;
- boolean withinOperationsElement = false;
- final boolean isForwardDir = direction == Direction.Forward;
- final String closingTag = getClosingTag(isForwardDir);
- String line = reader.readLine();
- while (line != null && !line.contains(closingTag)) {
- if (line.contains(getOpeningTag(isForwardDir))) {
- withinOperationsElement = true;
- } else if (withinOperationsElement) {
- operationsFound = true;
- pos.write(line.getBytes());
- }
- line = reader.readLine();
- }
- if (line != null) {
- withinOperationsElement = false;
- }
- if (!operationsFound) {
- writeDummyResourceToStream(pos);
- }
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- } finally {
- try {
- pos.close();
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
- }
-
- private void readForward(DataInput reader, PipedOutputStream pos) {
- try {
- boolean operationsFound = false;
- boolean withinOperationsElement = true;
- final String closingTag = getClosingTag(true);
- String line = reader.readLine();
- while (line != null && !line.contains(closingTag)) {
- if (line.contains(getOpeningTag(true))) {
- withinOperationsElement = true;
- } else if (withinOperationsElement && line.length() > 0) {
- operationsFound = true;
- pos.write(line.getBytes());
- }
- line = reader.readLine();
- }
-
- if (!operationsFound) {
- writeDummyResourceToStream(pos);
- }
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- } finally {
- try {
- pos.close();
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
- }
-
- private void readBackward(PipedOutputStream pos) {
-
- if (currentOpIndex < 0) {
- try {
- writeDummyResourceToStream(pos);
- pos.close();
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- return;
- }
-
- final long offset = forwardOffsets.get(currentOpIndex);
- currentOpIndex -= 1;
-
- RandomAccessFile raf = null;
- try {
- raf = new RandomAccessFile(operationsFile, "r"); //$NON-NLS-1$
- raf.skipBytes((int) offset);
- readForward(raf, pos);
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- } finally {
- try {
- raf.close();
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
+ super(direction, file);
}
/**
@@ -265,7 +65,7 @@
new Thread(new Runnable() {
public void run() {
- if (direction == Direction.Forward) {
+ if (getDirection() == Direction.Forward) {
readForward(pos);
} else {
readBackward(pos);
@@ -284,15 +84,6 @@
} finally {
pis.close();
}
-
- }
-
- private String getClosingTag(boolean isForward) {
- return isForward ? XmlTags.OPERATIONS_END_TAG : XmlTags.OPERATIONS_START_TAG;
- }
-
- private String getOpeningTag(boolean isForward) {
- return isForward ? XmlTags.OPERATIONS_START_TAG : XmlTags.OPERATIONS_END_TAG;
}
private EObject deserialize(final PipedInputStream pis) throws IOException {
@@ -303,15 +94,4 @@
xmlLoadImpl.load((XMLResource) resource, pis, ModelUtil.getResourceLoadOptions());
return resource.getContents().get(0);
}
-
- /**
- * Closes the emitter.
- */
- public void close() {
- try {
- reader.close();
- } catch (final IOException ex) {
- ModelUtil.logException(ex);
- }
- }
}
diff --git a/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/SerializedOperationEmitter.java b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/SerializedOperationEmitter.java
new file mode 100644
index 0000000..77486ba
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.server.model/src/org/eclipse/emf/emfstore/internal/server/model/versioning/impl/persistent/SerializedOperationEmitter.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.internal.server.model.versioning.impl.persistent;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Scanner;
+
+import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation;
+
+import com.google.common.base.Optional;
+
+/**
+ * Type for emitting {@link AbstractOperation}s in their serialized form when given a {@link ReadLineCapable} type.
+ *
+ * @author Johannes Faltermeier
+ *
+ */
+public class SerializedOperationEmitter extends AbstractOperationEmitter {
+
+ /**
+ * Constructor.
+ *
+ * @param direction
+ * the {@link Direction} that is used for reading
+ * @param file
+ * the operation file
+ */
+ public SerializedOperationEmitter(Direction direction, File file) {
+ super(direction, file);
+ }
+
+ /**
+ * Tries to parse an operation in the reading directions and emits it,
+ * if parsing has been successful. The operation is returned in its parsed string representation.
+ *
+ * @return the successfully parsed operation as a string representation
+ * @throws IOException
+ * in case reading from the {@link ReadLineCapable} fails
+ */
+ public Optional<String> tryEmit() throws IOException {
+ final PipedOutputStream pos = new PipedOutputStream();
+ final PipedInputStream pis = new PipedInputStream(pos);
+
+ new Thread(new Runnable() {
+ public void run() {
+ if (getDirection() == Direction.Forward) {
+ readForward(pos);
+ } else {
+ readBackward(pos);
+ }
+ }
+ }).start();
+
+ try {
+ final String streamToString = convertStreamToString(pis);
+ if (XmlTags.XML_RESOURCE_WITH_EOBJECT.equals(streamToString)) {
+ return Optional.absent();
+ }
+ return Optional.of(streamToString);
+ } finally {
+ pis.close();
+ }
+ }
+
+ private static String convertStreamToString(InputStream inputStream) {
+ final Scanner scanner = new Scanner(inputStream);
+ scanner.useDelimiter("\\A"); //$NON-NLS-1$
+ final String result = scanner.hasNext() ? scanner.next() : ""; //$NON-NLS-1$
+ scanner.close();
+ return result;
+ }
+
+}