blob: 234c9a2cb0362ca6a2105fc5a1de32dbfd314fc8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2016 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 java.util.Collection;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jpt.common.core.internal.utility.JavaProjectTools;
import org.eclipse.jpt.common.core.internal.utility.TypeTools;
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.ClassNameTools;
import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
import org.eclipse.jpt.jpa.core.JpaFile;
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.PersistentType;
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.java.JavaSpecifiedPersistentAttribute;
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.AbstractJavaContextModel;
import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaNullAttributeMapping;
import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField2_0;
import org.eclipse.jpt.jpa.core.jpa2.context.SpecifiedPersistentAttribute2_0;
import org.eclipse.jpt.jpa.core.jpa2.resource.java.JPA2_0;
import org.eclipse.jpt.jpa.eclipselink.core.context.java.EclipseLinkJavaPersistentAttribute;
import org.eclipse.jpt.jpa.eclipselink.core.internal.plugin.JptJpaEclipseLinkCorePlugin;
import org.eclipse.jpt.jpa.eclipselink.core.resource.orm.XmlAttributeMapping;
public class EclipseLinkVirtualJavaPersistentAttribute
extends AbstractJavaContextModel<OrmPersistentType>
implements JavaSpecifiedPersistentAttribute, SpecifiedPersistentAttribute2_0, EclipseLinkJavaPersistentAttribute
{
private final XmlAttributeMapping xmlAttributeMapping;
private final JavaAttributeMapping attributeMapping;
private JpaContainerDefinition jpaContainerDefinition = JpaContainerDefinition.Null.instance();
public EclipseLinkVirtualJavaPersistentAttribute(OrmPersistentType parent, XmlAttributeMapping xmlAttributeMapping) {
super(parent);
this.xmlAttributeMapping = xmlAttributeMapping;
this.attributeMapping = new GenericJavaNullAttributeMapping(this);
}
@Override
public void update(IProgressMonitor monitor) {
super.update(monitor);
this.updateJpaContainerDefinition();
}
public void addRootStructureNodesTo(JpaFile jpaFile, Collection<JpaStructureNode> rootStructureNodes) {
throw new UnsupportedOperationException();
}
public XmlAttributeMapping getXmlAttributeMapping() {
return this.xmlAttributeMapping;
}
public JavaAttributeMapping getMapping() {
return this.attributeMapping;
}
public JavaAttributeMapping setMappingKey(String key) {
throw new UnsupportedOperationException();
}
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 String getTypeName() {
String typeName = this.xmlAttributeMapping.getAttributeType();
return typeName == null ? null : this.getEntityMappings().qualify(typeName);
}
public String getTypeName(PersistentType contextType) {
// only ever has its specified type name
return getTypeName();
}
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();
}
public JavaSpecifiedPersistentAttribute getJavaPersistentAttribute() {
return this;
}
// ********** JpaStructureNode implementation **********
public TextRange getFullTextRange() {
throw new UnsupportedOperationException();
}
public boolean containsOffset(int offset) {
throw new UnsupportedOperationException();
}
public JpaStructureNode getStructureNode(int textOffset) {
throw new UnsupportedOperationException();
}
public TextRange getSelectionTextRange() {
throw new UnsupportedOperationException();
}
public ContextType getContextType() {
throw new UnsupportedOperationException();
}
/**
* Virtual Java attributes will never show up in the JPA Structure view
* or the JPA Details view because there is no corresponding source file
* to be displayed in the editor.
*/
public Class<JavaPersistentAttribute> getStructureType() {
throw new UnsupportedOperationException();
}
/**
* @see #getStructureType()
*/
public Iterable<JpaStructureNode> getStructureChildren() {
throw new UnsupportedOperationException();
}
public int getStructureChildrenSize() {
throw new UnsupportedOperationException();
}
public AccessType getAccess() {
return null;
}
public AccessType getSpecifiedAccess() {
return null;
}
public void setSpecifiedAccess(AccessType newSpecifiedAccess) {
throw new UnsupportedOperationException();
}
public AccessType getDefaultAccess() {
return null;
}
public TextRange getValidationTextRange() {
throw new UnsupportedOperationException();
}
public boolean typeIsDateOrCalendar() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
return TypeTools.isSubTypeOf(typeName, DATE_TYPE_NAME, this.getJavaProject())
|| TypeTools.isSubTypeOf(typeName, CALENDAR_TYPE_NAME, this.getJavaProject());
}
public boolean typeIsSerializable() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
return TypeTools.isSerializable(typeName, this.getJavaProject());
}
public boolean typeIsValidForVariableOneToOne() {
String typeName = this.getTypeName();
if (typeName == null) {
return false;
}
IType type = JavaProjectTools.findType(getJavaProject(), typeName);
try {
return type != null &&
type.isInterface() &&
this.interfaceIsValidForVariableOneToOne();
}
catch (JavaModelException e) {
JptJpaEclipseLinkCorePlugin.instance().logError(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() {
// parent OrmPersistentAttribute implements this
throw new UnsupportedOperationException();
}
public String getMetamodelContainerFieldMapKeyTypeName() {
// parent OrmPersistentAttribute implements this
throw new UnsupportedOperationException();
}
public String getMetamodelTypeName() {
String typeName = this.getTypeName();
if (typeName == null) {
return MetamodelField2_0.DEFAULT_TYPE_NAME;
}
if (ClassNameTools.isPrimitive(typeName)) {
return ClassNameTools.primitiveWrapperClassName(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 (TypeTools.isSubTypeOf(typeName, definition.getTypeName(), this.getJavaProject())) {
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 = IterableTools.iterable(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 **********
public OrmPersistentType getDeclaringPersistentType() {
return this.parent;
}
public TypeMapping getDeclaringTypeMapping() {
return this.getDeclaringPersistentType().getMapping();
}
protected EntityMappings getEntityMappings() {
return (EntityMappings) this.parent.getMappingFileRoot();
}
public String getPrimaryKeyColumnName() {
// parent OrmPersistentAttribute implements this
throw new UnsupportedOperationException();
}
public IJavaElement getJavaElement() {
return null;
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
}