blob: 5ba031bd1dc80940b11e629b25f32264c244239a [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;
private JpaContainerDefinition jpaContainerDefinition = JpaContainerDefinition.Null.instance();
public VirtualJavaPersistentAttribute(OrmPersistentType parent, XmlAttributeMapping xmlAttributeMapping) {
super(parent);
this.xmlAttributeMapping = xmlAttributeMapping;
this.attributeMapping = new GenericJavaNullAttributeMapping(this);
}
@Override
public void update() {
super.update();
this.updateJpaContainerDefinition();
}
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();
}
catch (JavaModelException e) {
JptJpaEclipseLinkCorePlugin.log(e);
return false;
}
}
protected boolean interfaceIsValidForVariableOneToOne() {
return ! this.interfaceIsInvalidForVariableOneToOne();
}
// TODO we could probably add more interfaces to this list...
protected boolean interfaceIsInvalidForVariableOneToOne() {
String interfaceName = this.getTypeName();
return (interfaceName == null) ||
this.typeIsContainer() ||
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() {
return this.getJpaContainerDefinition().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() {
return this.jpaContainerDefinition;
}
protected void updateJpaContainerDefinition() {
this.setJpaContainerDefinition(this.buildJpaContainerDefinition());
}
protected void setJpaContainerDefinition(JpaContainerDefinition jpaContainerDefinition) {
JpaContainerDefinition old = this.jpaContainerDefinition;
this.jpaContainerDefinition = jpaContainerDefinition;
firePropertyChanged(JPA_CONTAINER_DEFINITION, old, this.jpaContainerDefinition);
}
//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 buildJpaContainerDefinition() {
String typeName = this.getTypeName();
if (typeName != null) {
//performance - loop and check for .equals() first
for (JpaContainerDefinition definition : this.getJpaContainerDefinitions()) {
if (definition.getTypeName().equals(typeName)) {
return definition;
}
}
for (JpaContainerDefinition definition : this.getJpaContainerDefinitions()) {
if (JDTTools.typeIsSubType(this.getJavaProject(), typeName, definition.getTypeName())) {
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 String typeName;
protected final String metamodelContainerFieldTypeName;
protected AbstractJpaContainerDefinition(Class<?> containerClass, String metamodelContainerFieldTypeName) {
this(containerClass.getName(), metamodelContainerFieldTypeName);
}
protected AbstractJpaContainerDefinition(String typeName, String metamodelContainerFieldTypeName) {
super();
if ((typeName == null) || (metamodelContainerFieldTypeName == null)) {
throw new NullPointerException();
}
this.typeName = typeName;
this.metamodelContainerFieldTypeName = metamodelContainerFieldTypeName;
}
public String getTypeName() {
return this.typeName;
}
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());
}
}