package com.eas.client.model; import com.eas.client.metadata.Field; import com.eas.client.metadata.Fields; import com.eas.client.metadata.Parameter; import com.eas.client.metadata.Parameters; import com.eas.client.model.visitors.ModelVisitor; import com.eas.client.queries.Query; import java.beans.PropertyChangeSupport; import java.util.*; /** * @param <E> Entity generic type. * @param <Q> Query generic type. * @author mg */ public abstract class Model<E extends Entity<?, Q, E>, Q extends Query> { public static final String DATASOURCE_METADATA_SCRIPT_NAME = "schema"; protected Set<Relation<E>> relations = new HashSet<>(); protected Map<Long, E> entities = new HashMap<>(); protected ModelEditingSupport<E> editingSupport = new ModelEditingSupport<>(); protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); protected boolean relationsAgressiveCheck; public Model<E, Q> copy() throws Exception { Model<E, Q> copied = getClass().newInstance(); for (E entity : entities.values()) { copied.addEntity((E) entity.copy()); } for (Relation<E> relation : relations) { Relation<E> rcopied = relation.copy(); copied.resolveRelation(rcopied); copied.addRelation(rcopied); } return copied; } /** * Base model constructor. */ protected Model() { super(); } public PropertyChangeSupport getChangeSupport() { return changeSupport; } public void clearRelations() { if (relations != null) { relations.clear(); entities.values().stream().forEach((e) -> { e.getInRelations().clear(); e.getOutRelations().clear(); }); } } /** * Tests if entities' internal data is actual, updating it if necessary. * * @return True if any change occur and false is all is actual. * @throws java.lang.Exception */ public synchronized boolean validate() throws Exception { if (validateEntities()) { validateRelations(); checkRelationsIntegrity(); return true; } else { return false; } } protected void validateRelations() throws Exception { for (Relation<E> rel : relations) { resolveRelation(rel); } } protected boolean validateEntities() throws Exception { boolean res = false; for (E e : entities.values()) { if (e.validate()) { res = true; } } return res; } public void fireAllQueriesChanged() throws Exception { for (E e : getEntities().values()) { boolean queryExists; try { queryExists = e.getQuery() != null; } catch (Exception ex) { queryExists = false; } e.getChangeSupport().firePropertyChange(Entity.QUERY_VALID_PROPERTY, !queryExists, queryExists); } } public ModelEditingSupport<E> getEditingSupport() { return editingSupport; } /** * Finds entity by table name. Takes into account only table name, ignoring * schema, even it's exist. * * @param aTableName * @return Entity found; */ public E getEntityByTableName(String aTableName) { if (aTableName != null && !aTableName.isEmpty() && entities != null) { for (E ent : entities.values()) { String tableName = ent.getTableName(); if (tableName != null && !tableName.isEmpty()) { if (tableName.toLowerCase().equals(aTableName.toLowerCase())) { return ent; } } } } return null; } /** * Finds entity by full table name. Takes into account schema name. * * @param aTableName * @return Entity found; */ public E getEntityByFullTableName(String aTableName) { if (aTableName != null && !aTableName.isEmpty() && entities != null) { for (E ent : entities.values()) { String tableName = ent.getTableName(); if (tableName != null && !tableName.isEmpty()) { if (ent.getTableSchemaName() != null && !ent.getTableSchemaName().isEmpty()) { tableName = ent.getTableSchemaName() + "." + tableName; } if (tableName.toLowerCase().equals(aTableName.toLowerCase())) { return ent; } } } } return null; } /** * Finds entity by name. * * @param aName * @return Entity found; */ public E getEntityByName(String aName) { for (E appEntity : getEntities().values()) { if (appEntity.getName() != null && appEntity.getName().equalsIgnoreCase(aName)) { return appEntity; } } return null; } public abstract E newGenericEntity(); public abstract <M extends Model<E, ?>> void accept(ModelVisitor<E, M> visitor); /** * Registers an <code>DatamodelEditingValidator</code>. The validator is * notified whenever an datamodel edit action will occur. * * @param v an <code>DatamodelEditingValidator</code> object * @see #removeEditingValidator(com.eas.client.model.ModelEditingValidator) */ public synchronized void addEditingValidator(ModelEditingValidator<E> v) { editingSupport.addValidator(v); } /** * Removes an <code>DatamodelEditingValidator</code>. * * @param v the <code>DatamodelEditingValidator</code> object to be removed * @see #addEditingValidator(com.eas.client.model.ModelEditingValidator) */ public synchronized void removeEditingValidator(ModelEditingValidator<E> v) { editingSupport.removeValidator(v); } public boolean checkRelationAddingValid(Relation<E> aRelation) { return editingSupport.checkRelationAddingValid(aRelation); } public boolean checkRelationRemovingValid(Relation<E> aRelation) { return editingSupport.checkRelationRemovingValid(aRelation); } public boolean checkEntityAddingValid(E aEntity) { return editingSupport.checkEntityAddingValid(aEntity); } public boolean checkEntityRemovingValid(E aEntity) { return editingSupport.checkEntityRemovingValid(aEntity); } public void addEditingListener(ModelEditingListener<E> l) { editingSupport.addListener(l); } public void removeEditingListener(ModelEditingListener<E> l) { editingSupport.removeListener(l); } private void fireEntityAdded(E ent) { editingSupport.fireEntityAdded(ent); } private void fireEntityRemoved(E ent) { editingSupport.fireEntityRemoved(ent); } public void fireRelationAdded(Relation<E> aRel) { editingSupport.fireRelationAdded(aRel); } public void fireRelationRemoved(Relation<E> aRel) { editingSupport.fireRelationRemoved(aRel); } public void addRelation(Relation<E> aRel) { relations.add(aRel); E lEntity = aRel.getLeftEntity(); E rEntity = aRel.getRightEntity(); if (lEntity != null && rEntity != null) { lEntity.addOutRelation(aRel); rEntity.addInRelation(aRel); } fireRelationAdded(aRel); } public Set<Relation<E>> collectRelationsByEntity(E aEntity) { return aEntity.getInOutRelations(); } public void removeRelation(Relation<E> aRelation) { relations.remove(aRelation); E lEntity = aRelation.getLeftEntity(); E rEntity = aRelation.getRightEntity(); if (lEntity != null && rEntity != null) { lEntity.removeOutRelation(aRelation); rEntity.removeInRelation(aRelation); } fireRelationRemoved(aRelation); } public void addEntity(E aEntity) { entities.put(aEntity.getEntityId(), aEntity); fireEntityAdded(aEntity); } public boolean removeEntity(E aEnt) { return aEnt != null && removeEntity(aEnt.getEntityId()) != null; } public E removeEntity(Long aEntId) { E lent = entities.get(aEntId); if (lent != null) { entities.remove(aEntId); fireEntityRemoved(lent); } return lent; } public Map<Long, E> getEntities() { return entities; } public E getEntityById(Long aId) { return entities.get(aId); } public void setEntities(Map<Long, E> aValue) { entities = aValue; } public Set<Relation<E>> getRelations() { return relations; } public void setRelations(Set<Relation<E>> aRelations) { relations = aRelations; } public boolean isFieldInRelations(E aEntity, Set<Relation<E>> aRelations, Field aField) { for (Relation<E> lrel : aRelations) { if (lrel.getLeftField() == aField || lrel.getLeftParameter() == aField || lrel.getRightField() == aField || lrel.getRightParameter() == aField) { return true; } } return false; } public boolean isNamePresent(String aName, E toExclude, Field field2Exclude) { if (entities != null && aName != null) { for (E ent : entities.values()) { if (ent != null && ent != toExclude) { String lName = ent.getName(); if (lName != null && aName.equals(lName)) { return true; } Fields mayBeParams = ent.getFields(); if (mayBeParams != null && mayBeParams instanceof Parameters && mayBeParams.isNameAlreadyPresent(aName, field2Exclude)) { return true; } } } } return false; } public boolean isRelationsAgressiveCheck() { return relationsAgressiveCheck; } public void setRelationsAgressiveCheck(boolean aValue) { relationsAgressiveCheck = aValue; } public void resolveRelation(Relation<E> aRelation) throws Exception { resolveRelationEntities(aRelation); resolveRelationFields(aRelation); } protected void resolveRelationFields(Relation<E> aRelation) { if (aRelation.getLeftField() != null) { String targetName = aRelation.getLeftField().getName(); if (aRelation.getLeftEntity() != null) { Q lQuery = aRelation.getLeftEntity().getQuery(); if (aRelation.isLeftParameter() && aRelation.getLeftEntity().getQueryName() != null) { if (lQuery != null) { aRelation.setLeftField(lQuery.getParameters().get(targetName)); } else if (relationsAgressiveCheck) { aRelation.setLeftField(null); } else { aRelation.setLeftField(new Parameter(targetName)); } } else { Fields lFields = aRelation.getLeftEntity().getFields(); if (lFields != null && lQuery != null && lQuery.isMetadataAccessible()) { aRelation.setLeftField(lFields.get(targetName)); } else if (relationsAgressiveCheck) { aRelation.setLeftField(null); } else { aRelation.setLeftField(new Field(targetName)); } } } else if (relationsAgressiveCheck) { aRelation.setLeftField(null); } else { aRelation.setLeftField(new Field(targetName)); } } if (aRelation.getRightField() != null) { String targetName = aRelation.getRightField().getName(); if (aRelation.getRightEntity() != null) { Q rQuery = aRelation.getRightEntity().getQuery(); if (aRelation.isRightParameter() && aRelation.getRightEntity().getQueryName() != null) { if (rQuery != null) { aRelation.setRightField(rQuery.getParameters().get(targetName)); } else if (relationsAgressiveCheck) { aRelation.setRightField(null); } else { aRelation.setRightField(new Parameter(targetName)); } } else { Fields rFields = aRelation.getRightEntity().getFields(); if (rFields != null && rQuery != null && rQuery.isMetadataAccessible()) { aRelation.setRightField(rFields.get(targetName)); } else if (relationsAgressiveCheck) { aRelation.setRightField(null); } else { aRelation.setRightField(new Field(targetName)); } } } else if (relationsAgressiveCheck) { aRelation.setRightField(null); } else { aRelation.setRightField(new Field(targetName)); } } } protected void resolveRelationEntities(Relation<E> aRelation) { if (aRelation.getLeftEntity() != null) { aRelation.setLeftEntity(getEntityById(aRelation.getLeftEntity().getEntityId())); } if (aRelation.getRightEntity() != null) { aRelation.setRightEntity(getEntityById(aRelation.getRightEntity().getEntityId())); } } public void checkRelationsIntegrity() { List<Relation<E>> toDel = new ArrayList<>(); relations.stream().forEach((rel) -> { if (rel.getLeftEntity() == null || (rel.getLeftField() == null && rel.getLeftParameter() == null) || rel.getRightEntity() == null || (rel.getRightField() == null && rel.getRightParameter() == null)) { toDel.add(rel); } }); toDel.stream().forEach((rel) -> { removeRelation(rel); }); } }