/*******************************************************************************
* 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;
}
}