Java tutorial
//======================================================================== // //File: $RCSfile: ModelMergeProcessor.java,v $ //Version: $Revision: 1.5.14.5 $ //Modified: $Date: 2013/07/23 15:06:35 $ // //Copyright 2005-2014 Mentor Graphics Corporation. All rights reserved. // //======================================================================== // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //======================================================================== // package org.xtuml.bp.model.compare; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.xtuml.bp.core.Association_c; import org.xtuml.bp.core.CantHappen_c; import org.xtuml.bp.core.ClassAsAssociatedOneSide_c; import org.xtuml.bp.core.ClassAsSimpleParticipant_c; import org.xtuml.bp.core.ClassAsSubtype_c; import org.xtuml.bp.core.ClassInAssociation_c; import org.xtuml.bp.core.CorePlugin; import org.xtuml.bp.core.CreationTransition_c; import org.xtuml.bp.core.DataType_c; import org.xtuml.bp.core.Elementtypeconstants_c; import org.xtuml.bp.core.EventIgnored_c; import org.xtuml.bp.core.Gd_c; import org.xtuml.bp.core.LinkedAssociation_c; import org.xtuml.bp.core.ModelClass_c; import org.xtuml.bp.core.Modeleventnotification_c; import org.xtuml.bp.core.NewStateTransition_c; import org.xtuml.bp.core.NoEventTransition_c; import org.xtuml.bp.core.NonLocalEvent_c; import org.xtuml.bp.core.Ooaofooa; import org.xtuml.bp.core.PackageableElement_c; import org.xtuml.bp.core.ReferringClassInAssoc_c; import org.xtuml.bp.core.SemEvent_c; import org.xtuml.bp.core.SignalEvent_c; import org.xtuml.bp.core.SimpleAssociation_c; import org.xtuml.bp.core.StateEventMatrixEntry_c; import org.xtuml.bp.core.StateMachineEvent_c; import org.xtuml.bp.core.StateMachineState_c; import org.xtuml.bp.core.StateMachine_c; import org.xtuml.bp.core.SubtypeSupertypeAssociation_c; import org.xtuml.bp.core.Transition_c; import org.xtuml.bp.core.common.BaseModelDelta; import org.xtuml.bp.core.common.ClassQueryInterface_c; import org.xtuml.bp.core.common.IPersistableElementParentDetails; import org.xtuml.bp.core.common.InstanceList; import org.xtuml.bp.core.common.ModelElement; import org.xtuml.bp.core.common.ModelRoot; import org.xtuml.bp.core.common.ModelStreamProcessor; import org.xtuml.bp.core.common.NonRootModelElement; import org.xtuml.bp.core.common.PersistenceManager; import org.xtuml.bp.core.inspector.IModelClassInspector; import org.xtuml.bp.core.inspector.ModelInspector; import org.xtuml.bp.core.inspector.ObjectElement; import org.xtuml.bp.core.sorter.MetadataSortingManager; import org.xtuml.bp.core.ui.IModelImport; import org.xtuml.bp.core.ui.Selection; import org.xtuml.bp.core.util.SupertypeSubtypeUtil; import org.xtuml.bp.io.core.CoreExport; import org.xtuml.bp.io.core.CoreImport; import org.xtuml.bp.model.compare.providers.ComparableProvider; import org.xtuml.bp.model.compare.providers.NonRootModelElementComparable; import org.xtuml.bp.model.compare.providers.ObjectElementComparable; import org.xtuml.bp.ui.canvas.ElementSpecification_c; import org.xtuml.bp.ui.canvas.GraphicalElement_c; import org.xtuml.bp.ui.canvas.Layer_c; import org.xtuml.bp.ui.canvas.Model_c; import org.xtuml.bp.ui.canvas.Ooaofgraphics; import org.xtuml.bp.ui.canvas.inspector.GraphicalModelInspector; public class ModelMergeProcessor { public static boolean merge(TreeDifferencer differencer, TreeDifference difference, boolean rightToLeft, ITreeDifferencerProvider contentProvider, ITableLabelProvider labelProvider, Ooaofooa destinationModelRoot) throws IOException { // this is a removal if (difference.getElement() instanceof EmptyElement && difference.getMatchingDifference().getElement() instanceof NonRootModelElementComparable) { NonRootModelElementComparable localComparable = (NonRootModelElementComparable) difference .getMatchingDifference().getElement(); disposeElement(localComparable); return true; } Object diffElement = difference.getElement(); // if the difference is name based if (difference.getType() == TreeDifference.NAME_DIFFERENCE) { // find the child's difference that actually effects the // element name String text = labelProvider.getColumnText(diffElement, 0); difference = getDifferenceForNameChange(contentProvider, diffElement, text, rightToLeft, differencer); if (difference == null) { return false; } diffElement = difference.getElement(); } if (diffElement instanceof NonRootModelElementComparable && difference.getElement() != null && difference.getMatchingDifference().getElement() != null && difference.getLocation() != difference.getMatchingDifference().getLocation() && !(difference.getMatchingDifference().getElement() instanceof EmptyElement)) { // this is a positional change return handlePositionChange(difference, contentProvider); } if (diffElement instanceof NonRootModelElementComparable) { // do not allow the merge if there is no parent // this is a case where the left element is null and // merging would result in the creation of a new element // This new element could however result in a case where // a duplicate element is created (rename) which the tool // currently does not behave well with if (difference.getElement() == null && difference.getMatchingDifference().getParent() == null) { return false; } return handleNewElement(difference, contentProvider, diffElement, destinationModelRoot, differencer, rightToLeft); } else if (difference.getElement() instanceof ObjectElementComparable) { // just copy the value over, but create deltas so that they // can be applied to the real local copy ObjectElementComparable comparable = (ObjectElementComparable) difference.getElement(); ObjectElementComparable localComparable = (ObjectElementComparable) difference.getMatchingDifference() .getElement(); ObjectElement element = (ObjectElement) comparable.getRealElement(); ObjectElement localElement = (ObjectElement) localComparable.getRealElement(); if (element.getType() == ObjectElement.ATTRIBUTE_ELEMENT) { return handleAttributeChange(localElement, element); } else if (element.getType() == ObjectElement.REFERENTIAL_ATTRIBUTE_ELEMENT) { handleReferential(element, localElement, contentProvider, destinationModelRoot, differencer, rightToLeft, difference); return true; } } return false; } /** * This method will move the element to the same location as * determined by the difference * * @param difference * @return boolean, true if a change was made */ private static boolean handlePositionChange(TreeDifference difference, ITreeContentProvider contentProvider) { ComparableTreeObject comparable = (ComparableTreeObject) difference.getElement(); Object destinationElement = difference.getMatchingDifference().getElement(); Object destinationParent = contentProvider.getParent(destinationElement); Object localParent = contentProvider.getParent(comparable); int location = TreeDifferencer.getLocationOfElement(localParent, comparable, (ITreeDifferencerProvider) contentProvider); int destinationLocation = TreeDifferencer.getLocationOfElement(destinationParent, destinationElement, (ITreeDifferencerProvider) contentProvider); if (location == destinationLocation) { // another difference has already handled this return false; } // if this is a change that does not have user ordering // then modify the persistence ordering NonRootModelElement element = (NonRootModelElement) comparable.getRealElement(); if (!MetadataSortingManager.isOrderedElement(element)) { IPersistableElementParentDetails parentDetails = PersistenceManager.getHierarchyMetaData() .getParentDetails(element); Object[] localDetails = new Object[] { parentDetails.getParent(), parentDetails.getChild(), parentDetails.getAssociationNumber(), parentDetails.getAssociationPhrase(), parentDetails.getChildKeyLetters() }; callSetOrderOperation(location, localDetails); return true; } boolean up = location < destinationLocation; if (up) { insertElementAt(location, difference, contentProvider, true); } else { insertElementAt(location, difference, contentProvider, false); } return true; } private static void insertElementAt(int location, TreeDifference difference, ITreeContentProvider contentProvider, boolean moveUp) { NonRootModelElementComparable comparable = null; if (difference.getMatchingDifference().getElement() instanceof EmptyElement) { // find the newly copied over comparable NonRootModelElementComparable remoteComparable = (NonRootModelElementComparable) difference .getElement(); NonRootModelElement remoteElement = (NonRootModelElement) remoteComparable.getRealElement(); EmptyElement localEmptyElement = ((EmptyElement) difference.getMatchingDifference().getElement()); NonRootModelElement parent = (NonRootModelElement) localEmptyElement.getParent(); Object newElementInDestination = findObjectInDestination(parent.getModelRoot(), remoteElement); comparable = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject(newElementInDestination); } else { comparable = (NonRootModelElementComparable) difference.getMatchingDifference().getElement(); } NonRootModelElement element = (NonRootModelElement) comparable.getRealElement(); Object[] existingChildren = ((ITreeDifferencerProvider) contentProvider) .getChildren(contentProvider.getParent(element)); if (!moveUp && location >= existingChildren.length) { location = existingChildren.length - 1; } Object existingElementAtNewLocation = existingChildren[location]; if (existingElementAtNewLocation != null) { existingElementAtNewLocation = ((ComparableTreeObject) existingElementAtNewLocation).getRealElement(); } String associationNumber = MetadataSortingManager.getAssociationNumber(element); String associationPhrase = MetadataSortingManager.getAssociationPhrase(element); if (moveUp) { NonRootModelElement previousElementToExisting = (NonRootModelElement) MetadataSortingManager .getPreviousElement((NonRootModelElement) existingElementAtNewLocation); if (previousElementToExisting != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, existingElementAtNewLocation.getClass(), new Class[] { existingElementAtNewLocation.getClass() }); invokeMethod(unrelate, existingElementAtNewLocation, new Object[] { previousElementToExisting }); } NonRootModelElement previousToSelf = (NonRootModelElement) MetadataSortingManager .getPreviousElement(element); if (previousToSelf != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, element.getClass(), new Class[] { element.getClass() }); invokeMethod(unrelate, element, new Object[] { previousToSelf }); } NonRootModelElement nextToSelf = (NonRootModelElement) MetadataSortingManager.getNextElement(element); if (nextToSelf != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, nextToSelf.getClass(), new Class[] { nextToSelf.getClass() }); invokeMethod(unrelate, nextToSelf, new Object[] { element }); Method relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, nextToSelf.getClass(), new Class[] { nextToSelf.getClass() }); invokeMethod(relate, nextToSelf, new Object[] { previousToSelf }); } Method relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, existingElementAtNewLocation.getClass(), new Class[] { existingElementAtNewLocation.getClass() }); invokeMethod(relate, existingElementAtNewLocation, new Object[] { element }); if (previousElementToExisting != null) { relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, element.getClass(), new Class[] { element.getClass() }); invokeMethod(relate, element, new Object[] { previousElementToExisting }); } } else { NonRootModelElement nextElementToExisting = (NonRootModelElement) MetadataSortingManager .getNextElement((NonRootModelElement) existingElementAtNewLocation); if (nextElementToExisting != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, nextElementToExisting.getClass(), new Class[] { nextElementToExisting.getClass() }); invokeMethod(unrelate, nextElementToExisting, new Object[] { existingElementAtNewLocation }); } NonRootModelElement nextToSelf = (NonRootModelElement) MetadataSortingManager.getNextElement(element); if (nextToSelf != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, nextToSelf.getClass(), new Class[] { nextToSelf.getClass() }); invokeMethod(unrelate, nextToSelf, new Object[] { element }); } NonRootModelElement previousToSelf = (NonRootModelElement) MetadataSortingManager .getPreviousElement(element); if (previousToSelf != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, element.getClass(), new Class[] { element.getClass() }); invokeMethod(unrelate, element, new Object[] { previousToSelf }); } if (nextToSelf != null && previousToSelf != null) { Method relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, nextToSelf.getClass(), new Class[] { nextToSelf.getClass() }); invokeMethod(relate, nextToSelf, new Object[] { previousToSelf }); } Method relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, element.getClass(), new Class[] { element.getClass() }); invokeMethod(relate, element, new Object[] { existingElementAtNewLocation }); if (nextElementToExisting != null) { relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, nextElementToExisting.getClass(), new Class[] { nextElementToExisting.getClass() }); invokeMethod(relate, nextElementToExisting, new Object[] { element }); } } } private static boolean handleAttributeChange(ObjectElement localElement, ObjectElement element) { // skip graphical.represents() if (element.getName().equals("represents") && (element.getParent() instanceof GraphicalElement_c || element.getParent() instanceof Model_c)) { return false; } String attributeName = localElement.getValueAccessor().replaceAll("get", ""); if (attributeName.contains("Action_semantics")) { attributeName = attributeName + "_internal"; } Object attributeOwner = localElement.getAttributeOwner(); if (attributeOwner == null) { attributeOwner = localElement.getParent(); } Class<?> paramClass = element.getValue().getClass(); if (paramClass == Integer.class) { // use the int class paramClass = Integer.TYPE; } else if (paramClass == Float.class) { paramClass = Float.TYPE; } Method setMethod = findMethod("set" + attributeName, attributeOwner.getClass(), new Class[] { paramClass }); invokeMethod(setMethod, attributeOwner, new Object[] { element.getValue() }); return true; } private static boolean handleNewElement(TreeDifference difference, ITreeDifferencerProvider contentProvider, Object diffElement, Ooaofooa modelRoot, TreeDifferencer differencer, boolean rightToLeft) throws IOException { Object matchingDiffElement = difference.getMatchingDifference().getElement(); if (!(matchingDiffElement instanceof EmptyElement) && !matchingDiffElement.getClass().isInstance(diffElement)) { // not supported return false; } Object remoteParent = contentProvider.getParent(difference.getElement()); int newElementLocation = difference.getLocation(); NonRootModelElement parent = null; if (matchingDiffElement instanceof EmptyElement) { EmptyElement empty = (EmptyElement) matchingDiffElement; parent = (NonRootModelElement) empty.getParent(); newElementLocation = empty.getLocation(); } else { ComparableTreeObject parentObject = (ComparableTreeObject) contentProvider .getParent(matchingDiffElement); parent = (NonRootModelElement) parentObject.getRealElement(); } // grab the existing children, so that ordering can be // fixed after the batch relate calls Object[] existingChildren = ((ITreeDifferencerProvider) contentProvider).getChildren(parent); // create deltas for the creation of a new element NonRootModelElement newObject = null; Object realElement = ((ComparableTreeObject) diffElement).getRealElement(); List<Object> orderList = new ArrayList<Object>(); if (MetadataSortingManager.isOrderedElement(realElement)) { // create a list to capture the existing order for (Object child : existingChildren) { if (((ComparableTreeObject) child).getRealElement() .getClass() == ((ComparableTreeObject) diffElement).getRealElement().getClass()) { orderList.add(child); } } } if (realElement instanceof NonRootModelElement) { newObject = (NonRootModelElement) realElement; } else if (realElement instanceof ObjectElement) { newObject = (NonRootModelElement) ((ObjectElement) realElement).getValue(); } if (matchingDiffElement != null && !(matchingDiffElement instanceof EmptyElement)) { Object existingDiffElement = ((ComparableTreeObject) matchingDiffElement).getRealElement(); // first adjust so that the ordering matches for undo // this will place the element at the end position // and allow a restored deletion to get placed at // the proper location int length = getPersistenceLocation(parent, existingDiffElement, contentProvider, true); adjustPersistenceOrdering(existingDiffElement, length - 1); // this is a value difference, we need to dispose the current value // first // disable listeners as we do not want graphics deleted // for this case, they will have their own differences if // deletion is required try { Ooaofgraphics.disableChangeNotification(); disposeElement(matchingDiffElement); } finally { Ooaofgraphics.enableChangeNotification(); } } // look for the element locally, certain differences that // were // before this one may have created it, or it may be a // location difference in the file Object object = findObjectInDestination(modelRoot, newObject); if (object != null && !((NonRootModelElement) object).isProxy()) { newElementLocation = getPersistenceLocation(parent, newObject, contentProvider, false); return adjustPersistenceOrdering(object, newElementLocation); } // some situations required other data to be created first handleCopyNew(newObject, differencer, contentProvider, modelRoot, rightToLeft); // export the element String export = copyExternal(modelRoot, newObject, false, false); newObject = importExternal(newObject, export, parent, modelRoot, getPersistenceLocation(remoteParent, difference.getElement(), contentProvider, false)); // if this element is a graphical element we need to // associate it with an element specification so the // proper ooa_type is exported if (newObject instanceof GraphicalElement_c) { final GraphicalElement_c element = (GraphicalElement_c) newObject; ElementSpecification_c spec = ElementSpecification_c .ElementSpecificationInstance(Ooaofgraphics.getDefaultInstance(), new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((ElementSpecification_c) candidate).getOoa_type() == element .getOoa_typeCachedValue(); } }); if (spec != null) { spec.relateAcrossR10To(element); } // additionally if the Model_c instance is null // the graphical element came from a situation where // the semantic elements were different (one case is // a state machine being created in two different branches) if (Model_c.getOneGD_MDOnR1(element) == null) { Model_c newModel = Model_c.ModelInstance(Ooaofgraphics.getInstance(modelRoot.getId())); element.relateAcrossR1To(newModel); } } // as above we may need to reassociate graphical layers with // the new Model instance if (newObject instanceof Layer_c) { Layer_c layer = (Layer_c) newObject; if (Model_c.getOneGD_MDOnR34(layer) == null) { Model_c newModel = Model_c.ModelInstance(Ooaofgraphics.getInstance(modelRoot.getId())); layer.relateAcrossR34To(newModel); } } Object[] children = contentProvider.getChildren(contentProvider.getParent(diffElement)); // we need to look at all the referentials for this element // as they may not yet exist in the target, if that is the // case we create a copy now and associate children = contentProvider.getChildren(newObject); recursivelyCopyChildren(children, contentProvider, diffElement, modelRoot, differencer, rightToLeft); // if this is an ordered element we need to adjust the ordering accordingly if (MetadataSortingManager.isOrderedElement(realElement)) { // reset the order in the destination, placing the // new element at the end String associationNumber = MetadataSortingManager.getAssociationNumber(newObject); String associationPhrase = MetadataSortingManager.getAssociationPhrase(newObject); for (Object element : orderList) { NonRootModelElementComparable comparable = (NonRootModelElementComparable) element; NonRootModelElement orderedElement = (NonRootModelElement) comparable.getRealElement(); ModelElement nextElement = MetadataSortingManager.getNextElement(orderedElement); if (nextElement != null) { Method unrelate = findMethod("unrelateAcrossR" + associationNumber + "From" + associationPhrase, orderedElement.getClass(), new Class[] { orderedElement.getClass() }); invokeMethod(unrelate, nextElement, new Object[] { orderedElement }); } else { // in some cases we may need to // check the previous element ModelElement previous = MetadataSortingManager.getPreviousElement(orderedElement); if (previous != null) { Method unrelate = findMethod( "unrelateAcrossR" + associationNumber + "From" + associationPhrase, orderedElement.getClass(), new Class[] { orderedElement.getClass() }); invokeMethod(unrelate, orderedElement, new Object[] { previous }); } } } int count = 0; for (Object element : orderList) { Object relateTo = null; NonRootModelElementComparable comparable = (NonRootModelElementComparable) element; NonRootModelElement orderedElement = (NonRootModelElement) comparable.getRealElement(); if (count + 1 == orderList.size()) { // associate the new element relateTo = newObject; } else { relateTo = orderList.get(count + 1); NonRootModelElementComparable relateComparable = (NonRootModelElementComparable) relateTo; relateTo = (NonRootModelElement) relateComparable.getRealElement(); } // relate each Method relate = findMethod("relateAcrossR" + associationNumber + "To" + associationPhrase, orderedElement.getClass(), new Class[] { orderedElement.getClass() }); invokeMethod(relate, relateTo, new Object[] { orderedElement }); count++; } int currentLocation = TreeDifferencer.getLocationOfElement(parent, ComparableProvider.getComparableTreeObject(newObject), contentProvider); // the element will be at the end of the destination // list, now call the moveUp and moveDown accordingly if (currentLocation > newElementLocation) { // move up insertElementAt(newElementLocation, difference, contentProvider, true); } if (currentLocation < newElementLocation) { // move down insertElementAt(newElementLocation, difference, contentProvider, false); } } else { newElementLocation = getPersistenceLocation(remoteParent, difference.getElement(), contentProvider, false); adjustPersistenceOrdering(newObject, newElementLocation); batchRelateAll(newObject, modelRoot, contentProvider); } handlePostCreation(newObject, (NonRootModelElement) realElement); return true; } private static void batchRelateAll(NonRootModelElement newObject, ModelRoot modelRoot, ITreeContentProvider provider) { newObject.batchRelate(modelRoot, false, false); Object[] children = provider.getChildren(newObject); for (Object element : children) { if (element instanceof NonRootModelElementComparable) { NonRootModelElementComparable comparable = (NonRootModelElementComparable) element; batchRelateAll((NonRootModelElement) comparable.getRealElement(), modelRoot, provider); } } } private static int getPersistenceLocation(Object parent, Object newObject, ITreeDifferencerProvider contentProvider, boolean returnLength) { newObject = ComparableProvider.getComparableTreeObject(newObject); int location = 0; Object[] children = contentProvider.getChildren(parent); for (Object child : children) { if (child.equals(newObject) && !returnLength) { break; } Object realChild = child; if (realChild instanceof ComparableTreeObject) { realChild = ((ComparableTreeObject) realChild).getRealElement(); } Object realNewObject = newObject; if (newObject instanceof ComparableTreeObject) { realNewObject = ((ComparableTreeObject) realNewObject).getRealElement(); } if (realChild.getClass() == realNewObject.getClass()) { location++; } } return location; } private static boolean adjustPersistenceOrdering(Object object, int newElementLocation) { Object lastSupertype = getLastSupertype((NonRootModelElement) object); // assure that the persisted location is correct IPersistableElementParentDetails parentDetails = PersistenceManager.getHierarchyMetaData() .getParentDetails((NonRootModelElement) lastSupertype); if (parentDetails.isMany()) { Object[] localDetails = new Object[] { parentDetails.getParent(), parentDetails.getChild(), parentDetails.getAssociationNumber(), parentDetails.getAssociationPhrase(), parentDetails.getChildKeyLetters() }; int localLocation = getLocationForElementInSource(localDetails); if (newElementLocation != localLocation) { callSetOrderOperation(newElementLocation, localDetails); return true; } } return false; } private static void handlePostCreation(NonRootModelElement newObject, NonRootModelElement originalObject) { // for events we must create can't happens for all pre-existing // states if (newObject instanceof StateMachineEvent_c) { final StateMachineEvent_c event = (StateMachineEvent_c) newObject; StateMachine_c machine = StateMachine_c.getOneSM_SMOnR502(event); StateMachineState_c[] states = StateMachineState_c.getManySM_STATEsOnR501(machine); for (StateMachineState_c state : states) { StateEventMatrixEntry_c entry = StateEventMatrixEntry_c.getOneSM_SEMEOnR503(state, new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((StateEventMatrixEntry_c) candidate).getSmevt_id() .equals(event.getSmevt_id()); } }); if (entry == null) { SemEvent_c sem = SemEvent_c.getOneSM_SEVTOnR525(event); createSEME(sem, state); } } } if (newObject instanceof StateMachineState_c) { final StateMachineState_c state = (StateMachineState_c) newObject; StateMachine_c machine = StateMachine_c.getOneSM_SMOnR501(state); StateMachineEvent_c[] events = StateMachineEvent_c.getManySM_EVTsOnR502(machine); for (StateMachineEvent_c event : events) { SemEvent_c sem = SemEvent_c.getOneSM_SEVTOnR525(event); StateEventMatrixEntry_c entry = StateEventMatrixEntry_c.getOneSM_SEMEOnR503(sem, new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((StateEventMatrixEntry_c) candidate).getSmstt_id() .equals(state.getSmstt_id()); } }); if (entry == null) { createSEME(sem, state); } } // also check all events assigned to transitions leaving this state // as they may have been created as part of this merge Transition_c[] outgoing = Transition_c.getManySM_TXNsOnR507(NewStateTransition_c .getManySM_NSTXNsOnR504(StateEventMatrixEntry_c.getManySM_SEMEsOnR503(state))); for (Transition_c transition : outgoing) { final StateMachineEvent_c evt = StateMachineEvent_c .getOneSM_EVTOnR525(SemEvent_c.getOneSM_SEVTOnR503(StateEventMatrixEntry_c .getOneSM_SEMEOnR504(NewStateTransition_c.getOneSM_NSTXNOnR507(transition)))); StateMachineState_c[] states = StateMachineState_c.getManySM_STATEsOnR501(machine); for (StateMachineState_c otherState : states) { StateEventMatrixEntry_c entry = StateEventMatrixEntry_c.getOneSM_SEMEOnR503(otherState, new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((StateEventMatrixEntry_c) candidate).getSmevt_id() .equals(evt.getSmevt_id()); } }); if (entry == null) { SemEvent_c sem = SemEvent_c.getOneSM_SEVTOnR525(evt); createSEME(sem, otherState); } } } } if (newObject instanceof Transition_c) { // here we need to create a new SEME entry // or convert an existing one Transition_c transition = (Transition_c) newObject; // only do so if we are dealing with a transition with // an assigned event NoEventTransition_c net = NoEventTransition_c.getOneSM_NETXNOnR507(transition); if (net != null) { return; } // this includes creation transitions as well even if an // event is assigned CreationTransition_c crt = CreationTransition_c.getOneSM_CRTXNOnR507(transition); if (crt != null) { return; } StateEventMatrixEntry_c seme = StateEventMatrixEntry_c .getOneSM_SEMEOnR504(NewStateTransition_c.getOneSM_NSTXNOnR507((Transition_c) newObject)); if (seme == null) { // look for the source state StateEventMatrixEntry_c originalSEM = StateEventMatrixEntry_c.getOneSM_SEMEOnR504( NewStateTransition_c.getOneSM_NSTXNOnR507((Transition_c) originalObject)); StateMachineState_c originalState = StateMachineState_c.getOneSM_STATEOnR503(originalSEM); SemEvent_c originalEvent = SemEvent_c.getOneSM_SEVTOnR503(originalSEM); SemEvent_c destEvent = (SemEvent_c) getMatchingElement(originalEvent); StateMachineState_c destState = (StateMachineState_c) getMatchingElement(originalState); StateEventMatrixEntry_c newEntry = new StateEventMatrixEntry_c(transition.getModelRoot()); destState.relateAcrossR503To(newEntry); destEvent.relateAcrossR503To(newEntry); newEntry.relateAcrossR504To(NewStateTransition_c.getOneSM_NSTXNOnR507(transition)); } else { // convert the existing SEM CantHappen_c ch = CantHappen_c.getOneSM_CHOnR504(seme); if (ch != null) { ch.Dispose(); } EventIgnored_c ei = EventIgnored_c.getOneSM_EIGNOnR504(seme); if (ei != null) { ei.unrelateAcrossR504From(seme); ei.delete(); } seme.relateAcrossR504To(NewStateTransition_c.getOneSM_NSTXNOnR507(transition)); } } } private static void createSEME(SemEvent_c sem, StateMachineState_c state) { StateEventMatrixEntry_c newEntry = new StateEventMatrixEntry_c(state.getModelRoot()); CantHappen_c ch = new CantHappen_c(state.getModelRoot()); ch.relateAcrossR504To(newEntry); newEntry.relateAcrossR503To(sem); newEntry.relateAcrossR503To(state); } private static NonRootModelElement importExternal(NonRootModelElement remoteObject, String export, NonRootModelElement parent, Ooaofooa modelRoot, int newElementLocation) { NonRootModelElement newObject = null; ModelStreamProcessor processor = new ModelStreamProcessor(); processor.setContents(export); processor.setDestinationElement(parent); ByteArrayInputStream in = new ByteArrayInputStream(export.getBytes()); try { CoreImport.createUniqueIds = false; IModelImport importer = CorePlugin.getStreamImportFactory().create(in, modelRoot, false, Path.EMPTY); processor.runImporter(importer, new NullProgressMonitor()); // locate the new object from the loaded instances NonRootModelElement[] loadedInstances = importer.getLoadedInstances(); if (parent.getModelRoot() instanceof Ooaofgraphics) { loadedInstances = importer.getLoadedGraphicalInstances(); } for (NonRootModelElement elem : loadedInstances) { if (!elem.isProxy()) { IPersistableElementParentDetails parentDetails = PersistenceManager.getHierarchyMetaData() .getParentDetails(elem); if (parentDetails == null) { // old data type that has a packageable element with // no package or component, these have PEs so that they // can be used in the chooser dialog if (elem.cachedIdentityEquals(remoteObject)) { newObject = elem; } continue; } if (parentDetails.isMany()) { Object[] localDetails = new Object[] { parentDetails.getParent(), parentDetails.getChild(), parentDetails.getAssociationNumber(), parentDetails.getAssociationPhrase(), parentDetails.getChildKeyLetters() }; if (newElementLocation == -1) { IPersistableElementParentDetails remoteParentDetails = PersistenceManager .getHierarchyMetaData().getParentDetails(getMatchingElement(elem)); Object[] remoteDetails = new Object[] { remoteParentDetails.getParent(), remoteParentDetails.getChild(), remoteParentDetails.getAssociationNumber(), remoteParentDetails.getAssociationPhrase(), remoteParentDetails.getChildKeyLetters() }; newElementLocation = getLocationForElementInSource(remoteDetails); } callSetOrderOperation(newElementLocation, localDetails); NonRootModelElement matchingElement = getMatchingElement(elem); if (matchingElement != null) { Method getLocationInOrdering = findMethod("Getlocationinordering", matchingElement.getClass(), new Class[0]); if (getLocationInOrdering != null) { // adjust user configurable order, to do this we unassociate the new // element from the ordering association first int order = (Integer) invokeMethod(getLocationInOrdering, getMatchingElement(elem), new Object[0]); Method mergeOrdering = findMethod("Mergeordering", elem.getClass(), new Class[] { Integer.TYPE }); if (mergeOrdering != null) { invokeMethod(mergeOrdering, elem, new Object[] { order }); } } } } if (elem.equals(remoteObject)) { newObject = elem; } else { if (elem.cachedIdentityEquals(remoteObject)) { newObject = elem; } } } } } catch (IOException e) { CorePlugin.logError("Unable to import external merge data.", e); } finally { CoreImport.createUniqueIds = true; } return newObject; } private static void handleCopyNew(NonRootModelElement newObject, TreeDifferencer differencer, ITreeDifferencerProvider contentProvider, Ooaofooa modelRoot, boolean rightToLeft) throws IOException { Object[] children = contentProvider.getChildren(newObject); for (Object child : children) { if (child instanceof ObjectElementComparable) { ObjectElement element = (ObjectElement) ((ObjectElementComparable) child).getRealElement(); if (element.getValue() instanceof NonRootModelElement) { NonRootModelElementComparable value = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject((NonRootModelElement) element.getValue()); List<TreeDifference> differences = differencer.getDifferences(value, !rightToLeft); if (!differences.isEmpty()) { TreeDifference difference = differences.get(0); if (difference.getMatchingDifference().getElement() == null) { // copy over handleNewElement(difference, contentProvider, difference.getElement(), modelRoot, differencer, rightToLeft); } } } } } // For SEME instances we may need to copy the SemEvent first if (newObject instanceof StateEventMatrixEntry_c) { SemEvent_c sem = SemEvent_c.getOneSM_SEVTOnR503((StateEventMatrixEntry_c) newObject); if (sem != null) { StateMachineEvent_c evt = StateMachineEvent_c.getOneSM_EVTOnR525(sem); NonRootModelElementComparable value = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject(evt); List<TreeDifference> differences = differencer.getDifferences(value, !rightToLeft); if (!differences.isEmpty()) { TreeDifference difference = differences.get(0); if (difference.getMatchingDifference().getElement() == null) { // copy over handleNewElement(difference, contentProvider, difference.getElement(), modelRoot, differencer, rightToLeft); } } } } } private static void recursivelyCopyChildren(Object[] children, ITreeDifferencerProvider contentProvider, Object diffElement, Ooaofooa modelRoot, TreeDifferencer differencer, boolean rightToLeft) throws IOException { for (Object child : children) { Object[] otherChildren = contentProvider.getChildren(diffElement); ComparableTreeObject matchingComparable = null; for (Object otherChild : otherChildren) { if (otherChild.equals(child)) { matchingComparable = (ComparableTreeObject) otherChild; break; } } if (child instanceof ObjectElementComparable) { ObjectElement localElement = (ObjectElement) ((ObjectElementComparable) child).getRealElement(); if (localElement.getType() == ObjectElement.REFERENTIAL_ATTRIBUTE_ELEMENT) { if (matchingComparable != null) { ObjectElement element = (ObjectElement) matchingComparable.getRealElement(); NonRootModelElementComparable localValue = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject((NonRootModelElement) localElement.getValue()); NonRootModelElementComparable value = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject((NonRootModelElement) element.getValue()); if (localValue == null && value == null) { continue; } NonRootModelElementComparable localComp = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject(localValue); NonRootModelElementComparable remoteComp = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject(value); if (localComp != null && localComp.equals(remoteComp)) { continue; } handleReferential(element, localElement, contentProvider, modelRoot, differencer, rightToLeft, null); } } } else { Object[] newChildren = contentProvider.getChildren(child); recursivelyCopyChildren(newChildren, contentProvider, matchingComparable, modelRoot, differencer, rightToLeft); } } } /** * Using the details generated in the corresponding inspector class we determine * the actual association between the container and the new element. The details * are as follows * * details[0] = the parent object * details[1] = the child object * details[2] = the association number * details[3] = an association phrase if present * details[4] = the key letters of the child class */ private static int getLocationForElementInSource(Object[] details) { int location = 0; String methodName = "getMany" + (String) details[4] + "sOnR" + (String) details[2] + (String) details[3]; Method method = findMethod(methodName, details[1].getClass(), new Class[] { details[0].getClass() }); if (method == null) { CorePlugin.logError("Could not locate method with name: " + methodName + " in " + details[0].getClass().getSimpleName(), null); } Object[] children = (Object[]) invokeMethod(method, details[1], new Object[] { details[0] }); if (children == null) return 0; for (int i = 0; i < children.length; i++) { // if we are dealing with PEs they have been moved such // that they are persisted in the same file as the subtype // we do not want to include such PEs if (!considerChild(children[i])) { continue; } if (children[i] == details[1]) { return location; } location++; } // return location putting it at the end, should not happen // though return location; } private static boolean considerChild(Object object) { if (object instanceof PackageableElement_c) { PackageableElement_c pe = (PackageableElement_c) object; if (pe.getType() == Elementtypeconstants_c.CLASS) { return false; } else if (pe.getType() == Elementtypeconstants_c.COMPONENT) { return false; } else if (pe.getType() == Elementtypeconstants_c.INTERFACE) { return false; } else if (pe.getType() == Elementtypeconstants_c.PACKAGE) { return false; } } return true; } private static Method findMethod(String methodName, Class<?> owner, Class<?>[] parameters) { try { Method method = owner.getMethod(methodName, parameters); return method; } catch (SecurityException e) { ComparePlugin.writeToLog("Unable to locate method.", e, owner); } catch (NoSuchMethodException e) { // do not log anything this is expected } return null; } private static Object invokeMethod(Method method, Object element, Object[] parameters) { if (method == null) { return null; } try { return method.invoke(element, parameters); } catch (IllegalArgumentException e) { ComparePlugin.writeToLog("Unable to execute method.", e, element.getClass()); } catch (IllegalAccessException e) { ComparePlugin.writeToLog("Unable to execute method.", e, element.getClass()); } catch (InvocationTargetException e) { ComparePlugin.writeToLog("Unable to execute method.", e, element.getClass()); } return null; } private static void disposeElement(Object element) { // this is a removal NonRootModelElementComparable localComparable = (NonRootModelElementComparable) element; NonRootModelElement realElement = (NonRootModelElement) localComparable.getRealElement(); // look for a special case merge disposal before // calling Dispose directly Method method = findMethod("Mergedispose", realElement.getClass(), new Class[0]); if (method != null) { invokeMethod(method, realElement, new Object[0]); return; } method = findMethod("Dispose", realElement.getClass(), new Class[0]); if (method != null) { invokeMethod(method, realElement, new Object[0]); return; } else { realElement.batchUnrelate(true); realElement.delete_unchecked(); BaseModelDelta delete = new BaseModelDelta(Modeleventnotification_c.DELTA_DELETE, realElement); if (realElement.getModelRoot() instanceof Ooaofooa) { Ooaofooa.getDefaultInstance().fireModelElementDeleted(delete); } else { Ooaofgraphics.getDefaultInstance().fireModelElementDeleted(delete); } } } /** * This method makes use of referentail details that are generated in the respective * inspector classes. The details are as follows: * * details[0] = the referred to object * details[1] = the referring object * details[2] = the association number * details[3] = association phrase if necessary * */ private static void handleReferential(ObjectElement element, ObjectElement localElement, ITreeDifferencerProvider contentProvider, Ooaofooa modelRoot, TreeDifferencer differencer, boolean rightToLeft, TreeDifference difference) throws IOException { IModelClassInspector insp = new ModelInspector(); if (((NonRootModelElement) element.getParent()).getModelRoot() instanceof Ooaofgraphics) { insp = new GraphicalModelInspector(); } Class<?> clazz = null; if (element.getValue() != null) { clazz = element.getValue().getClass(); } else { clazz = localElement.getValue().getClass(); } // allow pre-processing to prepare for merge if (element.getValue() != null) { String preprocessor = "Premerge" + element.getValue().getClass().getSimpleName().replaceAll("_c", "").toLowerCase() + element.getName().replaceAll("referential_", "").replaceAll("_", "").toLowerCase(); Method preprocessMethod = findMethod(preprocessor, localElement.getParent().getClass(), new Class[0]); if (preprocessMethod != null) { invokeMethod(preprocessMethod, localElement.getParent(), new Object[0]); } } Object[] remoteReferentialData = insp.getReferentialDetails(clazz, element.getParent()); Object[] localReferentialData = insp.getReferentialDetails(clazz, localElement.getParent()); // referred to local element and referring local element Object referredLocal = localReferentialData[0]; Object originalReferredLocal = referredLocal; Object referringLocal = localReferentialData[1]; // referred to remote element Object referredRemote = remoteReferentialData[0]; if (referredRemote != null && referringLocal != null) { // we need to make a copy here, unless it exists // in the target Object object = findObjectInDestination(modelRoot, (NonRootModelElement) referredRemote); if (((NonRootModelElement) referredRemote).isProxy()) { // this is a referential only difference, we need to copy the proxy // value over object = handleNewProxy((NonRootModelElement) referredRemote, modelRoot); // this batch relate may have handled hook up batchRelateSelfAndSupertypes((NonRootModelElement) referringLocal, modelRoot); localReferentialData = insp.getReferentialDetails(clazz, localElement.getParent()); if (localReferentialData[0] != null) { return; } } if (object == null) { NonRootModelElementComparable comparable = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject(getElement((NonRootModelElement) element.getValue())); List<TreeDifference> differences = differencer.getDifferences(comparable, !rightToLeft); TreeDifference newDifference = differences.get(0); handleNewElement(newDifference, contentProvider, comparable, modelRoot, differencer, rightToLeft); Object newObject = null; NonRootModelElementComparable parentComparable = (NonRootModelElementComparable) ComparableProvider .getComparableTreeObject((NonRootModelElement) localElement.getParent()); // locate the new ObjectElement ObjectElement newObjEle = null; Object[] newChildren = contentProvider.getChildren(parentComparable); for (Object child : newChildren) { if (child instanceof ObjectElementComparable) { ObjectElementComparable oec = (ObjectElementComparable) child; ObjectElement objEle = (ObjectElement) oec.getRealElement(); if (objEle.equals(element)) { newObjEle = objEle; break; } } } if (newObjEle == null) { newObjEle = localElement; } if (newObjEle != null) { if (handleSpecialCase(element, localElement, rightToLeft, differencer, modelRoot, contentProvider)) { return; } localElement = newObjEle; Object parent = contentProvider.getParent(localElement.getValue()); Object[] children = contentProvider.getChildren(parent); for (Object child : children) { if (child instanceof NonRootModelElementComparable) { NonRootModelElement childEle = (NonRootModelElement) ((NonRootModelElementComparable) child) .getRealElement(); if (childEle.cachedIdentityEquals(element.getValue())) { newObject = childEle; break; } } } if (newObject != null) { localReferentialData = insp.getReferentialDetails(clazz, localElement.getParent()); // referred to local element and referring local element originalReferredLocal = localReferentialData[0]; referringLocal = localReferentialData[1]; referredLocal = newObject; } } } else { if (handleSpecialCase(element, localElement, rightToLeft, differencer, modelRoot, contentProvider)) { return; } // if the element exists set it as the referred referredLocal = object; } } if (referredLocal == null && referredRemote == null) { // nothing to do here return; } // look for a special case operation to handle the referential // merge before attempting the generic approach // if the referential is null, then we will pass in an empty // UUID if (referringLocal != null) { handlePreSpecialCase(element, contentProvider, modelRoot, rightToLeft, differencer, localElement, difference); UUID newId = Gd_c.Null_unique_id(); if (referredRemote != null && referredLocal != null) { newId = ((NonRootModelElement) referredLocal).Get_ooa_id(); } Class<?> referredClass = null; if (referredRemote != null) { referredClass = referredRemote.getClass(); } else { referredClass = referredLocal.getClass(); } String methodName = "Merge" + referredClass.getSimpleName().replaceAll("_c", "").toLowerCase() + element.getName().replaceAll("referential_", "").replaceAll("_", "").toLowerCase(); Method method = findMethod(methodName, referringLocal.getClass(), new Class[] { UUID.class }); if (method != null) { Object result = invokeMethod(method, referringLocal, new Object[] { newId }); if (result != null && result instanceof Boolean) { if ((Boolean) result) { return; } } else { return; } } } // another merge action has already handled this if (referredLocal == originalReferredLocal && referredRemote != null) { return; } // if the referred local element is null do not bother // with an unrelate if (originalReferredLocal != null) { Method unrelateMethod = findMethod( "unrelateAcrossR" + (String) localReferentialData[2] + "From" + (String) localReferentialData[3], referringLocal.getClass(), new Class[] { originalReferredLocal.getClass() }); invokeMethod(unrelateMethod, referringLocal, new Object[] { originalReferredLocal }); } if (referredRemote == null) { // only need the unrelate return; } Method relateMethod = findMethod( "relateAcrossR" + (String) localReferentialData[2] + "To" + (String) localReferentialData[3], referringLocal.getClass(), new Class[] { referredLocal.getClass() }); invokeMethod(relateMethod, referringLocal, new Object[] { referredLocal }); } private static void handlePreSpecialCase(ObjectElement element, ITreeDifferencerProvider contentProvider, Ooaofooa modelRoot, boolean rightToLeft, TreeDifferencer differencer, ObjectElement localElement, TreeDifference originalDifference) { if (element.getName().equals("referential_To") && element.getParent() instanceof Transition_c && originalDifference != null) { // in this case we are treating two different transitions as a // conflict // the reason is that a state cannot have two transitions out of it // that // are assigned to the same event // To merge this we need to copy over the new transition ComparableTreeObject localOwner = ComparableProvider .getComparableTreeObject(contentProvider.getParent(localElement.getParent())); TreeDifference difference = new TreeDifference(element.getParent(), TreeDifference.LOCATION_DIFFERENCE, true, TreeDifferencer.RIGHT | TreeDifferencer.ADDITION, TreeDifferencer.getPathForElement( ComparableProvider.getComparableTreeObject(element.getParent()), contentProvider), false, null); // locate the new empty element's parent Object otherElement = originalDifference.getMatchingDifference().getElement(); // the parent is this element's parent's parent Object parent = contentProvider.getParent(contentProvider.getParent(otherElement)); parent = ((ComparableTreeObject) parent).getRealElement(); TreeDifference matchingDifference = new TreeDifference( new EmptyElement(element.getParent(), parent, TreeDifferencer.getLocationOfElement(contentProvider.getParent(element.getParent()), element.getParent(), contentProvider)), TreeDifference.LOCATION_DIFFERENCE, true, TreeDifferencer.RIGHT | TreeDifferencer.ADDITION, TreeDifferencer.getPathForElement(localOwner, contentProvider), false, null); matchingDifference.setParent(localOwner); difference.setMatchingDifference(matchingDifference); matchingDifference.setMatchingDifference(difference); try { handleNewElement(difference, contentProvider, ComparableProvider.getComparableTreeObject(element.getParent()), modelRoot, differencer, rightToLeft); if ((originalDifference.getKind() & Differencer.DIRECTION_MASK) != Differencer.CONFLICTING) { // for non-conflicting differences we need to get rid of the old // transition here disposeElement(ComparableProvider.getComparableTreeObject(localElement.getParent())); } else { // we need to migrate the old transition Transition_c transition = (Transition_c) localElement.getParent(); StateEventMatrixEntry_c seme = StateEventMatrixEntry_c .getOneSM_SEMEOnR504(NewStateTransition_c.getOneSM_NSTXNOnR507(transition)); SignalEvent_c sigEvt = SignalEvent_c.getOneSM_SGEVTOnR526(SemEvent_c.getOneSM_SEVTOnR503(seme)); if (sigEvt != null) { transition.Removesignal(); } else { transition.Removeevent(); } // need to remove the CH that was created CantHappen_c ch = CantHappen_c.getOneSM_CHOnR504(seme); ch.Dispose(); } } catch (IOException e) { CorePlugin.logError("Unable to merge new element.", e); } } } private static void batchRelateSelfAndSupertypes(NonRootModelElement element, ModelRoot modelRoot) { element.batchRelate(modelRoot, true, false); IPersistableElementParentDetails parentDetails = PersistenceManager.getHierarchyMetaData() .getParentDetails(element); NonRootModelElement parent = parentDetails.getParent(); if (parentDetails.getChild() instanceof PackageableElement_c) { parent = parentDetails.getChild(); } NonRootModelElement supertype = null; if (parent != null && SupertypeSubtypeUtil.isSupertypeOf(element, parent)) { supertype = parent; } while (supertype != null) { supertype.batchRelate(modelRoot, true, false); parentDetails = PersistenceManager.getHierarchyMetaData().getParentDetails(supertype); parent = parentDetails.getParent(); if (parent != null && SupertypeSubtypeUtil.isSupertypeOf(supertype, parent)) { supertype = parent; } else { supertype = null; } } } /** * Special case to handle certain elements that currently have no generic * way to address * * @param element * @param localElement * @return * @throws IOException */ private static boolean handleSpecialCase(ObjectElement element, ObjectElement localElement, boolean rightToLeft, TreeDifferencer differencer, Ooaofooa modelRoot, ITreeContentProvider contentProvider) throws IOException { if (localElement.getName().startsWith("referential_Assigned")) { //$NON-NLS-1$ Object value = element.getValue(); if (value != null && (value instanceof StateMachineEvent_c || value instanceof NonLocalEvent_c || value instanceof SignalEvent_c)) { final Object remoteTransition = element.getParent(); Object localTransition = localElement.getParent(); if (remoteTransition instanceof Transition_c) { final StateMachineEvent_c newEvent = StateMachineEvent_c.getOneSM_EVTOnR525( SemEvent_c.getOneSM_SEVTOnR503(StateEventMatrixEntry_c.getOneSM_SEMEOnR504( NewStateTransition_c.getOneSM_NSTXNOnR507((Transition_c) remoteTransition)))); // dispose the old transition and any SEME associated // with the event StateMachineState_c state = StateMachineState_c .getOneSM_STATEOnR503(StateEventMatrixEntry_c.getOneSM_SEMEOnR504( NewStateTransition_c.getOneSM_NSTXNOnR507((Transition_c) localTransition))); if (state == null) { state = StateMachineState_c.getOneSM_STATEOnR508( NoEventTransition_c.getOneSM_NETXNOnR507((Transition_c) localTransition)); } StateEventMatrixEntry_c[] semes = StateEventMatrixEntry_c.getManySM_SEMEsOnR503(state, new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((StateEventMatrixEntry_c) candidate).getSmevt_idCachedValue() .equals(newEvent.getSmevt_id()); } }); for (StateEventMatrixEntry_c entry : semes) { entry.Mergedispose(); } try { Ooaofooa.disableChangeNotification(); ((Transition_c) localTransition).Mergedispose(); } finally { Ooaofooa.enableChangeNotification(); } // the event will have already been copied over // now we must copy the transition over StateEventMatrixEntry_c seme = StateEventMatrixEntry_c.getOneSM_SEMEOnR504( NewStateTransition_c.getOneSM_NSTXNOnR507((Transition_c) remoteTransition)); String remoteSEMEData = copyExternal(modelRoot, seme, false, false); NonRootModelElement newSEME = importExternal(seme, remoteSEMEData, state, modelRoot, -1); newSEME.batchRelate(modelRoot, true, false); String remoteTransitionData = copyExternal(modelRoot, (Transition_c) remoteTransition, false, false); final NonRootModelElement newObject = importExternal((Transition_c) remoteTransition, remoteTransitionData, state, modelRoot, -1); // locate the GD_GE associated with the new transition // and update the path to the represented element GraphicalElement_c remoteGelem = GraphicalElement_c.GraphicalElementInstance( Ooaofgraphics.getInstance(seme.getModelRoot().getId()), new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((GraphicalElement_c) candidate).getOoa_id() .equals(((Transition_c) remoteTransition).getTrans_id()); } }); GraphicalElement_c gelem = GraphicalElement_c.GraphicalElementInstance( Ooaofgraphics.getInstance(modelRoot.getId()), new ClassQueryInterface_c() { @Override public boolean evaluate(Object candidate) { return ((GraphicalElement_c) candidate).getOoa_id() .equals(((Transition_c) newObject).getTrans_id()); } }); gelem.Setcachedrepresentspath(remoteGelem.Getcachedrepresentspath()); newObject.batchRelate(modelRoot, true, false); return true; } } } return false; } private static Object findObjectInDestination(ModelRoot modelRoot, NonRootModelElement remoteElement) { Object object = modelRoot.getInstanceList(remoteElement.getClass()).get(remoteElement.getInstanceKey()); if (object == null) { // see if its a global element object = Ooaofooa.getDefaultInstance().getInstanceList(remoteElement.getClass()) .get(((NonRootModelElement) remoteElement).getInstanceKey()); } if (object == null) { // consider graphical element object = Ooaofgraphics.getInstance(modelRoot.getId()).getInstanceList(remoteElement.getClass()) .get(remoteElement.getInstanceKey()); } if (remoteElement instanceof StateEventMatrixEntry_c && object != null) { // only consider this as existing if the subtypes are the same StateEventMatrixEntry_c remoteSeme = (StateEventMatrixEntry_c) remoteElement; StateEventMatrixEntry_c localSeme = (StateEventMatrixEntry_c) object; List<NonRootModelElement> remoteSubtypes = SupertypeSubtypeUtil.getSubtypes(remoteSeme); List<NonRootModelElement> localSubtypes = SupertypeSubtypeUtil.getSubtypes(localSeme); if (localSubtypes.isEmpty() || !remoteSubtypes.get(0).getClass().isInstance(localSubtypes.get(0))) { object = null; } } return object; } private static Object handleNewProxy(NonRootModelElement referredRemote, ModelRoot modelRoot) { Object newObject = null; String export = copyExternal(null, referredRemote, true, true); // now paste the external data ModelStreamProcessor processor = new ModelStreamProcessor(); processor.setContents(export); ByteArrayInputStream in = new ByteArrayInputStream(export.getBytes()); try { CoreImport.createUniqueIds = false; IModelImport importer = CorePlugin.getStreamImportFactory().create(in, Ooaofooa.getInstance(modelRoot.getId()), false, Path.EMPTY); processor.runImporter(importer, new NullProgressMonitor()); // locate the new object from the loaded instances NonRootModelElement[] loadedInstances = importer.getLoadedInstances(); if (modelRoot instanceof Ooaofgraphics) { loadedInstances = importer.getLoadedGraphicalInstances(); } for (NonRootModelElement elem : loadedInstances) { if (elem.cachedIdentityEquals(referredRemote)) { newObject = elem; break; } } } catch (IOException e) { CorePlugin.logError("Unable to import copy", e); } finally { CoreImport.createUniqueIds = true; } return newObject; } private static NonRootModelElement getMatchingElement(NonRootModelElement elem) { ModelRoot otherRoot = elem.getModelRoot(); if (elem.getModelRoot().getId().startsWith(Ooaofooa.leftCompareRootId)) { if (otherRoot instanceof Ooaofooa) { otherRoot = Ooaofooa.getInstance(elem.getModelRoot().getId().replaceAll(Ooaofooa.leftCompareRootId, Ooaofooa.rightCompareRootId)); } else { otherRoot = Ooaofgraphics.getInstance(elem.getModelRoot().getId() .replaceAll(Ooaofooa.leftCompareRootId, Ooaofooa.rightCompareRootId)); } } else { if (otherRoot instanceof Ooaofooa) { otherRoot = Ooaofooa.getInstance(elem.getModelRoot().getId().replaceAll(Ooaofooa.rightCompareRootId, Ooaofooa.leftCompareRootId)); } else { otherRoot = Ooaofgraphics.getInstance(elem.getModelRoot().getId() .replaceAll(Ooaofooa.rightCompareRootId, Ooaofooa.leftCompareRootId)); } } InstanceList instanceList = otherRoot.getInstanceList(elem.getClass()); for (Object instance : instanceList) { NonRootModelElement other = (NonRootModelElement) instance; if (other.equals(elem)) { return other; } if (other.cachedIdentityEquals(elem)) { return other; } } return null; } private static NonRootModelElement getElement(NonRootModelElement value) { if (value instanceof DataType_c) { return SupertypeSubtypeUtil.getSubtypes(value).get(0); } return value; } private static TreeDifference getDifferenceForNameChange(ITreeContentProvider contentProvider, Object diffElement, String text, boolean rightToLeft, TreeDifferencer differencer) { Object[] children = contentProvider.getChildren(diffElement); for (int i = 0; i < children.length; i++) { if (children[i] instanceof ObjectElementComparable) { ObjectElement objEle = (ObjectElement) ((ObjectElementComparable) children[i]).getRealElement(); if (objEle.getValue().equals(text)) { List<TreeDifference> differences = differencer.getDifferences(children[i], !rightToLeft); if (differences.size() != 0) { return differences.get(0); } } } else { TreeDifference diff = getDifferenceForNameChange(contentProvider, children[i], text, rightToLeft, differencer); if (diff != null) { return diff; } } } return null; } /** * This method moves the copied element into the appropriate association * location, allowing a complete match with the source it was copied from. * * It makes use of details generated in the corresponding inspector class for * the new element. * * See {@code ModelMergeProcessor#getLocationForElementInSource(Object[])} for * more details. */ private static void callSetOrderOperation(int position, Object[] details) { String className = details[1].getClass().getSimpleName().replaceAll("_c", ""); if (className.equals("FunctionInPackage")) { className = "FunctioninPackage"; } String methodName = "set" + className + "OrderInChildListR" + details[2]; Method method = findMethod(methodName, details[0].getClass(), new Class[] { details[1].getClass(), Integer.TYPE }); if (method != null) { invokeMethod(method, details[0], new Object[] { details[1], position }); } // do not log an error as not all // elements support reordering (reflexives and // linked associations) } private static NonRootModelElement getLastSupertype(NonRootModelElement element) { IPersistableElementParentDetails parentDetails = PersistenceManager.getHierarchyMetaData() .getParentDetails(element); NonRootModelElement parent = parentDetails.getParent(); // special case for PE_PE, its considered a child of its subtype for // persistence reasons if (parentDetails.getChild() instanceof PackageableElement_c) { parent = parentDetails.getChild(); } NonRootModelElement supertype = null; NonRootModelElement lastSupertype = null; if (parent != null && SupertypeSubtypeUtil.isSupertypeOf((NonRootModelElement) element, parent)) { lastSupertype = parent; supertype = parent; } while (supertype != null) { parentDetails = PersistenceManager.getHierarchyMetaData().getParentDetails(supertype); parent = parentDetails.getParent(); // special case for PE_PE, its considered a child of its subtype for // persistence reasons if (parentDetails.getChild() instanceof PackageableElement_c) { parent = parentDetails.getChild(); } if (parent != null && SupertypeSubtypeUtil.isSupertypeOf(supertype, parent)) { supertype = parent; lastSupertype = parent; } else { supertype = null; } } if (lastSupertype != null) { element = lastSupertype; } return element; } private static String copyExternal(ModelRoot modelRoot, Object element, boolean writeAsProxy, boolean forceProxies) { if (element instanceof NonRootModelElement) { // there is a strange special case situation // for Supertype/Subtype associations, it exists // because during a copy with the supertype included // the Association must be included, which in turn // includes the subtype parts even if not selected for // a copy Therefore we must add the O_OBJ to the selection // to get around this limitation here if the element is // the subtype object ModelClass_c[] clazzes = null; if (element instanceof Association_c) { ClassAsSubtype_c[] subtypes = ClassAsSubtype_c.getManyR_SUBsOnR213( SubtypeSupertypeAssociation_c.getOneR_SUBSUPOnR206((Association_c) element)); if (subtypes != null && subtypes.length != 0) { clazzes = ModelClass_c.getManyO_OBJsOnR201(ClassInAssociation_c .getManyR_OIRsOnR203(ReferringClassInAssoc_c.getManyR_RGOsOnR205(subtypes))); for (ModelClass_c clazz : clazzes) { Selection.getInstance().addToSelection(clazz); } } } else if (element instanceof ClassAsSubtype_c) { ModelClass_c clazz = ModelClass_c.getOneO_OBJOnR201(ClassInAssociation_c .getOneR_OIROnR203(ReferringClassInAssoc_c.getOneR_RGOOnR205((ClassAsSubtype_c) element))); Selection.getInstance().addToSelection(clazz); clazzes = new ModelClass_c[] { clazz }; } NonRootModelElement[] elements = new NonRootModelElement[] { (NonRootModelElement) element }; if (!writeAsProxy) { NonRootModelElement[] specialElements = includeSpecialElements(element, modelRoot); // the stream export logic writes the supertype for // an element if that element is the one selected // we actually need to export (not just write the sql statement) // the supertype, so if this element has a supertype use it instead // however, only do this if the supertype does not already exist NonRootModelElement supertype = getLastSupertype((NonRootModelElement) element); Object existingObject = findObjectInDestination(modelRoot, supertype); if (existingObject == null) { // include the supertype element = supertype; } NonRootModelElement[] originalElements = new NonRootModelElement[] { (NonRootModelElement) element }; elements = new NonRootModelElement[originalElements.length + specialElements.length]; System.arraycopy(originalElements, 0, elements, 0, originalElements.length); if (specialElements.length != 0) { System.arraycopy(specialElements, 0, elements, originalElements.length, specialElements.length); } } CoreExport.ignoreAlternateChildren = true; CoreExport.exportSupertypes = false; CoreExport.ignoreMissingPMCErrors = true; if (writeAsProxy) { CoreExport.forceWriteAsProxy = true; } try { ByteArrayOutputStream out = new ByteArrayOutputStream(); String streamContents = ""; ; IRunnableWithProgress progress = CorePlugin.getStreamExportFactory().create(out, elements, true, false, true); progress.run(new NullProgressMonitor()); out.close(); streamContents = new String(out.toByteArray()); return streamContents; } catch (InvocationTargetException e) { ComparePlugin.writeToLog("Unable to copy external data.", e, CorePlugin.class); } catch (InterruptedException e) { ComparePlugin.writeToLog("Unable to copy external data.", e, CorePlugin.class); } catch (IOException e) { ComparePlugin.writeToLog("Unable to copy external data.", e, CorePlugin.class); } finally { // if the clazz is not null then remove from the // selection if (clazzes != null && clazzes.length != 0) { for (ModelClass_c clazz : clazzes) { Selection.getInstance().removeFromSelection(clazz); } } CoreExport.ignoreAlternateChildren = false; CoreExport.exportSupertypes = true; CoreExport.ignoreMissingPMCErrors = false; if (writeAsProxy) { CoreExport.forceWriteAsProxy = false; } } } return ""; } private static NonRootModelElement[] includeSpecialElements(Object element, ModelRoot destinationRoot) { List<NonRootModelElement> specialElements = new ArrayList<NonRootModelElement>(); if (element instanceof ClassAsSimpleParticipant_c) { // must include the Simple Association instance SimpleAssociation_c simp = SimpleAssociation_c.getOneR_SIMPOnR207((ClassAsSimpleParticipant_c) element); if (simp != null) { return new NonRootModelElement[] { simp }; } } if (element instanceof ClassAsAssociatedOneSide_c) { // must include the Linked Association instance LinkedAssociation_c link = LinkedAssociation_c .getOneR_ASSOCOnR209((ClassAsAssociatedOneSide_c) element); if (link != null) { return new NonRootModelElement[] { link }; } } // for states we need to also include all transitions out of the state if (element instanceof StateMachineState_c) { Transition_c[] transitions = Transition_c .getManySM_TXNsOnR507(NewStateTransition_c.getManySM_NSTXNsOnR504( StateEventMatrixEntry_c.getManySM_SEMEsOnR503((StateMachineState_c) element))); Transition_c[] noEvents = Transition_c.getManySM_TXNsOnR507( NoEventTransition_c.getManySM_NETXNsOnR508((StateMachineState_c) element)); for (int i = 0; i < transitions.length; i++) { Transition_c transition = transitions[i]; StateMachineEvent_c event = StateMachineEvent_c .getOneSM_EVTOnR525(SemEvent_c.getOneSM_SEVTOnR503(StateEventMatrixEntry_c .getOneSM_SEMEOnR504(NewStateTransition_c.getOneSM_NSTXNOnR507(transition)))); if (findObjectInDestination(destinationRoot, event) == null) { // we need to include the event as well specialElements.add(event); } specialElements.add(transition); } for (int i = 0; i < noEvents.length; i++) { specialElements.add(noEvents[i]); } } return specialElements.toArray(new NonRootModelElement[specialElements.size()]); } }