/******************************************************************************* * Copyright (c) 2007-2009 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributor: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.hibernate.ui.diagram.editors.model; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.hibernate.console.ConsoleConfiguration; import org.hibernate.console.KnownConfigurations; import org.jboss.tools.hibernate.runtime.spi.IColumn; import org.jboss.tools.hibernate.runtime.spi.IConfiguration; import org.jboss.tools.hibernate.runtime.spi.IForeignKey; import org.jboss.tools.hibernate.runtime.spi.IJoin; import org.jboss.tools.hibernate.runtime.spi.IPersistentClass; import org.jboss.tools.hibernate.runtime.spi.IProperty; import org.jboss.tools.hibernate.runtime.spi.IService; import org.jboss.tools.hibernate.runtime.spi.ITable; import org.jboss.tools.hibernate.runtime.spi.IType; import org.jboss.tools.hibernate.runtime.spi.IValue; /** * Responsible to create diagram elements for given * Hibernate Console Configuration. * * @author Vitali Yemialyanchyk */ public class ElementsFactory { private final String consoleConfigName; private final HashMap<String, OrmShape> elements; private final ArrayList<Connection> connections; private IService service; public ElementsFactory(String consoleConfigName, HashMap<String, OrmShape> elements, ArrayList<Connection> connections) { this.consoleConfigName = consoleConfigName; this.elements = elements; this.connections = connections; } @SuppressWarnings("unchecked") public void createForeingKeyConnections() { // do clone cause elements could be changed during iteration! HashMap<String, OrmShape> elementsTmp = (HashMap<String, OrmShape>)elements.clone(); Iterator<OrmShape> it = elementsTmp.values().iterator(); while (it.hasNext()) { final OrmShape shape = it.next(); Object ormElement = shape.getOrmElement(); if (ormElement instanceof ITable) { ITable databaseTable = (ITable)ormElement; Iterator<IForeignKey> itFK = databaseTable.getForeignKeyIterator(); while (itFK.hasNext()) { final IForeignKey fk = itFK.next(); ITable referencedTable = fk.getReferencedTable(); final OrmShape referencedShape = getOrCreateDatabaseTable(referencedTable); // Iterator<IColumn> itColumns = fk.columnIterator(); while (itColumns.hasNext()) { IColumn col = itColumns.next(); Shape shapeColumn = shape.getChild(col); Iterator<IColumn> itReferencedColumns = null; if (fk.isReferenceToPrimaryKey()) { itReferencedColumns = (Iterator<IColumn>)referencedTable.getPrimaryKey().columnIterator(); } else { itReferencedColumns = (Iterator<IColumn>)fk.getReferencedColumns().iterator(); } while (itReferencedColumns != null && itReferencedColumns.hasNext()) { IColumn colReferenced = itReferencedColumns.next(); Shape shapeReferencedColumn = referencedShape.getChild(colReferenced); if (shouldCreateConnection(shapeColumn, shapeReferencedColumn)) { connections.add(new Connection(shapeColumn, shapeReferencedColumn)); } } } } } } } public void createChildren(BaseElement element) { if (element.getClass().equals(ExpandableShape.class)) { processExpand((ExpandableShape)element); } else if (element.getClass().equals(ComponentShape.class)) { refreshComponentReferences((ComponentShape)element); } Iterator<Shape> it = element.getChildrenList().iterator(); while (it.hasNext()) { final Shape shape = it.next(); createChildren(shape); } } protected void processExpand(ExpandableShape shape) { Object element = shape.getOrmElement(); if (!(element instanceof IProperty)) { return; } OrmShape s = null; IProperty property = (IProperty)element; if (!property.isComposite()) { final IConfiguration config = getConfig(); // IValue v = property.getValue(); IType type = UtilTypeExtract.getTypeUsingExecContext(v, getConsoleConfig()); if (type != null && type.isEntityType()) { Object clazz = config != null ? config.getClassMapping(type.getAssociatedEntityName()) : null; if (clazz instanceof IPersistentClass && ((IPersistentClass)clazz).isInstanceOfRootClass()) { IPersistentClass rootClass = (IPersistentClass)clazz; s = getOrCreatePersistentClass(rootClass, null); if (shouldCreateConnection(shape, s)) { connections.add(new Connection(shape, s)); } } else if (clazz instanceof IPersistentClass && ((IPersistentClass)clazz).isInstanceOfSubclass()) { s = getOrCreatePersistentClass(((IPersistentClass)clazz).getRootClass(), null); } } } else { s = getOrCreatePersistentClass(getService().newSpecialRootClass(property), null); if (shouldCreateConnection(shape, s)) { connections.add(new Connection(shape, s)); } createConnections(s, getOrCreateDatabaseTable(property.getValue().getTable())); } } protected void refreshComponentReferences(ComponentShape componentShape) { IProperty property = (IProperty)componentShape.getOrmElement(); IValue v = property.getValue(); if (!v.isCollection()) { return; } IValue collection = v; IValue component = collection.getElement(); Shape csChild0 = null, csChild1 = null; Iterator<Shape> tmp = componentShape.getChildrenIterator(); if (tmp.hasNext()) { csChild0 = tmp.next(); } if (tmp.hasNext()) { csChild1 = tmp.next(); } OrmShape childShape = null; if (component.isComponent()) { childShape = elements.get(component.getComponentClassName()); if (childShape == null) { childShape = getOrCreateComponentClass(property); } IValue value = (IValue)csChild0.getOrmElement(); OrmShape tableShape = getOrCreateDatabaseTable(value.getTable()); if (tableShape != null) { Iterator<IColumn> it = value.getColumnIterator(); while (it.hasNext()) { IColumn el = it.next(); Shape shape = tableShape.getChild(el); if (shouldCreateConnection(csChild0, shape)) { connections.add(new Connection(csChild0, shape)); } } } if (shouldCreateConnection(csChild1, childShape)) { connections.add(new Connection(csChild1, childShape)); } } else if (collection.isOneToMany()) { childShape = getOrCreateAssociationClass(property); if (childShape != null) { if (shouldCreateConnection(csChild1, childShape)) { connections.add(new Connection(csChild1, childShape)); } OrmShape keyTableShape = getOrCreateDatabaseTable(collection.getKey().getTable()); Iterator<IColumn> it = collection.getKey().getColumnIterator(); while (it.hasNext()) { Object el = it.next(); if (el instanceof IColumn) { IColumn col = (IColumn)el; Shape shape = keyTableShape.getChild(col); if (shouldCreateConnection(csChild0, shape)) { connections.add(new Connection(csChild0, shape)); } } } } } else { // this is case: if (collection.isMap() || collection.isSet()) childShape = getOrCreateDatabaseTable(collection.getCollectionTable()); if (childShape != null) { Iterator<IColumn> it = ((IValue)csChild0.getOrmElement()).getColumnIterator(); while (it.hasNext()) { Object el = it.next(); if (el instanceof IColumn) { IColumn col = (IColumn)el; Shape shape = childShape.getChild(col); if (shouldCreateConnection(csChild0, shape)) { connections.add(new Connection(csChild0, shape)); } } } it = ((IValue)csChild1.getOrmElement()).getColumnIterator(); while (it.hasNext()) { Object el = it.next(); if (el instanceof IColumn) { IColumn col = (IColumn)el; Shape shape = childShape.getChild(col); if (shouldCreateConnection(csChild1, shape)) { connections.add(new Connection(csChild1, shape)); } } } } } } @SuppressWarnings("rawtypes") protected OrmShape getOrCreateDatabaseTable(ITable databaseTable) { OrmShape tableShape = null; if (databaseTable != null) { tableShape = getShape(databaseTable); if (tableShape == null) { tableShape = createShape(databaseTable); final IConfiguration config = getConfig(); if (config != null) { Iterator iterator = config.getClassMappings(); while (iterator.hasNext()) { Object clazz = iterator.next(); if (clazz instanceof IPersistentClass && ((IPersistentClass)clazz).isInstanceOfRootClass()) { IPersistentClass cls = (IPersistentClass)clazz; if (databaseTable.equals(cls.getTable())) { // create persistent class shape only for RootClass, // which has same table reference getOrCreatePersistentClass(cls, null); } } } } } } return tableShape; } @SuppressWarnings({ "rawtypes" }) protected OrmShape getOrCreatePersistentClass(IPersistentClass persistentClass, ITable componentClassDatabaseTable) { OrmShape classShape = null; if (persistentClass == null) { return classShape; } OrmShape shape = null; classShape = getShape(persistentClass.getEntityName()); if (classShape == null) { classShape = createShape(persistentClass); } if (componentClassDatabaseTable == null && persistentClass.getTable() != null) { componentClassDatabaseTable = persistentClass.getTable(); } if (componentClassDatabaseTable != null) { shape = getShape(componentClassDatabaseTable); if (shape == null) { shape = getOrCreateDatabaseTable(componentClassDatabaseTable); } createConnections(classShape, shape); if (shouldCreateConnection(classShape, shape)) { connections.add(new Connection(classShape, shape)); } } IPersistentClass rc = persistentClass; Iterator iter = rc.getSubclassIterator(); while (iter.hasNext()) { Object element = iter.next(); if (element instanceof IPersistentClass && ((IPersistentClass)element).isInstanceOfSubclass()) { IPersistentClass subclass = (IPersistentClass)element; OrmShape subclassShape = getShape(subclass); if (subclassShape == null) { subclassShape = createShape(subclass); } if (((IPersistentClass)element).isJoinedSubclass()) { ITable jcTable = ((IPersistentClass)element).getTable(); OrmShape jcTableShape = getOrCreateDatabaseTable(jcTable); createConnections(subclassShape, jcTableShape); if (shouldCreateConnection(subclassShape, jcTableShape)) { connections.add(new Connection(subclassShape, jcTableShape)); } } else { createConnections(subclassShape, shape); if (shouldCreateConnection(subclassShape, shape)) { connections.add(new Connection(subclassShape, shape)); } } OrmShape ownerTableShape = getOrCreateDatabaseTable(((IPersistentClass)element).getRootTable()); createConnections(subclassShape, ownerTableShape); Iterator<IJoin> joinIterator = subclass.getJoinIterator(); while (joinIterator.hasNext()) { IJoin join = joinIterator.next(); Iterator<IProperty> iterator = join.getPropertyIterator(); while (iterator.hasNext()) { IProperty property = iterator.next(); OrmShape tableShape = getOrCreateDatabaseTable(property.getValue().getTable()); createConnections(subclassShape, tableShape); } } } } IValue identifier = persistentClass.getIdentifier(); if (identifier != null && identifier.isComponent()) { if (identifier.getComponentClassName() != null && !identifier.getComponentClassName().equals(identifier.getOwner().getEntityName())) { OrmShape componentClassShape = elements.get(identifier.getComponentClassName()); if (componentClassShape == null && persistentClass.isInstanceOfRootClass()) { componentClassShape = getOrCreateComponentClass(persistentClass.getIdentifierProperty()); Shape idPropertyShape = classShape.getChild(persistentClass.getIdentifierProperty()); if (shouldCreateConnection(idPropertyShape, componentClassShape)) { connections.add(new Connection(idPropertyShape, componentClassShape)); } OrmShape tableShape = getOrCreateDatabaseTable(identifier.getTable()); if (componentClassShape != null) { createConnections(componentClassShape, tableShape); } } } } Iterator<IJoin> joinIterator = persistentClass.getJoinIterator(); while (joinIterator.hasNext()) { IJoin join = (IJoin)joinIterator.next(); Iterator<IProperty> iterator = join.getPropertyIterator(); while (iterator.hasNext()) { IProperty property = iterator.next(); OrmShape tableShape = getOrCreateDatabaseTable(property.getValue().getTable()); createConnections(classShape, tableShape); } } return classShape; } protected OrmShape getOrCreateComponentClass(IProperty property) { OrmShape classShape = null; if (property == null) { return classShape; } IValue value = property.getValue(); if (value.isCollection()) { IValue component = value.getElement(); if (component != null) { classShape = createShape(property); OrmShape tableShape = elements.get(Utils.getTableName(component.getTable())); if (tableShape == null) { tableShape = getOrCreateDatabaseTable(component.getTable()); } createConnections(classShape, tableShape); if (shouldCreateConnection(classShape, tableShape)) { connections.add(new Connection(classShape, tableShape)); } Shape parentShape = ((SpecialOrmShape)classShape).getParentShape(); if (parentShape != null) { OrmShape parentClassShape = elements.get( Utils.getName(((IProperty)parentShape.getOrmElement()).getPersistentClass().getEntityName())); if (shouldCreateConnection(parentShape, parentClassShape)) { connections.add(new Connection(parentShape, parentClassShape)); } } } } else if (value.isComponent()) { classShape = elements.get(value.getComponentClassName()); if (classShape == null) { classShape = createShape(property); } } return classShape; } protected OrmShape getOrCreateAssociationClass(IProperty property) { OrmShape classShape = null; IValue component = property.getValue().getElement(); if (component == null) { return classShape; } if (component.getAssociatedClass().isInstanceOfRootClass()) { classShape = getOrCreatePersistentClass(component.getAssociatedClass(), null); if (classShape == null) { classShape = createShape(component.getAssociatedClass()); } OrmShape tableShape = elements.get(Utils.getTableName( component.getAssociatedClass().getTable())); if (tableShape == null) { tableShape = getOrCreateDatabaseTable( component.getAssociatedClass().getTable()); } createConnections(classShape, tableShape); if (shouldCreateConnection(classShape, tableShape)) { connections.add(new Connection(classShape, tableShape)); } } return classShape; } protected OrmShape createShape(Object ormElement) { OrmShape ormShape = null; if (ormElement instanceof IProperty) { IPersistentClass specialRootClass = getService().newSpecialRootClass((IProperty)ormElement); String key = Utils.getName(specialRootClass.getEntityName()); ormShape = elements.get(key); if (null == ormShape) { ormShape = new SpecialOrmShape(specialRootClass, consoleConfigName); elements.put(key, ormShape); } } else { String key = Utils.getName(ormElement); ormShape = elements.get(key); if (null == ormShape) { ormShape = new OrmShape(ormElement, consoleConfigName); elements.put(key, ormShape); } } return ormShape; } @SuppressWarnings("rawtypes") private boolean createConnections(ExpandableShape persistentClass, ExpandableShape dbTable) { boolean res = false; if (persistentClass == null || dbTable == null) { return res; } IProperty parentProperty = null; if (persistentClass.getOrmElement() instanceof IPersistentClass && ((IPersistentClass)persistentClass.getOrmElement()).isInstanceOfSpecialRootClass()) { parentProperty = ((IPersistentClass)persistentClass.getOrmElement()).getParentProperty(); } Iterator<Shape> itFields = persistentClass.getChildrenIterator(); Set<Shape> processed = new HashSet<Shape>(); while (itFields.hasNext()) { final Shape shape = itFields.next(); Object element = shape.getOrmElement(); if (!(element instanceof IProperty && parentProperty != element)) { continue; } IValue value = ((IProperty)element).getValue(); Iterator iterator = value.getColumnIterator(); while (iterator.hasNext()) { Object o = iterator.next(); if (!(o instanceof IColumn)) { continue; } IColumn dbColumn = (IColumn)o; Iterator<Shape> itColumns = dbTable.getChildrenIterator(); while (itColumns.hasNext()) { final Shape shapeCol = itColumns.next(); if (processed.contains(shapeCol)) { continue; } if (shape.equals(shapeCol)) { continue; } Object ormElement = shapeCol.getOrmElement(); String name2 = ""; //$NON-NLS-1$ if (ormElement instanceof IColumn) { IColumn dbColumn2 = (IColumn)ormElement; name2 = dbColumn2.getName(); } else if (ormElement instanceof IProperty) { IProperty property2 = (IProperty)ormElement; name2 = property2.getName(); } if (dbColumn.getName().equals(name2)) { if (shouldCreateConnection(shape, shapeCol)) { connections.add(new Connection(shape, shapeCol)); res = true; } processed.add(shapeCol); } } } } return res; } public OrmShape getShape(Object ormElement) { OrmShape ormShape = null; if (ormElement instanceof IProperty) { IPersistentClass specialRootClass = getService().newSpecialRootClass((IProperty)ormElement); ormShape = elements.get(Utils.getName(specialRootClass.getEntityName())); } else { ormShape = elements.get(Utils.getName(ormElement)); } return ormShape; } private boolean isConnectionExist(Shape source, Shape target) { return Utils.isConnectionExist(source, target); } private boolean shouldCreateConnection(Shape source, Shape target) { if (source == null || target == null || source == target) { return false; } if (isConnectionExist(source, target)) { return false; } return true; } public ConsoleConfiguration getConsoleConfig() { final KnownConfigurations knownConfigurations = KnownConfigurations.getInstance(); ConsoleConfiguration consoleConfig = knownConfigurations.find(consoleConfigName); return consoleConfig; } public IConfiguration getConfig() { IConfiguration config = null; final ConsoleConfiguration consoleConfig = getConsoleConfig(); if (consoleConfig != null) { config = consoleConfig.getConfiguration(); } return config; } private IService getService() { if (service == null) { service = getConsoleConfig().getHibernateExtension().getHibernateService(); } return service; } }