| /******************************************************************************* |
| * 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 2.0, which accompanies this distribution |
| * and is available at https://www.eclipse.org/legal/epl-2.0/. |
| * |
| * 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 |
| )); |
| } |
| } |