/******************************************************************************* * Copyright (c) 2010, 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.jaxb.core.internal.context.java; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.jpt.common.core.internal.resource.java.source.SourceNode; import org.eclipse.jpt.common.core.resource.java.JavaResourceAbstractType; import org.eclipse.jpt.common.core.utility.TextRange; import org.eclipse.jpt.common.utility.internal.ObjectTools; import org.eclipse.jpt.common.utility.internal.TypeDeclarationTools; import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable; import org.eclipse.jpt.common.utility.internal.iterable.IterableTools; import org.eclipse.jpt.jaxb.core.context.JaxbContextNode; import org.eclipse.jpt.jaxb.core.context.JaxbPackage; import org.eclipse.jpt.jaxb.core.context.JaxbPackageInfo; import org.eclipse.jpt.jaxb.core.context.TypeName; import org.eclipse.jpt.jaxb.core.context.XmlJavaTypeAdapter; import org.eclipse.jpt.jaxb.core.context.java.JavaType; import org.eclipse.jpt.jaxb.core.context.java.JavaTypeMapping; import org.eclipse.jpt.jaxb.core.resource.java.JAXB; import org.eclipse.jpt.jaxb.core.resource.java.XmlJavaTypeAdapterAnnotation; import org.eclipse.jpt.jaxb.core.resource.java.XmlRootElementAnnotation; import org.eclipse.jpt.jaxb.core.resource.java.XmlTransientAnnotation; import org.eclipse.jpt.jaxb.core.resource.java.XmlTypeAnnotation; import org.eclipse.wst.validation.internal.provisional.core.IMessage; import org.eclipse.wst.validation.internal.provisional.core.IReporter; public abstract class AbstractJavaType extends AbstractJavaContextNode implements JavaType { protected final JavaResourceAbstractType resourceType; protected final TypeName typeName; protected JavaTypeMapping mapping; protected boolean defaultMapped = false; protected XmlJavaTypeAdapter xmlJavaTypeAdapter; protected AbstractJavaType(JaxbContextNode parent, JavaResourceAbstractType resourceType) { super(parent); this.resourceType = resourceType; this.typeName = buildTypeName(); initMapping(); initXmlJavaTypeAdapter(); } // ***** overrides ***** @Override public IResource getResource() { return this.resourceType.getFile(); } // ***** sync/update ***** @Override public void synchronizeWithResourceModel() { super.synchronizeWithResourceModel(); syncMapping(); syncXmlJavaTypeAdapter(); } @Override public void update() { super.update(); updateMapping(); updateXmlJavaTypeAdapter(); } // ***** mapping ***** public JavaTypeMapping getMapping() { return this.mapping; } protected void setMapping_(JavaTypeMapping newMapping) { JavaTypeMapping old = this.mapping; this.mapping = newMapping; firePropertyChanged(MAPPING_PROPERTY, old, newMapping); } protected abstract JavaTypeMapping buildMapping(); protected void initMapping() { if (isDefaultMapped() || isSpecifiedMapped()) { this.mapping = buildMapping(); } } protected void syncMapping() { if (this.mapping != null) { this.mapping.synchronizeWithResourceModel(); } } protected void updateMapping() { boolean isMapped = isDefaultMapped() || isSpecifiedMapped(); if (isMapped) { if (this.mapping != null) { this.mapping.update(); } else { setMapping_(buildMapping()); } } else if (this.mapping != null) { setMapping_(null); } } /* * Return true if the annotations on this type indicate it should have a mapping */ protected boolean isSpecifiedMapped() { return getXmlTypeAnnotation() != null || getXmlRootElementAnnotation() != null || getXmlTransientAnnotation() != null; } protected XmlTypeAnnotation getXmlTypeAnnotation() { return (XmlTypeAnnotation) getJavaResourceType().getAnnotation(JAXB.XML_TYPE); } protected XmlRootElementAnnotation getXmlRootElementAnnotation() { return (XmlRootElementAnnotation) getJavaResourceType().getAnnotation(JAXB.XML_ROOT_ELEMENT); } protected XmlTransientAnnotation getXmlTransientAnnotation() { return (XmlTransientAnnotation) getJavaResourceType().getAnnotation(JAXB.XML_TRANSIENT); } // ***** default mapped ***** public boolean isDefaultMapped() { return this.defaultMapped; } public void setDefaultMapped(boolean newValue) { boolean old = this.defaultMapped; this.defaultMapped = newValue; firePropertyChanged(DEFAULT_MAPPED_PROPERTY, old, newValue); } // ***** XmlJavaTypeAdapter ***** public XmlJavaTypeAdapter getXmlJavaTypeAdapter() { return this.xmlJavaTypeAdapter; } protected void setXmlJavaTypeAdapter_(XmlJavaTypeAdapter xmlJavaTypeAdapter) { XmlJavaTypeAdapter oldXmlJavaTypeAdapter = this.xmlJavaTypeAdapter; this.xmlJavaTypeAdapter = xmlJavaTypeAdapter; firePropertyChanged(XML_JAVA_TYPE_ADAPTER_PROPERTY, oldXmlJavaTypeAdapter, xmlJavaTypeAdapter); } public XmlJavaTypeAdapter addXmlJavaTypeAdapter() { if (this.xmlJavaTypeAdapter != null) { throw new IllegalStateException(); } XmlJavaTypeAdapterAnnotation annotation = (XmlJavaTypeAdapterAnnotation) getJavaResourceType().addAnnotation(0, JAXB.XML_JAVA_TYPE_ADAPTER); XmlJavaTypeAdapter xmlJavaTypeAdapter = buildXmlJavaTypeAdapter(annotation); setXmlJavaTypeAdapter_(xmlJavaTypeAdapter); return xmlJavaTypeAdapter; } public void removeXmlJavaTypeAdapter() { if (this.xmlJavaTypeAdapter == null) { throw new IllegalStateException(); } getJavaResourceType().removeAnnotation(0, JAXB.XML_JAVA_TYPE_ADAPTER); setXmlJavaTypeAdapter_(null); } protected XmlJavaTypeAdapterAnnotation getXmlJavaTypeAdapterAnnotation() { if (getJavaResourceType().getAnnotationsSize(JAXB.XML_JAVA_TYPE_ADAPTER) > 0) { return (XmlJavaTypeAdapterAnnotation) getJavaResourceType().getAnnotation(0, JAXB.XML_JAVA_TYPE_ADAPTER); } return null; } protected XmlJavaTypeAdapter buildXmlJavaTypeAdapter(XmlJavaTypeAdapterAnnotation xmlJavaTypeAdapterAnnotation) { return new GenericJavaTypeXmlJavaTypeAdapter(this, xmlJavaTypeAdapterAnnotation); } protected void initXmlJavaTypeAdapter() { XmlJavaTypeAdapterAnnotation annotation = getXmlJavaTypeAdapterAnnotation(); if (annotation != null) { this.xmlJavaTypeAdapter = buildXmlJavaTypeAdapter(annotation); } } protected void syncXmlJavaTypeAdapter() { XmlJavaTypeAdapterAnnotation annotation = getXmlJavaTypeAdapterAnnotation(); if (annotation != null) { if (this.xmlJavaTypeAdapter != null) { this.xmlJavaTypeAdapter.synchronizeWithResourceModel(); } else { setXmlJavaTypeAdapter_(buildXmlJavaTypeAdapter(annotation)); } } else { setXmlJavaTypeAdapter_(null); } } protected void updateXmlJavaTypeAdapter() { if (this.xmlJavaTypeAdapter != null) { this.xmlJavaTypeAdapter.update(); } } // ***** JavaType misc ***** public JavaResourceAbstractType getJavaResourceType() { return this.resourceType; } protected TypeName buildTypeName() { return new JavaTypeName(this.resourceType); } public TypeName getTypeName() { return this.typeName; } public JaxbPackage getJaxbPackage() { return getContextRoot().getPackage(getTypeName().getPackageName()); } public JaxbPackageInfo getJaxbPackageInfo() { JaxbPackage pkg = getJaxbPackage(); return (pkg == null) ? null : pkg.getPackageInfo(); } // ***** content assist ***** @Override public Iterable getCompletionProposals(int pos) { Iterable result = super.getCompletionProposals(pos); if (! IterableTools.isEmpty(result)) { return result; } if (this.mapping != null) { result = this.mapping.getCompletionProposals(pos); if (! IterableTools.isEmpty(result)) { return result; } } if (this.xmlJavaTypeAdapter != null) { result = this.xmlJavaTypeAdapter.getCompletionProposals(pos); if (! IterableTools.isEmpty(result)) { return result; } } return EmptyIterable.instance(); } // ***** validation ***** /** * Override as needed */ @Override public TextRange getValidationTextRange() { return getJavaResourceType().getNameTextRange(); } @Override public void validate(List messages, IReporter reporter) { super.validate(messages, reporter); // TODO temporary hack since we don't know yet where to put // any messages for types in another project IFile file = this.resourceType.getFile(); // 'file' will be null if the type is "external" and binary; // the file will be in a different project if the type is "external" and source; // the type will be binary if it is in a JAR in the current project if ((file != null) && file.getProject().equals(getJaxbProject().getProject()) && (this.resourceType instanceof SourceNode)) { if (this.mapping != null) { this.mapping.validate(messages, reporter); } if (this.xmlJavaTypeAdapter != null) { this.xmlJavaTypeAdapter.validate(messages, reporter); } } } protected static class JavaTypeName implements TypeName { protected String packageName; protected String qualifiedName; protected JavaTypeName(JavaResourceAbstractType resourceType) { this.packageName = buildPackageName(resourceType); this.qualifiedName = buildQualifiedName(resourceType); } protected String buildPackageName(JavaResourceAbstractType resourceType) { return resourceType.getTypeBinding().getPackageName(); } protected String buildQualifiedName(JavaResourceAbstractType resourceType) { return resourceType.getTypeBinding().getQualifiedName(); } public String getPackageName() { return this.packageName; } public String getSimpleName() { return TypeDeclarationTools.simpleName(this.qualifiedName); } public String getTypeQualifiedName() { return (this.packageName.length() == 0) ? this.qualifiedName : this.qualifiedName.substring(packageName.length() + 1); } public String getFullyQualifiedName() { return this.qualifiedName; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } return ObjectTools.equals(this.packageName, ((JavaTypeName) obj).packageName) && ObjectTools.equals(this.qualifiedName, ((JavaTypeName) obj).qualifiedName); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ObjectTools.hashCode(this.packageName); result = prime * result + ObjectTools.hashCode(this.qualifiedName); return result; } } }