/* * ==================================================================== * * The ObjectStyle Group Software License, Version 1.0 * * Copyright (c) 2006 The ObjectStyle Group and individual authors of the * software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowlegement: "This product includes software * developed by the ObjectStyle Group (http://objectstyle.org/)." Alternately, * this acknowlegement may appear in the software itself, if and wherever such * third-party acknowlegements normally appear. * * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse or * promote products derived from this software without prior written permission. * For written permission, please contact andrus@objectstyle.org. * * 5. Products derived from this software may not be called "ObjectStyle" nor * may "ObjectStyle" appear in their names without prior written permission of * the ObjectStyle Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * OBJECTSTYLE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many individuals on * behalf of the ObjectStyle Group. For more information on the ObjectStyle * Group, please see <http://objectstyle.org/>. * */ package org.objectstyle.wolips.eomodeler.core.model; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.jar.JarEntry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.objectstyle.woenvironment.plist.PropertyListParserException; import org.objectstyle.woenvironment.plist.WOLPropertyListSerialization; import org.objectstyle.wolips.baseforplugins.util.URLUtils; import org.objectstyle.wolips.eomodeler.core.Activator; public class EOModelGroup extends EOModelObject<Object> { public static final String MODELS = "models"; private Set<EOModel> _models; private String _editingModelName; private boolean _dirty; public EOModelGroup() { _models = new HashSet<EOModel>(); } public boolean hasProjectWonder() { return containsModelNamed("erprototypes"); } public Set<EOModelReferenceFailure> getReferenceFailures() { return new HashSet<EOModelReferenceFailure>(); } public void setDirty(boolean dirty) { _dirty = dirty; } public boolean isDirty() { boolean dirty = false; for (EOModel model : getModels()) { try { if (model.isDirty() && model.canSave()) { dirty = true; break; } } catch (MalformedURLException e) { Activator.getDefault().log("Unable to determine if the model " + model.getName() + " was dirty, so we skipped it.", e); } } return dirty; } @SuppressWarnings("unused") protected void _modelChanged(EOModel model, String propertyName, Object oldValue, Object newValue) { if (EOModel.DIRTY.equals(propertyName)) { boolean oldDirty = _dirty; boolean dirty = isDirty(); firePropertyChange(propertyName, Boolean.valueOf(oldDirty), Boolean.valueOf(dirty)); _dirty = dirty; } } @Override protected void _propertyChanged(String name, Object value, Object value2) { // DO NOTHING } public Set<EOModel> getModels() { return _models; } public Set<EOModel> getSortedModels() { return new PropertyListSet<EOModel>(_models); } /** * Returns the list of names of entities that are not prototypes. * * @return list of entity names */ public Set<String> getNonPrototypeEntityNames() { Set<String> entityNames = new TreeSet<String>(); for (EOModel model : _models) { for (EOEntity entity : model.getEntities()) { if (!entity.isPrototype()) { entityNames.add(entity.getName()); } } } return entityNames; } public Set<String> getEntityNames() { Set<String> entityNames = new TreeSet<String>(); for (EOModel model : _models) { for (EOEntity entity : model.getEntities()) { entityNames.add(entity.getName()); } } return entityNames; } /** * Returns the list of entities that are not prototypes. * * @return list of non prototype entities */ public Set<EOEntity> getNonPrototypeEntities() { Set<EOEntity> entities = new HashSet<EOEntity>(); for (EOModel model : _models) { entities.addAll(model.getNonPrototypeEntities()); } return entities; } public Set<EOEntity> getEntities() { Set<EOEntity> allEntities = new HashSet<EOEntity>(); for (EOModel model : _models) { allEntities.addAll(model.getEntities()); } return allEntities; } public Set<EOEntity> getSortedEntities() { return new PropertyListSet<EOEntity>(getEntities()); } public String findUnusedEntityName(String _newName) { return _findUnusedName(_newName, "getEntityNamed"); } public EOEntity getEntityNamed(String _entityName) { EOEntity matchingEntity = null; Iterator modelsIter = _models.iterator(); while (matchingEntity == null && modelsIter.hasNext()) { EOModel model = (EOModel) modelsIter.next(); matchingEntity = model.getEntityNamed(_entityName); } return matchingEntity; } public boolean containsModelNamed(String _entityName) { return getModelNamed(_entityName) != null; } public void _checkForDuplicateModelName(EOModel _model, String _newName) throws DuplicateModelNameException { EOModel model = getModelNamed(_newName); if (model != null && model != _model) { throw new DuplicateModelNameException(_newName, this); } } public void addModel(EOModel _model) throws DuplicateEntityNameException, DuplicateModelNameException { addModel(_model, null); } public void addModel(EOModel _model, Set<EOModelVerificationFailure> _failures) throws DuplicateEntityNameException, DuplicateModelNameException { Set<EOModel> oldModels = new HashSet<EOModel>(_models); _model._setModelGroup(this); _checkForDuplicateModelName(_model, _model.getName()); for (EOEntity entity : _model.getEntities()) { _model._checkForDuplicateEntityName(entity, entity.getName(), _failures); } _models.add(_model); clearCachedPrototypes(_failures); firePropertyChange(EOModelGroup.MODELS, oldModels, _models); } public void removeModel(EOModel _model, Set<EOModelVerificationFailure> _failures) { Set<EOModel> oldModels = new HashSet<EOModel>(_models); _models.remove(_model); clearCachedPrototypes(_failures); firePropertyChange(EOModelGroup.MODELS, oldModels, _models); _model._setModelGroup(null); } public Set<EOEntity> getPrototypeEntities() { Set<EOEntity> prototypeEntities = new HashSet<EOEntity>(); for (EOModel model : _models) { for (EOEntity entity : model.getEntities()) { if (entity.isPrototype()) { prototypeEntities.add(entity); } } } return prototypeEntities; } protected void clearCachedPrototypes(Set<EOModelVerificationFailure> _failures) { for (EOModel model : _models) { model.clearCachedPrototypes(_failures, false); } } public Map<EOAttribute, Set<EORelationship>> _createReferencingRelationshipsCache() { Map<EOAttribute, Set<EORelationship>> cache = new HashMap<EOAttribute, Set<EORelationship>>(); for (EOModel model : getModels()) { model._createReferencingRelationshipsCache(cache); } return cache; } public Map<EOEntity, Set<EOEntity>> _createInheritanceCache() { Map<EOEntity, Set<EOEntity>> cache = new HashMap<EOEntity, Set<EOEntity>>(); for (EOModel model : getModels()) { model._createInheritanceCache(cache); } return cache; } public EOModel getModelNamed(String _name) { EOModel matchingModel = null; Iterator<EOModel> modelsIter = _models.iterator(); while (matchingModel == null && modelsIter.hasNext()) { EOModel model = modelsIter.next(); if (model.getName().equals(_name)) { matchingModel = model; } } return matchingModel; } /** * Sets the URL of the model that is being editing (considered the primary * model). * * @param editingModelURL * the url of the model that is in edit mode */ public void setEditingModelURL(URL editingModelURL) { setEditingModelName(EOModelGroup.getModelNameForURL(editingModelURL)); } /** * Sets the name of the model that is being editing (considered the primary * model). * * @param editingModelName * the name of the model that is in edit mode */ public void setEditingModelName(String editingModelName) { _editingModelName = editingModelName; } /** * Returns the name of the model that is being editing (considered the * primary model). * * @return the name of the model that is in edit mode */ public String getEditingModelName() { return _editingModelName; } /** * Returns the model that is being editing (considered the primary model). * * @return the model that is in edit mode */ public EOModel getEditingModel() { return getModelNamed(_editingModelName); } /** * Returns the model name for the given URL. * * @param url * the URL to lookup (could be index.eomodeld file, or .eomodeld * folder) * @return the model name for the given URL */ public static String getModelNameForURL(URL url) { String modelName; if (url == null) { modelName = null; } else { String protocol = url.getProtocol(); if ("jar".equals(protocol)) { try { JarURLConnection conn = (JarURLConnection) url.openConnection(); JarEntry jarEntry = conn.getJarEntry(); if (jarEntry != null) { modelName = EOModelGroup.getModelNameForJarEntry(jarEntry); } else { modelName = null; } } catch (IOException ioe) { throw new IllegalStateException("The jar url '" + url.toString() + "' was unable to be used to find out the EO model's name.", ioe); } } else { File file = URLUtils.cheatAndTurnIntoFile(url); modelName = EOModelGroup.getModelNameForFile(file); } } return modelName; } /** * Returns the model name for the given jar entry. This would be used in the * situation where a Jar file is being introspected for the models within * it. * * @param jarEntry * the jar entry to lookup (could be index.eomodeld file, or * .eomodeld folder) * @return the model name for the given jar entry */ public static String getModelNameForJarEntry(JarEntry jarEntry) { String modelName = null; if (jarEntry != null) { String jarEntryName = jarEntry.getName(); if (jarEntryName.endsWith("index.eomodeld")) { int lastSlashIndex = jarEntryName.lastIndexOf('/'); if (lastSlashIndex == -1) { jarEntryName = null; } else { jarEntryName = jarEntryName.substring(0, lastSlashIndex + 1); } } if (jarEntryName != null) { if (jarEntryName.endsWith(".eomodeld/")) { int lastDotIndex = jarEntryName.lastIndexOf('.', jarEntryName.length() - 2); int lastSlashIndex = jarEntryName.lastIndexOf('/', jarEntryName.length() - 2); modelName = jarEntryName.substring(lastSlashIndex + 1, lastDotIndex); if (modelName.length() == 0) { modelName = null; } } } } return modelName; } /** * Returns the model name for the given file. * * @param url * the file to lookup (could be index.eomodeld file, or .eomodeld * folder) * @return the model name for the given file */ public static String getModelNameForFile(File file) { String modelName = null; if (file != null) { String fileName = file.getName(); if (file.getName().equals("index.eomodeld")) { fileName = file.getParentFile().getName(); } if (fileName.endsWith(".eomodeld")) { modelName = fileName.substring(0, fileName.lastIndexOf('.')); } } return modelName; } public EOModel loadModelFromURL(URL url) throws IOException, EOModelException { Set<EOModelVerificationFailure> failures = new HashSet<EOModelVerificationFailure>(); EOModel model = loadModelFromURL(url, failures, true, new NullProgressMonitor()); if (failures.size() > 0) { throw new EOModelException("Failed to load model from URL '" + url + "': " + failures); } return model; } public EOModel loadModelFromURL(URL url, Set<EOModelVerificationFailure> failures) throws IOException, EOModelException { EOModel model = loadModelFromURL(url, failures, true, new NullProgressMonitor()); return model; } public EOModel loadModelFromURL(URL url, Set<EOModelVerificationFailure> failures, IProgressMonitor progressMonitor) throws IOException, EOModelException { EOModel model = loadModelFromURL(url, failures, true, progressMonitor); return model; } public void loadModelsFromURL(URL url, Set<EOModelVerificationFailure> failures, IProgressMonitor progressMonitor) throws IOException, EOModelException { loadModelsFromURL(url, -1, failures, true, progressMonitor); } protected void loadModelsFromURL(URL url, Set<EOModelVerificationFailure> failures, boolean skipOnDuplicates, IProgressMonitor progressMonitor) throws IOException, EOModelException { loadModelsFromURL(url, -1, failures, skipOnDuplicates, progressMonitor); } public void loadModelsFromURL(URL url, int maxDepth, Set<EOModelVerificationFailure> failures, boolean skipOnDuplicates, IProgressMonitor progressMonitor) throws IOException, EOModelException { String path = url.getPath(); if (path.endsWith(".eomodeld") || path.endsWith(".eomodeld/")) { loadModelFromURL(url, failures, skipOnDuplicates, progressMonitor); } else if (maxDepth != 0) { for (URL childURL : URLUtils.getChildrenFolders(url)) { if (URLUtils.isFolder(childURL)) { boolean processFolder = true; // Skip over Resources/*.wo and Resources/Java ... just a performance optimization String childPath = childURL.getPath(); if (childPath.endsWith("/Java/") || childPath.endsWith(".wo/")) { processFolder = false; } if (processFolder) { loadModelsFromURL(childURL, maxDepth - 1, failures, skipOnDuplicates, progressMonitor); } } } } } public EOModel loadModelFromURL(URL modelURL, Set<EOModelVerificationFailure> failures, boolean skipOnDuplicates, IProgressMonitor progressMonitor) throws IOException, EOModelException { String modelName = EOModelGroup.getModelNameForURL(modelURL); progressMonitor.setTaskName("Loading " + modelName + " ..."); EOModel model = getModelNamed(modelName); if (model != null) { if (skipOnDuplicates) { // _failures.add(new EOModelVerificationFailure(model, "The // model named '" + modelName + "' exists in " + // model.getIndexURL() + " and " + _folder + ". Skipping " + // _folder + ".", true)); } else { failures.add(new EOModelVerificationFailure(model, model, "The model named '" + modelName + "' exists in " + model.getIndexURL() + " and " + modelURL + ".", true)); } } if (!skipOnDuplicates || model == null) { boolean reloadModel = true; while (reloadModel) { model = new EOModel(modelName); model.setModelURL(modelURL); URL indexURL = model.getIndexURL(); if (!URLUtils.exists(indexURL)) { reloadModel = false; failures.add(new EOModelVerificationFailure(model, model, "Skipping model because " + indexURL + " does not exist.", true)); } else { model._setModelGroup(this); try { model.loadFromURL(modelURL, failures); addModel(model, failures); reloadModel = false; } catch (DuplicateEntityNameException e) { e.printStackTrace(); if (!skipOnDuplicates) { throw e; } EOEntity existingEntity = e.getExistingEntity(); EOModel existingEntityModel = existingEntity.getModel(); failures.add(new EOModelVerificationFailure(model, model, existingEntityModel.getName() + " and " + model.getName() + " both declare an entity named " + existingEntity.getName() + ", so " + existingEntityModel.getName() + " is being removed. You can create an EOModelGroup file to resolve this.", true, e)); removeModel(existingEntityModel, failures); } catch (Exception e) { e.printStackTrace(); failures.add(new EOModelVerificationFailure(model, model, model.getName() + " failed to load.", true, e)); reloadModel = false; } } } } return model; } public void verify(Set<EOModelVerificationFailure> _failures) { VerificationContext verificationContext = new VerificationContext(this); for (EOModel model : _models) { model.verify(_failures, verificationContext); } } public void resolve(Set<EOModelVerificationFailure> _failures) { for (EOModel model : _models) { model.resolve(_failures); } for (EOModel model : _models) { model.resolveFlattened(_failures); } } public String getFullyQualifiedName() { return "EOModelGroup"; } public String toString() { return "[EOModelGroup: models = " + _models + "]"; } @Override public String getName() { return "EOModelGroup"; } @Override public EOModelGroup _cloneModelObject() { throw new IllegalStateException("Not implemented"); } @Override public void _addToModelParent(Object modelParent, boolean findUniqueName, Set<EOModelVerificationFailure> failures) { // DO NOTHING } @Override public Class<Object> _getModelParentType() { return null; } @Override public Object _getModelParent() { return null; } @Override public void _removeFromModelParent(Set<EOModelVerificationFailure> failures) { // DO NOTHING } public static void main(String[] args) throws IOException, PropertyListParserException { long a = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) { WOLPropertyListSerialization.propertyListFromFile(new File("/Users/mschrag/Documents/workspace/MDTask/Resources/MDTask.eomodeld/index.eomodeld")); } System.out.println("EOModelGroup.main: " + (System.currentTimeMillis() - a)); } }