blob: 7b48deec37c1a816349260b0880f9ada9b3ac483 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2015 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.eclipselink.core.internal.context;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.eclipse.jpt.common.core.internal.utility.EmptyTextRange;
import org.eclipse.jpt.common.core.resource.xml.JptXmlResource;
import org.eclipse.jpt.common.core.utility.TextRange;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
import org.eclipse.jpt.jaxb.core.JaxbProject;
import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping;
import org.eclipse.jpt.jaxb.core.context.JaxbPackage;
import org.eclipse.jpt.jaxb.core.context.JaxbTypeMapping;
import org.eclipse.jpt.jaxb.core.context.TypeKind;
import org.eclipse.jpt.jaxb.core.internal.context.AbstractJaxbContextRoot;
import org.eclipse.jpt.jaxb.core.resource.jaxbprops.JaxbPropertiesResource;
import org.eclipse.jpt.jaxb.eclipselink.core.ELJaxbProject;
import org.eclipse.jpt.jaxb.eclipselink.core.context.ELJaxbContextRoot;
import org.eclipse.jpt.jaxb.eclipselink.core.context.oxm.OxmFile;
import org.eclipse.jpt.jaxb.eclipselink.core.context.oxm.OxmJavaType;
import org.eclipse.jpt.jaxb.eclipselink.core.context.oxm.OxmTypeMapping;
import org.eclipse.jpt.jaxb.eclipselink.core.context.oxm.OxmXmlEnum;
import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.oxm.OxmFileImpl;
import org.eclipse.jpt.jaxb.eclipselink.core.validation.JptJaxbEclipseLinkCoreValidationMessages;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
public class ELJaxbContextRootImpl
extends AbstractJaxbContextRoot
implements ELJaxbContextRoot {
// store as SortedSet ordered by file path
private SortedSet<OxmFile> oxmFiles;
// store map of type mappings for easiest (and fastest) lookup
private Hashtable<String, OxmTypeMapping> oxmTypeMappingMap;
public ELJaxbContextRootImpl(JaxbProject jaxbProject) {
super(jaxbProject);
}
// ***** overrides *****
@Override
public ELJaxbProject getJaxbProject() {
return (ELJaxbProject) super.getJaxbProject();
}
@Override
public JaxbClassMapping getClassMapping(String typeName) {
OxmTypeMapping mapping = this.oxmTypeMappingMap.get(typeName);
if (mapping != null) {
return (mapping.getTypeKind() == TypeKind.CLASS) ?
(JaxbClassMapping) mapping
: null; // mapping is not a class mapping, return null
}
return super.getClassMapping(typeName);
}
// ***** initialize/update *****
@Override
protected void initialize() {
// initialize oxm files and type mappings *first*
initOxmFiles();
// map should at least not be null
this.oxmTypeMappingMap = new Hashtable<String, OxmTypeMapping>();
super.initialize();
}
@Override
public void synchronizeWithResourceModel() {
super.synchronizeWithResourceModel();
for (OxmFile oxmFile : getOxmFiles()) {
oxmFile.synchronizeWithResourceModel();
}
}
@Override
public void update() {
// rebuild type mapping map before anything
rebuildOxmTypeMappingMap();
// update oxm files before calling update on superclass
updateOxmFiles();
super.update();
}
protected void rebuildOxmTypeMappingMap() {
synchronized (this.oxmTypeMappingMap) {
Hashtable<String, OxmTypeMapping> oldMap = new Hashtable<String, OxmTypeMapping>(this.oxmTypeMappingMap);
this.oxmTypeMappingMap.clear();
for (OxmFile oxmFile : getOxmFiles()) {
for (OxmXmlEnum oxmXmlEnum: oxmFile.getXmlBindings().getXmlEnums()) {
String typeName = oxmXmlEnum.getTypeName().getFullyQualifiedName();
if (! StringTools.isBlank(typeName)) {
if (! this.oxmTypeMappingMap.containsKey(typeName)) {
this.oxmTypeMappingMap.put(typeName, oxmXmlEnum);
}
}
}
for (OxmJavaType oxmJavaType : oxmFile.getXmlBindings().getJavaTypes()) {
String typeName = oxmJavaType.getTypeName().getFullyQualifiedName();
if (! StringTools.isBlank(typeName)) {
if (! this.oxmTypeMappingMap.containsKey(typeName)) {
this.oxmTypeMappingMap.put(typeName, oxmJavaType);
}
}
}
}
if (! oldMap.equals(this.oxmTypeMappingMap)) {
// no aspect associated with this. this is just to cover the cases where this is
// the only thing that changes, as no further update will be scheduled.
fireStateChanged();
}
}
}
@Override
protected Set<String> calculateInitialPackageNames() {
Set<String> initialPackageNames = super.calculateInitialPackageNames();
for (OxmFile oxmFile : getOxmFiles()) {
String packageName = oxmFile.getPackageName();
if (! StringTools.isBlank(packageName)) {
initialPackageNames.add(packageName);
}
}
return initialPackageNames;
}
// ***** oxm files *****
public Iterable<OxmFile> getOxmFiles() {
synchronized (this.oxmFiles) {
return IterableTools.cloneSnapshot(this.oxmFiles);
}
}
public int getOxmFilesSize() {
return this.oxmFiles.size();
}
protected void addOxmFile(OxmFile oxmFile) {
addItemToCollection(oxmFile, this.oxmFiles, OXM_FILES_COLLECTION);
}
protected void removeOxmFile(OxmFile oxmFile) {
removeItemFromCollection(oxmFile, this.oxmFiles, OXM_FILES_COLLECTION);
}
public OxmFile getOxmFile(String packageName) {
for (OxmFile oxmFile : getOxmFiles()) {
if (packageName.equals(oxmFile.getPackageName())) {
return oxmFile;
}
}
return null;
}
protected OxmFile buildOxmFile(JptXmlResource oxmResource) {
return new OxmFileImpl(this, oxmResource);
}
protected void initOxmFiles() {
// can't do this statically, since this gets called during constructor
this.oxmFiles = Collections.synchronizedSortedSet(
new TreeSet<OxmFile>(
new Comparator<OxmFile>() {
public int compare(OxmFile of1, OxmFile of2) {
return of1.getResource().getProjectRelativePath().toString().compareTo(
of2.getResource().getProjectRelativePath().toString());
}
}));
synchronized (this.oxmFiles) {
for (JptXmlResource oxmResource : getJaxbProject().getOxmResources()) {
this.oxmFiles.add(buildOxmFile(oxmResource));
}
}
}
protected void updateOxmFiles() {
Collection<JptXmlResource>
unmatchedOxmResources = CollectionTools.hashBag(getJaxbProject().getOxmResources());
for (OxmFile oxmFile : getOxmFiles()) {
JptXmlResource oxmResource = oxmFile.getOxmResource();
if (! unmatchedOxmResources.remove(oxmResource)) {
removeOxmFile(oxmFile);
}
else {
oxmFile.update();
}
}
for (JptXmlResource oxmResource : unmatchedOxmResources) {
addOxmFile(buildOxmFile(oxmResource));
}
}
// ***** misc *****
@Override
public JaxbTypeMapping getTypeMapping(String typeName) {
if (typeName == null) {
return null;
}
OxmTypeMapping oxmTypeMapping = getOxmTypeMapping(typeName);
return (oxmTypeMapping != null) ? oxmTypeMapping : super.getTypeMapping(typeName);
}
public OxmTypeMapping getOxmTypeMapping(String typeName) {
return this.oxmTypeMappingMap.get(typeName);
}
// ***** validation *****
@Override
public TextRange getValidationTextRange() {
return EmptyTextRange.instance(); //?
}
@Override
public void validate(List<IMessage> messages, IReporter reporter) {
super.validate(messages, reporter);
validateJaxbProperties(messages, reporter);
for (OxmFile oxmFile : getOxmFiles()) {
oxmFile.validate(messages, reporter);
}
}
protected void validateJaxbProperties(List<IMessage> messages, IReporter reporter) {
String factoryProp = "javax.xml.bind.context.factory";
String factoryPropValue = "org.eclipse.persistence.jaxb.JAXBContextFactory";
for (JaxbPackage jp : getPackages()) {
String pn = jp.getName();
JaxbPropertiesResource jpr = getJaxbProject().getJaxbPropertiesResource(pn);
if (jpr != null && ObjectTools.equals(jpr.getProperty(factoryProp), factoryPropValue)) {
return;
}
}
messages.add(
this.buildValidationMessage(
getJaxbProject(),
JptJaxbEclipseLinkCoreValidationMessages.PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY
));
}
}