blob: 0076d351e75079c6ae10f7d32b9bd86f4b969ffd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Oracle. All rights reserved.
* This program and the accompanying materials are 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.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.eclipselink.core.internal.context.orm;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jpt.common.core.internal.utility.JDTTools;
import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute;
import org.eclipse.jpt.common.core.resource.java.JavaResourceField;
import org.eclipse.jpt.common.core.resource.java.JavaResourceMethod;
import org.eclipse.jpt.common.core.utility.TextRange;
import org.eclipse.jpt.common.utility.internal.ClassName;
import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable;
import org.eclipse.jpt.jpa.core.JpaStructureNode;
import org.eclipse.jpt.jpa.core.context.AccessType;
import org.eclipse.jpt.jpa.core.context.CollectionMapping;
import org.eclipse.jpt.jpa.core.context.TypeMapping;
import org.eclipse.jpt.jpa.core.context.java.Accessor;
import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping;
import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute;
import org.eclipse.jpt.jpa.core.context.orm.EntityMappings;
import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentType;
import org.eclipse.jpt.jpa.core.internal.context.java.AbstractJavaJpaContextNode;
import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaNullAttributeMapping;
import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField;
import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentAttribute2_0;
import org.eclipse.jpt.jpa.core.jpa2.resource.java.JPA2_0;
import org.eclipse.jpt.jpa.eclipselink.core.JptJpaEclipseLinkCorePlugin;
import org.eclipse.jpt.jpa.eclipselink.core.context.java.JavaEclipseLinkPersistentAttribute;
import org.eclipse.jpt.jpa.eclipselink.core.resource.orm.XmlAttributeMapping;
public class VirtualJavaPersistentAttribute extends AbstractJavaJpaContextNode
implements JavaPersistentAttribute2_0, JavaEclipseLinkPersistentAttribute
{
private final XmlAttributeMapping xmlAttributeMapping;
private final JavaAttributeMapping attributeMapping;
public VirtualJavaPersistentAttribute(OrmPersistentType parent, XmlAttributeMapping xmlAttributeMapping) {
super(parent);
this.xmlAttributeMapping = xmlAttributeMapping;
this.attributeMapping = new GenericJavaNullAttributeMapping(this);
}
public XmlAttributeMapping getXmlAttributeMapping() {
return this.xmlAttributeMapping;
}
public JavaAttributeMapping getMapping() {
return this.attributeMapping;
}
public JavaAttributeMapping setMappingKey(String key) {
throw new UnsupportedOperationException("cannot set anything on a virtual java persistent attribute"); //$NON-NLS-1$
}
public Accessor getAccessor() {
return null;
}
public JavaResourceAttribute getResourceAttribute() {
return null;
}
public boolean isFor(JavaResourceField resourceField) {
return false;
}
public boolean isFor(JavaResourceMethod resourceGetter, JavaResourceMethod resourceSetter) {
return false;
}
public boolean contains(int offset, CompilationUnit astRoot) {
throw new UnsupportedOperationException();
}
public String getTypeName() {
String typeName = this.xmlAttributeMapping.getAttributeType();
return typeName == null ? null : this.getEntityMappings().getFullyQualifiedName(typeName);
}
public boolean typeIsBasic() {
return false;//not valid for a default basic mapping, specified in orm.xml
}
public String getSingleReferenceTargetTypeName() {
return null; //used for building default target entity/embeddable, must be specified in a virtual mapping
}
public String getMultiReferenceTargetTypeName() {
return null; //used for building default target entity/target class, must be specified in a virtual mapping
}
public String getMultiReferenceMapKeyTypeName() {
return null; //used for building default map key class, must be specified in a virtual mapping
}
public String getName() {
return this.xmlAttributeMapping.getName();
}
public String getMappingKey() {
return null;
}
public String getDefaultMappingKey() {
return null;
}
public boolean isVirtual() {
throw new UnsupportedOperationException("Owing orm persistent attribute is specified, this should not be called."); //$NON-NLS-1$
}
public JavaPersistentAttribute getJavaPersistentAttribute() {
return this;
}
// ********** JpaStructureNode implementation **********
public JpaStructureNode getStructureNode(int textOffset) {
throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$
}
public TextRange getSelectionTextRange() {
throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$
}
public ContextType getContextType() {
throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$
}
public Class<? extends JpaStructureNode> getType() {
throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$
}
public void dispose() {
throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$
}
public AccessType getAccess() {
return null;
}
public AccessType getSpecifiedAccess() {
return null;
}
public void setSpecifiedAccess(AccessType newSpecifiedAccess) {
throw new UnsupportedOperationException("cannot set anything on a virtual java persistent attribute"); //$NON-NLS-1$
}
public AccessType getDefaultAccess() {
return null;
}
public TextRange getValidationTextRange(CompilationUnit astRoot) {
throw new UnsupportedOperationException();
}
public boolean typeIsDateOrCalendar() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
return JDTTools.typeIsSubType(this.getJavaProject(), typeName, DATE_TYPE_NAME)
|| JDTTools.typeIsSubType(this.getJavaProject(), typeName, CALENDAR_TYPE_NAME);
}
public boolean typeIsSerializable() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
return JDTTools.typeIsSubType(this.getJavaProject(), typeName, JDTTools.SERIALIZABLE_CLASS_NAME);
}
public boolean typeIsValidForVariableOneToOne() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
IType type = JDTTools.findType(getJavaProject(), typeName);
try {
return type != null &&
type.isInterface() &&
this.interfaceIsValidForVariableOneToOne(typeName);
}
catch (JavaModelException e) {
JptJpaEclipseLinkCorePlugin.log(e);
return false;
}
}
protected boolean interfaceIsValidForVariableOneToOne(String interfaceName) {
return ! this.interfaceIsInvalidForVariableOneToOne(interfaceName);
}
// TODO we could probably add more interfaces to this list...
protected boolean interfaceIsInvalidForVariableOneToOne(String interfaceName) {
return (interfaceName == null) ||
this.typeIsContainer(interfaceName) ||
interfaceName.equals("org.eclipse.persistence.indirection.ValueHolderInterface"); //$NON-NLS-1$
}
/**
* return whether the specified type is one of the container
* types allowed by the JPA spec
*/
protected boolean typeIsContainer(String typeName) {
return this.getJpaContainerDefinition(typeName).isContainer();
}
// ********** metamodel **********
public String getMetamodelContainerFieldTypeName() {
throw new UnsupportedOperationException("parent OrmPersistentAttribute implements this"); //$NON-NLS-1$
}
public String getMetamodelContainerFieldMapKeyTypeName() {
throw new UnsupportedOperationException("parent OrmPersistentAttribute implements this"); //$NON-NLS-1$
}
public String getMetamodelTypeName() {
String typeName = this.getTypeName();
if (typeName == null) {
return MetamodelField.DEFAULT_TYPE_NAME;
}
if (ClassName.isPrimitive(typeName)) {
return ClassName.getWrapperClassName(typeName); // ???
}
return typeName;
}
public JpaContainerDefinition getJpaContainerDefinition() {
// 'typeName' may include array brackets ("[]")
// but not generic type arguments (e.g. "<java.lang.String>")
return this.getJpaContainerDefinition(this.getTypeName());
}
//I don't think we should be doing this here, I think OrmAttributeMappings should be responsible for their own JpaContainerDefinition
//Generic can just get it from the JavaPersistentAttribute
/**
* Return the JPA container definition corresponding to the specified type;
* return a "null" definition if the specified type is not "assignable to" one of the
* container types allowed by the JPA spec.
*/
protected JpaContainerDefinition getJpaContainerDefinition(String typeName) {
if (typeName != null) {
for (JpaContainerDefinition definition : getJpaContainerDefinitions()) {
if (definition.isAssignableFrom(typeName)) {
return definition;
}
}
}
return JpaContainerDefinition.Null.instance();
}
protected Iterable<JpaContainerDefinition> getJpaContainerDefinitions() {
return JPA_CONTAINER_DEFINITIONS;
}
protected static final JpaContainerDefinition[] JPA_CONTAINER_DEFINITION_ARRAY = new JpaContainerDefinition[] {
new CollectionJpaContainerDefinition(java.util.Set.class, JPA2_0.SET_ATTRIBUTE),
new CollectionJpaContainerDefinition(java.util.List.class, JPA2_0.LIST_ATTRIBUTE),
new CollectionJpaContainerDefinition(java.util.Collection.class, JPA2_0.COLLECTION_ATTRIBUTE),
new MapJpaContainerDefinition(java.util.Map.class, JPA2_0.MAP_ATTRIBUTE)
};
protected static final Iterable<JpaContainerDefinition> JPA_CONTAINER_DEFINITIONS = new ArrayIterable<JpaContainerDefinition>(JPA_CONTAINER_DEFINITION_ARRAY);
/**
* Abstract JPA container definition
*/
protected abstract static class AbstractJpaContainerDefinition
implements JpaContainerDefinition
{
protected final Class<?> containerClass;
protected final String metamodelContainerFieldTypeName;
protected AbstractJpaContainerDefinition(Class<?> containerClass, String metamodelContainerFieldTypeName) {
super();
if ((containerClass == null) || (metamodelContainerFieldTypeName == null)) {
throw new NullPointerException();
}
this.containerClass = containerClass;
this.metamodelContainerFieldTypeName = metamodelContainerFieldTypeName;
}
public boolean isAssignableFrom(String typeName) {
try {
return this.containerClass.isAssignableFrom(Class.forName(typeName));
}
catch (ClassNotFoundException e) {
return false;
}
}
public boolean isContainer() {
return true;
}
public String getMetamodelContainerFieldTypeName() {
return this.metamodelContainerFieldTypeName;
}
public String getMultiReferenceTargetTypeName(JavaResourceAttribute resourceAttribute) {
throw new UnsupportedOperationException();
}
public String getMultiReferenceMapKeyTypeName(JavaResourceAttribute resourceAttribute) {
throw new UnsupportedOperationException();
}
}
/**
* Collection JPA container definition
*/
protected static class CollectionJpaContainerDefinition
extends AbstractJpaContainerDefinition
{
protected CollectionJpaContainerDefinition(Class<?> collectionClass, String staticMetamodelTypeDeclarationTypeName) {
super(collectionClass, staticMetamodelTypeDeclarationTypeName);
}
public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) {
return null;
}
public boolean isMap() {
return false;
}
}
/**
* Map JPA container definition
*/
protected static class MapJpaContainerDefinition
extends AbstractJpaContainerDefinition
{
protected MapJpaContainerDefinition(Class<?> mapClass, String staticMetamodelTypeDeclarationTypeName) {
super(mapClass, staticMetamodelTypeDeclarationTypeName);
}
public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) {
return mapping.getMetamodelFieldMapKeyTypeName();
}
public boolean isMap() {
return true;
}
}
// ********** misc **********
@Override
public OrmPersistentType getParent() {
return (OrmPersistentType) super.getParent();
}
public OrmPersistentType getOwningPersistentType() {
return this.getParent();
}
public TypeMapping getOwningTypeMapping() {
return this.getOwningPersistentType().getMapping();
}
protected EntityMappings getEntityMappings() {
return (EntityMappings) getParent().getMappingFileRoot();
}
public String getPrimaryKeyColumnName() {
throw new UnsupportedOperationException("Owing orm persistent attribute should handle, this should not be called."); //$NON-NLS-1$
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
}