/******************************************************************************* * Copyright (c) 2007-2008 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.hibernate.eclipse.jdt.ui.internal.jpa.common; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; /** * Service place to collect information about entity class. * Then this info has been transformed according annotations * creation assumption. * * @author Vitali */ public class EntityInfo { /* * fully java project name */ protected String javaProjectName = ""; //$NON-NLS-1$ /* * fully qualified entity name */ protected String fullyQualifiedName = ""; //$NON-NLS-1$ /* * fully qualified parent name */ protected String fullyQualifiedParentName = ""; //$NON-NLS-1$ /* * true in case of compiler problems */ protected boolean compilerProblemsFlag = false; /* * true in case of implicit constructor */ protected boolean implicitConstructorFlag = true; /* * true in case of default constructor */ protected boolean defaultConstructorFlag = false; /* * if true - "@Entity" annotation should be added */ protected boolean addEntityFlag = true; /* * if true - "@MappedSuperclass" annotation should be added */ protected boolean addMappedSuperclassFlag = false; /* * if true - "@MappedSuperclass" exist for the entity */ protected boolean hasMappedSuperclassAnnotation = false; /* * existing imports set */ protected Set<String> setExistingImports = new TreeSet<String>(); /* * required imports set */ protected Set<String> setRequiredImports = new TreeSet<String>(); /* * if true - "implements java.io.Serializable" or * "implements Serializable" should be added */ protected boolean addSerializableInterfaceFlag = true; /* * if true - this is abstract class declaration */ protected boolean isAbstractFlag = false; /* * if true - this is interface declaration */ protected boolean isInterfaceFlag = false; /* * paths to entity java files which has a reference from current entity */ protected Set<String> dependences = new TreeSet<String>(); /* * reference to primary id property */ protected String primaryIdName = ""; //$NON-NLS-1$ /* * if true - add primary id marker for primaryIdName */ protected boolean addPrimaryIdFlag = true; /* * if true - add generated value marker for primaryIdName */ protected boolean addGeneratedValueFlag = true; /* * if true - add version marker for "version" field */ protected boolean addVersionFlag = false; // public enum FieldGetterType { UNDEF(0), FIELD(1), GETTER(2), FIELD_GETTER(3); FieldGetterType(int id) { this.id = id; } private int id; public int getId() { return id; } public static String getClassName() { return FieldGetterType.class.getName(); } } /* * if true - entity has "version" field */ protected FieldGetterType versionFieldGetter = FieldGetterType.UNDEF; /* * if true - there is a property with @Version */ protected boolean hasVersionAnnotation = false; /* * define relations between entities * field id -> RefEntityInfo */ protected Map<String, RefEntityInfo> references = new TreeMap<String, RefEntityInfo>(); /* * store declared column information for particular field * field id -> RefColumnInfo */ protected Map<String, RefColumnInfo> columns = new TreeMap<String, RefColumnInfo>(); /* * fully qualified entity name -> Set<RefFieldInfo> * this is generated from references map for easy information get */ protected Map<String, Set<RefFieldInfo>> mapRefFieldInfo = null; /* */ protected Set<String> primaryIdCandidates = new TreeSet<String>(); /* */ protected int fromVariableCounter = 0; /* */ protected int fromMethodCounter = 0; public void generateRefFieldInfoMap() { mapRefFieldInfo = new TreeMap<String, Set<RefFieldInfo>>(); Iterator<Map.Entry<String, RefEntityInfo>> referencesIt = getReferences().entrySet().iterator(); while (referencesIt.hasNext()) { Map.Entry<String, RefEntityInfo> entry = referencesIt.next(); RefEntityInfo refEntityInfo = entry.getValue(); Set<RefFieldInfo> fieldInfoSet = null; if (mapRefFieldInfo.containsKey(refEntityInfo.fullyQualifiedName)) { fieldInfoSet = mapRefFieldInfo.get(refEntityInfo.fullyQualifiedName); } else { fieldInfoSet = new TreeSet<RefFieldInfo>(); } RefFieldInfo fieldInfo = new RefFieldInfo(entry.getKey(), refEntityInfo.refType); fieldInfoSet.add(fieldInfo); mapRefFieldInfo.put(refEntityInfo.fullyQualifiedName, fieldInfoSet); } referencesIt = null; } public void adjustPrimaryId(EntityInfo parentEI) { if (parentEI != null) { String parentPrimaryIdName = parentEI.getPrimaryIdName(); if (parentPrimaryIdName != null && parentPrimaryIdName.length() > 0) { primaryIdName = ""; //$NON-NLS-1$ } } if (isAddPrimaryIdFlag()) { setAddPrimaryIdFlag(primaryIdName.length() > 0); if (isAddPrimaryIdFlag()) { addRequiredImport(JPAConst.IMPORT_ID); } } if (isAddGeneratedValueFlag()) { setAddGeneratedValueFlag(primaryIdName.length() > 0); if (isAddGeneratedValueFlag()) { addRequiredImport(JPAConst.IMPORT_GENERATED_VALUE); } } } public RefType getFieldIdRelValue(String fieldId) { if (references == null || fieldId == null || !references.containsKey(fieldId)) { return RefType.UNDEF; } return references.get(fieldId).refType; } public boolean getFieldIdAnnotatedValue(String fieldId) { if (references == null || fieldId == null || !references.containsKey(fieldId)) { return false; } return references.get(fieldId).annotated; } public String getFieldIdFQNameValue(String fieldId) { if (references == null || fieldId == null || !references.containsKey(fieldId)) { return ""; //$NON-NLS-1$ } return references.get(fieldId).fullyQualifiedName; } public RefEntityInfo getFieldIdRefEntityInfo(String fieldId) { if (references == null || fieldId == null || !references.containsKey(fieldId)) { return null; } return references.get(fieldId); } public void adjustParameters() { if (isImplicitConstructorFlag() == true || isDefaultConstructorFlag() == true) { setAddSerializableInterfaceFlag(false); } else { addRequiredImport(JPAConst.IMPORT_SERIALIZABLE); } if (isAddEntityFlag()) { addRequiredImport(JPAConst.IMPORT_ENTITY); } else { removeRequiredImport(JPAConst.IMPORT_ENTITY); } if (isAddMappedSuperclassFlag()) { addRequiredImport(JPAConst.IMPORT_MAPPEDSUPERCLASS); } else { removeRequiredImport(JPAConst.IMPORT_MAPPEDSUPERCLASS); } updateVersionImport(FieldGetterType.UNDEF != getVersionFieldGetter()); updateColumnAnnotationImport(false); Iterator<Map.Entry<String, RefEntityInfo>> referencesIt = getReferences().entrySet().iterator(); while (referencesIt.hasNext()) { Map.Entry<String, RefEntityInfo> entry = referencesIt.next(); RefEntityInfo refEntityInfo = entry.getValue(); if (refEntityInfo.owner == OwnerType.NO) { addRequiredImport(JPAConst.IMPORT_JOINCOLUMN); } } // try to intellectually get primary id primaryIdName = null; String entityName = getName().toLowerCase(); Iterator<String> it = primaryIdCandidates.iterator(); while (it.hasNext()) { String name = it.next(); String check = name.toLowerCase(); if ("id".equalsIgnoreCase(check)) { //$NON-NLS-1$ primaryIdName = name; break; } else if (check.indexOf("id") != -1 && check.indexOf(entityName) != -1) { //$NON-NLS-1$ if (primaryIdName == null) { primaryIdName = name; } else if (primaryIdName.toLowerCase().indexOf(entityName) == -1 || primaryIdName.length() > name.length()) { primaryIdName = name; } } else if (check.indexOf("id") != -1) { //$NON-NLS-1$ if (primaryIdName == null) { primaryIdName = name; } else if (primaryIdName.toLowerCase().indexOf(entityName) == -1 && primaryIdName.length() > name.length()) { primaryIdName = name; } } } if (primaryIdName == null) { primaryIdName = ""; //$NON-NLS-1$ } } public void updateVersionImport(boolean includeFlag) { if (includeFlag) { addRequiredImport(JPAConst.IMPORT_VERSION); } else { removeRequiredImport(JPAConst.IMPORT_VERSION); } } public void updateColumnAnnotationImport(boolean nonDefault) { if (isNonColumnAnnotatedStringField() && nonDefault) { addRequiredImport(JPAConst.IMPORT_COLUMN); } else { removeRequiredImport(JPAConst.IMPORT_COLUMN); } } public String getName() { String[] arr = fullyQualifiedName.split("\\."); //$NON-NLS-1$ if (arr.length > 0) { return arr[arr.length - 1]; } return ""; //$NON-NLS-1$ } public String getJavaProjectName() { return javaProjectName; } public void setJavaProjectName(String javaProjectName) { this.javaProjectName = javaProjectName; } public String getFullyQualifiedName() { return fullyQualifiedName; } public void setFullyQualifiedName(String fullyQualifiedName) { this.fullyQualifiedName = fullyQualifiedName; } public String getFullyQualifiedParentName() { return fullyQualifiedParentName; } public void setFullyQualifiedParentName(String fullyQualifiedParentName) { this.fullyQualifiedParentName = fullyQualifiedParentName; } public boolean isCompilerProblemsFlag() { return compilerProblemsFlag; } public void setCompilerProblemsFlag(boolean compilerProblemsFlag) { this.compilerProblemsFlag = compilerProblemsFlag; } public boolean isImplicitConstructorFlag() { return implicitConstructorFlag; } public void setImplicitConstructorFlag(boolean implicitConstructorFlag) { this.implicitConstructorFlag = implicitConstructorFlag; } public boolean isDefaultConstructorFlag() { return defaultConstructorFlag; } public void setDefaultConstructorFlag(boolean defaultConstructorFlag) { this.defaultConstructorFlag = defaultConstructorFlag; } public boolean isAddEntityFlag() { return addEntityFlag; } public void setAddEntityFlag(boolean addEntityFlag) { this.addEntityFlag = addEntityFlag; } public boolean isAddMappedSuperclassFlag() { return addMappedSuperclassFlag; } public void setAddMappedSuperclassFlag(boolean addMappedSuperclassFlag) { this.addMappedSuperclassFlag = addMappedSuperclassFlag; } public boolean hasMappedSuperclassAnnotation() { return hasMappedSuperclassAnnotation; } public void setHasMappedSuperclassAnnotation(boolean hasMappedSuperclassAnnotation) { this.hasMappedSuperclassAnnotation = hasMappedSuperclassAnnotation; } public boolean isAddSerializableInterfaceFlag() { return addSerializableInterfaceFlag; } public void setAddSerializableInterfaceFlag(boolean addSerializableInterfaceFlag) { this.addSerializableInterfaceFlag = addSerializableInterfaceFlag; } public boolean isAbstractFlag() { return isAbstractFlag; } public void setAbstractFlag(boolean isAbstractFlag) { this.isAbstractFlag = isAbstractFlag; } public boolean isInterfaceFlag() { return isInterfaceFlag; } public void setInterfaceFlag(boolean isInterfaceFlag) { this.isInterfaceFlag = isInterfaceFlag; } public String getPrimaryIdName() { return primaryIdName; } public void setPrimaryIdName(String primaryIdName) { this.primaryIdName = primaryIdName; } public Map<String, RefEntityInfo> getReferences() { return references; } public void addReference(String fieldId, String fullyQualifiedName, RefType refType) { if (references == null || fieldId == null) { return; } if (references.containsKey(fieldId)) { RefEntityInfo rei = references.get(fieldId); if (rei != null) { if (rei.fullyQualifiedName != null) { assert(rei.fullyQualifiedName.equals(fullyQualifiedName)); } if (rei.refType != null) { assert(rei.refType.equals(refType)); } } return; } references.put(fieldId, new RefEntityInfo(fullyQualifiedName, refType)); } public void updateReference(String fieldId, boolean annotated, RefType refType, String mappedBy, boolean resolvedAnnotationName, boolean fromVariable) { if (references == null || fieldId == null || !references.containsKey(fieldId)) { return; } RefEntityInfo rei = references.get(fieldId); if (rei != null) { if (rei.updateCounter == 0) { rei.annotated = annotated; rei.refType = refType; rei.mappedBy = mappedBy; if (rei.mappedBy != null) { rei.owner = OwnerType.YES; } rei.resolvedAnnotationName = resolvedAnnotationName; } else { // TODO: possible conflicting info - think about it assert(false); } rei.updateCounter++; } if (fromVariable) { fromVariableCounter++; } else { fromMethodCounter++; } } public void updateAnnotationColumn(String fieldId, NormalAnnotation node, boolean exist) { if (columns == null || fieldId == null) { return; } RefColumnInfo rci = columns.get(fieldId); if (rci == null) { rci = new RefColumnInfo(fieldId); } if (!rci.isExist()) { rci.setExist(exist); } if (node != null) { Map<String, Expression> rciValues = rci.getValues(); Iterator<?> it = node.values().iterator(); while (it.hasNext()) { Object obj = it.next(); if (obj instanceof MemberValuePair) { MemberValuePair mvp = (MemberValuePair)obj; rciValues.put(mvp.getName().getIdentifier(), mvp.getValue()); } } } columns.put(fieldId, rci); } public RefColumnInfo getRefColumnInfo(String fieldId) { return columns.get(fieldId); } /** * returns true in case of there is String field which is not * annotated with @Column */ public boolean isNonColumnAnnotatedStringField() { boolean res = false; Iterator<Map.Entry<String, RefColumnInfo>> it = columns.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, RefColumnInfo> entry = it.next(); if (!entry.getValue().isExist()) { res = true; break; } } return res; } public Set<RefFieldInfo> getRefFieldInfoSet(String fullyQualifiedName) { if (mapRefFieldInfo == null) { return null; } return mapRefFieldInfo.get(fullyQualifiedName); } public Iterator<String> getDependences() { return dependences.iterator(); } public void addDependency(String entityFullyQualifiedName) { dependences.add(entityFullyQualifiedName); } public void addPrimaryIdCandidate(String name) { if (name != null && name.length() > 0) { primaryIdCandidates.add(name); } } public boolean isAddPrimaryIdFlag() { return addPrimaryIdFlag; } public void setAddPrimaryIdFlag(boolean addPrimaryIdFlag) { this.addPrimaryIdFlag = addPrimaryIdFlag; } public boolean isAddGeneratedValueFlag() { return addGeneratedValueFlag; } public void setAddGeneratedValueFlag(boolean addGeneratedValueFlag) { this.addGeneratedValueFlag = addGeneratedValueFlag; } public boolean isAddVersionFlag() { return addVersionFlag; } public void setAddVersionFlag(boolean addVersionFlag) { this.addVersionFlag = addVersionFlag; } public FieldGetterType getVersionFieldGetter() { return versionFieldGetter; } public void setVersionFieldGetter(FieldGetterType versionFieldGetter) { this.versionFieldGetter = versionFieldGetter; } public boolean hasVersionAnnotation() { return hasVersionAnnotation; } public void setHasVersionAnnotation(boolean hasVersionAnnotation) { this.hasVersionAnnotation = hasVersionAnnotation; } public void addExistingImport(String existingImport) { setExistingImports.add(existingImport); } public void removeExistingImport(String existingImport) { setExistingImports.remove(existingImport); } public void collectExistingImport(Set<String> setExistingImports) { setExistingImports.addAll(this.setExistingImports); } public void addRequiredImport(String requiredImport) { setRequiredImports.add(requiredImport); } public void removeRequiredImport(String requiredImport) { setRequiredImports.remove(requiredImport); } public void collectRequiredImport(Set<String> setRequiredImports) { setRequiredImports.addAll(this.setRequiredImports); } public boolean needImport(String checkImport) { return (!setExistingImports.contains(checkImport) && setRequiredImports.contains(checkImport)); } public int getFromVariableCounter() { return fromVariableCounter; } public int getFromMethodCounter() { return fromMethodCounter; } public String toString() { return getFullyQualifiedName(); } public int hashCode() { return getFullyQualifiedName().hashCode(); } public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof EntityInfo)) { return false; } EntityInfo ei = (EntityInfo)obj; if (getFullyQualifiedName().equals(ei.getFullyQualifiedName()) && getFullyQualifiedParentName().equals(ei.getFullyQualifiedParentName())) { return true; } return false; } }