/* Copyright (C) 2010 by Claas Wilke (claaswilke@gmx.net) This file is part of the XML Model Instance Plug-in of Dresden OCL2 for Eclipse. Dresden OCL2 for Eclipse is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Dresden OCL2 for Eclipse is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Dresden OCL2 for Eclipse. If not, see <http://www.gnu.org/licenses/>. */ package org.dresdenocl.modelinstancetype.xml.internal.modelinstance; import java.io.File; import java.io.IOException; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.log4j.Logger; import org.eclipse.osgi.util.NLS; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; import org.dresdenocl.model.IModel; import org.dresdenocl.model.ModelAccessException; import org.dresdenocl.modelinstance.IModelInstance; import org.dresdenocl.modelinstance.base.AbstractModelInstance; import org.dresdenocl.modelinstancetype.exception.OperationAccessException; import org.dresdenocl.modelinstancetype.exception.OperationNotFoundException; import org.dresdenocl.modelinstancetype.exception.PropertyAccessException; import org.dresdenocl.modelinstancetype.exception.PropertyNotFoundException; import org.dresdenocl.modelinstancetype.exception.TypeNotFoundInModelException; import org.dresdenocl.modelinstancetype.types.IModelInstanceCollection; import org.dresdenocl.modelinstancetype.types.IModelInstanceElement; import org.dresdenocl.modelinstancetype.types.IModelInstanceObject; import org.dresdenocl.modelinstancetype.xml.XmlModelInstanceTypePlugin; import org.dresdenocl.modelinstancetype.xml.internal.msg.XmlModelInstanceTypeMessages; import org.dresdenocl.pivotmodel.Operation; import org.dresdenocl.pivotmodel.Property; /** * <p> * Represents instances of {@link IModel}s represented by XML files. * </p> * * @author Claas Wilke */ public class XmlModelInstance extends AbstractModelInstance { /** The {@link Logger} for this class. */ private static final Logger LOGGER = XmlModelInstanceTypePlugin .getLogger(XmlModelInstance.class); /** * A counter used to generated default names for empty * {@link XmlModelInstance}s. */ private static int nameCounter = 0; /** * <p> * Creates an empty {@link XmlModelInstance}. * </p> * * @param model * The {@link IModel} for that the {@link IModelInstance} shall * be loaded. */ public XmlModelInstance(IModel model) { /* Probably debug the entry of this method. */ if (LOGGER.isDebugEnabled()) { String msg; msg = "XMLModelInstance("; //$NON-NLS-1$ msg += ", model = " + model; //$NON-NLS-1$ msg += ")"; //$NON-NLS-1$ LOGGER.debug(msg); } // no else. /* Initialize the instance. */ this.myModel = model; this.myName = model.getDisplayName() + "_XMLInstance" + nameCounter; nameCounter++; this.myModelInstanceFactory = new XmlModelInstanceFactory(this.myModel); /* Probably debug the exit of this method. */ if (LOGGER.isDebugEnabled()) { String msg; msg = "XMLModelInstance(IModel) - exit"; //$NON-NLS-1$ LOGGER.debug(msg); } // no else. } /** * <p> * Creates a new {@link XmlModelInstance} for a given XML {@link File} and a * given {@link IModel}. * </p> * * @param modelInstanceFile * The {@link File} that represents the XML document. * @param model * The {@link IModel} for that the {@link IModelInstance} shall * be loaded. * @throws ModelAccessException * Thrown, if an error during loading the {@link IModelInstance} * occurs. */ public XmlModelInstance(File modelInstanceFile, IModel model) throws ModelAccessException { /* Probably debug the entry of this method. */ if (LOGGER.isDebugEnabled()) { String msg; msg = "XMLModelInstance("; //$NON-NLS-1$ msg += "modelInstanceFile = " + modelInstanceFile; //$NON-NLS-1$ msg += ", model = " + model; //$NON-NLS-1$ msg += ")"; //$NON-NLS-1$ LOGGER.debug(msg); } // no else. /* Initialize the instance. */ this.myModel = model; this.myName = modelInstanceFile.toString(); this.myModelInstanceFactory = new XmlModelInstanceFactory(this.myModel); /* Parse the XML file. */ this.parseXMLFile(modelInstanceFile); /* Probably debug the exit of this method. */ if (LOGGER.isDebugEnabled()) { String msg; msg = "XMLModelInstance(File, IModel) - exit"; //$NON-NLS-1$ LOGGER.debug(msg); } // no else. } /* * (non-Javadoc) * * @seeorg.dresdenocl.modelbus.modelinstance.IModelInstance# * addModelInstanceElement(java.lang.Object) */ public IModelInstanceElement addModelInstanceElement(Object object) throws TypeNotFoundInModelException { if (object == null) { throw new IllegalArgumentException( "Parameter 'object' must not be null."); } // no else. IModelInstanceElement result; result = this.myModelInstanceFactory.createModelInstanceElement(object); if (result instanceof IModelInstanceObject) { this.addModelInstanceObject((IModelInstanceObject) result); } // no else. return result; } /* * (non-Javadoc) * * @see * org.dresdenocl.modelbus.modelinstance.IModelInstance#getStaticProperty * (org.dresdenocl.pivotmodel.Property) */ public IModelInstanceElement getStaticProperty(Property property) throws PropertyAccessException, PropertyNotFoundException { if (property == null) { throw new IllegalArgumentException( "Parameter 'property' must not be null."); } // no else. throw new PropertyNotFoundException( XmlModelInstanceTypeMessages.XmlModelInstance_StaticPropertiesAreNotSupported); } /* * (non-Javadoc) * * @seeorg.dresdenocl.modelbus.modelinstance.IModelInstance# * invokeStaticOperation(org.dresdenocl.pivotmodel.Operation, * java.util.List) */ public IModelInstanceElement invokeStaticOperation(Operation operation, List<IModelInstanceElement> args) throws OperationAccessException, OperationNotFoundException { if (operation == null) { throw new IllegalArgumentException( "Parameter 'operation' must not be null."); } else if (args == null) { throw new IllegalArgumentException( "Parameter 'args' must not be null."); } // no else. throw new OperationNotFoundException( XmlModelInstanceTypeMessages.XmlModelInstance_StaticOperationsAreNotSupported); } /** * <p> * Adds an already adapted {@link IModelInstanceObject} to this * {@link IModelInstance}. * </p> */ protected void addModelInstanceObject(IModelInstanceObject imiObject) { this.myModelInstanceObjects.add(imiObject); this.addAssociatedElementsAsWell(imiObject); this.initializeTypeMapping(); } /** * <p> * A helper method that recursively adds the associated * {@link IModelInstanceObject}s of a given {@link IModelInstanceObject} to * this {@link XmlModelInstance} as well. The {@link IModelInstanceObject} * can be associated via properties. * </p> * * @param imiObject * The {@link IModelInstanceObject} those associated * {@link IModelInstanceObject}s shall be added as well. */ @SuppressWarnings("unchecked") private void addAssociatedElementsAsWell(IModelInstanceObject imiObject) { /* Probably adapt recursively associated elements. */ if (!imiObject.isUndefined()) { for (Property property : imiObject.getType().allProperties()) { try { IModelInstanceElement propertyValue; propertyValue = imiObject.getProperty(property); /* * If a property's value is a IMIObject and not added yet, * add it (adds its property's values recursively as well). */ if (propertyValue instanceof IModelInstanceObject && !this.myModelInstanceObjects .contains((IModelInstanceObject) propertyValue)) { this .addModelInstanceObject((IModelInstanceObject) propertyValue); } /* * Else if a property's value is an IMICollection, probably * add all its elements. */ if (propertyValue instanceof IModelInstanceCollection<?>) { this .addModelInstanceCollection((IModelInstanceCollection<IModelInstanceElement>) propertyValue); } } // end try. catch (PropertyAccessException e) { /* Do nothing. */ } catch (PropertyNotFoundException e) { /* Do nothing. */ } // end catch. } // end for. } // no else. } /** * <p> * A helper method that recursively adds the contained * {@link IModelInstanceElement}s if they are {@link IModelInstanceObject}s * and have not been added yet. * </p> * * @param collection * The {@link IModelInstanceCollection} to be checked. */ @SuppressWarnings("unchecked") private void addModelInstanceCollection( IModelInstanceCollection<IModelInstanceElement> collection) { for (IModelInstanceElement element : collection.getCollection()) { if (element instanceof IModelInstanceObject && !this.myModelInstanceObjects .contains((IModelInstanceObject) element)) { this.addModelInstanceObject((IModelInstanceObject) element); } else if (element instanceof IModelInstanceCollection<?>) { this .addModelInstanceCollection((IModelInstanceCollection<IModelInstanceElement>) element); } } // end for. } /** * <p> * Parses a given {@link File} as XML file and adds all its elements to this * {@link IModelInstance}. * </p> * * @param modelInstanceFile * The {@link File} that shall be parsed. * @throws ModelAccessException * Thrown, if an error during parsing or {@link IModelObject} * adaptation occurs. */ private void parseXMLFile(File modelInstanceFile) throws ModelAccessException { /* Parse the XML file. */ try { DocumentBuilder documentBuilder; Document instanceDocument; Node rootNode; documentBuilder = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); instanceDocument = documentBuilder.parse(modelInstanceFile); rootNode = instanceDocument.getFirstChild(); /* Add the container node. */ this.addModelInstanceElement(rootNode); /* * Initialize the caching maps for the operations getObjectsOfType * etc. */ this.initializeTypeMapping(); } // end try. catch (ParserConfigurationException e) { String msg; msg = XmlModelInstanceTypeMessages.XMLModelInstance_ParserWrongConfigured; LOGGER.error(msg); throw new ModelAccessException(msg, e); } catch (SAXException e) { String msg; msg = XmlModelInstanceTypeMessages.XMLModelInstance_SaxExceptionOccurred; NLS.bind(msg, e.getMessage()); LOGGER.error(msg); throw new ModelAccessException(msg, e); } catch (IOException e) { String msg; msg = XmlModelInstanceTypeMessages.XMLModelInstance_IOExceptionOccurred; NLS.bind(msg, e.getMessage()); LOGGER.error(msg); throw new ModelAccessException(msg, e); } catch (TypeNotFoundInModelException e) { throw new ModelAccessException(e.getMessage(), e); } // end catch. } }