/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.dm.eo.model;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.cayenne.wocompat.PropertyListSerialization;
import org.openflexo.logging.FlexoLogger;
import org.openflexo.toolbox.FileUtils;
/**
* @author gpolet
*
*/
public class EOModel extends EOObject {
private static final Logger logger = FlexoLogger.getLogger(EOModel.class.getPackage().getName());
private static final String EOMODEL_VERSION_KEY = "EOModelVersion";
private static final String EOPROTOTYPES = "EOPrototypes";
public static final String INDEX_EOMODELD = "index.eomodeld";
private static final String ADAPTOR_NAME_KEY = "adaptorName";
private static final String ENTITIES_KEY = "entities";
private static final String CONNECTION_DICTIONARY = "connectionDictionary";
private static final String CLASS_NAME_KEY = "className";
private Vector<String> missingEntities;
private String adaptorName;
private Map<String, Object> connectionDictionary;
private List<EOEntity> entities;
private EOModelGroup modelGroup;
private Vector<File> filesToDelete;
private File file;
@SuppressWarnings("unchecked")
public static EOModel createEOModelFromFile(File file, String name, EOModelGroup group) throws FileNotFoundException,
PropertyListDeserializationException {
File dir = file;
if (file.isDirectory()) {
file = new File(file, INDEX_EOMODELD);
} else {
dir = file.getParentFile();
}
if (name == null) {// If we don't know the name, we compute it from the
// file
name = file.getParentFile().getName();
if (name.endsWith(".eomodeld")) {
name = name.substring(0, name.indexOf(".eomodeld"));
}
}
Map<Object, Object> map = (Map<Object, Object>) PropertyListSerialization.propertyListFromFile(file);
if (map == null) {
throw new PropertyListDeserializationException(file);
}
if (map.get(NAME_KEY) != null) {
// then it is the real model name
name = (String) map.get(NAME_KEY);
}
EOModel model = new EOModel();
model.setName(name);
model.setAdaptorName((String) map.get(ADAPTOR_NAME_KEY));
model.setConnectionDictionary((Map<String, Object>) map.get(CONNECTION_DICTIONARY));
model.setOriginalMap(map);
model.setFile(dir);
model.loadEntities();
model.setModelGroup(group != null ? group : EOModelGroup.getDefaultGroup());
return model;
}
/**
*
*/
public EOModel() {
entities = new Vector<EOEntity>();
filesToDelete = new Vector<File>();
createHashMap();
}
public Map<Object, Object> getMapRepresentation() {
Map<Object, Object> map = new HashMap<Object, Object>();
if (map.get(EOMODEL_VERSION_KEY) == null) {
map.put(EOMODEL_VERSION_KEY, "2.1");
}
map.put(NAME_KEY, getName());
if (getAdaptorName() != null) {
map.put(ADAPTOR_NAME_KEY, getAdaptorName());
} else {
map.remove(ADAPTOR_NAME_KEY);
}
if (getConnectionDictionary() != null) {
map.put(CONNECTION_DICTIONARY, getConnectionDictionary());
} else {
map.remove(CONNECTION_DICTIONARY);
}
Vector<HashMap<String, String>> entityVector = new Vector<HashMap<String, String>>();
Iterator<EOEntity> i = getEntities().iterator();
while (i.hasNext()) {
HashMap<String, String> map1 = new HashMap<String, String>();
EOEntity entity = i.next();
map1.put(NAME_KEY, entity.getName());
if (entity.getClassName() != null) {
map1.put(CLASS_NAME_KEY, entity.getClassName());
}
entityVector.add(map1);
}
map.put(ENTITIES_KEY, entityVector);
return map;
}
public String getPListRepresentation() {
return FlexoPropertyListSerialization.getPListRepresentation(getMapRepresentation());
}
/**
* @param file
* @throws IOException
*/
public void writeToFile(File file) throws IOException {
makeBackup();
// We delete the files before writing the entities so that if the user
// deletes an entity and then decides to add it again, the file won't
// get deleted by mistake
Iterator<File> it = getFilesToDelete().iterator();
while (it.hasNext()) {
File f = it.next();
if (f.delete()) {
it.remove();
}
}
if (getOriginalMap().get(EOMODEL_VERSION_KEY) == null) {
getOriginalMap().put(EOMODEL_VERSION_KEY, "2.1");
}
if (entityNamed(EOPROTOTYPES) != null) {
if (entityNamed(EOPROTOTYPES).getModel() == this) {
return;
}
}
getOriginalMap().put(NAME_KEY, getName());
if (getAdaptorName() != null) {
getOriginalMap().put(ADAPTOR_NAME_KEY, getAdaptorName());
} else {
getOriginalMap().remove(ADAPTOR_NAME_KEY);
}
if (getConnectionDictionary() != null) {
getOriginalMap().put(CONNECTION_DICTIONARY, getConnectionDictionary());
} else {
getOriginalMap().remove(CONNECTION_DICTIONARY);
}
// Model serialization
if (!file.exists()) {
file.mkdirs();
}
Vector<HashMap<String, String>> entityVector = new Vector<HashMap<String, String>>();
Iterator<EOEntity> i = getEntities().iterator();
while (i.hasNext()) {
HashMap<String, String> map = new HashMap<String, String>();
EOEntity entity = i.next();
map.put(NAME_KEY, entity.getName());
if (entity.getClassName() != null) {
map.put(CLASS_NAME_KEY, entity.getClassName());
}
entityVector.add(map);
}
getOriginalMap().put(ENTITIES_KEY, entityVector);
File f = new File(file, INDEX_EOMODELD);
if (!f.exists()) {
f.createNewFile();
}
FlexoPropertyListSerialization.propertyListToFile(f, getOriginalMap());
// Entities serialization
i = getEntities().iterator();
while (i.hasNext()) {
EOEntity entity = i.next();
entity.writeToFile(file);
}
setFile(file);
}
/**
*
*/
private void makeBackup() {
if (getFile() == null || !getFile().exists()) {
return;
}
File bak = new File(getFile().getParentFile(), getFile().getName() + ".bak");
FileUtils.deleteFilesInDir(bak, true);
try {
FileUtils.copyContentDirToDir(getFile(), bak);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the entity named <code>name</code>. This methods looks in the model and all the other registered models of this model group.
*
* @param name
* - the name of the entity to return
* @return the entity named <code>name</code>
*/
public EOEntity entityNamed(String name) {
EOEntity e = _entityNamed(name);
if (e != null) {
return e;
} else {
return modelGroup.entityNamed(name);
}
}
/**
* Returns the entity name <code>name</code> if it is found in this model. This method can be used by third-party but is first intended
* toward the model.
*
* @param name
* - the name of the entity to be found
* @return the entity named <code>name</code> if it is found in this model
* @see #entityNamed(String)
*/
public EOEntity _entityNamed(String name) {
if (name == null) {
return null;
}
Iterator<EOEntity> i = entities.iterator();
while (i.hasNext()) {
EOEntity e = i.next();
if (name.equals(e.getName())) {
return e;
}
}
if (modelGroup != null) {
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Found an EOModel outside of a model group.");
}
return null;
}
/**
* Returns the entity named <code>name</code>. This methods looks in the model and all the other registered models of this model group.
*
* @param name
* - the name of the entity to return
* @return the entity named <code>name</code>
*/
public EOEntity entityNamedIgnoreCase(String name) {
EOEntity e = _entityNamedIgnoreCase(name);
if (e != null) {
return e;
} else {
return modelGroup.entityNamedIgnoreCase(name);
}
}
/**
* Returns the entity name <code>name</code> if it is found in this model. This method can be used by third-party but is first intended
* toward the model.
*
* @param name
* - the name of the entity to be found
* @return the entity named <code>name</code> if it is found in this model
* @see #entityNamed(String)
*/
public EOEntity _entityNamedIgnoreCase(String name) {
if (name == null) {
return null;
}
Iterator<EOEntity> i = entities.iterator();
while (i.hasNext()) {
EOEntity e = i.next();
if (name.equalsIgnoreCase(e.getName())) {
return e;
}
}
if (modelGroup != null) {
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Found an EOModel outside of a model group.");
}
return null;
}
public String getAdaptorName() {
return adaptorName;
}
public void setAdaptorName(String adaptorName) {
this.adaptorName = adaptorName;
}
public Map<String, Object> getConnectionDictionary() {
return connectionDictionary;
}
public void setConnectionDictionary(Map<String, Object> connectionDictionary) {
this.connectionDictionary = connectionDictionary;
}
public List<EOEntity> getEntities() {
return entities;
}
public void setEntities(List<EOEntity> entities) {
this.entities = entities;
}
/**
* @param newEOEntity
*/
public void addEntity(EOEntity entity) {
if (entities.contains(entity)) {
throw new IllegalArgumentException("Entity " + entity.getName() + " is already in model " + getName());
}
if (entityNamedIgnoreCase(entity.getName()) != null) {
throw new IllegalArgumentException("An other entity named " + entityNamedIgnoreCase(entity.getName()).getName()
+ " already exists in model " + getName());
}
entities.add(entity);
entity.setModel(this);
}
public void removeEntity(EOEntity entity) {
if (entities.contains(entity)) {
entities.remove(entity);
entity.delete();
}
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public File getIndexFile() {
return new File(getFile(), INDEX_EOMODELD);
}
public EOModelGroup getModelGroup() {
return modelGroup;
}
public void setModelGroup(EOModelGroup modelGroup) {
this.modelGroup = modelGroup;
}
/**
* Overrides resolveObjects
*
* @throws FileNotFoundException
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#resolveObjects()
*/
@Override
protected void resolveObjects() {
missingEntities = new Vector<String>();
Iterator<EOEntity> i = getEntities().iterator();
while (i.hasNext()) {
EOEntity e = i.next();
e.resolveObjects();
}
}
/**
* Overrides delete
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#delete()
*/
@Override
public void delete() {
Iterator<EOEntity> i = getEntities().iterator();
while (i.hasNext()) {
EOEntity e = i.next();
e.delete();
}
}
/**
* @param prototype
* @return
*/
public EOAttribute getPrototypeNamed(String prototype) {
EOEntity e = entityNamed(EOPROTOTYPES);
if (e != null) {
return e.attributeNamed(prototype);
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("Prototypes could not be found");
}
return null;
}
/**
* Overrides clearObjects
*
* @see org.openflexo.foundation.dm.eo.model.EOObject#clearObjects()
*/
@Override
protected void clearObjects() {
Iterator<EOEntity> i = getEntities().iterator();
while (i.hasNext()) {
EOEntity e = i.next();
e.clearObjects();
}
}
/**
*
*/
public void loadAllModelObjects() {
getModelGroup().loadAllModelObjects(this);
}
/**
* This call will load all entities from the original map.
*/
@SuppressWarnings("unchecked")
protected void loadEntities() {
Map<Object, Object> map = getOriginalMap();
List<Map<String, String>> entitiesList = (List<Map<String, String>>) map.get(ENTITIES_KEY);
if (entitiesList != null) {
Iterator<Map<String, String>> i = entitiesList.iterator();
List<EOEntity> entities = new Vector<EOEntity>();
while (i.hasNext()) {
Map<String, String> m = i.next();
EOEntity e = null;
try {
e = EOEntity.createEntityFromFile(this, new File(getFile(), m.get(NAME_KEY) + ".plist"));
} catch (FileNotFoundException e1) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find property list file "
+ new File(getFile(), m.get(NAME_KEY) + ".plist").getAbsolutePath());
}
} catch (Exception e2) {
e2.printStackTrace();
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not deserialize property list file "
+ new File(getFile(), m.get(NAME_KEY) + ".plist").getAbsolutePath());
}
} finally {
if (e == null) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Creating EOEntity " + m.get(NAME_KEY));
}
e = new EOEntity();
e.setName(m.get(NAME_KEY));
if (m.get(CLASS_NAME_KEY) != null) {
e.setClassName(m.get(CLASS_NAME_KEY));
} else {
e.setClassName(m.get(NAME_KEY));
}
}
}
entities.add(e);
}
setEntities(entities);
}
}
public void addToMissingEntities(String entityName) {
if (!missingEntities.contains(entityName)) {
missingEntities.add(entityName);
}
}
public Vector<String> getMissingEntities() {
return missingEntities;
}
public Vector<File> getFilesToDelete() {
return filesToDelete;
}
public void setFilesToDelete(Vector<File> filesToDelete) {
this.filesToDelete = filesToDelete;
}
public void addToFilesToDelete(File fileToDelete) {
filesToDelete.add(fileToDelete);
}
public void removeFilesToDelete(File fileToDelete) {
filesToDelete.remove(fileToDelete);
}
}