Package org.objectstyle.wolips.eomodeler.core.model

Source Code of org.objectstyle.wolips.eomodeler.core.model.EOModel

/*
* ====================================================================
*
* 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.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 org.objectstyle.woenvironment.plist.PropertyListParserException;
import org.objectstyle.woenvironment.plist.WOLPropertyListSerialization;
import org.objectstyle.wolips.baseforplugins.util.ComparisonUtils;
import org.objectstyle.wolips.baseforplugins.util.URLUtils;
import org.objectstyle.wolips.eomodeler.core.model.history.EOEntityAddedEvent;
import org.objectstyle.wolips.eomodeler.core.model.history.EOEntityDeletedEvent;
import org.objectstyle.wolips.eomodeler.core.model.history.ModelEvents;
import org.objectstyle.wolips.eomodeler.core.utils.NamingConvention;

public class EOModel extends UserInfoableEOModelObject<EOModelGroup> implements ISortableEOModelObject {
  public static final String CURRENT_VERSION = "1.0.1";

  public static final String DIRTY = "dirty";

  public static final String ENTITY = "entity";

  public static final String ADAPTOR_NAME = "adaptorName";

  public static final String VERSION = "version";

  public static final String NAME = "name";

  public static final String ENTITIES = "entities";

  public static final String STORED_PROCEDURE = "storedProcedure";

  public static final String STORED_PROCEDURES = "storedProcedures";

  public static final String ACTIVE_DATABASE_CONFIG = "activeDatabaseConfig";

  public static final String DATABASE_CONFIG = "databaseConfig";

  public static final String DATABASE_CONFIGS = "databaseConfigs";

  public static final String ATTRIBUTE_NAMING_CONVENTION = "attributeNamingConvention";

  public static final String ENTITY_NAMING_CONVENTION = "entityNamingConvention";

  public static final String MODEL_SAVING = "modelSaving";

  public static final String REVERSE_ENGINEERED = "reverseEngineered";

  private EOModelGroup myModelGroup;

  private String myName;

  private String myVersion;

  private Set<EOEntity> myEntities;

  private Set<EODatabaseConfig> myDatabaseConfigs;

  private EODatabaseConfig myActiveDatabaseConfig;

  private Set<EOStoredProcedure> myStoredProcedures;

  private Set<String> myDeletedEntityNamesInObjectStore;

  private Set<String> myDeletedEntityNames;

  private Set<String> myDeletedStoredProcedureNames;

  private EOModelMap myModelMap;

  private boolean myDirty;

  private URL myModelURL;

  private Set<EOAttribute> myPrototypeAttributeCache;

  private ModelEvents _modelEvents;

  private NamingConvention _entityNamingConvention;

  private NamingConvention _attributeNamingConvention;
 
  private boolean _reverseEngineered;
 
  private EOLastModified _lastModified;

  public EOModel(String _name) {
    myName = _name;
    myEntities = new HashSet<EOEntity>();
    myStoredProcedures = new HashSet<EOStoredProcedure>();
    myDatabaseConfigs = new HashSet<EODatabaseConfig>();
    myDeletedEntityNamesInObjectStore = new PropertyListSet<String>();
    myDeletedEntityNames = new PropertyListSet<String>();
    myDeletedStoredProcedureNames = new PropertyListSet<String>();
    myVersion = "2.1";
    myModelMap = new EOModelMap();
    _modelEvents = new ModelEvents();
    _entityNamingConvention = NamingConvention.DEFAULT;
    _attributeNamingConvention = NamingConvention.DEFAULT;
  }

  public EOModel(URL modelURL) throws EOModelException, IOException {
    this(EOModelGroup.getModelNameForURL(modelURL));
    Set<EOModelVerificationFailure> failures = new HashSet<EOModelVerificationFailure>();
    loadFromURL(modelURL, failures);
    if (failures.size() > 0) {
      throw new EOModelException("Failed to load model from URL '" + modelURL + "': " + failures);
    }
  }

  public EOModel(URL modelURL, Set<EOModelVerificationFailure> failures) throws EOModelException, IOException {
    this(EOModelGroup.getModelNameForURL(modelURL));
    loadFromURL(modelURL, failures);
  }

  protected void _storedProcedureChanged(EOStoredProcedure _storedProcedure, String _propertyName, Object _oldValue, Object _newValue) {
    firePropertyChange(EOModel.STORED_PROCEDURE + "." + _propertyName, _oldValue, _newValue);
    firePropertyChange(EOModel.STORED_PROCEDURE, null, _storedProcedure);
  }

  public void _setModelGroup(EOModelGroup _modelGroup) {
    myModelGroup = _modelGroup;
  }

  public void setEntityNamingConvention(NamingConvention entityNamingConvention) {
    NamingConvention oldEntityNamingConvention = _entityNamingConvention;
    _entityNamingConvention = entityNamingConvention;
    firePropertyChange(EOModel.ENTITY_NAMING_CONVENTION, oldEntityNamingConvention, _entityNamingConvention);
  }

  public NamingConvention getEntityNamingConvention() {
    return _entityNamingConvention;
  }

  public void setAttributeNamingConvention(NamingConvention attributeNamingConvention) {
    NamingConvention oldAttributeNamingConvention = _attributeNamingConvention;
    _attributeNamingConvention = attributeNamingConvention;
    firePropertyChange(EOModel.ATTRIBUTE_NAMING_CONVENTION, oldAttributeNamingConvention, _attributeNamingConvention);
  }

  public NamingConvention getAttributeNamingConvention() {
    return _attributeNamingConvention;
  }

  public Set<EOModelReferenceFailure> getReferenceFailures() {
    return new HashSet<EOModelReferenceFailure>();
  }

  public String guessPackageName() {
    return guessPackageName(getEntities());
  }

  public String guessPackageName(Set<EOEntity> _entities) {
    String guessPackageName = null;
    for (EOEntity entity : _entities) {
      String className = entity.getClassName();
      if (className != null) {
        int packageNameEnd = className.lastIndexOf('.');
        String packageName;
        if (packageNameEnd != -1) {
          packageName = className.substring(0, packageNameEnd);
        } else {
          packageName = "";
        }
        // ignore blank package names ...
        if (!"".equals(packageName)) {
          if (guessPackageName == null) {
            guessPackageName = packageName;
          } else if ("".equals(guessPackageName)) {
            // it can't change from ""
          } else if (!guessPackageName.equals(packageName)) {
            guessPackageName = "";
//            if (guessPackageName.startsWith(packageName)) {
//              guessPackageName = packageName;
//            } else if (packageName.startsWith(guessPackageName)) {
//              // leave it as is
//            } else {
//              int lastMatchingIndex = -1;
//              for (int index = 0; index < guessPackageName.length() && index < packageName.length(); index++) {
//                if (guessPackageName.charAt(index) == packageName.charAt(index)) {
//                  lastMatchingIndex = index;
//                } else {
//                  break;
//                }
//              }
//              if (lastMatchingIndex != -1) {
//                guessPackageName = guessPackageName.substring(0, lastMatchingIndex);
//                if (guessPackageName.endsWith(".")) {
//                  guessPackageName = guessPackageName.substring(0, guessPackageName.length() - 1);
//                }
//              } else {
//                guessPackageName = "";
//              }
//            }
          }
        }
      }
    }
    return guessPackageName;
  }

  public EOEntity addBlankEntity(String name) throws DuplicateNameException {
    String newEntityName = findUnusedEntityName(name);
    EOEntity entity = new EOEntity(newEntityName);
    entity.guessExternalNameInModel(this);
    entity.guessClassNameInModel(this);
    addEntity(entity);

    if (myModelGroup != null && myModelGroup.hasProjectWonder()) {
      EOAttribute pk = new EOAttribute("id");
      pk.setPrototype(getPrototypeAttributeNamed("id"));
      pk.setColumnName("id");
      pk.setPrimaryKey(Boolean.TRUE);
      pk.setClassProperty(Boolean.FALSE);
      pk.setUsedForLocking(Boolean.TRUE);
      entity.addAttribute(pk);
    }

    return entity;
  }

  public boolean isEditing() {
    EOModelGroup modelGroup = getModelGroup();
    boolean editing = (modelGroup == null || getName().equals(modelGroup.getEditingModelName()));
    return editing;
  }

  public boolean isReverseEngineered() {
    return _reverseEngineered;
  }

  public void setReverseEngineered(boolean reverseEngineered) {
    Boolean oldReverseEngineered = Boolean.valueOf(_reverseEngineered);
    _reverseEngineered = reverseEngineered;
    firePropertyChange(EOModel.REVERSE_ENGINEERED, oldReverseEngineered, Boolean.valueOf(_reverseEngineered));
  }

  public boolean isDirty() {
    return myDirty;
  }

  public void setDirty(boolean _dirty) {
    Boolean oldDirty = Boolean.valueOf(myDirty);
    myDirty = _dirty;
    firePropertyChange(EOModel.DIRTY, oldDirty, Boolean.valueOf(myDirty));
  }

  protected void firePropertyChange(String _propertyName, Object _oldValue, Object _newValue) {
    super.firePropertyChange(_propertyName, _oldValue, _newValue);
  }

  protected void _propertyChanged(String _propertyName, Object _oldValue, Object _newValue) {
    if (!myDirty && !EOModel.DIRTY.equals(_propertyName) && !EOModel.MODEL_SAVING.equals(_propertyName)) {
      setDirty(true);
    }
    if (myModelGroup != null) {
      myModelGroup._modelChanged(this, _propertyName, _oldValue, _newValue);
    }
  }

  protected void _entityChanged(EOEntity _entity, String _propertyName, Object _oldValue, Object _newValue) {
    firePropertyChange(EOModel.ENTITY + "." + _propertyName, _oldValue, _newValue);
    firePropertyChange(EOModel.ENTITY, null, _entity);
  }

  protected void _databaseConfigChanged(EODatabaseConfig _databaseConfig, String _propertyName, Object _oldValue, Object _newValue) {
    firePropertyChange(EOModel.DATABASE_CONFIG + "." + _propertyName, _oldValue, _newValue);
    firePropertyChange(EOModel.DATABASE_CONFIG, null, _databaseConfig);
    if (_databaseConfig == myActiveDatabaseConfig) {
      clearCachedPrototypes(null, false);
    }
  }

  public EODatabaseConfig getDatabaseConfigNamed(String _name) {
    EODatabaseConfig matchingDatabaseConfig = null;
    Iterator<EODatabaseConfig> databaseConfigsIter = myDatabaseConfigs.iterator();
    while (matchingDatabaseConfig == null && databaseConfigsIter.hasNext()) {
      EODatabaseConfig entity = databaseConfigsIter.next();
      if (ComparisonUtils.equals(entity.getName(), _name)) {
        matchingDatabaseConfig = entity;
      }
    }
    return matchingDatabaseConfig;
  }

  public String findUnusedDatabaseConfigName(String _newName) {
    return _findUnusedName(_newName, "getDatabaseConfigNamed");
  }

  public void _checkForDuplicateDatabaseConfigName(EODatabaseConfig _databaseConfig, String _newName, Set<EOModelVerificationFailure> _failures) throws DuplicateDatabaseConfigNameException {
    EODatabaseConfig existingDatabaseConfig = getDatabaseConfigNamed(_newName);
    if (existingDatabaseConfig != null && existingDatabaseConfig != _databaseConfig) {
      if (_failures == null) {
        throw new DuplicateDatabaseConfigNameException(_newName, this);
      }
      String unusedName = findUnusedDatabaseConfigName(_newName);
      existingDatabaseConfig.setName(unusedName, true);
      _failures.add(new DuplicateDatabaseConfigFailure(this, _newName, unusedName));
    }
  }

  public EODatabaseConfig addBlankDatabaseConfig(String _name) throws DuplicateNameException {
    String newDatabaseConfigNameBase = _name;
    String newDatabaseConfigName = findUnusedDatabaseConfigName(newDatabaseConfigNameBase);
    EODatabaseConfig databaseConfig = new EODatabaseConfig(newDatabaseConfigName);
    addDatabaseConfig(databaseConfig);
    return databaseConfig;
  }
 
  public boolean canConvertDatabaseConfigsToSingleConnectionDictionary() {
    boolean canConvertDatabaseConfigsToSingleConnectionDictionary;
    if (myDatabaseConfigs == null || myDatabaseConfigs.size() == 0) {
      canConvertDatabaseConfigsToSingleConnectionDictionary = true;
    }
    else if (myDatabaseConfigs.size() == 1) {
      EODatabaseConfig databaseConfig = getDatabaseConfigs().iterator().next();
      canConvertDatabaseConfigsToSingleConnectionDictionary = databaseConfig.canConvertToConnectionDictionary();
    }
    else {
      canConvertDatabaseConfigsToSingleConnectionDictionary = false;
    }
    return canConvertDatabaseConfigsToSingleConnectionDictionary;
  }

  public void addDatabaseConfig(EODatabaseConfig _databaseConfig) throws DuplicateNameException {
    addDatabaseConfig(_databaseConfig, true, null);
  }

  public void addDatabaseConfig(EODatabaseConfig _databaseConfig, boolean _fireEvents, Set<EOModelVerificationFailure> _failures) throws DuplicateNameException {
    _databaseConfig._setModel(this);
    _checkForDuplicateDatabaseConfigName(_databaseConfig, _databaseConfig.getName(), _failures);
    _databaseConfig.pasted();
    if (_fireEvents) {
      Set<EODatabaseConfig> oldDatabaseConfigs = null;
      oldDatabaseConfigs = myDatabaseConfigs;
      Set<EODatabaseConfig> newEntities = new HashSet<EODatabaseConfig>();
      newEntities.addAll(myDatabaseConfigs);
      newEntities.add(_databaseConfig);
      myDatabaseConfigs = newEntities;
      firePropertyChange(EOModel.DATABASE_CONFIGS, oldDatabaseConfigs, myDatabaseConfigs);
      if (myActiveDatabaseConfig == null) {
        setActiveDatabaseConfig(_databaseConfig);
      }
    } else {
      myDatabaseConfigs.add(_databaseConfig);
    }
  }

  public void removeDatabaseConfig(EODatabaseConfig _databaseConfig) {
    if (ComparisonUtils.equals(myActiveDatabaseConfig, _databaseConfig)) {
      EODatabaseConfig newActiveDatabaseConfig = null;
      if (!myDatabaseConfigs.isEmpty()) {
        Iterator<EODatabaseConfig> databaseConfigsIter = myDatabaseConfigs.iterator();
        while (newActiveDatabaseConfig == null && databaseConfigsIter.hasNext()) {
          EODatabaseConfig otherDatabaseConfig = databaseConfigsIter.next();
          if (otherDatabaseConfig != _databaseConfig) {
            newActiveDatabaseConfig = otherDatabaseConfig;
          }
        }
      }
      setActiveDatabaseConfig(newActiveDatabaseConfig);
    }
    Set<EODatabaseConfig> oldDatabaseConfigs = myDatabaseConfigs;
    Set<EODatabaseConfig> newDatabaseConfigs = new HashSet<EODatabaseConfig>();
    newDatabaseConfigs.addAll(myDatabaseConfigs);
    newDatabaseConfigs.remove(_databaseConfig);
    myDatabaseConfigs = newDatabaseConfigs;
    firePropertyChange(EOModel.DATABASE_CONFIGS, oldDatabaseConfigs, myDatabaseConfigs);
    _databaseConfig._setModel(null);
  }

  public void setActiveDatabaseConfig(EODatabaseConfig activeDatabaseConfig) {
    setActiveDatabaseConfig(activeDatabaseConfig, true);
  }

  public void setActiveDatabaseConfig(EODatabaseConfig activeDatabaseConfig, boolean fireEvents) {
    EODatabaseConfig oldActiveDatabaseConfig = myActiveDatabaseConfig;
    myActiveDatabaseConfig = activeDatabaseConfig;
    clearCachedPrototypes(null, false);
    if (fireEvents) {
      firePropertyChange(EOModel.ACTIVE_DATABASE_CONFIG, oldActiveDatabaseConfig, myActiveDatabaseConfig);
    }
  }

  public EODatabaseConfig getActiveDatabaseConfig() {
    return myActiveDatabaseConfig;
  }

  public EODatabaseConfig _createDatabaseConfig(String adaptorName, Map<Object, Object> connectionDictionary) {
    EODatabaseConfig defaultDatabaseConfig = new EODatabaseConfig(findUnusedDatabaseConfigName("Default"));
    defaultDatabaseConfig.setAdaptorName(adaptorName);
    if (connectionDictionary != null) {
      defaultDatabaseConfig.setConnectionDictionary(new HashMap<Object, Object>(connectionDictionary));
    }
    defaultDatabaseConfig.setPrototype(_getPreferredPrototypeEntity(adaptorName, connectionDictionary));
    defaultDatabaseConfig._setModel(this);
    return defaultDatabaseConfig;
  }

  public Map<EOAttribute, Set<EORelationship>> _createReferencingRelationshipsCache() {
    Map<EOAttribute, Set<EORelationship>> cache = new HashMap<EOAttribute, Set<EORelationship>>();
    _createReferencingRelationshipsCache(cache);
    return cache;
  }

  public void _createReferencingRelationshipsCache(Map<EOAttribute, Set<EORelationship>> cache) {
    for (EOEntity entity : getEntities()) {
      for (EORelationship relationship : entity.getRelationships()) {
        Set<EOAttribute> relatedAttributes = relationship.getRelatedAttributes();
        for (EOAttribute attribute : relatedAttributes) {
          Set<EORelationship> relatedRelationships = cache.get(attribute);
          if (relatedRelationships == null) {
            relatedRelationships = new HashSet<EORelationship>();
            cache.put(attribute, relatedRelationships);
          }
          relatedRelationships.add(relationship);
        }
      }
    }
  }

  public Map<EOEntity, Set<EOEntity>> _createInheritanceCache() {
    Map<EOEntity, Set<EOEntity>> cache = new HashMap<EOEntity, Set<EOEntity>>();
    _createInheritanceCache(cache);
    return cache;
  }

  public void _createInheritanceCache(Map<EOEntity, Set<EOEntity>> cache) {
    for (EOEntity entity : getEntities()) {
      EOEntity parentEntity = entity.getParent();
      if (parentEntity != null) {
        Set<EOEntity> childrenEntities = cache.get(parentEntity);
        if (childrenEntities == null) {
          childrenEntities = new HashSet<EOEntity>();
          cache.put(parentEntity, childrenEntities);
        }
        childrenEntities.add(entity);
      }
    }
  }

  public Set<EODatabaseConfig> getDatabaseConfigs() {
    return myDatabaseConfigs;
  }

  public Set<EODatabaseConfig> getSortedDatabaseConfigs() {
    return new PropertyListSet<EODatabaseConfig>(myDatabaseConfigs);
  }
 
//  public int hashCode() {
//    return myName.hashCode();
//  }
//
//  public boolean equals(Object _obj) {
//    return (_obj instanceof EOModel && ((EOModel) _obj).myName.equals(myName));
//  }

  public URL getModelURL() {
    return myModelURL;
  }

  public void setModelURL(URL _modelURL) {
    myModelURL = _modelURL;
  }

  public EOModelGroup getModelGroup() {
    return myModelGroup;
  }

  public String getVersion() {
    return myVersion;
  }

  public void setVersion(String _version) {
    String oldVersion = myVersion;
    myVersion = _version;
    firePropertyChange(EOModel.VERSION, _version, oldVersion);
  }

  public void setName(String _name) {
    String oldName = myName;
    myName = _name;
    firePropertyChange(EOModel.NAME, _name, oldName);
  }

  public String getName() {
    return myName;
  }

  /**
   * 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 (EOEntity entity : getEntities()) {
      if (!entity.isPrototype()) {
        entities.add(entity);
      }
    }
    return entities;
  }

  public Set<EOEntity> getEntities() {
    return myEntities;
  }

  public Set<EOEntity> getSortedEntities() {
    return new PropertyListSet<EOEntity>(myEntities);
  }

  public EOEntity _getEntityNamedAndCheckModelGroup(String newName) {
    EOEntity entity = myModelGroup.getEntityNamed(newName);
    if (entity == null) {
      entity = getEntityNamed(newName);
    }
    return entity;
  }

  public String findUnusedEntityName(String _newName) {
    return _findUnusedName(_newName, "_getEntityNamedAndCheckModelGroup");
  }

  public void _checkForDuplicateEntityName(EOEntity _entity, String _newName, Set<EOModelVerificationFailure> _failures) throws DuplicateEntityNameException {
    EOEntity existingEntity = null;
    if (myModelGroup != null) {
      existingEntity = myModelGroup.getEntityNamed(_newName);
    }
    // MS: We do this because at load time, the model thinks it's part of
    // the model group, but the model group doesnt'
    // think it contains the model, so we check both
    if (existingEntity == null) {
      existingEntity = getEntityNamed(_newName);
    }
    if (existingEntity != null && existingEntity != _entity) {
      // MS: For most duplicates, we can rename the original. But for
      // entities, they can be
      // in a totally separate model.
      if (_failures == null || _entity.getModel() != existingEntity.getModel()) {
        throw new DuplicateEntityNameException(_newName, this, existingEntity);
      }
      String unusedName = findUnusedEntityName(_newName);
      existingEntity.setName(unusedName, true);
      _failures.add(new DuplicateEntityFailure(this, _newName, unusedName));
    }
  }

  public void _entityNameChanged(String _originalName, String _oldName, String _newName) {
    if (myDeletedEntityNamesInObjectStore == null) {
      myDeletedEntityNamesInObjectStore = new PropertyListSet<String>();
    }
    if (_originalName != null && _originalName.length() > 0) {
      myDeletedEntityNamesInObjectStore.add(_originalName);
      // myDeletedEntityNamesInObjectStore.remove(_newName);
      myDeletedEntityNames.add(_originalName);
      // myDeletedEntityNames.remove(_newName);
      synchronized (_entitiesCache) {
        EOEntity entity = _entitiesCache.remove(_oldName);
        if (entity != null) {
          _entitiesCache.put(_newName, entity);
        }
      }
    }
  }

  public boolean containsEntityNamed(String _entityName) {
    return getEntityNamed(_entityName) != null;
  }

  public Set importEntitiesFromModel(URL sourceModelURL, Set<EOModelVerificationFailure> failures) throws EOModelException, IOException {
    EOModelGroup sourceModelGroup = new EOModelGroup();
    EOModel sourceModel = new EOModel("Temp");
    sourceModelGroup.addModel(sourceModel);
    sourceModel.loadFromURL(sourceModelURL, failures);
    sourceModel.resolve(failures);
    sourceModel.resolveFlattened(failures);
    return importEntitiesFromModel(sourceModel, failures);
  }

  public Set<EOEntity> importEntitiesFromModel(EOModel sourceModel, Set<EOModelVerificationFailure> failures) throws DuplicateNameException {
    Set<EOEntity> clonedEntities = new HashSet<EOEntity>();
    for (EOEntity entity : sourceModel.getEntities()) {
      clonedEntities.add(entity._cloneModelObject());
    }
    addEntities(clonedEntities, failures);
    guessPrototypes(clonedEntities);
    return clonedEntities;
  }

  public void guessPrototypes() {
    guessPrototypes(getEntities());
  }

  public void guessPrototypes(Set<EOEntity> entities) {
    for (EOEntity entity : entities) {
      // clonedEntity.setName(StringUtils.toUppercaseFirstLetter(clonedEntity.getName().toLowerCase()));
      for (EOAttribute attribute : entity.getAttributes()) {
        attribute.guessPrototype(true);
        // clonedAttribute.setName(clonedAttribute.getName().toLowerCase());
      }
      // Iterator clonedRelationshipsIter =
      // clonedEntity.getRelationships().iterator();
      // while (clonedRelationshipsIter.hasNext()) {
      // EORelationship clonedRelationship = (EORelationship)
      // clonedRelationshipsIter.next();
      // clonedRelationship.setName(clonedRelationship.getName().toLowerCase());
      // }
    }
  }

  private Map<String, EOEntity> _entitiesCache = new HashMap<String, EOEntity>();
 
  public void addEntities(Set<EOEntity> entities, Set<EOModelVerificationFailure> failures) throws DuplicateNameException {
    Set<EOEntity> oldEntities = new HashSet<EOEntity>();
    oldEntities.addAll(myEntities);

    for (EOEntity entity : entities) {
      addEntity(entity, false, false, failures);
    }
    for (EOEntity entity : entities) {
      entity.pasted();
    }

    firePropertyChange(EOModel.ENTITIES, oldEntities, myEntities);
  }

  public void addEntity(EOEntity _entity) throws DuplicateNameException {
    addEntity(_entity, true, true, null);
  }

  public void addEntity(EOEntity entity, boolean pasteImmediately, boolean fireEvents, Set<EOModelVerificationFailure> failures) throws DuplicateNameException {

    entity._setModel(this);
    _checkForDuplicateEntityName(entity, entity.getName(), failures);
    if (pasteImmediately) {
      entity.pasted();
    }
    synchronized (_entitiesCache) {
      _entitiesCache.put(entity.getName(), entity);
    }
    myDeletedEntityNames.remove(entity.getName());
    if (fireEvents) {
      Set<EOEntity> oldEntities = null;
      oldEntities = myEntities;
      Set<EOEntity> newEntities = new HashSet<EOEntity>();
      newEntities.addAll(myEntities);
      newEntities.add(entity);
      myEntities = newEntities;
      _modelEvents.addEvent(new EOEntityAddedEvent(entity));
      firePropertyChange(EOModel.ENTITIES, oldEntities, myEntities);
    } else {
      myEntities.add(entity);
    }
  }

  public void removeEntity(EOEntity _entity) {
    myDeletedEntityNames.add(_entity.getName());
    synchronized (_entitiesCache) {
      _entitiesCache.remove(_entity.getName());
    }
    Set<EOEntity> oldEntities = myEntities;
    Set<EOEntity> newEntities = new HashSet<EOEntity>();
    newEntities.addAll(myEntities);
    newEntities.remove(_entity);
    myEntities = newEntities;
    _modelEvents.addEvent(new EOEntityDeletedEvent(_entity));
    firePropertyChange(EOModel.ENTITIES, oldEntities, myEntities);
    _entity._setModel(null);
  }

  public EOEntity getEntityNamed(String name) {
    synchronized (_entitiesCache) {
      return _entitiesCache.get(name);
    }
  }

  public void _storedProcedureNameChanged(String _oldName, String _newName) {
    myDeletedStoredProcedureNames.add(_oldName);
    myDeletedStoredProcedureNames.remove(_newName);
  }

  public EOStoredProcedure addBlankStoredProcedure(String _name) throws DuplicateStoredProcedureNameException {
    String newStoredProcedureNameBase = _name;
    String newStoredProcedureName = findUnusedStoredProcedureName(newStoredProcedureNameBase);
    EOStoredProcedure storedProcedure = new EOStoredProcedure(newStoredProcedureName);
    addStoredProcedure(storedProcedure);
    return storedProcedure;
  }

  public void addStoredProcedure(EOStoredProcedure _storedProcedure) throws DuplicateStoredProcedureNameException {
    addStoredProcedure(_storedProcedure, true, null);
  }

  public void addStoredProcedure(EOStoredProcedure _storedProcedure, boolean _fireEvents, Set<EOModelVerificationFailure> _failures) throws DuplicateStoredProcedureNameException {
    _storedProcedure._setModel(this);
    _checkForDuplicateStoredProcedureName(_storedProcedure, _storedProcedure.getName(), _failures);
    _storedProcedure.pasted();
    myDeletedStoredProcedureNames.remove(_storedProcedure.getName());
    if (_fireEvents) {
      Set<EOStoredProcedure> oldStoredProcedures = myStoredProcedures;
      Set<EOStoredProcedure> newStoredProcedures = new HashSet<EOStoredProcedure>();
      newStoredProcedures.addAll(myStoredProcedures);
      newStoredProcedures.add(_storedProcedure);
      myStoredProcedures = newStoredProcedures;
      firePropertyChange(EOModel.STORED_PROCEDURES, oldStoredProcedures, myStoredProcedures);
    } else {
      myStoredProcedures.add(_storedProcedure);
    }
  }

  public void removeStoredProcedure(EOStoredProcedure _storedProcedure) {
    myDeletedStoredProcedureNames.add(_storedProcedure.getName());
    Set<EOStoredProcedure> oldStoredProcedures = myStoredProcedures;
    Set<EOStoredProcedure> newStoredProcedures = new HashSet<EOStoredProcedure>();
    newStoredProcedures.addAll(myStoredProcedures);
    newStoredProcedures.remove(_storedProcedure);
    myStoredProcedures = newStoredProcedures;
    firePropertyChange(EOModel.STORED_PROCEDURES, oldStoredProcedures, myStoredProcedures);
    _storedProcedure._setModel(null);
  }

  public String findUnusedStoredProcedureName(String _newName) {
    return _findUnusedName(_newName, "getStoredProcedureNamed");
  }

  public Set<EOStoredProcedure> getStoredProcedures() {
    return myStoredProcedures;
  }

  public Set<EOStoredProcedure> getSortedStoredProcedures() {
    return new PropertyListSet<EOStoredProcedure>(myStoredProcedures);
  }

  public EOStoredProcedure getStoredProcedureNamed(String _name) {
    EOStoredProcedure matchingStoredProcedure = null;
    Iterator<EOStoredProcedure> storedProceduresIter = myStoredProcedures.iterator();
    while (matchingStoredProcedure == null && storedProceduresIter.hasNext()) {
      EOStoredProcedure attribute = storedProceduresIter.next();
      if (ComparisonUtils.equals(attribute.getName(), _name)) {
        matchingStoredProcedure = attribute;
      }
    }
    return matchingStoredProcedure;
  }

  public void _checkForDuplicateStoredProcedureName(EOStoredProcedure _storedProcedure, String _newName, Set<EOModelVerificationFailure> _failures) throws DuplicateStoredProcedureNameException {
    EOStoredProcedure existingStoredProcedure = getStoredProcedureNamed(_newName);
    if (existingStoredProcedure != null && existingStoredProcedure != _storedProcedure) {
      if (_failures == null) {
        throw new DuplicateStoredProcedureNameException(_newName, this);
      }

      String unusedName = findUnusedStoredProcedureName(_newName);
      existingStoredProcedure.setName(unusedName, true);
      _failures.add(new DuplicateStoredProcedureFailure(this, _newName, unusedName));
    }
  }

  public URL getIndexURL() throws MalformedURLException {
    URL indexURL = null;
    if (myModelURL != null) {
      indexURL = new URL(myModelURL, "index.eomodeld");
    }
    return indexURL;
  }

  public void checkLastModified(Set<EOLastModified> lastModified) {
    if (_lastModified != null && _lastModified.hasBeenModified()) {
      lastModified.add(_lastModified);
    }
    for (EOEntity entity : getEntities()) {
      entity.checkLastModified(lastModified);
    }
    for (EOStoredProcedure storedProc : getStoredProcedures()) {
      storedProc.checkLastModified(lastModified);
    }
  }

  public void loadFromURL(URL _modelFolder, Set<EOModelVerificationFailure> _failures) throws EOModelException, MalformedURLException {
    // System.out.println("EOModel.loadFromURL: " + _modelFolder);
    URL indexURL = new URL(_modelFolder, "index.eomodeld");
    // if (!indexURL.exists()) {
    // throw new EOModelException(indexURL + " does not exist.");
    // }
    myModelURL = _modelFolder;
    Map rawModelMap;
    try {
      rawModelMap = (Map) WOLPropertyListSerialization.propertyListFromURL(indexURL, new EOModelParserDataStructureFactory());
    } catch (Exception e) {
      throw new EOModelException("index.eomodeld is corrupted.", e);
    }
    if (rawModelMap == null) {
      throw new EOModelException("index.eomodeld is corrupted.");
    }
    EOModelMap modelMap = new EOModelMap(rawModelMap);
    myModelMap = modelMap;
    Object version = modelMap.get("EOModelVersion");
    if (version instanceof String) {
      myVersion = (String) version;
    } else if (version instanceof Number) {
      myVersion = String.valueOf(((Number) version).floatValue());
    } else {
      throw new IllegalArgumentException("Unknown version format:" + version);
    }
    loadUserInfo(modelMap);

    Set<Map> entities = modelMap.getSet("entities");
    if (entities != null) {
      for (Map entitiesMap : entities) {
        EOModelMap entityMap = new EOModelMap(entitiesMap);
        String entityName = entityMap.getString("name", true);
        EOEntity entity = new EOEntity();
        URL entityURL = new URL(_modelFolder, entityName + ".plist");
        if (URLUtils.exists(entityURL)) {
          entity.loadFromURL(entityURL, _failures);
          URL fspecURL = new URL(_modelFolder, entityName + ".fspec");
          if (URLUtils.exists(fspecURL)) {
            entity.loadFetchSpecsFromURL(fspecURL, _failures);
          }
          if (entity.getName() == null) {
            _failures.add(new EOModelVerificationFailure(this, this, "The entity file " + entityURL + " defines an entity with no name.", false));
          }
          addEntity(entity, true, false, _failures);
        } else {
          _failures.add(new EOModelVerificationFailure(this, this, "The entity file " + entityURL + " was missing.", false));
        }
      }
    }

    Set<String> storedProcedureNames = modelMap.getSet("storedProcedures");
    if (storedProcedureNames != null) {
      for (String storedProcedureName : storedProcedureNames) {
        EOStoredProcedure storedProcedure = new EOStoredProcedure();
        URL storedProcedureURL = new URL(_modelFolder, storedProcedureName + ".storedProcedure");
        if (URLUtils.exists(storedProcedureURL)) {
          storedProcedure.loadFromURL(storedProcedureURL, _failures);
          addStoredProcedure(storedProcedure, false, _failures);
        } else {
          _failures.add(new EOModelVerificationFailure(this, this, "The stored procedure file " + storedProcedureURL + " was missing.", false));
        }
      }
    }

    Map<Object, Object> internalInfoMap = modelMap.getMap("internalInfo");
    if (internalInfoMap != null) {
      Set<String> deletedEntityNamesInObjectStore = modelMap.getSet("_deletedEntityNamesInObjectStore", true);
      if (deletedEntityNamesInObjectStore != null) {
        myDeletedEntityNamesInObjectStore = deletedEntityNamesInObjectStore;
      }
    }

    EOModelMap entityModelerMap = getEntityModelerMap(false);
    _entityNamingConvention = NamingConvention.loadFromMap("entityNamingConvention", entityModelerMap);
    _attributeNamingConvention = NamingConvention.loadFromMap("attributeNamingConvention", entityModelerMap);
    _reverseEngineered = entityModelerMap.getBoolean("reverseEngineered", false);

    Map<String, Map> databaseConfigs = entityModelerMap.getMap("databaseConfigs");
    if (databaseConfigs != null) {
      for (Map.Entry<String, Map> databaseConfigEntry : databaseConfigs.entrySet()) {
        String name = databaseConfigEntry.getKey();
        EODatabaseConfig databaseConfig = new EODatabaseConfig(name);
        databaseConfig.loadFromMap(new EOModelMap(databaseConfigEntry.getValue()), _failures);
        addDatabaseConfig(databaseConfig, false, _failures);
      }
    }
    EODatabaseConfig activeDatabaseConfig = null;
    String activeDatabaseConfigName = entityModelerMap.getString("activeDatabaseConfigName", false);
    if (activeDatabaseConfigName != null) {
      activeDatabaseConfig = getDatabaseConfigNamed(activeDatabaseConfigName);
    }

    String adaptorName = modelMap.getString("adaptorName", true);

    // If there is a connection dictionary, then look for a database config
    // that is equivalent ...
    Map<Object, Object> connectionDictionary = modelMap.getMap("connectionDictionary", true);
    if (connectionDictionary != null && !connectionDictionary.isEmpty()) {
      EODatabaseConfig tempConnectionDictionaryDatabaseConfig = _createDatabaseConfig(adaptorName, connectionDictionary);
      EODatabaseConfig connectionDictionaryDatabaseConfig = null;
      Iterator<EODatabaseConfig> databaseConfigsIter = myDatabaseConfigs.iterator();
      while (connectionDictionaryDatabaseConfig == null && databaseConfigsIter.hasNext()) {
        EODatabaseConfig databaseConfig = databaseConfigsIter.next();
        if (tempConnectionDictionaryDatabaseConfig.isEquivalent(databaseConfig, false)) {
          connectionDictionaryDatabaseConfig = databaseConfig;
        }
      }
     
      // if one isn't found, then make a new database config based off the
      // connection dictionary
      if (connectionDictionaryDatabaseConfig == null && canSave()) {
        connectionDictionaryDatabaseConfig = tempConnectionDictionaryDatabaseConfig;
        addDatabaseConfig(connectionDictionaryDatabaseConfig, false, _failures);
        //_failures.add(new EOModelVerificationFailure(this, this, "Creating default database config for model '" + getName() + "'.", true, null));
      }
     
      // if the identified active database config isn't the connection
      // dictionary config, then change the active config to the connection dictionary config
      if (activeDatabaseConfig != connectionDictionaryDatabaseConfig) {
        activeDatabaseConfig = connectionDictionaryDatabaseConfig;
      }
    }
   
    // If after all this, we still have no database configs, and you have an empty connection dictionary,
    // then make a new blank database config ... If you have a NULL connection dictionary, then we're
    // going to assume you did that on purpose.
    if (myDatabaseConfigs.isEmpty() && canSave() && connectionDictionary != null) {
      // If you didn't specify an adaptor name, let's just make it JDBC
      if (adaptorName == null) {
        adaptorName = EODatabaseConfig.JDBC_ADAPTOR_NAME;
      }
      addDatabaseConfig(_createDatabaseConfig(adaptorName, null), false, _failures);
    }
   
    // try to always have at least one active database config
    if (activeDatabaseConfig == null && !myDatabaseConfigs.isEmpty()) {
      activeDatabaseConfig = myDatabaseConfigs.iterator().next();
    }
    if (activeDatabaseConfig != null) {
      if (ComparisonUtils.equals(activeDatabaseConfig.getName(), activeDatabaseConfigName)) {
        myActiveDatabaseConfig = activeDatabaseConfig;
      } else {
        setActiveDatabaseConfig(activeDatabaseConfig, false);
      }
    }

    _lastModified = new EOLastModified(indexURL);
  }

  public EOModelMap toMap() {
    EOModelMap modelMap = myModelMap.cloneModelMap();
    modelMap.setString("EOModelVersion", myVersion, true);
    String adaptorName = EODatabaseConfig.JDBC_ADAPTOR_NAME;
    Map connectionDictionary = null;
    if (myActiveDatabaseConfig != null) {
      connectionDictionary = myActiveDatabaseConfig.getConnectionDictionary();
      adaptorName = myActiveDatabaseConfig.getAdaptorName();
    }
    modelMap.put("connectionDictionary", connectionDictionary);
    modelMap.setString("adaptorName", adaptorName, true);

    Set<Map> entities = new PropertyListSet<Map>(EOModelMap.asArray(myModelMap.get("entities")));
    Set<String> entitiesWithSharedObjects = new PropertyListSet<String>(EOModelMap.asArray(myModelMap.get("entitiesWithSharedObjects")));
    for (EOEntity entity : myEntities) {
      EOModelMap entityMap = new EOModelMap();
      entityMap.setString("className", entity.getClassName(), true);
      EOEntity parent = entity.getParent();
      String parentName = (parent == null) ? null : parent.getName();
      entityMap.setString("parent", parentName, true);
      entityMap.setString("name", entity.getName(), true);
      entities.add(entityMap);
      if (entity.hasSharedObjects()) {
        entitiesWithSharedObjects.add(entity.getName());
      }
    }
    modelMap.setSet("entities", entities, true);

    modelMap.setSet("entitiesWithSharedObjects", entitiesWithSharedObjects, true);

    Map<Object, Object> internalInfoMap = modelMap.getMap("internalInfo");
    if (internalInfoMap == null) {
      internalInfoMap = new HashMap<Object, Object>();
    }
    if (myDeletedEntityNamesInObjectStore != null && !myDeletedEntityNamesInObjectStore.isEmpty()) {
      internalInfoMap.put("_deletedEntityNamesInObjectStore", myDeletedEntityNamesInObjectStore);
    } else {
      internalInfoMap.remove("_deletedEntityNamesInObjectStore");
    }
    modelMap.setMap("internalInfo", internalInfoMap, true);

    Set<String> storedProcedures = new PropertyListSet<String>(EOModelMap.asArray(myModelMap.get("storedProcedures")));
    for (EOStoredProcedure storedProcedure : myStoredProcedures) {
      storedProcedures.add(storedProcedure.getName());
    }
    modelMap.setSet("storedProcedures", storedProcedures, true);

    EOModelMap entityModelerMap = getEntityModelerMap(true);
    boolean canConvertDatabaseConfigsToSingleConnectionDictionary = canConvertDatabaseConfigsToSingleConnectionDictionary();
    if (canConvertDatabaseConfigsToSingleConnectionDictionary) {
      entityModelerMap.remove("databaseConfigs");
      entityModelerMap.remove("activeDatabaseConfigName");
    }
    else {
      Map<String, Map> databaseConfigs = new PropertyListMap<String, Map>();
      for (EODatabaseConfig databaseConfig : myDatabaseConfigs) {
        databaseConfigs.put(databaseConfig.getName(), databaseConfig.toMap());
      }
      entityModelerMap.setMap("databaseConfigs", databaseConfigs, true);

      if (myActiveDatabaseConfig == null || databaseConfigs.get(myActiveDatabaseConfig.getName()) == null) {
        entityModelerMap.remove("activeDatabaseConfigName");
      } else {
        entityModelerMap.put("activeDatabaseConfigName", myActiveDatabaseConfig.getName());
      }
    }
   
    NamingConvention.toMap(_entityNamingConvention, "entityNamingConvention", entityModelerMap);
    NamingConvention.toMap(_attributeNamingConvention, "attributeNamingConvention", entityModelerMap);
   
    entityModelerMap.setBoolean("reverseEngineered", Boolean.valueOf(_reverseEngineered), EOModelMap.YNOptionalDefaultNo);

    writeUserInfo(modelMap);

    return modelMap;
  }

  /**
   * Returns the .eomodeld for the given folder. If this is an .eomodeld
   * folder, it returns the folder you pass in. Otherwise, it creates a child
   * with this model's name.
   *
   * @param folder
   *            the folder to write to
   * @return the corresponding .eomodeld folder
   */
  public File _eomodeldFolderForFolder(File folder) {
    File modelFolder;
    if (folder.getName().endsWith(".eomodeld")) {
      modelFolder = folder;
    } else {
      modelFolder = new File(folder, myName + ".eomodeld");
    }
    return modelFolder;
  }

  /**
   * Returns true if you are able to write this model to the folder it was
   * loaded from.
   *
   * @return true if you are able to save this model
   * @throws MalformedURLException
   *             if the index URL is invalid
   */
  public boolean canSave() throws MalformedURLException {
    boolean canSave;
    URL indexURL = getIndexURL();
    if (indexURL == null || indexURL.toExternalForm().startsWith("jar:")) {
      canSave = false;
    } else {
      File indexFile = URLUtils.cheatAndTurnIntoFile(indexURL);
      File modelFolder = indexFile.getParentFile();
      canSave = canSaveToFolder(modelFolder);
    }
    return canSave;
  }

  /**
   * Returns true if you are able to write this model to the given folder.
   *
   * @param parentFolder
   *            the folder to write the model into
   * @return true if you are able to write to the folder
   */
  public boolean canSaveToFolder(File parentFolder) {
    boolean canSave;
    File modelFolder = _eomodeldFolderForFolder(parentFolder);
    if (modelFolder.exists()) {
      if (modelFolder.isFile()) {
        canSave = false;
      } else {
        canSave = modelFolder.canWrite();
      }
    } else {
      canSave = modelFolder.getParentFile().canWrite();
    }
    return canSave;
  }

  /**
   * Saves this model to the same folder it was loaded from.
   *
   * @return the .eomodeld folder
   * @throws IOException
   *             if the model could not be saved
   * @throws PropertyListParserException
   */
  public File save() throws IOException, PropertyListParserException {
    URL indexURL = getIndexURL();
    if (indexURL == null) {
      throw new IOException("This model has no index file URL.");
    }
    File indexFile = URLUtils.cheatAndTurnIntoFile(indexURL);
    File modelFolder = indexFile.getParentFile();
    return saveToFolder(modelFolder.getParentFile());
  }

  public File saveToFolder(File parentFolder) throws IOException, PropertyListParserException {
    firePropertyChange(EOModel.MODEL_SAVING, Boolean.FALSE, Boolean.TRUE);
    try {
      File modelFolder = _eomodeldFolderForFolder(parentFolder);
      if (!modelFolder.exists()) {
        if (!modelFolder.mkdirs()) {
          throw new IOException("Failed to create folder '" + modelFolder + "'.");
        }
      }
      myModelURL = modelFolder.toURL();
      File indexFile = new File(modelFolder, "index.eomodeld");
      EOModelMap modelMap = toMap();
      WOLPropertyListSerialization.propertyListToFile("Entity Modeler v" + EOModel.CURRENT_VERSION, indexFile, modelMap);
 
      if (myDeletedEntityNames != null) {
        for (String entityName : myDeletedEntityNames) {
          if (getEntityNamed(entityName) == null) {
            File entityFile = new File(modelFolder, entityName + ".plist");
            if (entityFile.exists()) {
              entityFile.delete();
            }
            File fspecFile = new File(modelFolder, entityName + ".fspec");
            if (fspecFile.exists()) {
              fspecFile.delete();
            }
          }
        }
      }
 
      for (EOEntity entity : myEntities) {
        if (entity.isEntityDirty()) {
          String entityName = entity.getName();
          File entityFile = new File(modelFolder, entityName + ".plist");
          File fspecFile = new File(modelFolder, entityName + ".fspec");
          entity.saveToFile(entityFile, fspecFile);
        }
      }
 
      if (myDeletedStoredProcedureNames != null) {
        for (String storedProcedureName : myDeletedStoredProcedureNames) {
          if (getStoredProcedureNamed(storedProcedureName) == null) {
            File storedProcedureFile = new File(modelFolder, storedProcedureName + ".storedProcedure");
            if (storedProcedureFile.exists()) {
              storedProcedureFile.delete();
            }
          }
        }
      }
 
      for (EOStoredProcedure storedProcedure : myStoredProcedures) {
        if (storedProcedure.isStoredProcedureDirty()) {
          String storedProcedureName = storedProcedure.getName();
          File storedProcedureFile = new File(modelFolder, storedProcedureName + ".storedProcedure");
          storedProcedure.saveToFile(storedProcedureFile);
        }
      }
 
      setDirty(false);
      _lastModified = new EOLastModified(indexFile);
 
      return modelFolder;
    }
    finally {
      firePropertyChange(EOModel.MODEL_SAVING, Boolean.TRUE, Boolean.FALSE);
    }
  }

  public void resolve(Set<EOModelVerificationFailure> _failures) {
    for (EOEntity entity : myEntities) {
      entity.resolve(_failures);
    }
  }

  public void resolveFlattened(Set<EOModelVerificationFailure> _failures) {
    for (EOEntity entity : myEntities) {
      entity.resolveFlattened(_failures);
    }
  }

  public void verify(Set<EOModelVerificationFailure> _failures) {
    VerificationContext verificationContext;
    EOModelGroup modelGroup = getModelGroup();
    if (modelGroup == null) {
      verificationContext = new VerificationContext(this);
    } else {
      verificationContext = new VerificationContext(modelGroup);
    }
    verify(_failures, verificationContext);
  }

  public void verify(Set<EOModelVerificationFailure> _failures, VerificationContext verificationContext) {
    // TODO

    for (EOEntity entity : myEntities) {
      entity.verify(_failures, verificationContext);
    }
  }

  public String getFullyQualifiedName() {
    return myName == null ? "Unknown Model '" + getModelURL() + "'" : myName;
  }

  @Override
  public EOModel _cloneModelObject() {
    throw new IllegalStateException("Not implemented");
  }

  @Override
  public Class<EOModelGroup> _getModelParentType() {
    return EOModelGroup.class;
  }

  @Override
  public EOModelGroup _getModelParent() {
    return getModelGroup();
  }

  @Override
  public void _addToModelParent(EOModelGroup modelParent, boolean findUniqueName, Set<EOModelVerificationFailure> failures) throws EOModelException {
    if (findUniqueName) {
      throw new IllegalArgumentException("Unable to unique model names.");
    }
    modelParent.addModel(this, failures);
  }

  @Override
  public void _removeFromModelParent(Set<EOModelVerificationFailure> failures) {
    getModelGroup().removeModel(this, failures);
  }

  public ModelEvents getModelEvents() {
    return _modelEvents;
  }

  public String toString() {
    return "[EOModel: name = " + myName + "; entities = " + myEntities + "]";
  }

  /** Begin Prototypes * */
  public synchronized void clearCachedPrototypes(Set<EOModelVerificationFailure> _failures, boolean _reload) {
    myPrototypeAttributeCache = null;
    for (EOEntity entity : myEntities) {
      entity.clearCachedPrototypes(_failures, _reload);
    }
  }

  public synchronized Set<String> getPrototypeAttributeNames() {
    Set<String> prototypeAttributeNames = new PropertyListSet<String>();
    for (EOAttribute attribute : getPrototypeAttributes()) {
      prototypeAttributeNames.add(attribute.getName());
    }
    return prototypeAttributeNames;
  }

  public String _getDefaultPrototypeEntityName(String prefix, String name) {
    return "EO" + (prefix != null ? prefix : "") + (name != null ? name : "") + "Prototypes";
  }

  public String getAdaptorName() {
    String adaptorName = EODatabaseConfig.JDBC_ADAPTOR_NAME;
    if (myActiveDatabaseConfig != null) {
      adaptorName = myActiveDatabaseConfig.getAdaptorName();
    }
    return adaptorName;
  }

  public String _getAdaptorPrototypeEntityName(String prefix, String adaptorName, String name) {
    String adaptorPrototypeEntityName = null;
    if (adaptorName != null) {
      adaptorPrototypeEntityName = "EO" + adaptorName + (prefix != null ? prefix : "") + (name != null ? name : "") + "Prototypes";
    }
    return adaptorPrototypeEntityName;
  }

  public String _getDriverPrototypeEntityName(String prefix, Map _connectionDictionary, String name) {
    String driverPrototypeEntityName = null;
    String adaptorName = getAdaptorName();
    // MS: Hardcoded JDBC reference hack ...
    if ("JDBC".equals(adaptorName)) {
      if (_connectionDictionary != null) {
        String pluginName = (String) _connectionDictionary.get("plugin");
        if (pluginName == null || pluginName.length() == 0) {
          String jdbcUrl = (String) _connectionDictionary.get("URL");
          if (jdbcUrl != null && jdbcUrl.length() > 0) {
            int firstColon = jdbcUrl.indexOf(':');
            int secondColon = jdbcUrl.indexOf(':', firstColon + 1);
            if (firstColon != -1 && secondColon != -1) {
              pluginName = jdbcUrl.substring(firstColon + 1, secondColon);
            }
          }
        }
        if (pluginName != null) {
          driverPrototypeEntityName = "EOJDBC" + pluginName + (prefix != null ? prefix : "") + (name != null ? name : "") + "Prototypes";
        }
      }
    }
    return driverPrototypeEntityName;
  }

  public EOEntity _getPreferredPrototypeEntity(String adaptorName, Map connectionDictionary) {
    EOEntity preferredPrototypEntity = _getPreferredPrototypeEntity("Custom", adaptorName, null, connectionDictionary);
    if (preferredPrototypEntity == null) {
      preferredPrototypEntity = _getPreferredPrototypeEntity(null, adaptorName, getName(), connectionDictionary);
      if (preferredPrototypEntity == null) {
        preferredPrototypEntity = _getPreferredPrototypeEntity(null, adaptorName, null, connectionDictionary);
      }
    }
    return preferredPrototypEntity;
  }
 
  public EOEntity _getPreferredPrototypeEntity(String prefix, String adaptorName, String modelName, Map connectionDictionary) {
    EOEntity prototypeEntity = null;
    String driverPrototypeEntityName = _getDriverPrototypeEntityName(prefix, connectionDictionary, modelName);
    if (driverPrototypeEntityName != null && myModelGroup != null) {
      prototypeEntity = myModelGroup.getEntityNamed(driverPrototypeEntityName);
    }
    if (prototypeEntity == null) {
      String adaptorPrototypeEntityName = _getAdaptorPrototypeEntityName(prefix, adaptorName, modelName);
      if (adaptorPrototypeEntityName != null && myModelGroup != null) {
        prototypeEntity = myModelGroup.getEntityNamed(adaptorPrototypeEntityName);
      }
    }
    if (prototypeEntity == null && myModelGroup != null) {
      String defaultPrototypeEntityName = _getDefaultPrototypeEntityName(prefix, modelName);
      prototypeEntity = myModelGroup.getEntityNamed(defaultPrototypeEntityName);
    }
    return prototypeEntity;
  }

  public synchronized Set<EOAttribute> getPrototypeAttributes() {
    if (myPrototypeAttributeCache == null) {
      Map<String, EOAttribute> prototypeAttributeCache = new HashMap<String, EOAttribute>();

      Map connectionDictionary = null;
      EODatabaseConfig activeDatabaseConfig = getActiveDatabaseConfig();
      if (activeDatabaseConfig != null) {
        connectionDictionary = activeDatabaseConfig.getConnectionDictionary();
      }
      addPrototypeAttributes(_getDefaultPrototypeEntityName(null, null), prototypeAttributeCache);
      addPrototypeAttributes(_getAdaptorPrototypeEntityName(null, getAdaptorName(), null), prototypeAttributeCache);
      addPrototypeAttributes(_getDriverPrototypeEntityName(null, connectionDictionary, null), prototypeAttributeCache);
     
      addPrototypeAttributes(_getDefaultPrototypeEntityName("Custom", null), prototypeAttributeCache);
      addPrototypeAttributes(_getAdaptorPrototypeEntityName("Custom", getAdaptorName(), null), prototypeAttributeCache);
      addPrototypeAttributes(_getDriverPrototypeEntityName("Custom", connectionDictionary, null), prototypeAttributeCache);
     
      addPrototypeAttributes(_getDefaultPrototypeEntityName(null, getName()), prototypeAttributeCache);
      addPrototypeAttributes(_getAdaptorPrototypeEntityName(null, getAdaptorName(), getName()), prototypeAttributeCache);
      addPrototypeAttributes(_getDriverPrototypeEntityName(null, connectionDictionary, getName()), prototypeAttributeCache);

      if (activeDatabaseConfig != null) {
        EOEntity prototypeEntity = activeDatabaseConfig.getPrototype();
        if (prototypeEntity != null) {
          addPrototypeAttributes(prototypeEntity.getName(), prototypeAttributeCache);
        }
      }

      // Do we need to support "EOPrototypesToHide" entity?
      myPrototypeAttributeCache = new HashSet<EOAttribute>();
      myPrototypeAttributeCache.addAll(prototypeAttributeCache.values());
    }
    return myPrototypeAttributeCache;
  }

  protected void addPrototypeAttributes(String _prototypeEntityName, Map<String, EOAttribute> _prototypeAttributeCache) {
    if (_prototypeEntityName != null) {
      EOEntity prototypeEntity = myModelGroup.getEntityNamed(_prototypeEntityName);
      if (prototypeEntity != null) {
        for (EOAttribute prototypeAttribute : prototypeEntity.getAttributes()) {
          _prototypeAttributeCache.put(prototypeAttribute.getName(), prototypeAttribute);
        }
      }
    }
  }

  public EOAttribute getPrototypeAttributeNamed(String _name) {
    EOAttribute matchingAttribute = null;
    Set<EOAttribute> prototypeAttributes = getPrototypeAttributes();
    Iterator<EOAttribute> attributesIter = prototypeAttributes.iterator();
    while (matchingAttribute == null && attributesIter.hasNext()) {
      EOAttribute attribute = attributesIter.next();
      if (attribute.getName().equals(_name)) {
        matchingAttribute = attribute;
      }
    }
    return matchingAttribute;
  }

  /** End Prototypes * */

  /*
   * public static void main(String[] args) throws IOException,
   * EOModelException { Set<EOModelVerificationFailure> failures = new
   * LinkedHashSet<EOModelVerificationFailure>();
   *
   * EOModelGroup modelGroup = new EOModelGroup(); NullProgressMonitor
   * progressMonitor = new NullProgressMonitor();
   * modelGroup.loadModelsFromFolder(new
   * File("/Library/Frameworks/ERPrototypes.framework/Resources").toURL(),
   * failures, progressMonitor); modelGroup.loadModelsFromFolder(new
   * File("/Users/mschrag/Documents/workspace/MDTask").toURL(), failures,
   * progressMonitor); modelGroup.loadModelsFromFolder(new
   * File("/Users/mschrag/Documents/workspace/MDTAccounting").toURL(),
   * failures, progressMonitor); modelGroup.loadModelsFromFolder(new
   * File("/Users/mschrag/Documents/workspace/MDTCMS").toURL(), failures,
   * progressMonitor); modelGroup.loadModelsFromFolder(new
   * File("/Users/mschrag/Documents/workspace/MDTWOExtensions").toURL(),
   * failures, progressMonitor);
   *
   * modelGroup.resolve(failures); modelGroup.verify(failures); Iterator
   * failuresIter = failures.iterator(); while (failuresIter.hasNext()) {
   * EOModelVerificationFailure failure = (EOModelVerificationFailure)
   * failuresIter.next(); System.out.println("EOModel.main: " + failure); }
   *
   * File outputPath = new File("/tmp"); System.out.println("EOModel.main:
   * Saving model to " + outputPath + " ..."); EOModel mdtaskModel =
   * modelGroup.getModelNamed("MDTask"); mdtaskModel.saveToFolder(outputPath);
   * System.out.println("EOModel.main: Done."); }
   */
TOP

Related Classes of org.objectstyle.wolips.eomodeler.core.model.EOModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.