0001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
0002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
0003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
0004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
0005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
0006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
0012: // POSSIBILITY OF SUCH DAMAGE.
0013: //
0014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
0015: package com.metaboss.sdlctools.models.impl;
0016:
0017: import java.io.File;
0018: import java.io.FileFilter;
0019: import java.io.FileInputStream;
0020: import java.io.FileOutputStream;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.OutputStream;
0024: import java.net.URL;
0025: import java.util.ArrayList;
0026: import java.util.Collection;
0027: import java.util.Collections;
0028: import java.util.Comparator;
0029: import java.util.HashMap;
0030: import java.util.HashSet;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.Properties;
0035: import java.util.Set;
0036: import java.util.SortedMap;
0037: import java.util.SortedSet;
0038: import java.util.TreeMap;
0039: import java.util.TreeSet;
0040:
0041: import javax.jmi.model.AggregationKindEnum;
0042: import javax.jmi.model.AssociationEnd;
0043: import javax.jmi.model.ModelPackage;
0044: import javax.jmi.model.MofClass;
0045: import javax.jmi.model.MofPackage;
0046: import javax.jmi.reflect.JmiException;
0047: import javax.jmi.reflect.RefAssociation;
0048: import javax.jmi.reflect.RefBaseObject;
0049: import javax.jmi.reflect.RefClass;
0050: import javax.jmi.reflect.RefObject;
0051: import javax.jmi.reflect.RefPackage;
0052: import javax.jmi.xmi.MalformedXMIException;
0053: import javax.naming.Context;
0054: import javax.naming.InitialContext;
0055: import javax.naming.NamingException;
0056:
0057: import org.apache.commons.logging.Log;
0058: import org.apache.commons.logging.LogFactory;
0059: import org.netbeans.api.mdr.CreationFailedException;
0060: import org.netbeans.api.mdr.MDRManager;
0061: import org.netbeans.api.mdr.MDRepository;
0062: import org.netbeans.api.xmi.XMIReader;
0063: import org.netbeans.api.xmi.XMIReaderFactory;
0064: import org.netbeans.api.xmi.XMIReferenceProvider;
0065: import org.netbeans.api.xmi.XMIWriter;
0066: import org.netbeans.api.xmi.XMIWriterFactory;
0067:
0068: import com.metaboss.sdlctools.models.MetaModelNotLoadedException;
0069: import com.metaboss.sdlctools.models.ModelAssistant;
0070: import com.metaboss.sdlctools.models.ModelElementResolver;
0071: import com.metaboss.sdlctools.models.ModelListener;
0072: import com.metaboss.sdlctools.models.ModelNotLoadedException;
0073: import com.metaboss.sdlctools.models.ModelRepository;
0074: import com.metaboss.sdlctools.models.ModelRepositoryException;
0075: import com.metaboss.sdlctools.models.ModelRepositoryIllegalArgumentException;
0076: import com.metaboss.sdlctools.models.ModelRepositoryUtils;
0077: import com.metaboss.sdlctools.models.ModelValidationException;
0078: import com.metaboss.sdlctools.models.NoDefaultModelException;
0079: import com.metaboss.sdlctools.models.OperationAttemptedInTransactionException;
0080: import com.metaboss.sdlctools.models.OperationAttemptedOutsideTransactionException;
0081: import com.metaboss.sdlctools.models.TransientModelCanNotBeSavedException;
0082: import com.metaboss.sdlctools.models.xpathsearch.MOFXPath;
0083: import com.metaboss.util.ByteUtils;
0084: import com.metaboss.util.CollectionUtils;
0085: import com.metaboss.util.DirectoryUtils;
0086: import com.metaboss.util.FileUtils;
0087: import com.metaboss.util.PropertiesUtils;
0088: import com.metaboss.util.StringUtils;
0089:
0090: /** Implementation of the ModelRepository based on customised <a href="http://mdr.netbeans.org">NetBeans MetaDataRepository</a> mechanism. */
0091: public class ModelRepositoryImpl implements ModelRepository {
0092: private static final Log sLogger = LogFactory
0093: .getLog(ModelRepositoryImpl.class);
0094: private static boolean sClassInitialised = false;
0095: private static Object sClassInitialisationSemaphore = new Object();
0096: private static Object sRepositorySemaphore = new Object();
0097: private static ModelRepositoryImpl sRepository = null;
0098: // Utility comparator, which is used to sort properties in order of indexing
0099: // deals withthe fact that 10.xxxxx comes after 9.xxxxx
0100: private static Comparator sAssistantPropertiesComparator = new Comparator() {
0101: public int compare(Object o1, Object o2) {
0102: int lDotIndex1 = ((String) o1).indexOf(".");
0103: Integer lWeight1 = new Integer(
0104: lDotIndex1 > 0 ? ((String) o1).substring(0,
0105: lDotIndex1) : ((String) o1));
0106: int lDotIndex2 = ((String) o2).indexOf(".");
0107: Integer lWeight2 = new Integer(
0108: lDotIndex2 > 0 ? ((String) o2).substring(0,
0109: lDotIndex2) : ((String) o2));
0110: return lWeight1.compareTo(lWeight2);
0111: }
0112: };
0113: private static final String sAssistantPropertiesPrefix = "com.metaboss.sdlctools.models.ModelAssistant.";
0114: private static Map sAssistantProperties = new TreeMap(
0115: sAssistantPropertiesComparator); // Sorted map of assistant expressions
0116: private MDRepository mRepository = null; // null here indicates that this Repository is closed
0117: private RepositoryTransactionListenerImpl mInternalTransactionListener;
0118:
0119: class MetaModelDescriptor {
0120: public String MetaModelName;
0121: public String MetaModelExtentName;
0122: public ModelPackage MetaModelExtent;
0123: public MofPackage ModelExtentMetaObject; // The meta definition of the root package of the models based on this metamodel
0124: public Properties DefaultModelStorageProperties;
0125: public List RegisteredModelAssistants = new ArrayList(); // Registered assistants in the order of registration
0126: public Map ModelsByName = new HashMap(); // All model instances belonging to this meta model indexed by name
0127: }
0128:
0129: private Map mMetaModelsByName = new HashMap(); // Key - meta model name, Value - MetaModelDescriptor
0130:
0131: class ModelDescriptor {
0132: public MetaModelDescriptor MetaModelDescriptor;
0133: public String ModelName;
0134: public ModelInitialisationType InitialisationType;
0135: public File ModelRootFile;
0136: public File ModelRootDirectory;
0137: public File ModelStoragePropertiesFile;
0138: public Properties ModelStorageProperties;
0139: public String ModelRootURI;
0140: public String ModelExtentName;
0141: public RefPackage ModelExtent;
0142: public ModelChangesListenerImpl mInternalChangeListener;
0143: public File UnsavedAttachedFilesDir; // Files committed, but not yet saved
0144: public File UncomittedAttachedFilesDir; // Files not yet even committed in the transaction
0145: // This flag provides a 'hint' to the transaction commit process.
0146: // It saves time because the transaction commit/rollback logic does not have to perfrorm disk i/o
0147: // just to find out that there is nothing in the uncommitted attachments directory
0148: public boolean MayHaveUncomittedChangesToAttachments = false;
0149: // Map of URIs --> MetaPartitionDescriptor with TreeSet of XmiIds stored in there
0150: // This Map gets built when partitions are read (or remains empty for the new model)
0151: // Each saveModel() operation updates this map from the changes registered with the change listener
0152: public SortedMap PartitionsMap = null;
0153: // Map of XmiIds --> Relative path to the object attachment file
0154: // This Map gets built when partitions are read (or remains empty for the new model)
0155: // Each saveModel() operation updates this map from the changes registered with the change listener
0156: public SortedMap ObjectAttachmentsMap = null;
0157: // Set of modified objects XmiIds
0158: // This gets built when model is edited. Every object, when changed gets an entry in here.
0159: // This map gets emptied after save operation has completed.
0160: public Set ModifiedObjectsSet = new HashSet();
0161: // Set of created objects XmiIds
0162: // This gets built when model is edited. Every object, when created gets an entry in here.
0163: // This map gets emptied after save operation has completed.
0164: public Set CreatedObjectsSet = new HashSet();
0165: // Set of deleted objects XmiIds
0166: // This gets built when model is edited. Every object, when eleted gets an entry in here.
0167: // This map gets emptied after save operation has completed.
0168: public Set DeletedObjectsSet = new HashSet();
0169: // Xmi id only has to be unique within model, so each model gets its own generator
0170: public XmiIdGenerator XmiIdGenerator = new XmiIdGeneratorImpl();
0171: // List of model assistants in order of execution
0172: public List AssistantsList = new ArrayList();
0173: // Registered model listeners in no particular order
0174: public Set ListenersSet = new HashSet();
0175: }
0176:
0177: private ModelDescriptor mDefaultModelDescriptor = null;
0178: private Map mModelsByName = new HashMap(); // Key - model name, Value - ModelDescriptor
0179: private Map mModelsByOutermostPackageMofId = new HashMap(); // Key - Mof Id of the Outermost package, Value - ModelDescriptor
0180:
0181: // This class holds the description of the partition
0182: static class ModelPartitionDescriptor {
0183: // The record of all references from all objects stored in this partition
0184: // In format XMIId of object in this partition -> HRef of object on the other side
0185: public SortedSet ReferenceDescriptors = new TreeSet();
0186: // The system id of this partition
0187: public String SystemId = null;
0188: // The set of XmiIds stored in this partition
0189: public SortedSet ContentsXmiIds = new TreeSet();
0190: }
0191:
0192: // This class holds the description of the attachment
0193: static class ModelAttachmentUpdateDescriptor {
0194: // The path to the unsaved copy of the attachment - if there is one
0195: public String UnsavedCopyPath = null;
0196: // The path where attachment is expected to end up after update
0197: public String SavedCopyPath = null;
0198: }
0199:
0200: // This class contains the plan of how to update model file system in order to
0201: // bring it in synch to what is stored in memory
0202: class ModelUpdatePlan {
0203: XMIReferenceProvider UpdateXMIReferenceProvider = null;
0204: SortedMap NewPartitionsMap = null;
0205: SortedMap NewObjectAttachmentsMap = null;
0206: Set PartitionsToDelete = new HashSet();// URIs of partitions to delete
0207: Set PartitionsToCreate = new HashSet();// URIs of partitions to create
0208: Set PartitionsToUpdate = new HashSet(); // URI sof partitions to update
0209: Set AttachmentsToDelete = new HashSet(); // Absolute pathes of attachment files to be deleted
0210: Map AttachmentsToMove = new HashMap(); // Keys - Absolute pathes of the new location of attachment files. Values - Absolute pathes to the old location of the Atachment files
0211: boolean UpdateStorageProperties = true;
0212: }
0213:
0214: // This class contains the plan of how to export model to the pristine location
0215: class ModelExportPlan {
0216: public XMIReferenceProvider ExportXMIReferenceProvider = null;
0217: public String TargetRootDirectoryAbsolutePath = null;
0218: public File ModelStoragePropertiesFile;
0219: public Set PartitionsToCreate = new HashSet();// URIs of partitions to create
0220: public Map AttachmentsToCopy = new HashMap(); // Keys - Absolute pathes of the target location of attachment files. Values - Absolute pathes to the existing location of the Atachment files
0221: }
0222:
0223: private boolean mTransactionInProgress = false;
0224:
0225: // Pseudo class initialiser. Main feature that we can throw exception from here (unable to do that from native java class initialiser)
0226: private static void initialiseClassIfNecessary()
0227: throws ModelRepositoryException {
0228: if (!sClassInitialised) {
0229: synchronized (sClassInitialisationSemaphore) {
0230: if (!sClassInitialised) {
0231: // Configure MDR to use fast in-memory storage implementation
0232: System
0233: .setProperty(
0234: "org.netbeans.mdr.storagemodel.StorageFactoryClassName",
0235: org.netbeans.mdr.persistence.memoryimpl.StorageFactoryImpl.class
0236: .getName());
0237: try {
0238: File lTempFile = File.createTempFile("Mdr",
0239: ".log");
0240: // Set the logging so output does not go to standard out
0241: System.setProperty(
0242: "org.netbeans.lib.jmi.Logger.fileName",
0243: lTempFile.getAbsolutePath());
0244: sLogger
0245: .debug("Initialising repository to save MDR logs in the "
0246: + lTempFile.getAbsolutePath());
0247:
0248: // Read and store assistant configuration properties
0249: // Resulting map will have truncated keys in form num.[optional filter]
0250: sAssistantProperties.putAll(PropertiesUtils
0251: .filterProperties(System
0252: .getProperties(),
0253: sAssistantPropertiesPrefix,
0254: true));
0255: } catch (IOException e) {
0256: throw new ModelRepositoryException(
0257: "Unable to create temporary file for MDR logs.",
0258: e);
0259: }
0260: sClassInitialised = true;
0261: }
0262: }
0263: }
0264: }
0265:
0266: // Restrict access to constructor
0267: private ModelRepositoryImpl() throws ModelRepositoryException {
0268: initialiseClassIfNecessary();
0269: if (sRepository != null)
0270: throw new ModelRepositoryException(
0271: "Attempt to create another Repository. At the moment only one repository is supported. Please close current repository before creating a new one.");
0272: mRepository = MDRManager.getDefault().getDefaultRepository();
0273: mRepository
0274: .addListener(mInternalTransactionListener = new RepositoryTransactionListenerImpl(
0275: this ));
0276: mInternalTransactionListener.startListening();
0277:
0278: }
0279:
0280: // // Restrict access to constructor
0281: // private ModelRepositoryImpl(URL pMetaMetaModelURL) throws Exception
0282: // {
0283: // // Can only have one repository at most
0284: // synchronized(sRepositorySemaphore)
0285: // {
0286: // if (sRepository != null)
0287: // throw new ModelRepositoryException("Attempt to create another Repository. At the moment only one repository is supported. Please close current repository before creating a new one.");
0288: // mRepository = MDRManager.getDefault().getDefaultRepository();
0289: // loadMetaModel("MetaBossModel", pMetaMetaModelURL, META_PACKAGE, null);
0290: // mModel = mRepository.getExtent(MODEL_PACKAGE);
0291: // if (mModel != null)
0292: // {
0293: // sLogger.debug("Found previously loaded model. Will remove it");
0294: // mModel.refDelete();
0295: // sLogger.debug("Removed previously loaded model");
0296: // }
0297: // mModel = mRepository.createExtent(MODEL_PACKAGE, getMetaModelRootPackage("MetaBossModel"));
0298: // sLogger.debug("Successfully created the model");
0299: // // Create temporary directory where attached files will be maintained until saved in the premanent area
0300: // mUnsavedAttachedFilesDir = DirectoryUtils.createTempDir("MetaBossModel","UnsavedAttachedFiles");
0301: // sLogger.debug("Will use " + mUnsavedAttachedFilesDir.getAbsolutePath() + " directory for the unsaved attachments storage");
0302: // mUnsavedAttachedFilesDir.deleteOnExit();
0303: // // Create temporary directory where attached files will be maintained until transaction is committed
0304: // mUncomittedAttachedFilesDir = DirectoryUtils.createTempDir("MetaBossModel","UncomittedAttachedFiles");
0305: // sLogger.debug("Will use " + mUncomittedAttachedFilesDir.getAbsolutePath() + " directory for the uncommitted attachments storage");
0306: // mUncomittedAttachedFilesDir.deleteOnExit();
0307: // sRepository = this;
0308: // }
0309: // }
0310:
0311: /** Loads meta model from the specified URL to the model repository. After loading
0312: * meta model becomes available and models (i.e. instances of this metamodel) can be loaded.
0313: * @param pMetaModelName the unique name caller wishes to refer to this metamodel in the future. Must be unique name not used before in this repository session.
0314: * @param pMetaModelFile the File where MOF definition of the MetaModel can be loaded from. Must refer to the xmi file containing MOF model (i.e. definition of this metamodel).
0315: * @param pDefaultModelStorageProperties model storage properties to use as default in case model specific properties are not supplied when model is loaded
0316: * @return the package for newly loaded metamodel
0317: * @exception ModelRepositoryException thrown if there was a problem with the loading of the metamodel */
0318: public void loadMetaModel(String pMetaModelName,
0319: File pMetaModelFile,
0320: String pModelRootPackageMetaObjectName,
0321: Properties pDefaultModelStorageProperties)
0322: throws ModelRepositoryException {
0323: try {
0324: FileInputStream lInputStream = null;
0325: try {
0326: lInputStream = new FileInputStream(pMetaModelFile);
0327: loadMetaModel(pMetaModelName, lInputStream,
0328: pMetaModelFile.toURI().toString(),
0329: pModelRootPackageMetaObjectName,
0330: pDefaultModelStorageProperties);
0331: } finally {
0332: if (lInputStream != null)
0333: lInputStream.close();
0334: }
0335: } catch (IOException e) {
0336: throw new ModelRepositoryException("Error while reading '"
0337: + pMetaModelName + "' MetaModel definition from "
0338: + pMetaModelFile.getAbsolutePath(), e);
0339: }
0340: }
0341:
0342: /** Loads meta model from the specified URL to the model repository. After loading
0343: * meta model becomes available and models (i.e. instances of this metamodel) can be loaded.
0344: * @param pMetaModelName the unique name caller wishes to refer to this metamodel in the future. Must be unique name not used before in this repository session.
0345: * @param pMetaModelInputStream the input stream where MOF definition of the MetaModel can be loaded from. Must refer to the xmi file containing MOF model (i.e. definition of this metamodel).
0346: * @param pMetaModelURIString
0347: * @param pDefaultModelStorageProperties model storage properties to use as default in case model specific properties are not supplied when model is loaded. null passed here
0348: * indicates that there is no default properties. This primarily indicates that model storage will not be partitioned by default.
0349: * @return the package for newly loaded metamodel
0350: * @exception ModelRepositoryException thrown if there was a problem with the loading of the metamodel */
0351: public void loadMetaModel(String pMetaModelName,
0352: InputStream pMetaModelInputStream,
0353: String pMetaModelURIString,
0354: String pModelRootPackageMetaObjectName,
0355: Properties pDefaultModelStorageProperties)
0356: throws ModelRepositoryException {
0357: synchronized (sRepositorySemaphore) {
0358: if (isClosed())
0359: throw new ModelRepositoryException(
0360: "Repository is closed and can not be used.");
0361: if (isInTransaction())
0362: throw new OperationAttemptedInTransactionException(
0363: "loadMetaModel");
0364: if (mMetaModelsByName.containsKey(pMetaModelName))
0365: throw new ModelRepositoryException(
0366: "MetaModel "
0367: + pMetaModelName
0368: + " is already loaded. It needs to be removed before reloading.");
0369: try {
0370:
0371: sLogger.debug("Loading '" + pMetaModelName
0372: + "' MetaModel defined in "
0373: + pMetaModelURIString);
0374: MetaModelDescriptor lMetaModelDescriptor = new MetaModelDescriptor();
0375: lMetaModelDescriptor.MetaModelName = pMetaModelName;
0376: lMetaModelDescriptor.MetaModelExtentName = "metamodel:/"
0377: + pMetaModelName;
0378: lMetaModelDescriptor.MetaModelExtent = (ModelPackage) mRepository
0379: .createExtent(lMetaModelDescriptor.MetaModelExtentName);
0380: lMetaModelDescriptor.DefaultModelStorageProperties = pDefaultModelStorageProperties != null ? pDefaultModelStorageProperties
0381: : new Properties();
0382:
0383: // Read the metamodel
0384: // Use internal repository transaction directly
0385: boolean lTransactionNeedsRollback = true;
0386: mRepository.beginTrans(true);
0387: try {
0388: XMIReader xmiReader = XMIReaderFactory.getDefault()
0389: .createXMIReader();
0390: xmiReader.read(pMetaModelInputStream,
0391: pMetaModelURIString,
0392: lMetaModelDescriptor.MetaModelExtent);
0393: // Commit if we have reached this point
0394: mRepository.endTrans(false);
0395: lTransactionNeedsRollback = false;
0396: } finally {
0397: // Rollback if necessary
0398: if (lTransactionNeedsRollback)
0399: mRepository.endTrans(true);
0400: // Ensure that all events are consumed in repository and models
0401: mInternalTransactionListener
0402: .waitTillAllEventsAreConsumed();
0403: }
0404: // Find description for the root package name
0405: Iterator lIter = lMetaModelDescriptor.MetaModelExtent
0406: .getMofPackage().refAllOfClass().iterator();
0407: while (lIter.hasNext()) {
0408: MofPackage lMetaObject = (MofPackage) lIter.next();
0409: if (lMetaObject.getName().equals(
0410: pModelRootPackageMetaObjectName)) {
0411: lMetaModelDescriptor.ModelExtentMetaObject = lMetaObject;
0412: break;
0413: }
0414: }
0415: if (lMetaModelDescriptor.ModelExtentMetaObject == null)
0416: throw new ModelRepositoryException(
0417: "Failed to find package '"
0418: + pModelRootPackageMetaObjectName
0419: + "' in the '" + pMetaModelName
0420: + "' MetaModel loaded from "
0421: + pMetaModelURIString);
0422: mMetaModelsByName.put(pMetaModelName,
0423: lMetaModelDescriptor);
0424: } catch (CreationFailedException e) {
0425: throw new ModelRepositoryException(
0426: "Failed to create extent for '"
0427: + pMetaModelName
0428: + "' MetaModel in the repository");
0429: } catch (IOException e) {
0430: throw new ModelRepositoryException("Failed to read '"
0431: + pMetaModelName
0432: + "' MetaModel definition from "
0433: + pMetaModelURIString, e);
0434: } catch (MalformedXMIException e) {
0435: throw new ModelRepositoryException(
0436: "Failed to parse meta model from "
0437: + pMetaModelURIString, e);
0438: }
0439: }
0440: }
0441:
0442: /** Retrieves the ModelPackage representing the outermost package of the specified MetaModel.
0443: * All MetaModel exporation and navigation can start from here.
0444: * @param pMetaModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0445: * @return the requested MetaModelPackage.
0446: * @exception ModelRepositoryException thrown if there is a problem with obtaining the extent */
0447: public ModelPackage getMetaModelExtent(String pMetaModelName)
0448: throws ModelRepositoryException {
0449: if (isClosed())
0450: throw new ModelRepositoryException(
0451: "Repository is closed and can not be used.");
0452: MetaModelDescriptor lMetaModelDescriptor = (MetaModelDescriptor) mMetaModelsByName
0453: .get(pMetaModelName);
0454: if (lMetaModelDescriptor == null)
0455: throw new MetaModelNotLoadedException(pMetaModelName);
0456: return lMetaModelDescriptor.MetaModelExtent;
0457: }
0458:
0459: /** Retrieves the RefPackage representing the outermost package of the specified Model. All model exporation and navigation and editing can start from here
0460: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0461: * @return the requested RefPackage. */
0462: public RefPackage getModelExtent(String pModelName)
0463: throws ModelRepositoryException {
0464: if (isClosed())
0465: throw new ModelRepositoryException(
0466: "Repository is closed and can not be used.");
0467: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
0468: .get(pModelName);
0469: if (lModelDescriptor == null)
0470: throw new ModelNotLoadedException(pModelName);
0471: return lModelDescriptor.ModelExtent;
0472: }
0473:
0474: /** Retrieves the name of the MetaModel for this model
0475: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0476: * @return the matching MetaModel name. */
0477: public String getMetaModelName(String pModelName)
0478: throws ModelRepositoryException {
0479: if (isClosed())
0480: throw new ModelRepositoryException(
0481: "Repository is closed and can not be used.");
0482: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
0483: .get(pModelName);
0484: if (lModelDescriptor == null)
0485: throw new ModelNotLoadedException(pModelName);
0486: return lModelDescriptor.MetaModelDescriptor.MetaModelName;
0487: }
0488:
0489: /** Retrieves the collection of the RefBaseObjects matching given XPath expression
0490: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0491: * @param pXPathExpression the xpath expression
0492: * @return the requested RefBaseObject. */
0493: public List searchByXPath(String pModelName, String pXPathExpression)
0494: throws ModelRepositoryException {
0495: return MOFXPath.doSelectNodes(pXPathExpression,
0496: getModelExtent(pModelName));
0497: }
0498:
0499: /** Retrieves the collection of the RefBaseObjects matching given XPath expression
0500: * @param pContextObject the object relative to which the given XPath expression should be executed.
0501: * @param pXPathExpression the xpath expression
0502: * @return the requested RefBaseObject. */
0503: public List searchByXPath(RefBaseObject pRootObject,
0504: String pXPathExpression) throws ModelRepositoryException {
0505: return MOFXPath.doSelectNodes(pXPathExpression, pRootObject);
0506: }
0507:
0508: /** Retrieves the collection of the Objects matching given XPath expression.
0509: * @param pContextObjects the List of the RefBaseObjects to run XPath expression against.
0510: * @param pXPathExpression the xpath expression
0511: * @return the list with matching zero or more Objects. Objects may be
0512: * RefObjects if expression has matched model elements or plain java objects (eg. Strings) if expression has matched attributes */
0513: public List searchByXPath(Collection pRootObjects,
0514: String pXPathExpression) throws ModelRepositoryException {
0515: return MOFXPath.doSelectNodes(pXPathExpression, pRootObjects);
0516: }
0517:
0518: /** Retrieves the collection of the RefObjects which are at the top level
0519: * that is they are not owned by any other object.
0520: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0521: * @return the list with zero or more RefObjects, which are not owned by any other object. */
0522: public List getTopLevelModelObjects(String pModelName)
0523: throws ModelRepositoryException {
0524: RefPackage lModelExtent = getModelExtent(pModelName);
0525: List lTopLevelObjects = new ArrayList();
0526: // Deal with classes in the top level package
0527: for (Iterator lAllClassesIter = lModelExtent.refAllClasses()
0528: .iterator(); lAllClassesIter.hasNext();) {
0529: RefClass lClass = (RefClass) lAllClassesIter.next();
0530: for (Iterator lClassInstancesIterator = lClass
0531: .refAllOfClass().iterator(); lClassInstancesIterator
0532: .hasNext();) {
0533: RefObject lInstance = (RefObject) lClassInstancesIterator
0534: .next();
0535: if (lInstance.refImmediateComposite() == null)
0536: lTopLevelObjects.add(lInstance);
0537: }
0538: }
0539: // Deal with classes in subpackages
0540: for (Iterator lAllPackagesIter = lModelExtent.refAllPackages()
0541: .iterator(); lAllPackagesIter.hasNext();) {
0542: RefPackage lSubPackage = (RefPackage) lAllPackagesIter
0543: .next();
0544: for (Iterator lAllClassesIter = lSubPackage.refAllClasses()
0545: .iterator(); lAllClassesIter.hasNext();) {
0546: RefClass lClass = (RefClass) lAllClassesIter.next();
0547: for (Iterator lClassInstancesIterator = lClass
0548: .refAllOfClass().iterator(); lClassInstancesIterator
0549: .hasNext();) {
0550: RefObject lInstance = (RefObject) lClassInstancesIterator
0551: .next();
0552: if (lInstance.refImmediateComposite() == null)
0553: lTopLevelObjects.add(lInstance);
0554: }
0555: }
0556: }
0557: return lTopLevelObjects;
0558: }
0559:
0560: /** Retrieves the RefPackage representing the outermost package of the default Model.
0561: * The model is set as default by using setDefaultModel()
0562: * All model exploration and navigation and editing can start from here
0563: * @return the requested RefPackage. */
0564: public RefPackage getDefaultModelExtent()
0565: throws ModelRepositoryException {
0566: if (mDefaultModelDescriptor == null)
0567: throw new NoDefaultModelException();
0568: return mDefaultModelDescriptor.ModelExtent;
0569: }
0570:
0571: /** @return the name of the default model or null if default model is not setup */
0572: public String getDefaultModelName() throws ModelRepositoryException {
0573: return (mDefaultModelDescriptor != null) ? mDefaultModelDescriptor.ModelName
0574: : null;
0575: }
0576:
0577: /** @return the name of the metamodel of the default model or null if default model is not setup */
0578: public String getDefaultModelMetaModelName()
0579: throws ModelRepositoryException {
0580: return (mDefaultModelDescriptor != null) ? getMetaModelName(mDefaultModelDescriptor.ModelName)
0581: : null;
0582: }
0583:
0584: /** Saves default model at the location specified at the time model was created or opened.
0585: * Repository must not be in transaction at the time of this call. Only files modified since last save
0586: * will be saved. */
0587: public void saveDefaultModel(boolean pValidateModel)
0588: throws ModelRepositoryException, ModelValidationException {
0589: if (mDefaultModelDescriptor == null)
0590: throw new NoDefaultModelException();
0591: saveModel(mDefaultModelDescriptor.ModelName, pValidateModel);
0592: }
0593:
0594: /** Sets the default model name. This repository has a few methods
0595: * dealing with the default model, which do not require the name of the model
0596: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0597: * null can be passed to clear existing default model without setting a new one
0598: * @return the name of previous default model or null if there was no default model before
0599: * @exception ModelRepositoryException thrown if there is a problem with setting default model */
0600: public String setDefaultModel(String pModelName)
0601: throws ModelRepositoryException {
0602: ModelDescriptor lOldDefaultModelDescriptor = mDefaultModelDescriptor;
0603: if (pModelName != null) {
0604: // Setting new default model
0605: ModelDescriptor lNewDefaultModelDescriptor = (ModelDescriptor) mModelsByName
0606: .get(pModelName);
0607: if (lNewDefaultModelDescriptor == null)
0608: throw new ModelNotLoadedException(pModelName);
0609: mDefaultModelDescriptor = lNewDefaultModelDescriptor;
0610: } else {
0611: // Clearing existing defaut model
0612: mDefaultModelDescriptor = null;
0613: }
0614: return (lOldDefaultModelDescriptor != null) ? lOldDefaultModelDescriptor.ModelName
0615: : null;
0616: }
0617:
0618: /** Retrieves the RefPackage described by supplied package descriptor.
0619: * @param pModelName the unique name of the Model. Model with this name must have been opened or created previously in the repository.
0620: * @param pPackageDescriptor the descriptor of the package we are after.
0621: * @return the requested RefPackage.
0622: * @exception ModelRepositoryException thrown if there is a problem with obtaining the package from the model */
0623: public RefPackage getModelPackage(String pModelName,
0624: MofPackage pPackageDescriptor)
0625: throws ModelRepositoryException {
0626: MofPackage lParentPackageDescriptor = (MofPackage) pPackageDescriptor
0627: .getContainer();
0628: if (lParentPackageDescriptor == null) {
0629: // This is the request for the top package
0630: RefPackage lExtentPackage = getModelExtent(pModelName);
0631: if (!lExtentPackage.refMetaObject().equals(
0632: pPackageDescriptor))
0633: throw new ModelRepositoryException("Model "
0634: + pModelName
0635: + " does not contain requested package.");
0636: return lExtentPackage;
0637: }
0638: // We have got the parent package. Get to it by calling this method recursively
0639: RefPackage lParentPackage = getModelPackage(pModelName,
0640: lParentPackageDescriptor);
0641: return lParentPackage.refPackage(pPackageDescriptor);
0642: }
0643:
0644: /**@return true if object is part of any loaded model, false otherwise */
0645: boolean isLoadedModelObject(RefObject pRefObject)
0646: throws ModelRepositoryException {
0647: RefPackage lOutermostPackage = pRefObject.refOutermostPackage();
0648: String lMofId = lOutermostPackage.refMofId();
0649: return mModelsByOutermostPackageMofId.containsKey(lMofId);
0650: }
0651:
0652: /** Retrieves the name of the model given object belongs to.
0653: * @param pModelObject the object from the model.
0654: * @return the name of the model
0655: * @exception ModelRepositoryException thrown if there is a problem with obtaining the name of the model */
0656: public String getOwnerModelName(RefBaseObject pModelObject)
0657: throws ModelRepositoryException {
0658: return getModelDescriptor(pModelObject).ModelName;
0659: }
0660:
0661: /** Retrieves the name of the model given object belongs to.
0662: * @param pModelObject the object from the model.
0663: * @return the name of the model
0664: * @exception ModelRepositoryException thrown if there is a problem with obtaining the name of the model */
0665: public String getOwnerMetaModelName(RefBaseObject pModelObject)
0666: throws ModelRepositoryException {
0667: return getMetaModelName(getOwnerModelName(pModelObject));
0668: }
0669:
0670: /** Retrieves the ModelDescriptor given any RefObject belonging to the model
0671: * @return valid ModelDescriptor
0672: * @exception ModelRepositoryException thrown if given object is not part of any model */
0673: ModelDescriptor getModelDescriptor(RefBaseObject pModelObject)
0674: throws ModelRepositoryException {
0675: RefPackage lOutermostPackage = pModelObject
0676: .refOutermostPackage();
0677: String lMofId = lOutermostPackage.refMofId();
0678: if (!mModelsByOutermostPackageMofId.containsKey(lMofId))
0679: throw new ModelRepositoryException("Object " + pModelObject
0680: + " is not part of any Model");
0681: return (ModelDescriptor) mModelsByOutermostPackageMofId
0682: .get(lMofId);
0683: }
0684:
0685: /** Retrieves the RefBaseObject represented by the RepositoryId (MOF Id). All model exploration and navigation and editing can start from here
0686: * @param pRepositoryId the unique repository id of the object. Object with the same name must exist in the repository.
0687: * @return the requested RefBaseObject. */
0688: public RefBaseObject getModelObjectByRepositoryId(
0689: String pRepositoryId) throws ModelRepositoryException {
0690: if (isClosed())
0691: throw new ModelRepositoryException(
0692: "Repository is closed and can not be used.");
0693: return mRepository.getByMofId(pRepositoryId);
0694: }
0695:
0696: /** Removes MetaModel with the specified name. Also removes all Models governed by this MetaModel
0697: * @param pMetaModelName the unique name of the MetaModel. MetaModel with this name must have been added previously to the repository.
0698: * @exception ModelRepositoryException thrown if there is a problem with the removing of the MetaModel */
0699: public void removeMetaModel(String pMetaModelName)
0700: throws ModelRepositoryException {
0701: if (isClosed())
0702: throw new ModelRepositoryException(
0703: "Repository is closed and can not be used.");
0704: if (isInTransaction())
0705: throw new OperationAttemptedInTransactionException(
0706: "removeMetaModel");
0707: if (!mMetaModelsByName.containsKey(pMetaModelName))
0708: throw new ModelRepositoryException("MetaModel '"
0709: + pMetaModelName + " not found.");
0710: synchronized (sRepositorySemaphore) {
0711: sLogger
0712: .debug("Removing '" + pMetaModelName
0713: + "' MetaModel");
0714: MetaModelDescriptor lMetaModelDescriptor = (MetaModelDescriptor) mMetaModelsByName
0715: .get(pMetaModelName);
0716: // First remove all the models
0717: String[] lModelNames = (String[]) lMetaModelDescriptor.ModelsByName
0718: .keySet()
0719: .toArray(
0720: new String[lMetaModelDescriptor.ModelsByName
0721: .size()]);
0722: for (int i = 0; i < lModelNames.length; i++)
0723: closeModel(lModelNames[i]);
0724: // Now remove the MetaModel itself
0725: mMetaModelsByName.remove(pMetaModelName);
0726: // Now remove extent
0727: RefPackage lMetaModelExtent = mRepository
0728: .getExtent(lMetaModelDescriptor.MetaModelExtentName);
0729: lMetaModelExtent.refDelete();
0730: }
0731: }
0732:
0733: /** @param pMetaModelName the unique name of the MetaModel.
0734: * @return true if metamodel with the specified name is already loaded
0735: * @exception ModelRepositoryException thrown if there is a problem with answering the question */
0736: public boolean containsMetaModel(String pMetaModelName)
0737: throws ModelRepositoryException {
0738: return mMetaModelsByName.containsKey(pMetaModelName);
0739: }
0740:
0741: /** Lists names of the loaded MetaModels.
0742: * @return array of strings containg the names of the loaded MetaModels. Can be zero length array if repository is empty.
0743: * @exception ModelRepositoryException thrown if there is a problem with obtaining the list of MetaModels */
0744: public String[] listMetaModelNames()
0745: throws ModelRepositoryException {
0746: return (String[]) mMetaModelsByName.keySet().toArray(
0747: new String[mMetaModelsByName.size()]);
0748: }
0749:
0750: /** Opens the model from the specified URL to the model repository. The metamodel
0751: * of the model must have been loaded prior to this call. The opened model can be
0752: * modified and results saved back if required.
0753: * @param pModelName the unique name caller wishes to refer to this model in the future. Must be unique name not used before in this repository session.
0754: * @param pModelURL the URL where definition of the Model can be loaded from. Must refer to the xmi file containing the model (i.e. definition of this Model in XMI as per MetaModel).
0755: * If model storage is partitioned - this URL must refer to the root file. Locations of all other
0756: * partitions are expected to be relative to this URL.
0757: * @param pMetaModelName the unique name of the MetaModel. MetaModel with this name must have been added previously to the repository.
0758: * @param pModelStorageProperties model storage properties to use. null passed here
0759: * indicates that default properties should be used (default properties are set when MetaModel is opened
0760: * via {@link #loadMetaModel(String, URL, String, Properties) loadMetaModel} method. If default properties
0761: * are indicating partititoning and model being opened is not partitioned - empty properties object must be specified.
0762: * @exception ModelRepositoryException thrown if there was a problem with the loading of the Model */
0763: public void openModel(String pModelName, File pModelRootFile,
0764: String pMetaModelName) throws ModelRepositoryException {
0765: // Call the helper
0766: initModel(ModelInitialisationType.OPEN_EXISTING, pModelName,
0767: pModelRootFile, pMetaModelName, null);
0768: }
0769:
0770: /** Creates a new model in the model repository. This model is to be kept at the specified file location.
0771: * The metamodel of the model must have been loaded prior to this call. The created empty model can be
0772: * modified and results saved back if required.
0773: * @param pModelName the unique name caller wishes to refer to this model in the future. Must be unique name not used before in this repository session.
0774: * @param pModelRootFile the file where definition of the Model shall be kept. Must refer to the non-existing xmi file in the existing
0775: * and accessible directory. If model storage is partitioned - this file must refer to the root file. Locations of all other
0776: * partitions are expected to be relative to this file.
0777: * @param pMetaModelName the unique name of the MetaModel. MetaModel with this name must have been added previously to the repository.
0778: * @param pModelStorageProperties model storage properties to use. null passed here
0779: * indicates that default properties should be used (default properties are set when MetaModel is opened
0780: * via {@link #loadMetaModel(String, URL, String, Properties) loadMetaModel} method. If default properties
0781: * are indicating partititoning and model being opened is not partitioned - empty properties object must be specified.
0782: * @exception ModelRepositoryException thrown if there was a problem with the loading of the Model */
0783: public void createModel(String pModelName, File pModelRootFile,
0784: String pMetaModelName, Properties pModelStorageProperties)
0785: throws ModelRepositoryException {
0786: // Call the helper
0787: initModel(ModelInitialisationType.CREATE_NEW, pModelName,
0788: pModelRootFile, pMetaModelName, pModelStorageProperties);
0789: }
0790:
0791: // Helper. Opens or creates amodel. Common functionality between model open and create
0792: private void initModel(ModelInitialisationType pInitialisationType,
0793: String pModelName, File pModelRootFile,
0794: String pMetaModelName, Properties pModelStorageProperties)
0795: throws ModelRepositoryException {
0796: synchronized (sRepositorySemaphore) {
0797: if (isClosed())
0798: throw new ModelRepositoryException(
0799: "Repository is closed and can not be used.");
0800: if (isInTransaction())
0801: throw new OperationAttemptedInTransactionException(
0802: "initModel");
0803: // Declare descriptor here, so we could reference it from finally
0804: ModelDescriptor lModelDescriptor = null;
0805: boolean lInitialisationSuccessfull = false;
0806: try {
0807: // Open metamodel
0808: MetaModelDescriptor lMetaModelDescriptor = (MetaModelDescriptor) mMetaModelsByName
0809: .get(pMetaModelName);
0810: if (lMetaModelDescriptor == null)
0811: throw new ModelRepositoryException(
0812: "MetaModel not found. MetaModelName: "
0813: + pMetaModelName);
0814: if (mModelsByName.containsKey(pModelName))
0815: throw new ModelRepositoryException(
0816: "Model "
0817: + pModelName
0818: + " is already loaded. It needs to be removed before reloading.");
0819: if (pInitialisationType == ModelInitialisationType.OPEN_EXISTING) {
0820: // If we are opening an existing model - the model file must exist
0821: if (!pModelRootFile.exists())
0822: throw new ModelRepositoryException(
0823: "File "
0824: + pModelRootFile
0825: + " does not exist. Unable to read existing model from this location.");
0826: sLogger.debug("Loading '" + pModelName
0827: + "' Model stored in "
0828: + pModelRootFile.getAbsolutePath());
0829: } else if (pInitialisationType == ModelInitialisationType.CREATE_NEW) {
0830: // If we are creating transient model - the file argument will be null
0831: // If we are creating a persistent model - file argument will not be null
0832: if (pModelRootFile != null) {
0833: if (pModelRootFile.exists())
0834: throw new ModelRepositoryException(
0835: "File "
0836: + pModelRootFile
0837: + " already exists. Unable to create a new model at this location.");
0838: if (!pModelRootFile.getParentFile().exists())
0839: throw new ModelRepositoryException(
0840: "Directory "
0841: + pModelRootFile
0842: .getParentFile()
0843: + " does not exist. Unable to create a new model at this location.");
0844: sLogger.debug("Creating '" + pModelName
0845: + "' Model to be stored in "
0846: + pModelRootFile.getAbsolutePath());
0847: } else {
0848: sLogger
0849: .debug("Creating '"
0850: + pModelName
0851: + "' Transient Model which will not be stored anywhere.");
0852: }
0853: }
0854: lModelDescriptor = new ModelDescriptor();
0855: lModelDescriptor.ModelName = pModelName;
0856: lModelDescriptor.MetaModelDescriptor = lMetaModelDescriptor;
0857: lModelDescriptor.InitialisationType = pInitialisationType;
0858: if (pModelRootFile != null) {
0859: lModelDescriptor.ModelRootFile = pModelRootFile
0860: .getAbsoluteFile();
0861: lModelDescriptor.ModelRootDirectory = lModelDescriptor.ModelRootFile
0862: .getParentFile();
0863: lModelDescriptor.ModelRootURI = "/"
0864: + lModelDescriptor.ModelRootFile.getName();
0865: lModelDescriptor.ModelStoragePropertiesFile = new File(
0866: lModelDescriptor.ModelRootDirectory
0867: .getAbsolutePath()
0868: + File.separator
0869: + "storage.properties");
0870: } else {
0871: lModelDescriptor.ModelRootFile = null;
0872: lModelDescriptor.ModelRootDirectory = null;
0873: lModelDescriptor.ModelRootURI = null;
0874: lModelDescriptor.ModelStoragePropertiesFile = null;
0875: }
0876: lModelDescriptor.ModelExtentName = "model:/"
0877: + pModelName;
0878: // Create an extent for the model
0879: try {
0880: lModelDescriptor.ModelExtent = mRepository
0881: .createExtent(
0882: lModelDescriptor.ModelExtentName,
0883: lMetaModelDescriptor.ModelExtentMetaObject);
0884: lModelDescriptor.mInternalChangeListener = new ModelChangesListenerImpl(
0885: this , lModelDescriptor);
0886: ((org.netbeans.mdr.handlers.PackageProxyHandler) lModelDescriptor.ModelExtent)
0887: .addListener(lModelDescriptor.mInternalChangeListener);
0888: } catch (CreationFailedException e) {
0889: throw new ModelRepositoryException(
0890: "Failed to create extent for '"
0891: + pModelName
0892: + "' Model in the repository", e);
0893: }
0894: // Create temporary directories
0895: try {
0896: String lSuggestedName = StringUtils.suggestName(
0897: pModelName, true, false);
0898: // Create temporary directory where attached files will be maintained until saved in the premanent area
0899: lModelDescriptor.UnsavedAttachedFilesDir = DirectoryUtils
0900: .createTempDir(lSuggestedName,
0901: "UnsavedAttachedFiles");
0902: sLogger
0903: .debug("Will use "
0904: + lModelDescriptor.UnsavedAttachedFilesDir
0905: .getAbsolutePath()
0906: + " directory for the unsaved attachments storage");
0907: lModelDescriptor.UnsavedAttachedFilesDir
0908: .deleteOnExit();
0909: // Create temporary directory where attached files will be maintained until transaction is committed
0910: lModelDescriptor.UncomittedAttachedFilesDir = DirectoryUtils
0911: .createTempDir(lSuggestedName,
0912: "UncomittedAttachedFiles");
0913: sLogger
0914: .debug("Will use "
0915: + lModelDescriptor.UncomittedAttachedFilesDir
0916: .getAbsolutePath()
0917: + " directory for the uncommitted attachments storage");
0918: lModelDescriptor.UncomittedAttachedFilesDir
0919: .deleteOnExit();
0920: } catch (IOException e) {
0921: throw new ModelRepositoryException(
0922: "Failed to create temporary directory", e);
0923: }
0924: // Read existing model if necessary
0925: if (pInitialisationType == ModelInitialisationType.OPEN_EXISTING) {
0926: lModelDescriptor.ModelStorageProperties = new Properties();
0927: // Read model storage properties in
0928: if (lModelDescriptor.ModelStoragePropertiesFile
0929: .exists()) {
0930: try {
0931: InputStream lModelStoragePropertiesInputStream = null;
0932: try {
0933: lModelStoragePropertiesInputStream = new FileInputStream(
0934: lModelDescriptor.ModelStoragePropertiesFile);
0935: lModelDescriptor.ModelStorageProperties
0936: .load(lModelStoragePropertiesInputStream);
0937: } finally {
0938: if (lModelStoragePropertiesInputStream != null)
0939: lModelStoragePropertiesInputStream
0940: .close();
0941: }
0942: } catch (IOException e) {
0943: throw new ModelRepositoryException(
0944: "Error reading "
0945: + lModelDescriptor.ModelStoragePropertiesFile
0946: .getAbsolutePath()
0947: + " file. Model appears to be corrupt.",
0948: e);
0949: }
0950: } else
0951: sLogger
0952: .debug("File "
0953: + lModelDescriptor.ModelStoragePropertiesFile
0954: .getAbsolutePath()
0955: + " does not exists. Model appears to be stored in a single file.");
0956: // Read model
0957: try {
0958: // Use internal repository transaction directly
0959: boolean lTransactionNeedsRollback = true;
0960: mRepository.beginTrans(true);
0961: try {
0962: XMIReader lCreatedPartitionedXMIReader = XMIReaderFactory
0963: .getDefault().createXMIReader();
0964: lCreatedPartitionedXMIReader
0965: .getConfiguration()
0966: .setReferenceResolver(
0967: new XMIReferenceResolverImpl(
0968: lModelDescriptor.ModelRootDirectory,
0969: lModelDescriptor.XmiIdGenerator));
0970: lCreatedPartitionedXMIReader.read(
0971: lModelDescriptor.ModelRootFile
0972: .toURI().toString(),
0973: lModelDescriptor.ModelExtent);
0974: // Commit if we have reached this point
0975: mRepository.endTrans(false);
0976: lTransactionNeedsRollback = false;
0977: } finally {
0978: // Rollback if necessary
0979: if (lTransactionNeedsRollback)
0980: mRepository.endTrans(true);
0981: // Ensure that all events are consumed in repository and models
0982: mInternalTransactionListener
0983: .waitTillAllEventsAreConsumed();
0984: }
0985: // After data is read build the image of the existing stored model
0986: XMIReferenceProvider lModelXMIReferenceProvider = new XMIReferenceProviderImpl(
0987: lModelDescriptor.ModelRootURI,
0988: lModelDescriptor.ModelStorageProperties,
0989: lModelDescriptor.XmiIdGenerator);
0990: RefObject[] lAllInstances = ModelRepositoryUtils
0991: .getAllInstancesInPackage(lModelDescriptor.ModelExtent);
0992: lModelDescriptor.PartitionsMap = buildPartitionsMap(
0993: lAllInstances,
0994: lModelXMIReferenceProvider);
0995: lModelDescriptor.ObjectAttachmentsMap = buildObjectAttachmentsMapAfterRead(
0996: lAllInstances,
0997: lModelXMIReferenceProvider,
0998: lModelDescriptor.ModelRootDirectory);
0999: } catch (MalformedXMIException e) {
1000: throw new ModelRepositoryException("File "
1001: + lModelDescriptor.ModelRootFile
1002: .getAbsolutePath()
1003: + " contains invalid XMI data", e);
1004: } catch (IOException e) {
1005: throw new ModelRepositoryException(
1006: "Failed to read Model from "
1007: + lModelDescriptor.ModelRootFile
1008: .getAbsolutePath(), e);
1009: }
1010: } else if (pInitialisationType == ModelInitialisationType.CREATE_NEW) {
1011: // Setup model stroage properties either from supplied or default
1012: lModelDescriptor.ModelStorageProperties = pModelStorageProperties != null ? pModelStorageProperties
1013: : lMetaModelDescriptor.DefaultModelStorageProperties;
1014: // Create empty maps for the currently stored stuff
1015: lModelDescriptor.PartitionsMap = new TreeMap();
1016: lModelDescriptor.ObjectAttachmentsMap = new TreeMap();
1017: }
1018: // Now assign all necessary assistants
1019: for (Iterator lAssistantProperties = sAssistantProperties
1020: .entrySet().iterator(); lAssistantProperties
1021: .hasNext();) {
1022: Map.Entry lAssistantPropertyEntry = (Map.Entry) lAssistantProperties
1023: .next();
1024: String lAssistantPropertyKey = (String) lAssistantPropertyEntry
1025: .getKey();
1026: // First see if this key has a metamodel filter expression
1027: if (lAssistantPropertyKey
1028: .matches("((\\d)+)\\.metamodel\\[(([^\\[\\]])+)\\]")) {
1029: // This is the property applicable only for particular metmodels
1030: int lMetaModelNameStart = lAssistantPropertyKey
1031: .indexOf(".metamodel[") + 11;
1032: String lDesiredMetaModelName = lAssistantPropertyKey
1033: .substring(
1034: lMetaModelNameStart,
1035: lAssistantPropertyKey.length() - 1);
1036: if (!pMetaModelName
1037: .equals(lDesiredMetaModelName))
1038: continue; // This is not our metamodel. Skip this assistant
1039: } else
1040: // Now see if this key has a model filter expression
1041: if (lAssistantPropertyKey
1042: .matches("((\\d)+)\\.model\\[(([^\\[\\]])+)\\]")) {
1043: // This is the property applicable only for particular metmodels
1044: int lModelNameStart = lAssistantPropertyKey
1045: .indexOf(".model[") + 7;
1046: String lDesiredModelName = lAssistantPropertyKey
1047: .substring(
1048: lModelNameStart,
1049: lAssistantPropertyKey.length() - 1);
1050: if (!pModelName.equals(lDesiredModelName))
1051: continue; // This is not our model. Skip this assistant
1052: } else
1053: // The only chance now is that this key does not have any filter and should be applied to any model
1054: if (!lAssistantPropertyKey.matches("(\\d)+"))
1055: throw new ModelRepositoryException(
1056: "Error parsing ModelAssistant mapping property. Property key: '"
1057: + sAssistantPropertiesPrefix
1058: + lAssistantPropertyKey + "'");
1059: // At this point we are sure that this is our assistant
1060: // Look it up and register it
1061: try {
1062: Properties lContextProps = new Properties();
1063: lContextProps
1064: .setProperty(
1065: "com.metaboss.naming.component.com.metaboss.sdlctools.models.ModelAssistant",
1066: (String) lAssistantPropertyEntry
1067: .getValue());
1068: Context lAssistantContext = new InitialContext(
1069: lContextProps);
1070: ModelAssistant lAssistant = (ModelAssistant) lAssistantContext
1071: .lookup(ModelAssistant.COMPONENT_URL);
1072: lModelDescriptor.AssistantsList.add(lAssistant);
1073: } catch (NamingException e) {
1074: throw new ModelRepositoryException(
1075: "Unable to lookup ModelAssistant", e);
1076: }
1077: }
1078: // Register successfully loaded model
1079: lMetaModelDescriptor.ModelsByName.put(pModelName,
1080: lModelDescriptor);
1081: mModelsByName.put(pModelName, lModelDescriptor);
1082: mModelsByOutermostPackageMofId.put(
1083: lModelDescriptor.ModelExtent.refMofId(),
1084: lModelDescriptor);
1085: // Assign model assistants
1086: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1087: .iterator(); lModelAssistantsIterator.hasNext();)
1088: ((ModelAssistant) lModelAssistantsIterator.next())
1089: .assignToModel(pModelName);
1090: // Assign metamodel assistants
1091: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1092: .iterator(); lModelAssistantsIterator.hasNext();)
1093: ((ModelAssistant) lModelAssistantsIterator.next())
1094: .assignToModel(pModelName);
1095: lInitialisationSuccessfull = true;
1096: } finally {
1097: // If there was an error and this model was not opened - e need to clean up
1098: if (!lInitialisationSuccessfull) {
1099: // Inittiate cleanup
1100: if (lModelDescriptor != null) {
1101: if (lModelDescriptor.ModelExtent != null) {
1102: if (lModelDescriptor.mInternalChangeListener != null)
1103: ((org.netbeans.mdr.handlers.PackageProxyHandler) lModelDescriptor.ModelExtent)
1104: .removeListener(lModelDescriptor.mInternalChangeListener);
1105: lModelDescriptor.ModelExtent.refDelete();
1106: }
1107: }
1108: } else {
1109: // If there was no error - we have to start listener
1110: lModelDescriptor.mInternalChangeListener
1111: .startListening();
1112: }
1113: }
1114: }
1115: }
1116:
1117: /** Closes model in repository without saving any changes to the location specified at the time model was created or opened.
1118: * Repository must not be in transaction at the time of this call.
1119: * All modifications to the model will be lost
1120: * @param pModelName the unique name of the model.
1121: * @exception ModelRepositoryException thrown if there was a problem with the closing of the Model */
1122: public void closeModel(String pModelName)
1123: throws ModelRepositoryException {
1124: synchronized (sRepositorySemaphore) {
1125: if (isClosed())
1126: throw new ModelRepositoryException(
1127: "Repository is closed and can not be used.");
1128: if (isInTransaction())
1129: throw new OperationAttemptedInTransactionException(
1130: "closeModel");
1131: sLogger.debug("Closing '" + pModelName + "' Model");
1132: if (!mModelsByName.containsKey(pModelName))
1133: throw new ModelNotLoadedException(pModelName);
1134: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1135: .get(pModelName);
1136: // Deal with the listener first
1137: lModelDescriptor.mInternalChangeListener.stopListening();
1138: ((org.netbeans.mdr.handlers.PackageProxyHandler) lModelDescriptor.ModelExtent)
1139: .removeListener(lModelDescriptor.mInternalChangeListener);
1140: lModelDescriptor.mInternalChangeListener = null;
1141:
1142: // Now deregister the model descriptor
1143: mModelsByName.remove(pModelName);
1144: mModelsByOutermostPackageMofId
1145: .remove(lModelDescriptor.ModelExtent.refMofId());
1146: lModelDescriptor.MetaModelDescriptor.ModelsByName
1147: .remove(pModelName);
1148:
1149: // Now relieve assistants
1150: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1151: .iterator(); lModelAssistantsIterator.hasNext();)
1152: ((ModelAssistant) lModelAssistantsIterator.next())
1153: .dismissFromModel(pModelName);
1154: // Assign metamodel assistants
1155: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1156: .iterator(); lModelAssistantsIterator.hasNext();)
1157: ((ModelAssistant) lModelAssistantsIterator.next())
1158: .dismissFromModel(pModelName);
1159: // Now delete extent
1160: lModelDescriptor.ModelExtent.refDelete();
1161: // Now delete directories
1162: try {
1163: DirectoryUtils
1164: .deleteDirectory(lModelDescriptor.UncomittedAttachedFilesDir);
1165: } catch (IOException e) {
1166: throw new ModelRepositoryException("Error deleting "
1167: + lModelDescriptor.UncomittedAttachedFilesDir
1168: .getAbsolutePath() + " directory.", e);
1169: }
1170: try {
1171: DirectoryUtils
1172: .deleteDirectory(lModelDescriptor.UnsavedAttachedFilesDir);
1173: } catch (IOException e) {
1174: throw new ModelRepositoryException("Error deleting "
1175: + lModelDescriptor.UnsavedAttachedFilesDir
1176: .getAbsolutePath() + " directory.", e);
1177: }
1178: }
1179: }
1180:
1181: /** Lists names of the loaded Models.
1182: * @return array of strings containg the names of the loaded Models. Can be zero length array if repository has no models loaded.
1183: * @exception ModelRepositoryException thrown if there is a problem with obtaining the list of Models */
1184: public String[] listModelNames() throws ModelRepositoryException {
1185: return (String[]) mModelsByName.keySet().toArray(
1186: new String[mModelsByName.size()]);
1187: }
1188:
1189: /** @param pModelName the unique name of the Model given to it when it was opened or created.
1190: * @return true if model with the specified name is already loaded
1191: * @exception ModelRepositoryException thrown if there is a problem with answering the question */
1192: public boolean containsModel(String pModelName)
1193: throws ModelRepositoryException {
1194: return mModelsByName.containsKey(pModelName);
1195: }
1196:
1197: // Provides read only snapshot view of the collection of the model descriptors.
1198: Collection getModelDescriptors() {
1199: return Collections.unmodifiableCollection(new ArrayList(
1200: mModelsByName.values()));
1201: }
1202:
1203: /** Returns currently initialised Repository instance or creates one if necessary */
1204: public static ModelRepositoryImpl getRepository()
1205: throws ModelRepositoryException {
1206: if (sRepository == null) {
1207: synchronized (sRepositorySemaphore) {
1208: if (sRepository == null) {
1209: sRepository = new ModelRepositoryImpl();
1210: }
1211: }
1212: }
1213: return sRepository;
1214: }
1215:
1216: /** Closes this repository making it unuseable */
1217: public void close() throws ModelRepositoryException {
1218: // Can only have one repository at most
1219: synchronized (sRepositorySemaphore) {
1220: if (isClosed())
1221: return; // Already closed
1222: if (isInTransaction())
1223: throw new OperationAttemptedInTransactionException(
1224: "close");
1225:
1226: sLogger.debug("Closing the repository");
1227: // First close all models
1228: String[] lMetaModelNames = (String[]) mMetaModelsByName
1229: .keySet().toArray(
1230: new String[mMetaModelsByName.size()]);
1231: for (int i = 0; i < lMetaModelNames.length; i++)
1232: removeMetaModel(lMetaModelNames[i]);
1233: mRepository.removeListener(mInternalTransactionListener);
1234: mRepository = null;
1235: sRepository = null;
1236: }
1237: }
1238:
1239: /** Verifies model constraints on the given model.
1240: * Repository must not be in transaction at the time of this call.
1241: * @param pModelName the unique name of the model which must be loaded into the repository prior to this call.
1242: * @exception ModelRepositoryException thrown if there was a general problem with accessing the model
1243: * @exception ModelValidationException thrown if there was one or more validation problems.
1244: * Caller may use getExplanation() method offered by this exception to discover what is actually wrong */
1245: public void validateModel(String pModelName)
1246: throws ModelRepositoryException, ModelValidationException {
1247: synchronized (sRepositorySemaphore) {
1248: if (isClosed())
1249: throw new ModelRepositoryException(
1250: "Repository is closed and can not be used.");
1251: if (isInTransaction())
1252: throw new OperationAttemptedInTransactionException(
1253: "validateModel");
1254: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1255: .get(pModelName);
1256: if (lModelDescriptor == null)
1257: throw new ModelNotLoadedException(pModelName);
1258: // Ensure that all events are consumed
1259: lModelDescriptor.mInternalChangeListener
1260: .waitTillAllEventsAreConsumed();
1261: // Verify all constraints on the model and in all assistants
1262: Collection lProblems = lModelDescriptor.ModelExtent
1263: .refVerifyConstraints(true);
1264: // Verify problems on model assistants
1265: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1266: .iterator(); lModelAssistantsIterator.hasNext();)
1267: lProblems
1268: .addAll(((ModelAssistant) lModelAssistantsIterator
1269: .next()).verifyConstraints(pModelName));
1270: // Verify problems on metamodel assistants
1271: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1272: .iterator(); lModelAssistantsIterator.hasNext();)
1273: lProblems
1274: .addAll(((ModelAssistant) lModelAssistantsIterator
1275: .next()).verifyConstraints(pModelName));
1276: if (!lProblems.isEmpty())
1277: throw new ModelValidationException(
1278: "Errors occurred during validation of the '"
1279: + pModelName + "' model.",
1280: (JmiException[]) lProblems
1281: .toArray(new JmiException[lProblems
1282: .size()]));
1283: }
1284: }
1285:
1286: /** Attempts to correct the errors in the given model.
1287: * Repository must not be in transaction at the time of this call.
1288: * @param pModelName the unique name of the model which must be loaded into the repository prior to this call.
1289: * @exception ModelRepositoryException thrown if there was a general problem with accessing the model. */
1290: public void rectifyModel(String pModelName)
1291: throws ModelRepositoryException {
1292: synchronized (sRepositorySemaphore) {
1293: if (isClosed())
1294: throw new ModelRepositoryException(
1295: "Repository is closed and can not be used.");
1296: if (isInTransaction())
1297: throw new OperationAttemptedInTransactionException(
1298: "rectifyModel");
1299: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1300: .get(pModelName);
1301: if (lModelDescriptor == null)
1302: throw new ModelNotLoadedException(pModelName);
1303: // Ensure that all events are consumed
1304: lModelDescriptor.mInternalChangeListener
1305: .waitTillAllEventsAreConsumed();
1306: // Delegate the task to the model assistants
1307: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1308: .iterator(); lModelAssistantsIterator.hasNext();)
1309: ((ModelAssistant) lModelAssistantsIterator.next())
1310: .rectifyModel(pModelName);
1311: // Verify problems on metamodel assistants
1312: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1313: .iterator(); lModelAssistantsIterator.hasNext();)
1314: ((ModelAssistant) lModelAssistantsIterator.next())
1315: .rectifyModel(pModelName);
1316: }
1317: }
1318:
1319: /** Checks if model has been modified and needs saving
1320: * Repository must not be in transaction at the time of this call.
1321: * Only files modified since last save will be considered.
1322: * @param pModelName the unique name of the model.
1323: * @exception ModelRepositoryException thrown if there was a general problem with checking if model needs saving or not */
1324: public boolean isModelModified(String pModelName)
1325: throws ModelRepositoryException {
1326: synchronized (sRepositorySemaphore) {
1327: if (isClosed())
1328: throw new ModelRepositoryException(
1329: "Repository is closed and can not be used.");
1330: if (isInTransaction())
1331: throw new OperationAttemptedInTransactionException(
1332: "isModelModified");
1333: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1334: .get(pModelName);
1335: if (lModelDescriptor == null)
1336: throw new ModelRepositoryException("Model "
1337: + pModelName
1338: + " is not present in the repository.");
1339: // Ensure that all events are consumed
1340: lModelDescriptor.mInternalChangeListener
1341: .waitTillAllEventsAreConsumed();
1342: if ((lModelDescriptor.ModifiedObjectsSet.isEmpty() == false)
1343: || (lModelDescriptor.CreatedObjectsSet.isEmpty() == false)
1344: || (lModelDescriptor.DeletedObjectsSet.isEmpty() == false)
1345: || (lModelDescriptor.UnsavedAttachedFilesDir
1346: .listFiles().length > 0))
1347: return true; // There are changed objects or changed files therefore model has changed
1348: return false; // Model has nothing to save
1349: }
1350: }
1351:
1352: /** Saves model at the location specified explicitly in this call.
1353: * Repository must not be in transaction at the time of this call.
1354: * All files will be saved as this is not an existing location.
1355: * @param pModelName the unique name of the model.
1356: * @param pValidateModel if set to true - model will be validated before saving and
1357: * in case if validation errors have been discovered - exception will be thrown and
1358: * model will not be saved.
1359: * @param pModelRootFile the file where top level definition of the Model should be
1360: * saved to. If file exists it will be overwritten. If directory does not exist -
1361: * it will be created. If model storage is partitioned - more files and subdirectories will be created as needed.
1362: * @param pModelStorageProperties model storage properties to use. null passed here
1363: * indicates that default properties should be used (default properties are set when MetaModel is opened
1364: * via {@link #loadMetaModel(String, URL, String, Properties) loadMetaModel} method.
1365: * If it is desired to save model in unpartitioned fashion - empty properties object must be specified.
1366: * @exception ModelRepositoryException thrown if there was a general problem with the saving the Model
1367: * @exception ModelValidationException thrown if there was one or more validation problems.
1368: * Caller may use getExplanation() method offered by this exception to discover what is actually wrong */
1369: public void exportModel(String pModelName, boolean pValidateModel,
1370: File pModelRootFile, Properties pModelStorageProperties)
1371: throws ModelRepositoryException {
1372: synchronized (sRepositorySemaphore) {
1373: if (isClosed())
1374: throw new ModelRepositoryException(
1375: "Repository is closed and can not be used.");
1376: if (isInTransaction())
1377: throw new OperationAttemptedInTransactionException(
1378: "exportModel");
1379: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1380: .get(pModelName);
1381: if (lModelDescriptor == null)
1382: throw new ModelRepositoryException("Model "
1383: + pModelName
1384: + " is not present in the repository.");
1385: // Ensure that all events are consumed
1386: lModelDescriptor.mInternalChangeListener
1387: .waitTillAllEventsAreConsumed();
1388: // Verify all constraints on the model if necessary
1389: if (pValidateModel) {
1390: Collection lProblems = lModelDescriptor.ModelExtent
1391: .refVerifyConstraints(true);
1392: // Verify problems on model assistants
1393: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1394: .iterator(); lModelAssistantsIterator.hasNext();)
1395: lProblems
1396: .addAll(((ModelAssistant) lModelAssistantsIterator
1397: .next())
1398: .verifyConstraints(pModelName));
1399: // Verify problems on metamodel assistants
1400: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1401: .iterator(); lModelAssistantsIterator.hasNext();)
1402: lProblems
1403: .addAll(((ModelAssistant) lModelAssistantsIterator
1404: .next())
1405: .verifyConstraints(pModelName));
1406: if (!lProblems.isEmpty())
1407: throw new ModelValidationException(
1408: "Errors occurred during validation of the '"
1409: + pModelName
1410: + "' model. Unable to save it.",
1411: (JmiException[]) lProblems
1412: .toArray(new JmiException[lProblems
1413: .size()]));
1414: }
1415: ModelExportPlan lModelExportPlan = createModelExportPlan(
1416: lModelDescriptor, pModelRootFile,
1417: pModelStorageProperties);
1418: // At this point we have collected all info about what is required to be
1419: // created, deleted and updated. Lets do it !
1420: XMIWriter lPartitionedXMIWriter = XMIWriterFactory
1421: .getDefault().createXMIWriter();
1422: lPartitionedXMIWriter
1423: .getConfiguration()
1424: .setReferenceProvider(
1425: lModelExportPlan.ExportXMIReferenceProvider);
1426: // Create all partitions
1427: for (Iterator lPartitionsToCreateIterator = lModelExportPlan.PartitionsToCreate
1428: .iterator(); lPartitionsToCreateIterator.hasNext();) {
1429: String lURIToCreate = (String) lPartitionsToCreateIterator
1430: .next();
1431: File lFileToCreate = new File(
1432: lModelExportPlan.TargetRootDirectoryAbsolutePath
1433: + lURIToCreate);
1434: if (lFileToCreate.exists())
1435: throw new ModelRepositoryException("File "
1436: + lFileToCreate.getAbsolutePath()
1437: + " already exists");
1438: lFileToCreate.getParentFile().mkdirs();
1439: try {
1440: FileOutputStream lFileOutputStream = null;
1441: try {
1442: lFileOutputStream = new FileOutputStream(
1443: lFileToCreate);
1444: lPartitionedXMIWriter.write(lFileOutputStream,
1445: lURIToCreate,
1446: lModelDescriptor.ModelExtent, "1.2");
1447: // lPartitionedXMIWriter.write(lFileOutputStream,lURIToCreate,lModelDescriptor.ModelExtent,"2.0");
1448: lFileOutputStream.flush();
1449: } finally {
1450: if (lFileOutputStream != null)
1451: lFileOutputStream.close();
1452: }
1453: } catch (IOException e) {
1454: throw new ModelRepositoryException(
1455: "Error creating " + lFileToCreate
1456: + " model file.", e);
1457: }
1458: }
1459: // Move all planned attachments
1460: for (Iterator lAttachmentsToCopyIterator = lModelExportPlan.AttachmentsToCopy
1461: .entrySet().iterator(); lAttachmentsToCopyIterator
1462: .hasNext();) {
1463: Map.Entry lMoveInstruction = (Map.Entry) lAttachmentsToCopyIterator
1464: .next();
1465: String lTargetAbsolutePath = (String) lMoveInstruction
1466: .getKey();
1467: String lSourceAbsolutePath = (String) lMoveInstruction
1468: .getValue();
1469: try {
1470: FileUtils.copyFile(lSourceAbsolutePath,
1471: lTargetAbsolutePath);
1472: } catch (IOException e) {
1473: throw new ModelRepositoryException(
1474: "Error copying attachment file from "
1475: + lSourceAbsolutePath + " to "
1476: + lTargetAbsolutePath);
1477: }
1478: }
1479: // Save storage properties if necessary
1480: if (pModelStorageProperties != null
1481: && pModelStorageProperties.size() > 0) {
1482: try {
1483: OutputStream lModelStoragePropertiesOutputStream = null;
1484: try {
1485: lModelStoragePropertiesOutputStream = new FileOutputStream(
1486: lModelExportPlan.ModelStoragePropertiesFile);
1487: pModelStorageProperties.store(
1488: lModelStoragePropertiesOutputStream,
1489: "Storage properties of the model");
1490: lModelStoragePropertiesOutputStream.flush();
1491: } finally {
1492: if (lModelStoragePropertiesOutputStream != null)
1493: lModelStoragePropertiesOutputStream.close();
1494: }
1495: } catch (IOException e) {
1496: throw new ModelRepositoryException(
1497: "Error writing "
1498: + lModelDescriptor.ModelStoragePropertiesFile
1499: .getAbsolutePath()
1500: + " file.", e);
1501: }
1502: }
1503: }
1504: }
1505:
1506: /** Saves model at the location specified at the time model was created or opened.
1507: * Repository must not be in transaction at the time of this call. Only files modified since last save
1508: * will be saved
1509: * @param pModelName the unique name of the model.
1510: * @exception ModelRepositoryException thrown if there was a problem with the saving the Model */
1511: public void saveModel(String pModelName, boolean pValidateModel)
1512: throws ModelRepositoryException {
1513: synchronized (sRepositorySemaphore) {
1514: if (isClosed())
1515: throw new ModelRepositoryException(
1516: "Repository is closed and can not be used.");
1517: if (isInTransaction())
1518: throw new OperationAttemptedInTransactionException(
1519: "saveModel");
1520: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
1521: .get(pModelName);
1522: if (lModelDescriptor == null)
1523: throw new ModelNotLoadedException(pModelName);
1524: if (lModelDescriptor.ModelRootFile == null)
1525: throw new TransientModelCanNotBeSavedException(
1526: pModelName);
1527: // Ensure that all events are consumed
1528: lModelDescriptor.mInternalChangeListener
1529: .waitTillAllEventsAreConsumed();
1530: // Verify all constraints on the model if necessary
1531: if (pValidateModel) {
1532: Collection lProblems = lModelDescriptor.ModelExtent
1533: .refVerifyConstraints(true);
1534: // Verify problems on model assistants
1535: for (Iterator lModelAssistantsIterator = lModelDescriptor.AssistantsList
1536: .iterator(); lModelAssistantsIterator.hasNext();)
1537: lProblems
1538: .addAll(((ModelAssistant) lModelAssistantsIterator
1539: .next())
1540: .verifyConstraints(pModelName));
1541: // Verify problems on metamodel assistants
1542: for (Iterator lModelAssistantsIterator = lModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
1543: .iterator(); lModelAssistantsIterator.hasNext();)
1544: lProblems
1545: .addAll(((ModelAssistant) lModelAssistantsIterator
1546: .next())
1547: .verifyConstraints(pModelName));
1548: if (!lProblems.isEmpty())
1549: throw new ModelValidationException(
1550: "Errors occurred during validation of the '"
1551: + pModelName
1552: + "' model. Unable to save it.",
1553: (JmiException[]) lProblems
1554: .toArray(new JmiException[lProblems
1555: .size()]));
1556: }
1557: ModelUpdatePlan lModelUpdatePlan = createModelUpdatePlan(lModelDescriptor);
1558:
1559: // At this point we have collected all info about what is required to be
1560: // created, deleted and updated. Lets do it !
1561: XMIWriter lPartitionedXMIWriter = XMIWriterFactory
1562: .getDefault().createXMIWriter();
1563: lPartitionedXMIWriter
1564: .getConfiguration()
1565: .setReferenceProvider(
1566: lModelUpdatePlan.UpdateXMIReferenceProvider);
1567: // Delete all partitions
1568: for (Iterator lPartitionsToDeleteIterator = lModelUpdatePlan.PartitionsToDelete
1569: .iterator(); lPartitionsToDeleteIterator.hasNext();) {
1570: String lURIToDelete = (String) lPartitionsToDeleteIterator
1571: .next();
1572: File lFileToDelete = new File(
1573: lModelDescriptor.ModelRootDirectory
1574: .getAbsolutePath()
1575: + lURIToDelete);
1576: if (!lFileToDelete.delete())
1577: throw new ModelRepositoryException(
1578: "Unable to delete "
1579: + lFileToDelete.getAbsolutePath()
1580: + " file");
1581: }
1582: // Create all partitions
1583: for (Iterator lPartitionsToCreateIterator = lModelUpdatePlan.PartitionsToCreate
1584: .iterator(); lPartitionsToCreateIterator.hasNext();) {
1585: String lURIToCreate = (String) lPartitionsToCreateIterator
1586: .next();
1587: File lFileToCreate = new File(
1588: lModelDescriptor.ModelRootDirectory
1589: .getAbsolutePath()
1590: + lURIToCreate);
1591: if (lFileToCreate.exists())
1592: throw new ModelRepositoryException("File "
1593: + lFileToCreate.getAbsolutePath()
1594: + " already exists");
1595: lFileToCreate.getParentFile().mkdirs();
1596: try {
1597: FileOutputStream lFileOutputStream = null;
1598: try {
1599: lFileOutputStream = new FileOutputStream(
1600: lFileToCreate);
1601: lPartitionedXMIWriter.write(lFileOutputStream,
1602: lURIToCreate,
1603: lModelDescriptor.ModelExtent, "1.2");
1604: lFileOutputStream.flush();
1605: } finally {
1606: if (lFileOutputStream != null)
1607: lFileOutputStream.close();
1608: }
1609: } catch (IOException e) {
1610: throw new ModelRepositoryException(
1611: "Error creating " + lFileToCreate
1612: + " model file.", e);
1613: }
1614: }
1615: // Update all partitions
1616: for (Iterator lPartitionsToUpdateIterator = lModelUpdatePlan.PartitionsToUpdate
1617: .iterator(); lPartitionsToUpdateIterator.hasNext();) {
1618: String lURIToUpdate = (String) lPartitionsToUpdateIterator
1619: .next();
1620: File lFileToUpdate = new File(
1621: lModelDescriptor.ModelRootDirectory
1622: .getAbsolutePath()
1623: + lURIToUpdate);
1624: if (!lFileToUpdate.exists())
1625: throw new ModelRepositoryException("File "
1626: + lFileToUpdate.getAbsolutePath()
1627: + " does not exist");
1628: try {
1629: FileOutputStream lFileOutputStream = null;
1630: try {
1631: lFileOutputStream = new FileOutputStream(
1632: lFileToUpdate);
1633: lPartitionedXMIWriter.write(lFileOutputStream,
1634: lURIToUpdate,
1635: lModelDescriptor.ModelExtent, "1.2");
1636: lFileOutputStream.flush();
1637: } finally {
1638: if (lFileOutputStream != null)
1639: lFileOutputStream.close();
1640: }
1641: } catch (IOException e) {
1642: throw new ModelRepositoryException(
1643: "Error updating " + lFileToUpdate
1644: + " model file.", e);
1645: }
1646: }
1647: // Move all planned attachments
1648: for (Iterator lAttachmentsToMoveIterator = lModelUpdatePlan.AttachmentsToMove
1649: .entrySet().iterator(); lAttachmentsToMoveIterator
1650: .hasNext();) {
1651: Map.Entry lMoveInstruction = (Map.Entry) lAttachmentsToMoveIterator
1652: .next();
1653: String lNewAbsolutePath = (String) lMoveInstruction
1654: .getKey();
1655: String lOldAbsolutePath = (String) lMoveInstruction
1656: .getValue();
1657: try {
1658: FileUtils.moveFile(lOldAbsolutePath,
1659: lNewAbsolutePath);
1660: } catch (IOException e) {
1661: throw new ModelRepositoryException(
1662: "Error moving attachment file from "
1663: + lOldAbsolutePath + " to "
1664: + lNewAbsolutePath);
1665: }
1666: }
1667: // Delete all planned attachments
1668: for (Iterator lAttachmentsToDeleteIterator = lModelUpdatePlan.AttachmentsToDelete
1669: .iterator(); lAttachmentsToDeleteIterator.hasNext();) {
1670: File lOldFile = new File(
1671: (String) lAttachmentsToDeleteIterator.next());
1672: if (!lOldFile.delete())
1673: throw new ModelRepositoryException(
1674: "Error deleting "
1675: + lOldFile.getAbsolutePath()
1676: + " attachment file.");
1677: }
1678: // Now update storage properties if necessary
1679: if (lModelUpdatePlan.UpdateStorageProperties) {
1680: if (!lModelDescriptor.ModelStorageProperties.isEmpty()) {
1681: try {
1682: OutputStream lModelStoragePropertiesOutputStream = null;
1683: try {
1684: lModelStoragePropertiesOutputStream = new FileOutputStream(
1685: lModelDescriptor.ModelStoragePropertiesFile);
1686: lModelDescriptor.ModelStorageProperties
1687: .store(
1688: lModelStoragePropertiesOutputStream,
1689: "Storage properties of the model");
1690: lModelStoragePropertiesOutputStream.flush();
1691: } finally {
1692: if (lModelStoragePropertiesOutputStream != null)
1693: lModelStoragePropertiesOutputStream
1694: .close();
1695: }
1696: } catch (IOException e) {
1697: throw new ModelRepositoryException(
1698: "Error writing "
1699: + lModelDescriptor.ModelStoragePropertiesFile
1700: .getAbsolutePath()
1701: + " file.", e);
1702: }
1703: } else
1704: lModelDescriptor.ModelStoragePropertiesFile
1705: .delete();
1706: }
1707: // Trim directory tree
1708: try {
1709: DirectoryUtils
1710: .trimDirectoryTree(lModelDescriptor.ModelRootDirectory
1711: .getAbsolutePath());
1712: } catch (IOException e) {
1713: throw new ModelRepositoryException("Error trimming "
1714: + lModelDescriptor.ModelRootDirectory
1715: .getAbsolutePath() + " directory.", e);
1716: }
1717: // Update maps to reflect new situation
1718: lModelDescriptor.PartitionsMap = lModelUpdatePlan.NewPartitionsMap;
1719: lModelDescriptor.ObjectAttachmentsMap = lModelUpdatePlan.NewObjectAttachmentsMap;
1720: lModelDescriptor.ModifiedObjectsSet.clear();
1721: lModelDescriptor.CreatedObjectsSet.clear();
1722: lModelDescriptor.DeletedObjectsSet.clear();
1723: }
1724: }
1725:
1726: /** Saves model at the location specified in this method call. */
1727: public void saveModelAs(String pModelName, boolean pValidateModel,
1728: File pNewModelRootFile,
1729: Properties pNewModelStorageProperties)
1730: throws ModelRepositoryException, ModelValidationException {
1731: //TODO: Impplement saveModelAs()
1732: }
1733:
1734: /** Saves default model at the location specified in this method call. */
1735: public void saveDefaultModelAs(boolean pValidateModel,
1736: File pNewModelRootFile,
1737: Properties pNewModelStorageProperties)
1738: throws ModelRepositoryException, ModelValidationException {
1739: //TODO: Impplement saveDefaultModelAs()
1740: }
1741:
1742: /** Helper. Creates ModelUpdatePlan for the moment.
1743: * Assumes that the repository is synchronised not closed and not in transaction
1744: * Uses default storage properties and threfore default XMI reference provider
1745: * @param pModelDescriptor the descriptor of the model to generate plan for
1746: * @exception ModelRepositoryException thrown if there was a problem with the saving the Model */
1747: public ModelUpdatePlan createModelUpdatePlan(
1748: ModelDescriptor pModelDescriptor)
1749: throws ModelRepositoryException {
1750: ModelUpdatePlan lModelUpdatePlan = new ModelUpdatePlan();
1751: // Build new ObjectsInPartitions map as it should be after the save
1752: lModelUpdatePlan.UpdateXMIReferenceProvider = new XMIReferenceProviderImpl(
1753: pModelDescriptor.ModelRootURI,
1754: pModelDescriptor.ModelStorageProperties,
1755: pModelDescriptor.XmiIdGenerator);
1756: RefObject[] lAllObjects = ModelRepositoryUtils
1757: .getAllInstancesInPackage(pModelDescriptor.ModelExtent);
1758: lModelUpdatePlan.NewPartitionsMap = buildPartitionsMap(
1759: lAllObjects,
1760: lModelUpdatePlan.UpdateXMIReferenceProvider);
1761: SortedMap lModelAttachmentUpdateDescriptorMap = buildObjectAttachmentsMapBeforeSave(
1762: lAllObjects,
1763: lModelUpdatePlan.UpdateXMIReferenceProvider,
1764: pModelDescriptor.ModelRootDirectory,
1765: pModelDescriptor.UnsavedAttachedFilesDir,
1766: pModelDescriptor.ObjectAttachmentsMap.keySet());
1767: // Deal with xmi storage files
1768: // Iterate through alphabetically sorted lists of existing files and proposed files
1769: // As the result find out partitions to be created, to be deleted or to be updated
1770: {
1771: lModelUpdatePlan.PartitionsToDelete = new HashSet();
1772: lModelUpdatePlan.PartitionsToCreate = new HashSet();
1773: lModelUpdatePlan.PartitionsToUpdate = new HashSet();
1774: Iterator lExistingPartitionsIter = pModelDescriptor.PartitionsMap
1775: .entrySet().iterator();
1776: Iterator lProposedPartitionsIter = lModelUpdatePlan.NewPartitionsMap
1777: .entrySet().iterator();
1778: Map.Entry lExistingPartitionEntry = null;
1779: Map.Entry lProposedPartitionEntry = null;
1780: while (lExistingPartitionEntry != null
1781: || lExistingPartitionsIter.hasNext()
1782: || lProposedPartitionEntry != null
1783: || lProposedPartitionsIter.hasNext()) {
1784: // Get next partition entries if necessary
1785: if (lExistingPartitionEntry == null
1786: && lExistingPartitionsIter.hasNext())
1787: lExistingPartitionEntry = (Map.Entry) lExistingPartitionsIter
1788: .next();
1789: if (lProposedPartitionEntry == null
1790: && lProposedPartitionsIter.hasNext())
1791: lProposedPartitionEntry = (Map.Entry) lProposedPartitionsIter
1792: .next();
1793: // Work out if we have both.
1794: if (lExistingPartitionEntry != null
1795: && lProposedPartitionEntry != null) {
1796: String lExistingPartitionPath = (String) lExistingPartitionEntry
1797: .getKey();
1798: String lProposedPartitionPath = (String) lProposedPartitionEntry
1799: .getKey();
1800: int lCompareResult = lExistingPartitionPath
1801: .compareTo(lProposedPartitionPath);
1802: if (lCompareResult < 0) {
1803: // Existing partition must be deleted because it does not exist in the proposed ones
1804: lModelUpdatePlan.PartitionsToDelete
1805: .add(lExistingPartitionPath);
1806: lExistingPartitionEntry = null; // Processed existing partition entry
1807: } else if (lCompareResult > 0) {
1808: // Proposed partition must be created because it does not exist in the existing ones
1809: lModelUpdatePlan.PartitionsToCreate
1810: .add(lProposedPartitionPath);
1811: lProposedPartitionEntry = null; // Processed proposed partition entry
1812: } else {
1813: // Partitions are equal. Still partition may have to be updated
1814: // Find out if there is any difference in partition contents and if objects are changed or not
1815: // first hit to any discrepancy means that partition has to be updated
1816:
1817: SortedSet lExistingPartitionContent = (SortedSet) ((ModelPartitionDescriptor) lExistingPartitionEntry
1818: .getValue()).ContentsXmiIds;
1819: SortedSet lExistingPartitionReferences = (SortedSet) ((ModelPartitionDescriptor) lExistingPartitionEntry
1820: .getValue()).ReferenceDescriptors;
1821: SortedSet lProposedPartitionContent = (SortedSet) ((ModelPartitionDescriptor) lProposedPartitionEntry
1822: .getValue()).ContentsXmiIds;
1823: SortedSet lProposedPartitionReferences = (SortedSet) ((ModelPartitionDescriptor) lProposedPartitionEntry
1824: .getValue()).ReferenceDescriptors;
1825: boolean lPartititionsAreTheSame = true;
1826: // If content is different - partitons are different
1827: if (lExistingPartitionContent
1828: .equals(lProposedPartitionContent) == false) {
1829: // Content is differnt - partitons are different
1830: lPartititionsAreTheSame = false;
1831: } else
1832: // If list of references is different - partitons are different
1833: if (lExistingPartitionReferences
1834: .equals(lProposedPartitionReferences) == false) {
1835: // Lists of references are different - partitons are different
1836: lPartititionsAreTheSame = false;
1837: } else
1838: // If there are modified elements - partititons are different
1839: if (CollectionUtils.containsAny(
1840: pModelDescriptor.ModifiedObjectsSet,
1841: lProposedPartitionContent)) {
1842: // There appears to be modified elements - partititons are different
1843: lPartititionsAreTheSame = false;
1844: }
1845: // Old way - trying to replace that by use of equals()
1846: // if ((lExistingPartitionContent.size() != lProposedPartitionContent.size()) ||
1847: // (lExistingPartitionReferences.size() != lProposedPartitionReferences.size()))
1848: // {
1849: // // Size not equal - definitiely partiton needs updating
1850: // lPartititionsAreTheSame = false;
1851: // }
1852: // else
1853: // {
1854: // // Size equals - need to compare entries one by one. We will iterate through
1855: // // to sorted maps looking for any mismatch
1856: // Iterator lExistingPartitionXmiIdsIter = lExistingPartitionContent.iterator();
1857: // Iterator lProposedPartitionXmiIdsIter = lProposedPartitionContent.iterator();
1858: // String lExistingPartitionObjectXmiId = null;
1859: // String lProposedPartitionObjectXmiId = null;
1860: // while(lExistingPartitionObjectXmiId != null || lExistingPartitionXmiIdsIter.hasNext() ||
1861: // lProposedPartitionObjectXmiId != null || lProposedPartitionXmiIdsIter.hasNext())
1862: // {
1863: // // Get next entries if necessary
1864: // if (lExistingPartitionObjectXmiId == null && lExistingPartitionXmiIdsIter.hasNext())
1865: // lExistingPartitionObjectXmiId = (String)lExistingPartitionXmiIdsIter.next();
1866: // if (lProposedPartitionObjectXmiId == null && lProposedPartitionXmiIdsIter.hasNext())
1867: // lProposedPartitionObjectXmiId = (String)lProposedPartitionXmiIdsIter.next();
1868: // if (lExistingPartitionObjectXmiId == null || lProposedPartitionObjectXmiId == null || lExistingPartitionObjectXmiId.equals(lProposedPartitionObjectXmiId) == false)
1869: // {
1870: // // One of the entries is null or entries are not equal. This can not occur in sorted set
1871: // // unless two sets are not the same. We have found mismatch
1872: // lPartititionsAreTheSame = false;
1873: // break;
1874: // }
1875: // // We have got two same ids at the same position. See if they have been modified
1876: // if (pModelDescriptor.ModifiedObjectsSet.contains(lExistingPartitionObjectXmiId))
1877: // {
1878: // // Changes map had an entry for this object. This means that it has been changed
1879: // // We have found mismatch.
1880: // lPartititionsAreTheSame = false;
1881: // break;
1882: // }
1883: // // Clean considered partitions
1884: // lExistingPartitionObjectXmiId = null;
1885: // lProposedPartitionObjectXmiId = null;
1886: // }
1887: // }
1888: // If partitons are not the same - schedule for update
1889: if (!lPartititionsAreTheSame)
1890: lModelUpdatePlan.PartitionsToUpdate
1891: .add(lProposedPartitionPath);
1892: // In any case this entry is processed
1893: lExistingPartitionEntry = null; // Processed existing partition entry
1894: lProposedPartitionEntry = null; // Processed proposed partition entry
1895: }
1896: } else if (lExistingPartitionEntry != null) {
1897: String lExistingPartitionPath = (String) lExistingPartitionEntry
1898: .getKey();
1899: // Existing partition must be deleted because it does not exist in the proposed ones
1900: lModelUpdatePlan.PartitionsToDelete
1901: .add(lExistingPartitionPath);
1902: lExistingPartitionEntry = null; // Processed existing partition entry
1903: } else if (lProposedPartitionEntry != null) {
1904: String lProposedPartitionPath = (String) lProposedPartitionEntry
1905: .getKey();
1906: // Proposed partition must be created because it does not exist in the existing ones
1907: lModelUpdatePlan.PartitionsToCreate
1908: .add(lProposedPartitionPath);
1909: lProposedPartitionEntry = null; // Processed proposed partition entry
1910: }
1911: }
1912: // Now we have gone through first iteration - compared existing and proposed
1913: // partiton maps and marked partitions for create,update,delete. Now we have to make sure
1914: // that all depending partiotns of all partitions which are being created are
1915: // at least updated. This means that they should be put into the to be updated plan if they are not
1916: // themselves being deleted or created. This is because partition to be created may be a result
1917: // of the change to the objects inside (which in turn have triggered path change).
1918: // So in fact it may have been a rename.
1919:
1920: // // Work on partitons to be created first
1921: // {
1922: // // Build the set of partititions to check
1923: // Set lDependingPaths = new HashSet();
1924: // for (Iterator lPathsToCreateIterator = lModelUpdatePlan.PartitionsToCreate.iterator();lPathsToCreateIterator.hasNext();)
1925: // {
1926: // String lPathToCreate = (String)lPathsToCreateIterator.next();
1927: // ModelPartitionDescriptor lPartitionDescriptor = (ModelPartitionDescriptor)lModelUpdatePlan.NewPartitionsMap.get(lPathToCreate);
1928: // lDependingPaths.addAll(lPartitionDescriptor.ReferenceDescriptors);
1929: // }
1930: // // Now put them in to be updated pile if they are not in the created or deleted pile
1931: // for (Iterator lDependingPathsIterator = lDependingPaths.iterator();lDependingPathsIterator.hasNext();)
1932: // {
1933: // String lPathToUpdate = (String)lDependingPathsIterator.next();
1934: // if (lModelUpdatePlan.PartitionsToCreate.contains(lPathToUpdate) == false &&
1935: // lModelUpdatePlan.PartitionsToUpdate.contains(lPathToUpdate) == false &&
1936: // lModelUpdatePlan.PartitionsToDelete.contains(lPathToUpdate) == false)
1937: // {
1938: // // Partition will be updated
1939: // lModelUpdatePlan.PartitionsToUpdate.add(lPathToUpdate);
1940: // }
1941: // }
1942: // }
1943: }
1944: // Deal with attachments
1945: {
1946: lModelUpdatePlan.AttachmentsToDelete = new HashSet(); // Absolute pathes of attachment files to be deleted
1947: lModelUpdatePlan.AttachmentsToMove = new HashMap(); // Keys - Absolute pathes of the new location of attachment files. Values - Absolute pathes to the old location of the Atachment files
1948:
1949: Iterator lExistingAttachmentsIter = pModelDescriptor.ObjectAttachmentsMap
1950: .entrySet().iterator();
1951: Iterator lProposedAttachmentsIter = lModelAttachmentUpdateDescriptorMap
1952: .entrySet().iterator();
1953: Map.Entry lExistingAttachmentEntry = null;
1954: Map.Entry lProposedAttachmentEntry = null;
1955: while (lExistingAttachmentEntry != null
1956: || lExistingAttachmentsIter.hasNext()
1957: || lProposedAttachmentEntry != null
1958: || lProposedAttachmentsIter.hasNext()) {
1959: // Get next attachment entries if necessary
1960: if (lExistingAttachmentEntry == null
1961: && lExistingAttachmentsIter.hasNext())
1962: lExistingAttachmentEntry = (Map.Entry) lExistingAttachmentsIter
1963: .next();
1964: if (lProposedAttachmentEntry == null
1965: && lProposedAttachmentsIter.hasNext())
1966: lProposedAttachmentEntry = (Map.Entry) lProposedAttachmentsIter
1967: .next();
1968: // Work out if we have both.
1969: if (lExistingAttachmentEntry != null
1970: && lProposedAttachmentEntry != null) {
1971: String lExistingAttachmentXmiId = (String) lExistingAttachmentEntry
1972: .getKey();
1973: String lProposedAttachmentXmiId = (String) lProposedAttachmentEntry
1974: .getKey();
1975: int lCompareResult = lExistingAttachmentXmiId
1976: .compareTo(lProposedAttachmentXmiId);
1977: if (lCompareResult < 0) {
1978: // Existing attachment must be deleted because it is not mentioned in the proposed ones
1979: File lExistingAttachmentFile = new File(
1980: pModelDescriptor.ModelRootDirectory
1981: .getAbsolutePath()
1982: + (String) lExistingAttachmentEntry
1983: .getValue());
1984: lModelUpdatePlan.AttachmentsToDelete
1985: .add(lExistingAttachmentFile
1986: .getAbsolutePath());
1987: lExistingAttachmentEntry = null; // Processed existing partition entry
1988: } else if (lCompareResult > 0) {
1989: // Proposed attachment must be moved from saved area because it does not exist in the existing ones
1990: ModelAttachmentUpdateDescriptor lAttachmentUpdateDescriptor = (ModelAttachmentUpdateDescriptor) lProposedAttachmentEntry
1991: .getValue();
1992: File lUnsavedProposedAttachmentFile = new File(
1993: lAttachmentUpdateDescriptor.UnsavedCopyPath);
1994: File lSavedProposedAttachmentFile = new File(
1995: pModelDescriptor.ModelRootDirectory
1996: .getAbsolutePath()
1997: + lAttachmentUpdateDescriptor.SavedCopyPath);
1998: lModelUpdatePlan.AttachmentsToMove.put(
1999: lSavedProposedAttachmentFile
2000: .getAbsolutePath(),
2001: lUnsavedProposedAttachmentFile
2002: .getAbsolutePath());
2003: lProposedAttachmentEntry = null; // Processed proposed partition entry
2004: } else {
2005: // Attachment is mentioned in both existing and proposed lists
2006: // Still, we may have to do some work on attachment if it has changed or moved
2007: String lExistingAttachmentPath = (String) lExistingAttachmentEntry
2008: .getValue();
2009: ModelAttachmentUpdateDescriptor lAttachmentUpdateDescriptor = (ModelAttachmentUpdateDescriptor) lProposedAttachmentEntry
2010: .getValue();
2011: if (lAttachmentUpdateDescriptor.UnsavedCopyPath != null) {
2012: // We have an unsaved copy of the attachment. Create move command
2013: File lUnsavedProposedAttachmentFile = new File(
2014: lAttachmentUpdateDescriptor.UnsavedCopyPath);
2015: File lSavedProposedAttachmentFile = new File(
2016: pModelDescriptor.ModelRootDirectory
2017: .getAbsolutePath()
2018: + lAttachmentUpdateDescriptor.SavedCopyPath);
2019: lModelUpdatePlan.AttachmentsToMove.put(
2020: lSavedProposedAttachmentFile
2021: .getAbsolutePath(),
2022: lUnsavedProposedAttachmentFile
2023: .getAbsolutePath());
2024: // There is a possibility that the attachment has also been moved as well as updated
2025: // in this case all we have to do is to delete the existing copy (remember it is not use
2026: // because we have just saved updated copy)
2027: if (!lExistingAttachmentPath
2028: .equals(lAttachmentUpdateDescriptor.SavedCopyPath)) {
2029: // Attachment has also been moved - delete the old atachment at the old location
2030: File lExistingAttachmentFile = new File(
2031: pModelDescriptor.ModelRootDirectory
2032: .getAbsolutePath()
2033: + lExistingAttachmentPath);
2034: lModelUpdatePlan.AttachmentsToDelete
2035: .add(lExistingAttachmentFile
2036: .getAbsolutePath());
2037: }
2038: } else
2039: // Check if existing copy was moved without actually being edited
2040: if (!lExistingAttachmentPath
2041: .equals(lAttachmentUpdateDescriptor.SavedCopyPath)) {
2042: // Yes it has. Organise movement of the old file to the new location
2043: File lOldAttachmentFile = new File(
2044: pModelDescriptor.ModelRootDirectory
2045: .getAbsolutePath()
2046: + lExistingAttachmentPath);
2047: File lNewAttachmentFile = new File(
2048: pModelDescriptor.ModelRootDirectory
2049: .getAbsolutePath()
2050: + lAttachmentUpdateDescriptor.SavedCopyPath);
2051: lModelUpdatePlan.AttachmentsToMove.put(
2052: lNewAttachmentFile
2053: .getAbsolutePath(),
2054: lOldAttachmentFile
2055: .getAbsolutePath());
2056: }
2057: lProposedAttachmentEntry = null; // Processed proposed partition entry
2058: lExistingAttachmentEntry = null; // Processed existing partition entry
2059: }
2060: } else if (lExistingAttachmentEntry != null) {
2061: // Existing attachment must be deleted because it is not mentioned in the proposed ones
2062: File lExistingAttachmentFile = new File(
2063: pModelDescriptor.ModelRootDirectory
2064: .getAbsolutePath()
2065: + (String) lExistingAttachmentEntry
2066: .getValue());
2067: lModelUpdatePlan.AttachmentsToDelete
2068: .add(lExistingAttachmentFile
2069: .getAbsolutePath());
2070: lExistingAttachmentEntry = null; // Processed existing partition entry
2071: } else if (lProposedAttachmentEntry != null) {
2072: // Proposed attachment must be moved from saved area because it does not exist in the existing ones
2073: ModelAttachmentUpdateDescriptor lAttachmentUpdateDescriptor = (ModelAttachmentUpdateDescriptor) lProposedAttachmentEntry
2074: .getValue();
2075: File lUnsavedProposedAttachmentFile = new File(
2076: lAttachmentUpdateDescriptor.UnsavedCopyPath);
2077: File lSavedProposedAttachmentFile = new File(
2078: pModelDescriptor.ModelRootDirectory
2079: .getAbsolutePath()
2080: + lAttachmentUpdateDescriptor.SavedCopyPath);
2081: lModelUpdatePlan.AttachmentsToMove.put(
2082: lSavedProposedAttachmentFile
2083: .getAbsolutePath(),
2084: lUnsavedProposedAttachmentFile
2085: .getAbsolutePath());
2086: lProposedAttachmentEntry = null; // Processed proposed partition entry
2087: }
2088: }
2089: }
2090: // Populate proposed object attachments map with just resulting paths
2091: lModelUpdatePlan.NewObjectAttachmentsMap = new TreeMap();
2092: for (Iterator lIter = lModelAttachmentUpdateDescriptorMap
2093: .entrySet().iterator(); lIter.hasNext();) {
2094: Map.Entry lProposedAttachmentEntry = (Map.Entry) lIter
2095: .next();
2096: lModelUpdatePlan.NewObjectAttachmentsMap
2097: .put(
2098: lProposedAttachmentEntry.getKey(),
2099: ((ModelAttachmentUpdateDescriptor) lProposedAttachmentEntry
2100: .getValue()).SavedCopyPath);
2101: }
2102:
2103: // Deal with storage properties file
2104: if (pModelDescriptor.ModelStoragePropertiesFile.exists()) {
2105: try {
2106: InputStream lModelStoragePropertiesInputStream = null;
2107: try {
2108: lModelStoragePropertiesInputStream = new FileInputStream(
2109: pModelDescriptor.ModelStoragePropertiesFile);
2110: Properties lStoredProperties = new Properties();
2111: lStoredProperties
2112: .load(lModelStoragePropertiesInputStream);
2113: lModelUpdatePlan.UpdateStorageProperties = (!lStoredProperties
2114: .equals(pModelDescriptor.ModelStorageProperties));
2115: } finally {
2116: if (lModelStoragePropertiesInputStream != null)
2117: lModelStoragePropertiesInputStream.close();
2118: }
2119: } catch (IOException e) {
2120: throw new ModelRepositoryException("Error reading "
2121: + pModelDescriptor.ModelStoragePropertiesFile
2122: .getAbsolutePath() + " file.", e);
2123: }
2124: } else {
2125: // File does not exist. Only need to update if there is anything to save
2126: lModelUpdatePlan.UpdateStorageProperties = (!pModelDescriptor.ModelStorageProperties
2127: .isEmpty());
2128: }
2129: return lModelUpdatePlan;
2130: }
2131:
2132: /** Helper. Creates ModelUpdatePlan for the moment.
2133: * Assumes that the repository is synchronised not closed and not in transaction
2134: * Uses default storage properties and threfore default XMI reference provider
2135: * @param pModelDescriptor the descriptor of the model to generate plan for
2136: * @exception ModelRepositoryException thrown if there was a problem with the saving the Model */
2137: public ModelExportPlan createModelExportPlan(
2138: ModelDescriptor pModelDescriptor,
2139: File pTargetModelRootFile,
2140: Properties pTargetStorageProperties)
2141: throws ModelRepositoryException {
2142: String lTargetModelModelRootURI = "/"
2143: + pTargetModelRootFile.getAbsoluteFile().getName();
2144: ModelExportPlan lModelExportPlan = new ModelExportPlan();
2145: lModelExportPlan.TargetRootDirectoryAbsolutePath = pTargetModelRootFile
2146: .getAbsoluteFile().getParentFile().getAbsolutePath();
2147: lModelExportPlan.ModelStoragePropertiesFile = new File(
2148: lModelExportPlan.TargetRootDirectoryAbsolutePath
2149: + File.separator + "storage.properties");
2150:
2151: // Build new ObjectsInPartitions map as it should be after the save
2152: lModelExportPlan.ExportXMIReferenceProvider = new XMIReferenceProviderImpl(
2153: lTargetModelModelRootURI,
2154: pTargetStorageProperties != null ? pTargetStorageProperties
2155: : pModelDescriptor.ModelStorageProperties,
2156: pModelDescriptor.XmiIdGenerator);
2157: RefObject[] lAllObjects = ModelRepositoryUtils
2158: .getAllInstancesInPackage(pModelDescriptor.ModelExtent);
2159: // TODO: Remove the comment
2160: //System.out.println("Found " + lAllObjects.length + " objects");
2161: //for (int i = 0; i < lAllObjects.length; i++)
2162: //{
2163: // RefObject lRefObject = lAllObjects[i];
2164: // if (lRefObject instanceof com.metaboss.sdlctools.models.metabossmodel.ModelElement)
2165: // System.out.println("ModelElement #" + Integer.toString(i+1) + ". Ref: " + ((com.metaboss.sdlctools.models.metabossmodel.ModelElement)lRefObject).getRef());
2166: // else
2167: // System.out.println("RefObject #" + Integer.toString(i+1) + ". Class: " + lRefObject.getClass().getName() + " Type: " + lRefObject.refMetaObject().refGetValue("name"));
2168: //}
2169: SortedMap lObjectsInPartitionsMap = buildPartitionsMap(
2170: lAllObjects,
2171: lModelExportPlan.ExportXMIReferenceProvider);
2172: // Deal with xmi storage files
2173: {
2174: lModelExportPlan.PartitionsToCreate = new HashSet();
2175: for (Iterator lProposedPartitionsIter = lObjectsInPartitionsMap
2176: .entrySet().iterator(); lProposedPartitionsIter
2177: .hasNext();) {
2178: Map.Entry lProposedPartitionEntry = (Map.Entry) lProposedPartitionsIter
2179: .next();
2180: String lProposedPartitionPath = (String) lProposedPartitionEntry
2181: .getKey();
2182: // Proposed partition must be created because it does not exist in the existing ones
2183: lModelExportPlan.PartitionsToCreate
2184: .add(lProposedPartitionPath);
2185: }
2186: }
2187: // Deal with attachments
2188: {
2189: String lModelUnsavedAttachedFilesDirPath = pModelDescriptor.UnsavedAttachedFilesDir
2190: .getAbsolutePath();
2191: XMIReferenceProvider lSourceXMIReferenceProvider = new XMIReferenceProviderImpl(
2192: pModelDescriptor.ModelRootURI,
2193: pModelDescriptor.ModelStorageProperties,
2194: pModelDescriptor.XmiIdGenerator);
2195: lModelExportPlan.AttachmentsToCopy = new HashMap(); // Keys - Absolute pathes of the target location of attachment files. Values - Absolute pathes to the source location of the Atachment files
2196: for (int i = 0; i < lAllObjects.length; i++) {
2197: RefObject lObject = lAllObjects[i];
2198: XMIReferenceProvider.XMIReference lSourceXMIReference = lSourceXMIReferenceProvider
2199: .getReference(lObject);
2200: String lSourceDataFileName = lSourceXMIReference
2201: .getXmiId()
2202: + ".dat";
2203: String lSourceDeleteMarkerFileName = lSourceXMIReference
2204: .getXmiId()
2205: + ".del";
2206: File lSourceAttachmentFile = null;
2207: {
2208: // Ensure that we do not have an unsaved deletion marker
2209: File lUnsavedDeletedMarkerFile = new File(
2210: lModelUnsavedAttachedFilesDirPath
2211: + File.separator
2212: + lSourceDeleteMarkerFileName);
2213: if (!lUnsavedDeletedMarkerFile.exists()) {
2214: File lUpdatedAttachmentFile = new File(
2215: lModelUnsavedAttachedFilesDirPath
2216: + File.separator
2217: + lSourceDataFileName);
2218: if (lUpdatedAttachmentFile.exists()) {
2219: lSourceAttachmentFile = lUpdatedAttachmentFile
2220: .getAbsoluteFile();
2221: } else if (pModelDescriptor.ModelRootDirectory != null) {
2222: File lExistingAttachmentFile = new File(
2223: new File(
2224: pModelDescriptor.ModelRootDirectory
2225: .getAbsolutePath()
2226: + lSourceXMIReference
2227: .getSystemId())
2228: .getParent()
2229: + File.separator
2230: + lSourceDataFileName);
2231: if (lExistingAttachmentFile.exists())
2232: lSourceAttachmentFile = lExistingAttachmentFile
2233: .getAbsoluteFile();
2234: }
2235: }
2236: }
2237: // If there is something to copy - copy it
2238: if (lSourceAttachmentFile != null) {
2239: XMIReferenceProvider.XMIReference lTargetXMIReference = lModelExportPlan.ExportXMIReferenceProvider
2240: .getReference(lObject);
2241: String lTargetDataFileName = lTargetXMIReference
2242: .getXmiId()
2243: + ".dat";
2244: File lTargetAttachmentFile = new File(
2245: new File(
2246: lModelExportPlan.TargetRootDirectoryAbsolutePath
2247: + lTargetXMIReference
2248: .getSystemId())
2249: .getParent()
2250: + File.separator
2251: + lTargetDataFileName);
2252: lModelExportPlan.AttachmentsToCopy.put(
2253: lTargetAttachmentFile.getAbsolutePath(),
2254: lSourceAttachmentFile.getAbsolutePath());
2255: }
2256: }
2257: }
2258: return lModelExportPlan;
2259: }
2260:
2261: // Build a map with key - partiton name and value - sorted set of object xmi ids
2262: private static SortedMap buildPartitionsMap(
2263: RefObject[] pAllObjects,
2264: XMIReferenceProvider pXMIReferenceProvider)
2265: throws ModelRepositoryException {
2266: TreeMap lPartitionsMap = new TreeMap();
2267: for (int i = 0; i < pAllObjects.length; i++) {
2268: RefObject lObject = pAllObjects[i];
2269: XMIReferenceProvider.XMIReference lObjectReference = pXMIReferenceProvider
2270: .getReference(lObject);
2271: ModelPartitionDescriptor lPartitionDescriptor = (ModelPartitionDescriptor) lPartitionsMap
2272: .get(lObjectReference.getSystemId());
2273: if (lPartitionDescriptor == null) {
2274: lPartitionDescriptor = new ModelPartitionDescriptor();
2275: lPartitionDescriptor.SystemId = lObjectReference
2276: .getSystemId();
2277: lPartitionsMap.put(lObjectReference.getSystemId(),
2278: lPartitionDescriptor);
2279: }
2280: lPartitionDescriptor.ContentsXmiIds.add(lObjectReference
2281: .getXmiId());
2282: // Record all references from this object to any other object in the model
2283: Collection lAllReferences = ModelRepositoryUtils
2284: .getReferencedElements(lObject);
2285: for (Iterator lReferencesIterator = lAllReferences
2286: .iterator(); lReferencesIterator.hasNext();) {
2287: RefObject lReferencedObject = (RefObject) lReferencesIterator
2288: .next();
2289: // Get the xmi reference of the parent and see if it is located in different partition
2290: XMIReferenceProvider.XMIReference lReferencedObjectReference = pXMIReferenceProvider
2291: .getReference(lReferencedObject);
2292: String lReferencedObjectHRef = lReferencedObjectReference
2293: .getSystemId()
2294: + ":" + lReferencedObjectReference.getXmiId();
2295: lPartitionDescriptor.ReferenceDescriptors
2296: .add(lObjectReference.getXmiId() + "->"
2297: + lReferencedObjectHRef);
2298: }
2299: }
2300: return lPartitionsMap;
2301: }
2302:
2303: // Build a map with key - partiton name and value - sorted set of object xmi ids
2304: // It will consider uncommitted and unsaved directories if they are given
2305: private static SortedMap buildObjectAttachmentsMapAfterRead(
2306: RefObject[] pAllObjects,
2307: XMIReferenceProvider pXMIReferenceProvider,
2308: File pModelRootDirectory) throws ModelRepositoryException {
2309: TreeMap lObjectAttachmentsMap = new TreeMap();
2310: String lModelRootDirectoryAbsolutePath = pModelRootDirectory
2311: .getAbsolutePath();
2312: int lModelRootDirectoryAbsolutePathLength = lModelRootDirectoryAbsolutePath
2313: .length();
2314: // Internal class, which filters attachments file for the given object
2315: FileFilter lAttachmentFileFilter = new FileFilter() {
2316: public boolean accept(File pCandidateFile) {
2317: return pCandidateFile.isFile()
2318: && pCandidateFile.getName().endsWith(".dat");
2319: }
2320: };
2321: // We will cache information about partitions and attachment files inside this method
2322: // in order to speed up the mappling process. The cache will not survive this method, so next time
2323: // partition map will have to be built again
2324: Map lPartitions = new HashMap();
2325: for (int i = 0; i < pAllObjects.length; i++) {
2326: RefObject lObject = pAllObjects[i];
2327: XMIReferenceProvider.XMIReference lXMIReference = pXMIReferenceProvider
2328: .getReference(lObject);
2329: Map lFiles = (Map) lPartitions.get(lXMIReference
2330: .getSystemId());
2331: if (lFiles == null) {
2332: lPartitions.put(lXMIReference.getSystemId(),
2333: lFiles = new HashMap());
2334: File lAttachmentDirectory = new File(
2335: lModelRootDirectoryAbsolutePath
2336: + lXMIReference.getSystemId())
2337: .getParentFile();
2338: File[] lAttachmentFiles = lAttachmentDirectory
2339: .listFiles(lAttachmentFileFilter);
2340: if (lAttachmentFiles != null) {
2341: for (int j = 0; j < lAttachmentFiles.length; j++) {
2342: File lAttachmentFile = lAttachmentFiles[j];
2343: lFiles
2344: .put(
2345: lAttachmentFile.getName(),
2346: lAttachmentFile
2347: .getAbsolutePath()
2348: .substring(
2349: lModelRootDirectoryAbsolutePathLength));
2350: }
2351: }
2352: }
2353: String lRelativeAttachmentPath = (String) lFiles
2354: .get(lXMIReference.getXmiId() + ".dat");
2355: if (lRelativeAttachmentPath != null)
2356: lObjectAttachmentsMap.put(lXMIReference.getXmiId(),
2357: lRelativeAttachmentPath);
2358: }
2359: return lObjectAttachmentsMap;
2360: }
2361:
2362: // Build a map with key - XmiId of the object this attachment belongs to
2363: // and value - ModelAttachmentUpdateDescriptor
2364: private static SortedMap buildObjectAttachmentsMapBeforeSave(
2365: RefObject[] pAllObjects,
2366: XMIReferenceProvider pXMIReferenceProvider,
2367: File pModelRootDirectory,
2368: File pUnsavedAttachmentsDirectory,
2369: Set pXmiIdsOfPreexistingAtachments)
2370: throws ModelRepositoryException {
2371: TreeMap lObjectAttachmentsMap = new TreeMap();
2372: String lModelRootDirectoryAbsolutePath = pModelRootDirectory
2373: .getAbsolutePath();
2374: int lModelRootDirectoryAbsolutePathLength = lModelRootDirectoryAbsolutePath
2375: .length();
2376: for (int i = 0; i < pAllObjects.length; i++) {
2377: RefObject lObject = pAllObjects[i];
2378: XMIReferenceProvider.XMIReference lXMIReference = pXMIReferenceProvider
2379: .getReference(lObject);
2380: String lDataFileName = lXMIReference.getXmiId() + ".dat";
2381: String lDeleteMarkerFileName = lXMIReference.getXmiId()
2382: + ".del";
2383: // Work with unsaved first
2384: File lUnsavedDeletedMarkerFile = new File(
2385: pUnsavedAttachmentsDirectory.getAbsolutePath()
2386: + File.separator + lDeleteMarkerFileName);
2387: if (!lUnsavedDeletedMarkerFile.exists()) {
2388: File lUnsavedAttachmentChangeFile = new File(
2389: pUnsavedAttachmentsDirectory.getAbsolutePath()
2390: + File.separator + lDataFileName);
2391: if (lUnsavedAttachmentChangeFile.exists()
2392: || pXmiIdsOfPreexistingAtachments
2393: .contains(lXMIReference.getXmiId())) {
2394: File lDataFile = new File(new File(
2395: lModelRootDirectoryAbsolutePath
2396: + lXMIReference.getSystemId())
2397: .getParent()
2398: + File.separator + lDataFileName);
2399: ModelAttachmentUpdateDescriptor lDescriptor = new ModelAttachmentUpdateDescriptor();
2400: lDescriptor.SavedCopyPath = lDataFile
2401: .getAbsolutePath()
2402: .substring(
2403: lModelRootDirectoryAbsolutePathLength);
2404: if (lUnsavedAttachmentChangeFile.exists())
2405: lDescriptor.UnsavedCopyPath = lUnsavedAttachmentChangeFile
2406: .getAbsolutePath();
2407: lObjectAttachmentsMap.put(lXMIReference.getXmiId(),
2408: lDescriptor);
2409: }
2410: }
2411: }
2412: return lObjectAttachmentsMap;
2413: }
2414:
2415: public void beginTransaction() throws ModelRepositoryException {
2416: if (isClosed())
2417: throw new ModelRepositoryException(
2418: "Repository is closed and can not be used.");
2419: if (isInTransaction())
2420: throw new OperationAttemptedInTransactionException(
2421: "beginTransaction");
2422: sLogger.debug("Begining repository transaction");
2423: mRepository.beginTrans(true);
2424: mTransactionInProgress = true;
2425: }
2426:
2427: public boolean isInTransaction() throws ModelRepositoryException {
2428: if (isClosed())
2429: throw new ModelRepositoryException(
2430: "Repository is closed and can not be used.");
2431: return mTransactionInProgress;
2432: }
2433:
2434: public boolean isClosed() {
2435: return mRepository == null;
2436: }
2437:
2438: public void commitTransaction() throws ModelRepositoryException {
2439: if (isClosed())
2440: throw new ModelRepositoryException(
2441: "Repository is closed and can not be used.");
2442: if (!isInTransaction())
2443: throw new OperationAttemptedOutsideTransactionException(
2444: "commitTransaction");
2445: sLogger.debug("Committing repository transaction");
2446: mRepository.endTrans(false);
2447: // Ensure that all events are consumed in repository and models
2448: mInternalTransactionListener.waitTillAllEventsAreConsumed();
2449: for (Iterator lModelDescriptorsIterator = mModelsByName
2450: .values().iterator(); lModelDescriptorsIterator
2451: .hasNext();) {
2452: ModelDescriptor lModelDescriptor = (ModelDescriptor) lModelDescriptorsIterator
2453: .next();
2454: lModelDescriptor.mInternalChangeListener
2455: .waitTillAllEventsAreConsumed();
2456: }
2457: // Turn off the transaction flag
2458: mTransactionInProgress = false;
2459: }
2460:
2461: public void rollbackTransaction() throws ModelRepositoryException {
2462: if (isClosed())
2463: throw new ModelRepositoryException(
2464: "Repository is closed and can not be used.");
2465: if (!isInTransaction())
2466: throw new OperationAttemptedOutsideTransactionException(
2467: "rollbackTransaction");
2468: sLogger.debug("Rolling back repository transaction");
2469: mRepository.endTrans(true);
2470: mTransactionInProgress = false;
2471: // Ensure that all events are consumed in repository and models
2472: mInternalTransactionListener.waitTillAllEventsAreConsumed();
2473: for (Iterator lModelDescriptorsIterator = mModelsByName
2474: .values().iterator(); lModelDescriptorsIterator
2475: .hasNext();) {
2476: ModelDescriptor lModelDescriptor = (ModelDescriptor) lModelDescriptorsIterator
2477: .next();
2478: lModelDescriptor.mInternalChangeListener
2479: .waitTillAllEventsAreConsumed();
2480: }
2481: }
2482:
2483: /** @return the data attached to object or null if no data is attached to object */
2484: public byte[] getDataAttachedToObject(RefObject lObject)
2485: throws ModelRepositoryException {
2486: if (isClosed())
2487: throw new ModelRepositoryException(
2488: "Repository is closed and can not be used.");
2489: ModelDescriptor lModelDescriptor = getModelDescriptor(lObject);
2490: String lObjectXmiId = lModelDescriptor.XmiIdGenerator
2491: .getXmiId(lObject);
2492: String lDataFileName = lObjectXmiId + ".dat";
2493: String lDeletedMarkerFileName = lObjectXmiId + ".del";
2494: // Try transaction location first if we are in transaction
2495: if (isInTransaction()
2496: && lModelDescriptor.MayHaveUncomittedChangesToAttachments) {
2497: try {
2498: File lDataFile = new File(
2499: lModelDescriptor.UncomittedAttachedFilesDir
2500: .getAbsolutePath()
2501: + File.separator + lDataFileName);
2502: if (lDataFile.exists()) {
2503: FileInputStream lFileInputStream = null;
2504: try {
2505: lFileInputStream = new FileInputStream(
2506: lDataFile);
2507: return ByteUtils
2508: .readByteStreamFully(lFileInputStream);
2509: } finally {
2510: if (lFileInputStream != null)
2511: lFileInputStream.close();
2512: }
2513: } else {
2514: File lDeletedMarkerFile = new File(
2515: lModelDescriptor.UncomittedAttachedFilesDir
2516: .getAbsolutePath()
2517: + File.separator
2518: + lDeletedMarkerFileName);
2519: if (lDeletedMarkerFile.exists())
2520: return null; // Found deleted marker file - attachment is deleted
2521: }
2522: } catch (IOException e) {
2523: throw new ModelRepositoryException(
2524: "Unable to read data attachment from the uncommitted transaction area",
2525: e);
2526: }
2527: }
2528: // Now try unsaved location
2529: {
2530: try {
2531: File lDataFile = new File(
2532: lModelDescriptor.UnsavedAttachedFilesDir
2533: .getAbsolutePath()
2534: + File.separator + lDataFileName);
2535: if (lDataFile.exists()) {
2536: FileInputStream lFileInputStream = null;
2537: try {
2538: lFileInputStream = new FileInputStream(
2539: lDataFile);
2540: return ByteUtils
2541: .readByteStreamFully(lFileInputStream);
2542: } finally {
2543: if (lFileInputStream != null)
2544: lFileInputStream.close();
2545: }
2546: } else {
2547: File lDeletedMarkerFile = new File(
2548: lModelDescriptor.UnsavedAttachedFilesDir
2549: .getAbsolutePath()
2550: + File.separator
2551: + lDeletedMarkerFileName);
2552: if (lDeletedMarkerFile.exists())
2553: return null; // Found deleted marker file - attachment is deleted
2554: }
2555: } catch (IOException e) {
2556: throw new ModelRepositoryException(
2557: "Unable to read data attachment from the unsaved area",
2558: e);
2559: }
2560: }
2561: // Now try model location
2562: {
2563: try {
2564: if (lModelDescriptor.ObjectAttachmentsMap
2565: .containsKey(lObjectXmiId)) {
2566: File lDataFile = new File(
2567: lModelDescriptor.ModelRootDirectory
2568: .getAbsolutePath()
2569: + (String) lModelDescriptor.ObjectAttachmentsMap
2570: .get(lObjectXmiId));
2571: FileInputStream lFileInputStream = null;
2572: try {
2573: lFileInputStream = new FileInputStream(
2574: lDataFile);
2575: return ByteUtils
2576: .readByteStreamFully(lFileInputStream);
2577: } finally {
2578: if (lFileInputStream != null)
2579: lFileInputStream.close();
2580: }
2581: }
2582: } catch (IOException e) {
2583: throw new ModelRepositoryException(
2584: "Unable to read data attachment from the model area",
2585: e);
2586: }
2587: }
2588: return null; // No data attachment found
2589: }
2590:
2591: /** Attaches data to the object */
2592: public void setDataAttachedToObject(RefObject lObject,
2593: byte[] pAttachedData) throws ModelRepositoryException {
2594: if (isClosed())
2595: throw new ModelRepositoryException(
2596: "Repository is closed and can not be used.");
2597: if (!isInTransaction())
2598: throw new OperationAttemptedOutsideTransactionException(
2599: "setDataAttachedToObject");
2600: ModelDescriptor lModelDescriptor = getModelDescriptor(lObject);
2601: String lObjectXmiId = lModelDescriptor.XmiIdGenerator
2602: .getXmiId(lObject);
2603: String lDataFileName = lObjectXmiId + ".dat";
2604: // Mark the fact that we have worked on attachments during this transaction
2605: lModelDescriptor.MayHaveUncomittedChangesToAttachments = true;
2606: // Always save into the uncommitted area
2607: try {
2608: // First ensure that we do not have deleted marker file stored in the transaction area
2609: File lDeletedMarkerFile = new File(
2610: lModelDescriptor.UncomittedAttachedFilesDir
2611: .getAbsolutePath()
2612: + File.separator + lObjectXmiId + ".del");
2613: if (lDeletedMarkerFile.exists())
2614: lDeletedMarkerFile.delete();
2615: // Now store a data file with attachment
2616: File lDataFile = new File(
2617: lModelDescriptor.UncomittedAttachedFilesDir
2618: .getAbsolutePath()
2619: + File.separator + lObjectXmiId + ".dat");
2620: FileOutputStream lFileOutputStream = null;
2621: try {
2622: lFileOutputStream = new FileOutputStream(lDataFile);
2623: lFileOutputStream.write(pAttachedData);
2624: lFileOutputStream.flush();
2625: } finally {
2626: if (lFileOutputStream != null)
2627: lFileOutputStream.close();
2628: }
2629: } catch (IOException e) {
2630: sLogger
2631: .error(
2632: "Unable to write data attachment to the uncommitted transaction area",
2633: e);
2634: throw new ModelRepositoryException(
2635: "Unable to write data attachment to the uncommitted transaction area",
2636: e);
2637: }
2638: }
2639:
2640: /** Clears data attached to the object */
2641: public void clearDataAttachedToObject(RefObject lObject)
2642: throws ModelRepositoryException {
2643: if (isClosed())
2644: throw new ModelRepositoryException(
2645: "Repository is closed and can not be used.");
2646: if (!isInTransaction())
2647: throw new OperationAttemptedOutsideTransactionException(
2648: "clearDataAttachedToObject");
2649: ModelDescriptor lModelDescriptor = getModelDescriptor(lObject);
2650: String lObjectXmiId = lModelDescriptor.XmiIdGenerator
2651: .getXmiId(lObject);
2652: // Mark the fact that we have worked on attachments during this transaction
2653: lModelDescriptor.MayHaveUncomittedChangesToAttachments = true;
2654: // Always save into the uncommitted area
2655: try {
2656: // First ensure that we do not have data file stored in the transaction area
2657: File lDataFile = new File(
2658: lModelDescriptor.UncomittedAttachedFilesDir
2659: .getAbsolutePath()
2660: + File.separator + lObjectXmiId + ".dat");
2661: if (lDataFile.exists())
2662: lDataFile.delete();
2663: // Now store a small file marking that the attachment has in fact been deleted
2664: File lDeletedMarkerFile = new File(
2665: lModelDescriptor.UncomittedAttachedFilesDir
2666: .getAbsolutePath()
2667: + File.separator + lObjectXmiId + ".del");
2668: FileOutputStream lFileOutputStream = null;
2669: try {
2670: lFileOutputStream = new FileOutputStream(
2671: lDeletedMarkerFile);
2672: lFileOutputStream.write(0x00);
2673: lFileOutputStream.flush();
2674: } finally {
2675: if (lFileOutputStream != null)
2676: lFileOutputStream.close();
2677: }
2678: } catch (IOException e) {
2679: sLogger
2680: .error(
2681: "Unable to write data attachment to the uncommitted transaction area",
2682: e);
2683: throw new ModelRepositoryException(
2684: "Unable to write data attachment to the uncommitted transaction area",
2685: e);
2686: }
2687: }
2688:
2689: /** Adds the assistant to the metamodel. Supplied assistant will be assigned to
2690: * each model of this type. Assistants registered by this method will be installed in the
2691: * order of registration, but after all assitants declared in configuration/
2692: * @param pMetaModelName - the name of metamodel to attach this assistant to
2693: * @param pAssistant - the asssitant itself
2694: * @throws ModelRepositoryException thrown if there is a problem with registering the assistant */
2695: public void registerModelAssistant(String pMetaModelName,
2696: ModelAssistant pAssistant) throws ModelRepositoryException {
2697: synchronized (sRepositorySemaphore) {
2698: if (isClosed())
2699: throw new ModelRepositoryException(
2700: "Repository is closed and can not be used.");
2701: if (isInTransaction())
2702: throw new OperationAttemptedInTransactionException(
2703: "registerModelAssistant");
2704: // Obtain MetaModel descriptor
2705: MetaModelDescriptor lMetaModelDescriptor = (MetaModelDescriptor) mMetaModelsByName
2706: .get(pMetaModelName);
2707: if (lMetaModelDescriptor == null)
2708: throw new ModelRepositoryException(
2709: "MetaModel not found. MetaModelName: "
2710: + pMetaModelName);
2711: // Register the assistant
2712: if (!lMetaModelDescriptor.RegisteredModelAssistants
2713: .add(pAssistant))
2714: throw new IllegalArgumentException(
2715: " Specified Assistant is already registered as an Assistant for the '"
2716: + pMetaModelName + "' metamodels");
2717: // Add the assitant to all existing models
2718: for (Iterator lModelDescriptorsIterator = lMetaModelDescriptor.ModelsByName
2719: .values().iterator(); lModelDescriptorsIterator
2720: .hasNext();) {
2721: ModelDescriptor lModelDescriptor = (ModelDescriptor) lModelDescriptorsIterator
2722: .next();
2723: pAssistant.assignToModel(lModelDescriptor.ModelName);
2724: }
2725: sLogger.debug("Registered instance of "
2726: + pAssistant.getClass().getName()
2727: + " class as an Assistant for the '"
2728: + pMetaModelName + "' models");
2729: }
2730: }
2731:
2732: /** Removes the assistant from the metamodel. First the assistant will
2733: * be disassociated from all models it is attached to.
2734: * @param pMetaModelName - the name of metamodel to remove this assistant from
2735: * @param pAssistant - the asssitant itself
2736: * @throws ModelRepositoryException thrown if there is a problem with unregistering the assistant */
2737: public void unregisterModelAssistant(String pMetaModelName,
2738: ModelAssistant pAssistant) throws ModelRepositoryException {
2739: synchronized (sRepositorySemaphore) {
2740: if (isClosed())
2741: throw new ModelRepositoryException(
2742: "Repository is closed and can not be used.");
2743: if (isInTransaction())
2744: throw new OperationAttemptedInTransactionException(
2745: "unregisterModelAssistant");
2746: // Now obtain MetaModel descriptor
2747: MetaModelDescriptor lMetaModelDescriptor = (MetaModelDescriptor) mMetaModelsByName
2748: .get(pMetaModelName);
2749: if (lMetaModelDescriptor == null)
2750: throw new ModelRepositoryException(
2751: "MetaModel not found. MetaModelName: "
2752: + pMetaModelName);
2753: // Unregister the assistant
2754: if (!lMetaModelDescriptor.RegisteredModelAssistants
2755: .remove(pAssistant))
2756: throw new IllegalArgumentException(
2757: "Assistant is not registered as an Assistant for the '"
2758: + pMetaModelName + "' metamodels");
2759: // Remove the assistant to all existing models
2760: for (Iterator lModelDescriptorsIterator = lMetaModelDescriptor.ModelsByName
2761: .values().iterator(); lModelDescriptorsIterator
2762: .hasNext();) {
2763: ModelDescriptor lModelDescriptor = (ModelDescriptor) lModelDescriptorsIterator
2764: .next();
2765: pAssistant.dismissFromModel(lModelDescriptor.ModelName);
2766: }
2767: }
2768: }
2769:
2770: /** Adds a listener object to the model.
2771: * @param pModelName - the name of model to attach this listener to
2772: * @param pModelListener - the listener object to use
2773: * @throws ModelRepositoryException in case if there was a problem assigning the listener */
2774: public void registerModelListener(String pModelName,
2775: ModelListener pModelListener)
2776: throws ModelRepositoryException {
2777: synchronized (sRepositorySemaphore) {
2778: if (isClosed())
2779: throw new ModelRepositoryException(
2780: "Repository is closed and can not be used.");
2781: if (isInTransaction())
2782: throw new OperationAttemptedInTransactionException(
2783: "registerModelListener");
2784: // Get model descriptor
2785: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
2786: .get(pModelName);
2787: if (lModelDescriptor == null)
2788: throw new ModelNotLoadedException(pModelName);
2789: lModelDescriptor.ListenersSet.add(pModelListener);
2790: }
2791: }
2792:
2793: /** Removes a listener object from the metamodel.
2794: * @param pModelName - the name of model to remove this listener from
2795: * @param pModelListener - the listener object to remove
2796: * @throws ModelRepositoryException in case if there was a problem removing the listener */
2797: public void unregisterModelListener(String pModelName,
2798: ModelListener pModelListener)
2799: throws ModelRepositoryException {
2800: synchronized (sRepositorySemaphore) {
2801: if (isClosed())
2802: throw new ModelRepositoryException(
2803: "Repository is closed and can not be used.");
2804: if (isInTransaction())
2805: throw new OperationAttemptedInTransactionException(
2806: "registerModelListener");
2807: // Get model descriptor
2808: ModelDescriptor lModelDescriptor = (ModelDescriptor) mModelsByName
2809: .get(pModelName);
2810: if (lModelDescriptor == null)
2811: throw new ModelNotLoadedException(pModelName);
2812: lModelDescriptor.ListenersSet.remove(pModelListener);
2813: }
2814: }
2815:
2816: /** This helper method copies given object to different model and returns newly created object.
2817: * @param pSourceObject the object to copy from
2818: * @param pTargetModelName the model to copy. Must be different to the model which owns
2819: * source object and also must be of the same type (same metamodel)
2820: * @param pDeepCopy - if equals true - all contained objects are also copied. Associations within
2821: * copied hierarchy are copied, but external associations are dropped (note that this may make newly copied
2822: * object tree invalid). */
2823: public RefObject copyModelElement(RefObject pSourceObject,
2824: String pTargetModelName, boolean pDeepCopy,
2825: ModelElementResolver pExternalElementResolver)
2826: throws ModelRepositoryException {
2827: synchronized (sRepositorySemaphore) {
2828: if (isClosed())
2829: throw new ModelRepositoryException(
2830: "Repository is closed and can not be used.");
2831: Map lAllCopiedObjects = new HashMap();
2832: RefObject lTargetObject = createSameObject(pSourceObject,
2833: pTargetModelName);
2834: copyWithoutAssociations(pSourceObject, lTargetObject,
2835: pDeepCopy, lAllCopiedObjects);
2836: if (pDeepCopy) {
2837: // Deep copy may have copied more than one element.
2838: // We now have a map of all copied elements where
2839: // source object is a key and newly created object is a value.
2840: // We will now discover all associations, which can be resolved and copy them too.
2841: RefPackage lSourceModelExtent = pSourceObject
2842: .refOutermostPackage();
2843: RefPackage lTargetModelExtent = lTargetObject
2844: .refOutermostPackage();
2845: copyAssociations(lAllCopiedObjects, lSourceModelExtent,
2846: lTargetModelExtent, pExternalElementResolver);
2847: }
2848: return lTargetObject;
2849: }
2850: }
2851:
2852: /** This helper method duplicates given object in the same model and returns newly created object.
2853: * @param pSourceObject the object to copy from.
2854: */
2855: public RefObject duplicateModelElement(RefObject pSourceObject)
2856: throws ModelRepositoryException {
2857: synchronized (sRepositorySemaphore) {
2858: if (isClosed())
2859: throw new ModelRepositoryException(
2860: "Repository is closed and can not be used.");
2861: Map lAllCopiedObjects = new HashMap();
2862: String lModelName = getOwnerModelName(pSourceObject);
2863: RefObject lTargetObject = createSameObject(pSourceObject,
2864: lModelName);
2865: copyWithoutAssociations(pSourceObject, lTargetObject, true,
2866: lAllCopiedObjects);
2867: // Deep copy may have copied more than one element.
2868: // We now have a map of all copied elements where
2869: // source object is a key and newly created object is a value.
2870: // We will now discover all associations, which can be resolved and copy them too.
2871: // As all elements are from the same extent - we do not have to have ModelElementResolver
2872: RefPackage lSourceModelExtent = pSourceObject
2873: .refOutermostPackage();
2874: copyAssociations(lAllCopiedObjects, lSourceModelExtent,
2875: lSourceModelExtent, null);
2876: return lTargetObject;
2877: }
2878: }
2879:
2880: /** This helper method changes all internals of the target object to be exactly the same as
2881: * the internals of the sample object. Similar to the copyModelElement method the associations within copied hierarchy are copied, but external associations are dropped
2882: * (note that this may make newly copied object tree invalid).
2883: * @param pSampleObject the sample object to mirror all attributes and child elements from
2884: * @param pTargetObject the object which will get whole new content. Everything it has inside
2885: * (Attributes and Contained objects) will be replaced. Objects must be of the same type and belong to the
2886: * model (same or different - does not matter). */
2887: public void retrofitModelElement(RefObject pSampleObject,
2888: RefObject pTargetObject,
2889: ModelElementResolver pExternalElementResolver)
2890: throws ModelRepositoryException {
2891: synchronized (sRepositorySemaphore) {
2892: if (isClosed())
2893: throw new ModelRepositoryException(
2894: "Repository is closed and can not be used.");
2895: // Check if objects are not the same
2896: if (pSampleObject.equals(pTargetObject))
2897: throw new ModelRepositoryIllegalArgumentException(
2898: "Sample object and Target object must not be one and the same object.");
2899: // Check if objects are similar
2900: if (!pSampleObject.refMetaObject().equals(
2901: pTargetObject.refMetaObject()))
2902: throw new ModelRepositoryIllegalArgumentException(
2903: "Sample object and Target object must be of the same type in the retrofitModelElement() operation.");
2904: if ((pSampleObject.refMetaObject() instanceof MofClass) == false)
2905: throw new ModelRepositoryIllegalArgumentException(
2906: "Sample and Target objects are not instances of the class. Unable to retrofit anything but instances.");
2907: // Ensure that the target element is empty
2908: emptyModelElement(pTargetObject);
2909: // Copy all attributes and contained objects without associations
2910: Map lAllCopiedObjects = new HashMap();
2911: copyWithoutAssociations(pSampleObject, pTargetObject, true,
2912: lAllCopiedObjects);
2913: // Reestablish associations between copied objects
2914: RefPackage lSourceModelExtent = pSampleObject
2915: .refOutermostPackage();
2916: RefPackage lTargetModelExtent = pTargetObject
2917: .refOutermostPackage();
2918: copyAssociations(lAllCopiedObjects, lSourceModelExtent,
2919: lTargetModelExtent, pExternalElementResolver);
2920: }
2921: }
2922:
2923: /** This helper method empties given model element, which means it deletes all
2924: * attributes and contained objects
2925: * @param pModelElement the model element to empty */
2926: public void emptyModelElement(RefObject pModelElement)
2927: throws ModelRepositoryException {
2928: synchronized (sRepositorySemaphore) {
2929: if (isClosed())
2930: throw new ModelRepositoryException(
2931: "Repository is closed and can not be used.");
2932: MofClass lMetaObjectOfObject = (MofClass) pModelElement
2933: .refMetaObject();
2934:
2935: // Iterate through the contents of the object definition and copy the bits we are interested in
2936: // First build the list of all contained meta objects in here and in supertypes
2937: List lContainedMetaObjects = new ArrayList();
2938: lContainedMetaObjects.addAll(lMetaObjectOfObject
2939: .getContents());
2940: {
2941: List lAllSupertypes = lMetaObjectOfObject
2942: .allSupertypes();
2943: Iterator lAllSupertypesIterator = lAllSupertypes
2944: .iterator();
2945: while (lAllSupertypesIterator.hasNext()) {
2946: MofClass lMetaObjectOfObjectSupertype = (MofClass) lAllSupertypesIterator
2947: .next();
2948: lContainedMetaObjects
2949: .addAll(lMetaObjectOfObjectSupertype
2950: .getContents());
2951: }
2952: }
2953: for (Iterator lContainedMetaObjectsIterator = lContainedMetaObjects
2954: .iterator(); lContainedMetaObjectsIterator
2955: .hasNext();) {
2956: RefObject lMetaObjectOfContainedObject = (RefObject) lContainedMetaObjectsIterator
2957: .next();
2958: if (lMetaObjectOfContainedObject instanceof javax.jmi.model.Attribute) {
2959: // Delete value of the attribute
2960: pModelElement.refSetValue(
2961: lMetaObjectOfContainedObject, null);
2962: } else
2963: // Only look at contained objects and delete them
2964: if (lMetaObjectOfContainedObject instanceof javax.jmi.model.Reference) {
2965: // Look for the composite objects and copy them over
2966: AssociationEnd lExposedEnd = ((javax.jmi.model.Reference) lMetaObjectOfContainedObject)
2967: .getExposedEnd();
2968: if (lExposedEnd.getAggregation().equals(
2969: AggregationKindEnum.COMPOSITE)) {
2970: // Create copy of the contained object and register it with the container object
2971: Object lValue = pModelElement
2972: .refGetValue(lMetaObjectOfContainedObject);
2973: if (lValue instanceof Collection) {
2974: // This is the plural reference
2975: List lTempCollectionOfContainedObjects = new ArrayList();
2976: lTempCollectionOfContainedObjects
2977: .addAll((Collection) pModelElement
2978: .refGetValue(lMetaObjectOfContainedObject));
2979: for (Iterator lIter = lTempCollectionOfContainedObjects
2980: .iterator(); lIter.hasNext();) {
2981: RefObject lContainedObject = (RefObject) lIter
2982: .next();
2983: lContainedObject.refDelete();
2984: }
2985: } else if (lValue instanceof RefObject) {
2986: RefObject lContainedObject = (RefObject) lValue;
2987: lContainedObject.refDelete();
2988: } else
2989: throw new ModelRepositoryException(
2990: "Unexpected object at the reference end. Expecting Collection or single RefObject. Unable to copy objects between models");
2991: }
2992: }
2993: }
2994: // Also delete attachment if necessary
2995: clearDataAttachedToObject(pModelElement);
2996: }
2997: }
2998:
2999: // This method will execute deep copy of the object (copying all contained objects).
3000: // It will be called recursively to copy all contained elements, but it will not touch associations
3001: private void copyAssociations(Map pCopiedObjectsMap,
3002: RefPackage pSourceModelExtent,
3003: RefPackage pTargetModelExtent,
3004: ModelElementResolver pExternalElementResolver)
3005: throws ModelRepositoryException {
3006: try {
3007: String lSourceMetaModelName = getOwnerMetaModelName(pSourceModelExtent);
3008: String lTargetMetaModelName = getOwnerMetaModelName(pTargetModelExtent);
3009: boolean lIsMetaBossModel = lSourceMetaModelName
3010: .equals(ModelRepository.METAMODEL_NAME_METABOSS)
3011: && lTargetMetaModelName
3012: .equals(ModelRepository.METAMODEL_NAME_METABOSS);
3013: // Iterate through the source objects
3014: for (Iterator lCopiedObjectsIterator = pCopiedObjectsMap
3015: .entrySet().iterator(); lCopiedObjectsIterator
3016: .hasNext();) {
3017: Map.Entry lCopiedObjectEntry = (Map.Entry) lCopiedObjectsIterator
3018: .next();
3019: RefObject lSourceObject = (RefObject) lCopiedObjectEntry
3020: .getKey();
3021: RefObject lTargetObject = (RefObject) lCopiedObjectEntry
3022: .getValue();
3023: MofClass lMetaObjectOfObject = (MofClass) lSourceObject
3024: .refMetaObject();
3025:
3026: // Iterate through the contents of the object definition
3027: // find all references, check if in source model they are between contained objects and copy it if it is
3028: // First build the list of all contained meta objects in here and in supertypes
3029: List lContainedMetaObjects = new ArrayList();
3030: lContainedMetaObjects.addAll(lMetaObjectOfObject
3031: .getContents());
3032: {
3033: List lAllSupertypes = lMetaObjectOfObject
3034: .allSupertypes();
3035: for (Iterator lAllSupertypesIterator = lAllSupertypes
3036: .iterator(); lAllSupertypesIterator
3037: .hasNext();) {
3038: MofClass lMetaObjectOfObjectSupertype = (MofClass) lAllSupertypesIterator
3039: .next();
3040: lContainedMetaObjects
3041: .addAll(lMetaObjectOfObjectSupertype
3042: .getContents());
3043: }
3044: }
3045: // Iterate through all features
3046: for (Iterator lContainedMetaObjectsIterator = lContainedMetaObjects
3047: .iterator(); lContainedMetaObjectsIterator
3048: .hasNext();) {
3049: RefObject lMetaObjectOfContainedObject = (RefObject) lContainedMetaObjectsIterator
3050: .next();
3051: // Only look at contained objects if we are executing a deep copy
3052: if (lMetaObjectOfContainedObject instanceof javax.jmi.model.Reference) {
3053: // Look for the non composite associations (composite has been copied already)
3054: AssociationEnd lExposedEnd = ((javax.jmi.model.Reference) lMetaObjectOfContainedObject)
3055: .getExposedEnd();
3056: AssociationEnd lReferencedEnd = ((javax.jmi.model.Reference) lMetaObjectOfContainedObject)
3057: .getReferencedEnd();
3058: javax.jmi.model.Association lAssociation = (javax.jmi.model.Association) lExposedEnd
3059: .getContainer();
3060: boolean lExposedEndIsFirst = lAssociation
3061: .getContents().indexOf(lExposedEnd) == 0;
3062: if (lExposedEnd.getAggregation().equals(
3063: AggregationKindEnum.COMPOSITE) == false
3064: && lReferencedEnd
3065: .getAggregation()
3066: .equals(
3067: AggregationKindEnum.COMPOSITE) == false) {
3068: // This asociation is not containment association
3069: MofPackage lAssociationPackageDescriptor = (MofPackage) lAssociation
3070: .getContainer();
3071: RefPackage lSourceAssociationPackage = getModelPackage(
3072: getModelDescriptor(lSourceObject).ModelName,
3073: lAssociationPackageDescriptor);
3074: RefAssociation lSourceAssociation = lSourceAssociationPackage
3075: .refAssociation(lAssociation);
3076: RefPackage lTargetAssociationPackage = getModelPackage(
3077: getModelDescriptor(lTargetObject).ModelName,
3078: lAssociationPackageDescriptor);
3079: RefAssociation lTargetAssociation = lTargetAssociationPackage
3080: .refAssociation(lAssociation);
3081: // Find all associated objects in the source model and set them up in the target model
3082: Collection lCollectionOfAssociatedSourceObjects = lSourceAssociation
3083: .refQuery(lExposedEnd,
3084: lSourceObject);
3085: for (Iterator lAssociatedSourceObjectsIter = lCollectionOfAssociatedSourceObjects
3086: .iterator(); lAssociatedSourceObjectsIter
3087: .hasNext();) {
3088: RefObject lAssociatedSourceObject = (RefObject) lAssociatedSourceObjectsIter
3089: .next();
3090: RefObject lAssociatedTargetObject = null;
3091: // If we are copying object in the same extent
3092: // Copy all associations, providing that the muliplicity allows it
3093: if (pSourceModelExtent
3094: .equals(pTargetModelExtent)) {
3095: if (lExposedEnd.getMultiplicity()
3096: .getUpper() != 1)
3097: lAssociatedTargetObject = lAssociatedSourceObject;
3098: } else if (pCopiedObjectsMap
3099: .containsKey(lAssociatedSourceObject)) {
3100: // We have found associated object, which has also been copied into the target model
3101: // Therefore the reference will have to be copied also
3102: lAssociatedTargetObject = (RefObject) pCopiedObjectsMap
3103: .get(lAssociatedSourceObject);
3104: } else if (pExternalElementResolver != null) {
3105: // Delegate resolution to the external resolver
3106: lAssociatedTargetObject = pExternalElementResolver
3107: .getMatchingModelElement(
3108: lAssociatedSourceObject,
3109: pTargetModelExtent);
3110: }
3111: // Establish association if associated target object is found
3112: if (lAssociatedTargetObject != null) {
3113: if (lExposedEndIsFirst) {
3114: if (!lTargetAssociation
3115: .refLinkExists(
3116: lTargetObject,
3117: lAssociatedTargetObject))
3118: lTargetAssociation
3119: .refAddLink(
3120: lTargetObject,
3121: lAssociatedTargetObject);
3122: } else {
3123: if (!lTargetAssociation
3124: .refLinkExists(
3125: lAssociatedTargetObject,
3126: lTargetObject))
3127: lTargetAssociation
3128: .refAddLink(
3129: lAssociatedTargetObject,
3130: lTargetObject);
3131: }
3132: }
3133: }
3134: // if (lReferencedEnd.getMultiplicity().getUpper() != 1)
3135: // {
3136: // // Collection of referenced objects
3137: // Collection lCollectionOfAssociatedSourceObjects = (Collection)lSourceObject.refGetValue(lMetaObjectOfContainedObject);
3138: // for (Iterator lAssociatedSourceObjectsIter = lCollectionOfAssociatedSourceObjects.iterator();lAssociatedSourceObjectsIter.hasNext();)
3139: // {
3140: // RefObject lAssociatedSourceObject = (RefObject)lAssociatedSourceObjectsIter.next();
3141: // if (pCopiedObjectsMap.containsKey(lAssociatedSourceObject))
3142: // {
3143: // // We have found associated object, which has also been copied into the target model
3144: // // Therefore the reference will have to be copied also
3145: // RefObject lAssociatedTargetObject = (RefObject)pCopiedObjectsMap.get(lAssociatedSourceObject);
3146: // if (lExposedEndIsFirst)
3147: // lTargetAssociation.refAddLink(lTargetObject,lAssociatedTargetObject);
3148: // else
3149: // lTargetAssociation.refAddLink(lAssociatedTargetObject,lTargetObject);
3150: // }
3151: // }
3152: // }
3153: // else
3154: // {
3155: // // Single referenced object
3156: // RefObject lAssociatedSourceObject = (RefObject)lSourceObject.refGetValue(lMetaObjectOfContainedObject);
3157: // if (pCopiedObjectsMap.containsKey(lAssociatedSourceObject))
3158: // {
3159: // // We have found associated object, which has also been copied into the target model
3160: // // Therefore the reference will have to be copied also
3161: // RefObject lAssociatedTargetObject = (RefObject)pCopiedObjectsMap.get(lAssociatedSourceObject);
3162: // if (lExposedEndIsFirst)
3163: // lTargetAssociation.refAddLink(lTargetObject,lAssociatedTargetObject);
3164: // else
3165: // lTargetAssociation.refAddLink(lAssociatedTargetObject,lTargetObject);
3166: // }
3167: // }
3168: // Collection lCollectionOfAssociatedSourceObjects = lSourceAssociation.refQuery(lExposedEnd, lSourceObject);
3169: // for (Iterator lAssociatedSourceObjectsIter = lCollectionOfAssociatedSourceObjects.iterator();lAssociatedSourceObjectsIter.hasNext();)
3170: // {
3171: // RefObject lAssociatedSourceObject = (RefObject)lAssociatedSourceObjectsIter.next();
3172: // if (pCopiedObjectsMap.containsKey(lAssociatedSourceObject))
3173: // {
3174: // // We have found associated object, which has also been copied into the target model
3175: // // Therefore the reference will have to be copied also
3176: // RefObject lAssociatedTargetObject = (RefObject)pCopiedObjectsMap.get(lAssociatedSourceObject);
3177: // if (!lTargetAssociation.refLinkExists(lTargetObject,lAssociatedTargetObject))
3178: // lTargetAssociation.refAddLink(lTargetObject,lAssociatedTargetObject);
3179: // }
3180: // }
3181: //
3182: // // Find all associated objects in the source model and set them up in the target model
3183: // if (lReferencedEnd.getMultiplicity().getUpper() != 1)
3184: // {
3185: // // Collection of referenced objects
3186: // Collection lCollectionOfAssociatedSourceObjects = (Collection)lSourceObject.refGetValue(lMetaObjectOfContainedObject);
3187: // for (Iterator lAssociatedSourceObjectsIter = lCollectionOfAssociatedSourceObjects.iterator();lAssociatedSourceObjectsIter.hasNext();)
3188: // {
3189: // RefObject lAssociatedSourceObject = (RefObject)lAssociatedSourceObjectsIter.next();
3190: // if (pCopiedObjectsMap.containsKey(lAssociatedSourceObject))
3191: // {
3192: // // We have found associated object, which has also been copied into the target model
3193: // // Therefore the reference will have to be copied also
3194: // RefObject lAssociatedTargetObject = (RefObject)pCopiedObjectsMap.get(lAssociatedSourceObject);
3195: // if (!lTargetAssociation.refLinkExists(lTargetObject,lAssociatedTargetObject))
3196: // lTargetAssociation.refAddLink(lTargetObject,lAssociatedTargetObject);
3197: // }
3198: // }
3199: // }
3200: // else
3201: // {
3202: // // Single referenced object
3203: // RefObject lAssociatedSourceObject = (RefObject)lSourceObject.refGetValue(lMetaObjectOfContainedObject);
3204: // if (pCopiedObjectsMap.containsKey(lAssociatedSourceObject))
3205: // {
3206: // // We have found associated object, which has also been copied into the target model
3207: // // Therefore the reference will have to be copied also
3208: // RefObject lAssociatedTargetObject = (RefObject)pCopiedObjectsMap.get(lAssociatedSourceObject);
3209: // if (!lTargetAssociation.refLinkExists(lTargetObject,lAssociatedTargetObject))
3210: // lTargetAssociation.refAddLink(lTargetObject,lAssociatedTargetObject);
3211: // }
3212: // }
3213: }
3214: }
3215: }
3216: }
3217: } catch (JmiException e) {
3218: throw new ModelRepositoryException(e);
3219: }
3220: }
3221:
3222: // This method will create same object in the specified target model
3223: private RefObject createSameObject(RefObject pSourceObject,
3224: String pTargetModelName) throws ModelRepositoryException {
3225: if ((pSourceObject.refMetaObject() instanceof MofClass) == false)
3226: throw new ModelRepositoryIllegalArgumentException(
3227: "Supplied source object is not an instance of the class. Unable to copy anything but instances between models.");
3228: MofClass lMetaObjectOfObject = (MofClass) pSourceObject
3229: .refMetaObject();
3230: // Get target outermost package
3231: RefPackage lTargetOutermostPackage = getModelExtent(pTargetModelName);
3232: // Get source object package hierarchy
3233: RefPackage[] lSourceObjectPackageHierarchy = ModelRepositoryUtils
3234: .getPackageHierarchy(pSourceObject);
3235: // Sanity check
3236: if ((lSourceObjectPackageHierarchy.length == 0)
3237: || (!lTargetOutermostPackage.refMetaObject().equals(
3238: lSourceObjectPackageHierarchy[0]
3239: .refMetaObject())))
3240: throw new ModelRepositoryException(
3241: "Source and Target models are not of the same type. Unable to copy objects between models");
3242: // Navigate to immediate package in the target model
3243: RefPackage lTargetImmediatePackage = lTargetOutermostPackage;
3244: for (int i = 1; i < lSourceObjectPackageHierarchy.length; i++) {
3245: RefObject lMetaObjectOfPackage = lSourceObjectPackageHierarchy[i]
3246: .refMetaObject();
3247: lTargetImmediatePackage = lTargetImmediatePackage
3248: .refPackage(lMetaObjectOfPackage);
3249: }
3250: // Create instance of the object in the target package
3251: RefObject lMetaObjectOfObjectClass = pSourceObject.refClass()
3252: .refMetaObject();
3253: RefClass lTargetObjectClass = lTargetImmediatePackage
3254: .refClass(lMetaObjectOfObjectClass);
3255: return lTargetObjectClass.refCreateInstance(null);
3256: }
3257:
3258: // This method will execute deep copy of the object (copying all contained objects).
3259: // It will be called recursively to copy all contained elements, but it will not touch associations
3260: private void copyWithoutAssociations(RefObject pSourceObject,
3261: RefObject pTargetObject, boolean pDeepCopy,
3262: Map pCopiedObjectsMap) throws ModelRepositoryException {
3263: if ((pSourceObject.refMetaObject() instanceof MofClass) == false)
3264: throw new ModelRepositoryIllegalArgumentException(
3265: "Supplied source object is not an instance of the class. Unable to copy anything but instances between models.");
3266: if ((pTargetObject.refMetaObject() instanceof MofClass) == false)
3267: throw new ModelRepositoryIllegalArgumentException(
3268: "Supplied target object is not an instance of the class. Unable to copy anything but instances between models.");
3269: MofClass lMetaObjectOfObject = (MofClass) pSourceObject
3270: .refMetaObject();
3271: String lTargetModelName = getOwnerModelName(pTargetObject);
3272:
3273: // Iterate through the contents of the object definition and copy the bits we are interested in
3274: // First build the list of all contained meta objects in here and in supertypes
3275: List lContainedMetaObjects = new ArrayList();
3276: lContainedMetaObjects.addAll(lMetaObjectOfObject.getContents());
3277: {
3278: List lAllSupertypes = lMetaObjectOfObject.allSupertypes();
3279: for (Iterator lAllSupertypesIterator = lAllSupertypes
3280: .iterator(); lAllSupertypesIterator.hasNext();) {
3281: MofClass lMetaObjectOfObjectSupertype = (MofClass) lAllSupertypesIterator
3282: .next();
3283: lContainedMetaObjects
3284: .addAll(lMetaObjectOfObjectSupertype
3285: .getContents());
3286: }
3287: }
3288: // Copy attributes at the first iteration
3289: for (Iterator lContainedMetaObjectsIterator = lContainedMetaObjects
3290: .iterator(); lContainedMetaObjectsIterator.hasNext();) {
3291: RefObject lMetaObjectOfContainedObject = (RefObject) lContainedMetaObjectsIterator
3292: .next();
3293: if (lMetaObjectOfContainedObject instanceof javax.jmi.model.Attribute) {
3294: // Copy attributes if they are set
3295: Object lSourceAttributeValue = pSourceObject
3296: .refGetValue(lMetaObjectOfContainedObject);
3297: if (lSourceAttributeValue != null)
3298: pTargetObject.refSetValue(
3299: lMetaObjectOfContainedObject,
3300: lSourceAttributeValue);
3301: }
3302: }
3303: // Second iteration will copy contained objects only if we are executing a deep copy
3304: if (pDeepCopy) {
3305: for (Iterator lContainedMetaObjectsIterator = lContainedMetaObjects
3306: .iterator(); lContainedMetaObjectsIterator
3307: .hasNext();) {
3308: RefObject lMetaObjectOfContainedObject = (RefObject) lContainedMetaObjectsIterator
3309: .next();
3310: if (lMetaObjectOfContainedObject instanceof javax.jmi.model.Reference) {
3311: // Look for the composite objects and copy them over
3312: AssociationEnd lExposedEnd = ((javax.jmi.model.Reference) lMetaObjectOfContainedObject)
3313: .getExposedEnd();
3314: if (lExposedEnd.getAggregation().equals(
3315: AggregationKindEnum.COMPOSITE)) {
3316: javax.jmi.model.Association lAssociation = (javax.jmi.model.Association) lExposedEnd
3317: .getContainer();
3318: MofPackage lAssociationPackageDescriptor = (MofPackage) lAssociation
3319: .getContainer();
3320: RefPackage lTargetAssociationPackage = getModelPackage(
3321: lTargetModelName,
3322: lAssociationPackageDescriptor);
3323: RefAssociation lTargetAssociation = lTargetAssociationPackage
3324: .refAssociation(lAssociation);
3325:
3326: // Create copy of the contained object if one exists and register it with the container object
3327: Object lValue = pSourceObject
3328: .refGetValue(lMetaObjectOfContainedObject);
3329: if (lValue != null) {
3330: if (lValue instanceof Collection) {
3331: // This is the plural reference
3332: Collection lCollectionOfContainedSourceObjects = (Collection) lValue;
3333: for (Iterator lIter = lCollectionOfContainedSourceObjects
3334: .iterator(); lIter.hasNext();) {
3335: RefObject lContainedSourceObject = (RefObject) lIter
3336: .next();
3337: RefObject lContainedTargetObject = createSameObject(
3338: lContainedSourceObject,
3339: lTargetModelName);
3340: copyWithoutAssociations(
3341: lContainedSourceObject,
3342: lContainedTargetObject,
3343: true, pCopiedObjectsMap);
3344: lTargetAssociation.refAddLink(
3345: pTargetObject,
3346: lContainedTargetObject);
3347: }
3348: } else if (lValue instanceof RefObject) {
3349: RefObject lContainedSourceObject = (RefObject) lValue;
3350: RefObject lContainedTargetObject = createSameObject(
3351: lContainedSourceObject,
3352: lTargetModelName);
3353: copyWithoutAssociations(
3354: lContainedSourceObject,
3355: lContainedTargetObject, true,
3356: pCopiedObjectsMap);
3357: lTargetAssociation.refAddLink(
3358: pTargetObject,
3359: lContainedTargetObject);
3360: } else
3361: throw new ModelRepositoryException(
3362: "Unexpected object at the reference end. Expecting "
3363: + Collection.class
3364: .getName()
3365: + " or "
3366: + RefObject.class
3367: .getName()
3368: + " got "
3369: + lValue.getClass()
3370: .getName());
3371: }
3372: }
3373: }
3374: }
3375: }
3376: // Also copy attachment if necessary
3377: byte[] lAttachment = getDataAttachedToObject(pSourceObject);
3378: if (lAttachment != null)
3379: setDataAttachedToObject(pTargetObject, lAttachment);
3380: pCopiedObjectsMap.put(pSourceObject, pTargetObject);
3381: }
3382:
3383: // This helper method executes update attribute instance on model implementations and assistants
3384: public void processUpdateInstanceAttribute(
3385: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3386: RefObject pAffectedInstance, String pAffectedAttributeName,
3387: Object pOldAttributeValue, Object pNewAttributeValue) {
3388: try {
3389: // Iterate through the list of model assistants
3390: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.AssistantsList
3391: .iterator(); lModelAssistantsIterator.hasNext();)
3392: ((ModelAssistant) lModelAssistantsIterator.next())
3393: .onModelElementAttributeBeingUpdated(
3394: pAffectedModelDescriptor.ModelName,
3395: pAffectedInstance,
3396: pAffectedAttributeName,
3397: pOldAttributeValue, pNewAttributeValue);
3398: // Iterate through the list of metamodel assistants
3399: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
3400: .iterator(); lModelAssistantsIterator.hasNext();)
3401: ((ModelAssistant) lModelAssistantsIterator.next())
3402: .onModelElementAttributeBeingUpdated(
3403: pAffectedModelDescriptor.ModelName,
3404: pAffectedInstance,
3405: pAffectedAttributeName,
3406: pOldAttributeValue, pNewAttributeValue);
3407: } catch (ModelRepositoryException e) {
3408: sLogger.error(
3409: "Caught error while trying to dispatch event.", e);
3410: }
3411: }
3412:
3413: // This helper method executes update attribute instance on model implementations and assistants
3414: public void processPostUpdateInstanceAttribute(
3415: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3416: String pUpdatedInstanceRepositoryId,
3417: String pUpdatedAttributeName, Object pOldAttributeValue,
3418: Object pNewAttributeValue) {
3419: // Iterate through listeners giving them a chance to process changes
3420: for (Iterator lModelListenersIterator = pAffectedModelDescriptor.ListenersSet
3421: .iterator(); lModelListenersIterator.hasNext();) {
3422: ModelListener lModelListener = (ModelListener) lModelListenersIterator
3423: .next();
3424: lModelListener.onModelElementAttributeUpdated(
3425: pAffectedModelDescriptor.ModelName,
3426: pUpdatedInstanceRepositoryId,
3427: pUpdatedAttributeName, pOldAttributeValue,
3428: pNewAttributeValue);
3429: }
3430: }
3431:
3432: // This helper method executes update attribute instance on model implementations and assistants
3433: public void processUpdateInstanceReference(
3434: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3435: RefObject pAffectedInstance, String pAfectedReferenceName,
3436: RefObject pReferencedModelElementToRemove,
3437: RefObject pReferencedModelElementToAdd) {
3438: try {
3439: // Iterate through the list of model assistants
3440: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.AssistantsList
3441: .iterator(); lModelAssistantsIterator.hasNext();)
3442: ((ModelAssistant) lModelAssistantsIterator.next())
3443: .onModelElementReferenceBeingUpdated(
3444: pAffectedModelDescriptor.ModelName,
3445: pAffectedInstance,
3446: pAfectedReferenceName,
3447: pReferencedModelElementToRemove,
3448: pReferencedModelElementToAdd);
3449: // Iterate through the list of metamodel assistants
3450: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
3451: .iterator(); lModelAssistantsIterator.hasNext();)
3452: ((ModelAssistant) lModelAssistantsIterator.next())
3453: .onModelElementReferenceBeingUpdated(
3454: pAffectedModelDescriptor.ModelName,
3455: pAffectedInstance,
3456: pAfectedReferenceName,
3457: pReferencedModelElementToRemove,
3458: pReferencedModelElementToAdd);
3459: } catch (ModelRepositoryException e) {
3460: sLogger.error(
3461: "Caught error while trying to dispatch event.", e);
3462: }
3463: }
3464:
3465: // This helper method executes transaction commit event processing
3466: public void processPostCommitTransaction(
3467: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor) {
3468: // Iterate through listeners giving them a chance to process changes
3469: for (Iterator lModelListenersIterator = pAffectedModelDescriptor.ListenersSet
3470: .iterator(); lModelListenersIterator.hasNext();) {
3471: ModelListener lModelListener = (ModelListener) lModelListenersIterator
3472: .next();
3473: lModelListener
3474: .onModelTransactionCompleted(pAffectedModelDescriptor.ModelName);
3475: }
3476: }
3477:
3478: // This helper method executes post create instance on model implementations and assistants
3479: public void processCreateInstance(
3480: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3481: RefObject pAffectedParentInstance,
3482: RefObject pNewlyCreatedInstance) {
3483: try {
3484: // Iterate through the list of model assistants
3485: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.AssistantsList
3486: .iterator(); lModelAssistantsIterator.hasNext();)
3487: ((ModelAssistant) lModelAssistantsIterator.next())
3488: .onModelElementJustCreated(
3489: pAffectedModelDescriptor.ModelName,
3490: pNewlyCreatedInstance);
3491: // Iterate through the list of metamodel assistants
3492: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
3493: .iterator(); lModelAssistantsIterator.hasNext();)
3494: ((ModelAssistant) lModelAssistantsIterator.next())
3495: .onModelElementJustCreated(
3496: pAffectedModelDescriptor.ModelName,
3497: pNewlyCreatedInstance);
3498: } catch (ModelRepositoryException e) {
3499: sLogger.error(
3500: "Caught error while trying to dispatch event.", e);
3501: }
3502: }
3503:
3504: // This helper method executes post create instance on model implementations and assistants
3505: public void processPostCreateInstance(
3506: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3507: String pAffectedParentObjectRepositoryId,
3508: String pCreatedObjectRepositoryId) {
3509: // Iterate through listeners giving them a chance to process changes
3510: for (Iterator lModelListenersIterator = pAffectedModelDescriptor.ListenersSet
3511: .iterator(); lModelListenersIterator.hasNext();) {
3512: ModelListener lModelListener = (ModelListener) lModelListenersIterator
3513: .next();
3514: lModelListener.onModelElementCreated(
3515: pAffectedModelDescriptor.ModelName,
3516: pAffectedParentObjectRepositoryId,
3517: pCreatedObjectRepositoryId);
3518: }
3519: }
3520:
3521: // This helper method executes post create instance on model implementations and assistants
3522: public void processPostDeleteInstance(
3523: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3524: String pAffectedParentInstanceRepositoryId,
3525: String pDeletedInstanceRepositoryId) {
3526: // Iterate through listeners giving them a chance to respond
3527: for (Iterator lModelListenersIterator = pAffectedModelDescriptor.ListenersSet
3528: .iterator(); lModelListenersIterator.hasNext();) {
3529: ModelListener lModelListener = (ModelListener) lModelListenersIterator
3530: .next();
3531: lModelListener.onModelElementDeleted(
3532: pAffectedModelDescriptor.ModelName,
3533: pAffectedParentInstanceRepositoryId,
3534: pDeletedInstanceRepositoryId);
3535: }
3536: }
3537:
3538: // This helper method executes post create instance on model implementations and assistants
3539: public void processDeleteInstance(
3540: ModelRepositoryImpl.ModelDescriptor pAffectedModelDescriptor,
3541: RefObject pInstanceBeingDeleted) {
3542: try {
3543: // Iterate through the list of model assistants
3544: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.AssistantsList
3545: .iterator(); lModelAssistantsIterator.hasNext();)
3546: ((ModelAssistant) lModelAssistantsIterator.next())
3547: .onModelElementBeingDeleted(
3548: pAffectedModelDescriptor.ModelName,
3549: pInstanceBeingDeleted);
3550: // Iterate through the list of metamodel assistants
3551: for (Iterator lModelAssistantsIterator = pAffectedModelDescriptor.MetaModelDescriptor.RegisteredModelAssistants
3552: .iterator(); lModelAssistantsIterator.hasNext();)
3553: ((ModelAssistant) lModelAssistantsIterator.next())
3554: .onModelElementBeingDeleted(
3555: pAffectedModelDescriptor.ModelName,
3556: pInstanceBeingDeleted);
3557: } catch (ModelRepositoryException e) {
3558: sLogger.error(
3559: "Caught error while trying to dispatch event.", e);
3560: }
3561: }
3562: }
|