| /******************************************************************************* |
| * Copyright (c) 2010, 2011 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; |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.jpt.common.utility.internal.CollectionTools; |
| import org.eclipse.jpt.common.utility.internal.StringTools; |
| import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.SubIterableWrapper; |
| import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; |
| import org.eclipse.jpt.jaxb.core.JaxbProject; |
| import org.eclipse.jpt.jaxb.core.context.JaxbContextRoot; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPackage; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPersistentClass; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPersistentEnum; |
| import org.eclipse.jpt.jaxb.core.context.JaxbRegistry; |
| import org.eclipse.jpt.jaxb.core.context.JaxbType; |
| import org.eclipse.jpt.jaxb.core.context.JaxbType.Kind; |
| import org.eclipse.jpt.jaxb.core.resource.java.AbstractJavaResourceType; |
| import org.eclipse.jpt.jaxb.core.resource.java.JAXB; |
| import org.eclipse.jpt.jaxb.core.resource.java.JavaResourceEnum; |
| import org.eclipse.jpt.jaxb.core.resource.java.JavaResourcePackage; |
| import org.eclipse.jpt.jaxb.core.resource.java.JavaResourceType; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| |
| /** |
| * the context model root |
| */ |
| public class GenericContextRoot |
| extends AbstractJaxbContextNode |
| implements JaxbContextRoot { |
| |
| /* This object has no parent, so it must point to the JAXB project explicitly. */ |
| protected final JaxbProject jaxbProject; |
| |
| /* The map of package name to JaxbPackage objects */ |
| protected final Map<String, JaxbPackage> packages; |
| |
| /* The map of class name to JaxbType objects */ |
| protected final Map<String, JaxbType> types; |
| |
| |
| public GenericContextRoot(JaxbProject jaxbProject) { |
| super(null); // the JAXB project is not really a "parent"... |
| if (jaxbProject == null) { |
| throw new NullPointerException(); |
| } |
| this.jaxbProject = jaxbProject; |
| this.packages = new HashMap<String, JaxbPackage>(); |
| this.types = new HashMap<String, JaxbType>(); |
| initialize(); |
| } |
| |
| |
| @Override |
| public JaxbContextRoot getContextRoot() { |
| return this; |
| } |
| |
| @Override |
| protected boolean requiresParent() { |
| return false; |
| } |
| |
| protected void initialize() { |
| // determine set of registries |
| // (registries can be determined purely by resource model) |
| final Set<JavaResourceType> registries = calculateRegistries(); |
| |
| // determine initial set of persistent classes |
| // (persistent classes that can be determined purely by resource model) |
| final Set<JavaResourceType> initialPersistentClasses = calculateInitialPersistentClasses(); |
| |
| final Set<JavaResourceEnum> initialPersistentEnums = calculateInitialPersistentEnums(); |
| |
| final Set<AbstractJavaResourceType> initialTypes = new HashSet<AbstractJavaResourceType>(registries); |
| initialTypes.addAll(initialPersistentClasses); |
| initialTypes.addAll(initialPersistentEnums); |
| |
| // determine initial set of packages |
| final Set<String> initialPackages = calculateInitialPackageNames(initialTypes); |
| |
| for (String pkg : initialPackages) { |
| this.packages.put(pkg, buildPackage(pkg)); |
| } |
| |
| for (JavaResourceType resourceType : registries) { |
| this.types.put(resourceType.getName(), buildRegistry(resourceType)); |
| } |
| |
| for (JavaResourceType resourceType : initialPersistentClasses) { |
| this.types.put(resourceType.getName(), buildPersistentClass(resourceType)); |
| } |
| |
| for (JavaResourceEnum resourceType : initialPersistentEnums) { |
| this.types.put(resourceType.getName(), buildPersistentEnum(resourceType)); |
| } |
| } |
| |
| public void synchronizeWithResourceModel() { |
| for (JaxbPackage each : getPackages()) { |
| each.synchronizeWithResourceModel(); |
| } |
| for (JaxbType each : getTypes()) { |
| each.synchronizeWithResourceModel(); |
| } |
| } |
| |
| public void update() { |
| // determine set of registries |
| // (registries can be determined purely by resource model) |
| final Set<JavaResourceType> registries = calculateRegistries(); |
| |
| // determine initial set of persistent classes |
| // (persistent classes that can be determined purely by resource model) |
| final Set<JavaResourceType> initialPersistentClasses = calculateInitialPersistentClasses(); |
| final Set<JavaResourceEnum> initialPersistentEnums = calculateInitialPersistentEnums(); |
| |
| final Set<AbstractJavaResourceType> initialTypes = new HashSet<AbstractJavaResourceType>(registries); |
| initialTypes.addAll(initialPersistentClasses); |
| initialTypes.addAll(initialPersistentEnums); |
| |
| // determine initial set of packages |
| final Set<String> initialPackages = calculateInitialPackageNames(initialTypes); |
| |
| final Set<String> packagesToUpdate = CollectionTools.<String>set(); |
| final Set<String> packagesToRemove = CollectionTools.set(this.packages.keySet()); |
| final Set<String> typesToUpdate = CollectionTools.<String>set(); |
| final Set<String> typesToRemove = CollectionTools.set(this.types.keySet()); |
| |
| for (String pkg : initialPackages) { |
| if (this.packages.containsKey(pkg)) { |
| packagesToUpdate.add(pkg); |
| packagesToRemove.remove(pkg); |
| } |
| else { |
| this.addPackage(this.buildPackage(pkg)); |
| } |
| } |
| |
| for (JavaResourceType resourceType : registries) { |
| String className = resourceType.getQualifiedName(); |
| typesToRemove.remove(className); |
| if (this.types.containsKey(className)) { |
| if (this.types.get(className).getKind() == Kind.REGISTRY) { |
| typesToUpdate.add(className); |
| } |
| else { |
| this.removeType(className); // this will remove a type of another kind |
| this.addType(buildRegistry(resourceType)); |
| } |
| } |
| else { |
| this.addType(buildRegistry(resourceType)); |
| } |
| } |
| |
| for (JavaResourceType resourceType : initialPersistentClasses) { |
| String className = resourceType.getQualifiedName(); |
| typesToRemove.remove(className); |
| if (this.types.containsKey(className)) { |
| if (this.types.get(className).getKind() == Kind.PERSISTENT_CLASS) { |
| typesToUpdate.add(className); |
| } |
| else { |
| this.removeType(className); // this will remove a type of another kind |
| this.addType(buildPersistentClass(resourceType)); |
| } |
| } |
| else { |
| this.addType(buildPersistentClass(resourceType)); |
| } |
| } |
| |
| for (JavaResourceEnum resourceEnum : initialPersistentEnums) { |
| String className = resourceEnum.getQualifiedName(); |
| typesToRemove.remove(className); |
| if (this.types.containsKey(className)) { |
| if (this.types.get(className).getKind() == Kind.PERSISTENT_ENUM) { |
| typesToUpdate.add(className); |
| } |
| else { |
| this.removeType(className); // this will remove a type of another kind |
| this.addType(buildPersistentEnum(resourceEnum)); |
| } |
| } |
| else { |
| this.addType(buildPersistentEnum(resourceEnum)); |
| } |
| } |
| |
| for (String packageToUpdate : packagesToUpdate) { |
| this.packages.get(packageToUpdate).update(); |
| } |
| |
| for (String typeToUpdate : typesToUpdate) { |
| this.types.get(typeToUpdate).update(); |
| } |
| |
| for (String packageToRemove : packagesToRemove) { |
| removePackage(packageToRemove); |
| } |
| |
| for (String typeToRemove : typesToRemove) { |
| removeType(typeToRemove); |
| } |
| } |
| |
| /* |
| * calculate set of packages that can be determined purely by resource model and the given |
| * set of classes. |
| * This should include: |
| * - any annotated package |
| * - any package containing an included class |
| */ |
| protected Set<String> calculateInitialPackageNames(final Set<AbstractJavaResourceType> initialClasses) { |
| final Set<String> packages = CollectionTools.set( |
| new TransformationIterable<JavaResourcePackage, String>( |
| getJaxbProject().getAnnotatedJavaResourcePackages()) { |
| @Override |
| protected String transform(JavaResourcePackage o) { |
| return o.getName(); |
| } |
| }); |
| for (AbstractJavaResourceType clazz : initialClasses) { |
| packages.add(clazz.getPackageName()); |
| } |
| return packages; |
| } |
| |
| /* |
| * Calculate set of persistent classes that can be determined purely by resource model |
| * (so far, this should be all resource types with the @XmlType annotation) |
| * If both @XmlType and @XmlRegistry exist on a class, we will let @XmlRegistry take precedence |
| */ |
| protected Set<JavaResourceType> calculateInitialPersistentClasses() { |
| return CollectionTools.set( |
| new FilteringIterable<JavaResourceType>( |
| getJaxbProject().getJavaSourceResourceTypes()) { |
| @Override |
| protected boolean accept(JavaResourceType o) { |
| return o.getAnnotation(JAXB.XML_TYPE) != null && o.getAnnotation(JAXB.XML_REGISTRY) == null && o.getAnnotation(JAXB.XML_ENUM) == null; |
| } |
| }); |
| } |
| |
| /* |
| * Calculate set of persistent enums that can be determined purely by resource model |
| * (so far, this should be all resource types with the @XmlEnum annotation) |
| * If both @XmlEnum and @XmlRegistry exist on a class, we will let @XmlRegistry take precedence |
| */ |
| protected Set<JavaResourceEnum> calculateInitialPersistentEnums() { |
| return CollectionTools.set( |
| new FilteringIterable<JavaResourceEnum>( |
| getJaxbProject().getJavaSourceResourceEnums()) { |
| @Override |
| protected boolean accept(JavaResourceEnum o) { |
| return ((o.getAnnotation(JAXB.XML_ENUM) != null) || (o.getAnnotation(JAXB.XML_TYPE) != null)) && o.getAnnotation(JAXB.XML_REGISTRY) == null; |
| } |
| }); |
| } |
| |
| /* |
| * Calculate set of registries |
| * (this should be all resource types with the @XmlRegistry annotation) |
| */ |
| protected Set<JavaResourceType> calculateRegistries() { |
| return CollectionTools.set( |
| new FilteringIterable<JavaResourceType>( |
| getJaxbProject().getJavaSourceResourceTypes()) { |
| @Override |
| protected boolean accept(JavaResourceType o) { |
| return o.getAnnotation(JAXB.XML_REGISTRY) != null; |
| } |
| }); |
| } |
| |
| |
| // ********** AbstractJaxbNode overrides ********** |
| |
| @Override |
| public JaxbProject getJaxbProject() { |
| return this.jaxbProject; |
| } |
| |
| @Override |
| public IResource getResource() { |
| return this.getProject(); |
| } |
| |
| protected IProject getProject() { |
| return this.jaxbProject.getProject(); |
| } |
| |
| |
| // ************* packages *************** |
| |
| public Iterable<JaxbPackage> getPackages() { |
| return new LiveCloneIterable<JaxbPackage>(this.packages.values()); |
| } |
| |
| public int getPackagesSize() { |
| return this.packages.size(); |
| } |
| |
| public JaxbPackage getPackage(String packageName) { |
| for (JaxbPackage jaxbPackage : this.getPackages()) { |
| if (StringTools.stringsAreEqual(jaxbPackage.getName(), packageName)) { |
| return jaxbPackage; |
| } |
| } |
| return null; |
| } |
| |
| protected JaxbPackage addPackage(JaxbPackage contextPackage) { |
| if (this.packages.containsKey(contextPackage.getName())) { |
| throw new IllegalArgumentException("Package with that name already exists."); //$NON-NLS-1$ |
| } |
| this.packages.put(contextPackage.getName(), contextPackage); |
| fireItemAdded(PACKAGES_COLLECTION, contextPackage); |
| return contextPackage; |
| } |
| |
| protected void removePackage(JaxbPackage contextPackage) { |
| this.removePackage(contextPackage.getName()); |
| } |
| |
| protected void removePackage(String packageName) { |
| if (! this.packages.containsKey(packageName)) { |
| throw new IllegalArgumentException("No package with that name exists."); //$NON-NLS-1$ |
| } |
| JaxbPackage removedPackage = this.packages.remove(packageName); |
| fireItemRemoved(PACKAGES_COLLECTION, removedPackage); |
| } |
| |
| protected JaxbPackage buildPackage(String packageName) { |
| return this.getFactory().buildPackage(this, packageName); |
| } |
| |
| protected boolean isEmpty(JaxbPackage jaxbPackage) { |
| return jaxbPackage.isEmpty(); |
| } |
| |
| |
| // ********** types *********** |
| |
| public Iterable<JaxbType> getTypes() { |
| return new LiveCloneIterable<JaxbType>(this.types.values()); |
| } |
| |
| public int getTypesSize() { |
| return this.types.size(); |
| } |
| |
| public JaxbType getType(String typeName) { |
| return this.types.get(typeName); |
| } |
| |
| protected void addType(JaxbType type) { |
| if (this.types.containsKey(type.getFullyQualifiedName())) { |
| throw new IllegalArgumentException("Type with that name already exists."); //$NON-NLS-1$ |
| } |
| this.types.put(type.getFullyQualifiedName(), type); |
| fireItemAdded(TYPES_COLLECTION, type); |
| } |
| |
| protected void removeType(JaxbType type) { |
| removeType(type.getFullyQualifiedName()); |
| } |
| |
| protected void removeType(String typeName) { |
| if (! this.types.containsKey(typeName)) { |
| throw new IllegalArgumentException("No type with that name exists."); //$NON-NLS-1$ |
| } |
| JaxbType removedType = this.types.remove(typeName); |
| fireItemRemoved(TYPES_COLLECTION, removedType); |
| } |
| |
| public Iterable<JaxbType> getTypes(final JaxbPackage jaxbPackage) { |
| return new FilteringIterable<JaxbType>(getTypes()) { |
| @Override |
| protected boolean accept(JaxbType o) { |
| return o.getPackageName().equals(jaxbPackage.getName()); |
| } |
| }; |
| } |
| |
| |
| // ********** registries ********** |
| |
| public Iterable<JaxbRegistry> getRegistries() { |
| return new SubIterableWrapper<JaxbType, JaxbRegistry>( |
| new FilteringIterable<JaxbType>(getTypes()) { |
| @Override |
| protected boolean accept(JaxbType o) { |
| return o.getKind() == Kind.REGISTRY; |
| } |
| }); |
| } |
| |
| protected JaxbRegistry buildRegistry(JavaResourceType resourceType) { |
| return this.getFactory().buildRegistry(this, resourceType); |
| } |
| |
| public Iterable<JaxbRegistry> getRegistries(final JaxbPackage jaxbPackage) { |
| return new FilteringIterable<JaxbRegistry>(getRegistries()) { |
| @Override |
| protected boolean accept(JaxbRegistry o) { |
| return o.getPackageName().equals(jaxbPackage.getName()); |
| } |
| }; |
| } |
| |
| |
| // ********** persistent classes ********** |
| |
| public Iterable<JaxbPersistentClass> getPersistentClasses() { |
| return new SubIterableWrapper<JaxbType, JaxbPersistentClass>( |
| new FilteringIterable<JaxbType>(getTypes()) { |
| @Override |
| protected boolean accept(JaxbType o) { |
| return o.getKind() == Kind.PERSISTENT_CLASS; |
| } |
| }); |
| } |
| |
| protected JaxbPersistentClass buildPersistentClass(JavaResourceType resourceType) { |
| return this.getFactory().buildJavaPersistentClass(this, resourceType); |
| } |
| |
| public Iterable<JaxbPersistentClass> getPersistentClasses(final JaxbPackage jaxbPackage) { |
| return new FilteringIterable<JaxbPersistentClass>(getPersistentClasses()) { |
| @Override |
| protected boolean accept(JaxbPersistentClass o) { |
| return o.getPackageName().equals(jaxbPackage.getName()); |
| } |
| }; |
| } |
| |
| public JaxbPersistentClass getPersistentClass(String className) { |
| for (JaxbPersistentClass jaxbClass : this.getPersistentClasses()) { |
| if (StringTools.stringsAreEqual(jaxbClass.getFullyQualifiedName(), className)) { |
| return jaxbClass; |
| } |
| } |
| return null; |
| } |
| |
| // ********** persistent enums ********** |
| |
| public Iterable<JaxbPersistentEnum> getPersistentEnums() { |
| return new SubIterableWrapper<JaxbType, JaxbPersistentEnum>( |
| new FilteringIterable<JaxbType>(getTypes()) { |
| @Override |
| protected boolean accept(JaxbType o) { |
| return o.getKind() == Kind.PERSISTENT_ENUM; |
| } |
| }); |
| } |
| |
| protected JaxbPersistentEnum buildPersistentEnum(JavaResourceEnum resourceEnum) { |
| return this.getFactory().buildJavaPersistentEnum(this, resourceEnum); |
| } |
| |
| public Iterable<JaxbPersistentEnum> getPersistentEnums(final JaxbPackage jaxbPackage) { |
| return new FilteringIterable<JaxbPersistentEnum>(getPersistentEnums()) { |
| @Override |
| protected boolean accept(JaxbPersistentEnum o) { |
| return o.getPackageName().equals(jaxbPackage.getName()); |
| } |
| }; |
| } |
| |
| public JaxbPersistentEnum getPersistentEnum(String enumName) { |
| for (JaxbPersistentEnum jaxbEnum : this.getPersistentEnums()) { |
| if (StringTools.stringsAreEqual(jaxbEnum.getFullyQualifiedName(), enumName)) { |
| return jaxbEnum; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void stateChanged() { |
| super.stateChanged(); |
| // forward to JAXB project |
| this.jaxbProject.stateChanged(); |
| } |
| |
| |
| // **************** validation ******************************************** |
| |
| public void validate(List<IMessage> messages, IReporter reporter) { |
| for (JaxbPackage pkg : this.packages.values()) { |
| pkg.validate(messages, reporter); |
| } |
| for (JaxbType type : this.types.values()) { |
| type.validate(messages, reporter); |
| } |
| } |
| } |