package com.sap.furcas.ide.editor.junitcreate; //import com.sap.furcas.ide.editor.document.CtsHistoryDocument; /** * Document history used by {@link CtsHistoryDocument} to manage and record * snapshots and DocumentEvents. * * @author D049157 * */ public class DocumentHistory /* implements IDocumentListener */ { // // /** // * Set this to false to disable snapshotting. // * // * Automatically set to false once an internal error occurs // */ // private Boolean isActive = true; // // private static final String PRI_ENDING = ".types"; // private static final String PRI_FOLDER = "src/"; // // private static class Session { // Boolean isPersisted = false; // final String snapshotIdentifier = UUID.randomUUID().toString().replace("-", ""); // /** the copy of the rootObject of CtsHistoryDocument */ // EObject newDocumentRootObject; // /** all copied elements without a composite parent: HashMap<Original, Copy> */ // Map<EObject, EObject> rootElements; // /** all DocumentEvents on the CtsHistoryDocument under observation */ // final Collection<DocumentEvent> eventHistory = new LinkedList<DocumentEvent>(); // /** the transient model partitions which are used as model cache: <PartitionName, Partition> */ // Map<String, Resource> transientPartitions; // /** Pre-existing constraints errors of the model */ // public Collection<JmiException> knownConstraintErrors; // // Boolean isCompleted() { // return newDocumentRootObject != null; // } // } // // /** // * Editor session we use for test creation (Session between the last two // * save points.) // */ // private Session completedSession; // /** Currently active and still modified session */ // private Session currentSession; // // private final ResourceSet targetConnection; // private final CtsDocument document; // // public DocumentHistory(CtsDocument document, IProject project) { // this.document = document; // // // A new connection is required in order to persist snapshots without // // flushing a dirty editor connection. // targetConnection = createTargetConnection(project, document.getRootObject().get___Connection()); // // // initialize with Null-Objects // completedSession = new Session(); // currentSession = new Session(); // } // // /** // * Get the DocumentEvent history of the given snapshot version. // * // * @return // */ // public Collection<DocumentEvent> getHistory(SnapshotVersion version) { // Session session = getSessionOfVersion(version); // return session.eventHistory; // // } // // private Session getSessionOfVersion(SnapshotVersion version) { // if (version.equals(SnapshotVersion.CURRENT)) { // return currentSession; // } else { // assert version.equals(SnapshotVersion.COMPLETED); // return completedSession; // } // } // // /** // * Create a new snapshot of the actual document model. The previous // * snapshot can now be persisted. // * @param monitor // * // * @return // */ // public Boolean createNewSnapshot(IProgressMonitor monitor) { // if (!isActive) { // return false; // } // CommandStack cmdStk = targetConnection.getCommandStack(); // try { // cmdStk.openGroup("Document History: Create Snapshot"); // monitor.worked(100); // // drop outdated (still transient) partitions // dropTransientPartitions(completedSession.transientPartitions); // monitor.worked(100); // completedSession = currentSession; // currentSession = new Session(); // // assert targetConnection.getNullPartition().getElements().size() == 0 : "Copy PreCond: Nullpartiton not empty."; // DeepCopyResultSet result = createNewModelSnapshot((EObject) document.getRootObject(), document.getRootBlock()); // monitor.worked(100); // // extract result information before moving them into a transient // // partition (URI based lookup wouldn't work any longer) // currentSession.newDocumentRootObject = getNewRootObject(result, (EObject) document.getRootObject()); // currentSession.rootElements = getRootElements(result, targetConnection.getNullPartition()); // currentSession.knownConstraintErrors = getOriginalConstraintErrors(currentSession.rootElements); // currentSession.transientPartitions = repartitionModelCopy(result, currentSession.snapshotIdentifier); // assert targetConnection.getNullPartition().getElements().size() == 0 : "Copy PostCond: Nullpartiton not empty."; // // cmdStk.closeGroup(); // assertSideEffectFreeness(); // monitor.worked(100); // return true; // } catch (Throwable e) { // handle_error(e); // return false; // } // } // // /** // * Write the snapshot of the given version to disk. The copy will be renamed // * and placed next to the original version. // * // * <b>Warning: </b> If the persisted result seems invalid or does not show // * up (e.g. link from composite parent to this new copy is broken), then you // * may have encountered a MOIN bug. Please delete // * .metadata\.plugins\com.sap.tc.moin.facility.primary and then check again // * // * @param testCaseName, the prefix of the created partitions // * @return the URI of the copied document root. Will be null if persisting // * was not successful // */ // public URI persistSnapshot(String testCaseName, SnapshotVersion version) { // if (!isActive) { // return null; // } // Session toBePersisted = getSessionOfVersion(version); // if (!toBePersisted.isCompleted() || toBePersisted.isPersisted) { // throw new NoSuchSnapshotException("Your desired snapshot is not available."); // } // CommandStack cmdStk = targetConnection.getCommandStack(); // try { // cmdStk.openGroup("Document History: Persist Snapshot"); // EObject root = toBePersisted.newDocumentRootObject; // linkRootElementsToCompositeParent(toBePersisted.rootElements, toBePersisted.snapshotIdentifier); // // assert targetConnection.getElement(root.get___Mri()) != null : "Unable to resolve copied (transient) root element"; // Collection<Resource> partitions = persistTransientPartitions(testCaseName, toBePersisted.transientPartitions); // assertConstraintsValid(partitions, toBePersisted.knownConstraintErrors); // assert targetConnection.getElement(root.get___Mri()) != null : "Unable to resolve copied (moved) root element"; // // targetConnection.getConsistencyViolationListenerRegistry().performConsistencyCheck(root.eResource().getURI()); // for (ConsistencyViolation ic : targetConnection.getConsistencyViolationListenerRegistry() // .getAllConsistencyViolations()) { // System.err.println("IC " + ic.getDescription(targetConnection)); // } // // announceNewPartitions(partitions); // cmdStk.closeGroup(); // // ModelManager.getConnectionManager().save(targetConnection); // assert targetConnection.getElement(root.get___Mri()) != null : "Unable to resolve copied (persisted) root element"; // // toBePersisted.isPersisted = true; // we moved the model, this can only be done once // // return root.get___Mri(); // } catch (Throwable e) { // handle_error(e); // return null; // } // } // // /** // * Returns true if this DocumentHistory is still actively creating snapshots // * and no internal error has occurred, yet. // */ // public Boolean isActive() { // return isActive; // } // // /** // * Copy the document's rootObject including its composition and dependent // * model elements, as well as all textblocks. The copy result is placed into // * the null partition. // * // * @param rootObject // * @param rootBlock // * @return // */ // private DeepCopyResultSet createNewModelSnapshot(EObject _rootObject, EObject _rootBlock) { // URI rootObjectMRI = _rootObject.get___Mri(); // URI rootBlockMRI = _rootBlock.get___Mri(); // // // Resolve via our own connection // EObject rootObject = (EObject) targetConnection.getElement(rootObjectMRI); // EObject rootBlock = (EObject) targetConnection.getElement(rootBlockMRI); // assert rootObject != null : "Could not resolve document root object"; // // ArrayList<EObject> toBeCopied = new ArrayList<EObject>(2); // toBeCopied.add(rootObject); // if (rootBlock != null) { // Could be null if it was not saved yet // toBeCopied.add(rootBlock); // } // // disableEventListeners(targetConnection); // // // Copy composite of the rootObject // IModelTransferTarget target = DeepCopyHelper.getTransferTarget(rootObject); // DeepCopyResultSet resultSet = targetConnection.deepCopy(toBeCopied, target.getDeepCopyPolicyHandler(), target // .includeExternalCompositeParents()); // // enableEventListeners(targetConnection); // // // Report errors // if (!resultSet.getCopyErrors().isEmpty()) { // System.err.println("Model copy finished with errors. See Error Log."); // // just disable; errors are already logged within deep copy // targetConnection.close(); // isActive = false; // } // return resultSet; // } // // /** // * Repartition the copied model elements and move them from the null // * partition to a transient partition structure resembling the source // * structure. // * // * @param resultSet // * @param snapshotIdentifier // * @return the created transient partitions // */ // private Map<String, Resource> repartitionModelCopy(DeepCopyResultSet copyResultSet, String snapshotIdentifier) { // HashMap<String, Resource> result = new HashMap<String, Resource>(); // // for (EObject target : copyResultSet.getCopiedElements()) { // URI sourceMRI = copyResultSet.getInverseMriMappingTable().get(target.get___Mri()); // EObject source = (EObject) targetConnection.getElement(sourceMRI); // // String partitionIdentifier = source.eResource().getURI().hashCode() + snapshotIdentifier; // Resource transientPartition = targetConnection.getOrCreateTransientPartition(partitionIdentifier); // // target.assign___Partition(transientPartition); // result.put(partitionIdentifier, transientPartition); // } // return result; // } // // private EObject getNewRootObject(DeepCopyResultSet copyResultSet, EObject oldRoot) { // EObject newRoot = copyResultSet.getMappingTable().get(oldRoot).getMappingTarget(); // return newRoot; // } // // private Map<EObject, EObject> getRootElements(DeepCopyResultSet copyResultSet, Resource partition) { // Map<EObject, EObject> elements = new HashMap<EObject, EObject>(); // PartitionService service = ModelManager.getPartitionService(); // // for (EObject rootCopy : service.getRootElements(partition)) { // URI copyMRI = rootCopy.get___Mri(); // URI sourceMRI = copyResultSet.getInverseMriMappingTable().get(copyMRI); // // EObject rootSource = (EObject) targetConnection.getElement(sourceMRI); // elements.put(rootSource, (EObject) rootCopy); // } // return elements; // } // // private void linkRootElementsToCompositeParent(Map<EObject, EObject> rootElements, String identifier) { // for (Entry<EObject, EObject> entry : rootElements.entrySet()) { // EObject source = entry.getKey(); // EObject copy = entry.getValue(); // // if (copy instanceof TextBlock) { // continue; // } // // IModelTransferTarget transfer = DeepCopyHelper.getTransferTarget(copy); // DeepCopyPolicyHandler handler = transfer.getDeepCopyPolicyHandler(); // if (handler instanceof GenericModelCopyStrategy) { // GenericModelCopyStrategy strategy = (GenericModelCopyStrategy) handler; // Boolean shouldBeLinked = strategy.prepareLinkingToCompositeParent(identifier, source, copy); // if (shouldBeLinked) { // DeepCopyHelper.linkToCompositeParent(targetConnection, source, copy); // } // } else { // EObject parent = DeepCopyHelper.getCompositeParent(targetConnection, source); // transfer.handleTransfer(parent, new EObject[] { copy }, null); // } // } // } // // private void assertSideEffectFreeness() { // PartitionService service = ModelManager.getPartitionService(); // Collection<Resource> dirtyPartitions = service.getDirtyPartitions(targetConnection); // Collection<Resource> transientPartitions = targetConnection.getTransientPartitions(); // // for (Resource dirty : dirtyPartitions) { // if (!transientPartitions.contains(dirty)) { // throw new AssertionFailedException("Non transient partiton dirty: " + dirty); // } // } // if (targetConnection.isDirty()) { // throw new AssertionFailedException("Dirty target connection"); // } // } // // private void assertConstraintsValid(Collection<Resource> partitions, Collection<JmiException> knownErrors) { // for (Resource partition : partitions) { // for (EObject element : partition.getElements()) { // if (element instanceof EObject) { // EObject refObj = (EObject) element; // Collection<JmiException> errors = refObj.refVerifyConstraints(false); // // This check is only fuzzy: It is very unlikely that we // // have the same amount of errors but with totally different reasons // if (errors != null && (errors.size() > knownErrors.size())) { // for (JmiException err : errors) { // CtsActivator.logError(err, /* don't show popup */true); // } // throw new AssertionFailedException("Copy violates constraints. Errors have been logged."); // } // } // } // } // } // // private Collection<JmiException> getOriginalConstraintErrors(Map<EObject, EObject> rootElements) { // HashSet<JmiException> allErrors = new HashSet<JmiException>(); // for (EObject original : rootElements.keySet()) { // Collection<JmiException> errors = original.refVerifyConstraints(true); // if (errors != null) { // allErrors.addAll(errors); // } // } // return allErrors; // } // // private void handle_error(Throwable cause) { // Exception e = new RuntimeException("Disabling DocumentHistory Instance. See cause.", cause); // CtsActivator.logError(e, /* don't show popup */true); // System.err.println("Error in DocumentHistory, please consult error log!"); // isActive = false; // if (targetConnection != null) { // targetConnection.close(); // undo all our (potential) changes // } // } // // /** // * Materialize the given TransientPartitions. // * // * @return all newly created partitions // */ // private Collection<Resource> persistTransientPartitions(String testCaseName, // Map<String, Resource> transientPartitions) { // // Collection<Resource> result = new ArrayList<Resource>(); // for (Entry<String, Resource> entry : transientPartitions.entrySet()) { // Resource transientPartition = entry.getValue(); // String partitionIdentifier = entry.getKey(); // // URI targetPRI = targetConnection.getSession().getMoin().createPri(getFacilityId(), getDataAreaName(), // getContainerName(), PRI_FOLDER + testCaseName + partitionIdentifier + PRI_ENDING); // // Resource targetPartition = targetConnection.createPartition(targetPRI); // // result.add(targetPartition); // PartitionService.getInstance().moveElements(transientPartition, targetPartition); // } // return result; // } // // private void dropTransientPartitions(Map<String, Resource> partitions) { // if (partitions == null) { // return; // } // for (Resource partition : partitions.values()) { // assert targetConnection.getTransientPartitions().contains(partition); // partition.delete(); // } // } // // /** // * Create a new connection for the given project. // * // * @param project // * @param connection // * @return // */ // private ResourceSet createTargetConnection(final IProject project, final ResourceSet editorCo) { // final ResourceSet[] con = new ResourceSet[1]; // IRunnableWithProgress operation = new IRunnableWithProgress() { // public void run(IProgressMonitor monitor) { // // non UI thread // con[0] = ConnectionManager.getInstance().createConnection(project); // con[0].setLabel("DocumentHistory target connection of " + editorCo.getLabel()); // } // }; // IProgressService ps = PlatformUI.getWorkbench().getProgressService(); // try { // ps.busyCursorWhile(operation); // } catch (Throwable e) { // handle_error(e); // } // return con[0]; // } // // /** // * Deactivate event listeners on the given connection for save, // * uninterrupted copying // * // * @param co // */ // private void disableEventListeners(ResourceSet co) { // BundleContext context = CtsActivator.getDefault().getBundle().getBundleContext(); // ServiceReference ref = context.getServiceReference(GlobalEventListenerRegistry.class.getName()); // GlobalEventListenerRegistry registry = (GlobalEventListenerRegistry) context.getService(ref); // registry.deregisterFilters(co.getSession()); // } // // /** // * Restore deactivated event listeners on the given connection // * // * @param co // */ // private void enableEventListeners(ResourceSet co) { // BundleContext context = CtsActivator.getDefault().getBundle().getBundleContext(); // ServiceReference ref = context.getServiceReference(GlobalEventListenerRegistry.class.getName()); // GlobalEventListenerRegistry registry = (GlobalEventListenerRegistry) context.getService(ref); // registry.registerFilters(co.getSession()); // } // // protected String getDataAreaName() { // // e.g. "IDE"; // return document.getRootObject().eResource().getURI().getDataAreaDescriptor().getDataAreaName(); // } // // protected String getContainerName() { // // e.g. "ngpm.stdlib"; // return document.getRootObject().eResource().getURI().getContainerName(); // } // // protected String getFacilityId() { // // e.g. "PF"; // return document.getRootObject().eResource().getURI().getDataAreaDescriptor().getFacilityId(); // } // // @Override // public void documentAboutToBeChanged(DocumentEvent event) { // // do nothing, we use documentChanged // } // // @Override // public void documentChanged(DocumentEvent event) { // currentSession.eventHistory.add(event); // } // // @Override // protected void finalize() { // targetConnection.close(); // } // // /** // * Propagates the new partitions to the versioning system // */ // private void announceNewPartitions(Collection<Resource> partitions) { // if (partitions.size() > 0) { // // use a dummy command that returns the given partitions // Command cmd = new AnnounceNewPartitionsCommand(targetConnection, partitions); // cmd.execute(); // } // } // // private static final class AnnounceNewPartitionsCommand extends Command { // private final List<EOperation> mPartitions; // // private AnnounceNewPartitionsCommand(ResourceSet connection, Collection<Resource> partitions) { // super(connection, "Persist Testcase Partition Announcment"); // mPartitions = new ArrayList<EOperation>(partitions.size()); // for (Resource partition : partitions) { // mPartitions.add(new EOperation(EOperation.CREATE, partition.getURI())); // } // } // // @Override // public synchronized Collection<EOperation> getAffectedPartitions() { // return mPartitions; // } // // @Override // public boolean canExecute() { // return true; // } // // @Override // public void doExecute() { // } // } }