Skip to main content
summaryrefslogblamecommitdiffstats
blob: cf51426f6d42a8273e3fd8b94cec01a5e06b15b0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                                                                
                                                        








                                                                                
                         
                           




                                            



                                                                          
                                                           
                                                           







                                                                               
                                             

                                                         
                                                  
                                                     




                                                               
                                                    






                                                                      
                                             








                                                                                         

                                                       







                                                                             
                                                                     
                                                               














                                                 





                                                                   

                                                                               
                

                                                                                       
                                                                                             
                                                          


                                                                     
                                                                          











                                                                          
                                                      
































                                                                                                                      

                                                                                                     
                

                                                                                                              



                                                                                                                                                   
                                                                                                    


                                                                
                                                                                                                 



                                                                                                  
                                                                            
                                                       
                                                                                                                
                                                                                                                                             


                                                                                                                                                           
                                                                                                    























































                                                                                                      
                                                                     
                                               
                                                                                          
                         




                                    





                                                                                      
           
                                                                         
                                                                        

                                                                                                

                                                                                              











                                                                                                                 
                                                                                                                        





















                                                                                                                                                                                           
                                                                                                                             
                                                                            
                                                                                    

                                                        
                                                                  
                                                             
                                                             
                                                                     






                                                                                                      
                                                        

                                                     

         
                                                                                         
                                                                                   
                                             

                                       
                      
                                              


                 


                                                                             
                                                                              

                      
                                                                               



                 
                                                  















                                                     
                               










                                                                                  
                                                                                     



































                                                                                                                   
                            
        

                                                                            

         
                                       


                                         
                                                      
                                                                          

         

                                                                                 

         

                                                                                         

                                                                                                                
                               
                                                           

         

                                                                       





                                                                                                           

                                                                    

         

                                                                               
                                 

                                                                                                      



                         


                                                                                 
                                                 

                                                                                     



                                         


                                                                                            
                                                 

                                                                                     

                                         
         
        


                                                                                 
                                                 

                                                                                    



                                         


                                                                                            
                                                 

                                                                                    



                                         
        
                                                                           
                                                                            
         
        
                                                                         
                                                                           
         
        

                                                                                
                                                                                                                 
                                                 
                                                                                      
                                                                          
                                         

                                                        

         

                                                                
                                                                 

         



                                                                              
         

        









                                                                                   
                 
                                                                           
                                                   


                                                                
                                                           



                                                          
/*******************************************************************************
 * 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;

import java.util.HashSet;
import java.util.Hashtable;
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.core.resource.java.JavaResourceAbstractType;
import org.eclipse.jpt.common.core.resource.java.JavaResourceEnum;
import org.eclipse.jpt.common.core.resource.java.JavaResourcePackage;
import org.eclipse.jpt.common.core.resource.java.JavaResourceType;
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.filter.NotNullFilter;
import org.eclipse.jpt.common.utility.internal.iterable.CompositeIterable;
import org.eclipse.jpt.common.utility.internal.iterable.FilteringIterable;
import org.eclipse.jpt.common.utility.internal.iterable.LiveCloneIterable;
import org.eclipse.jpt.common.utility.internal.iterable.SnapshotCloneIterable;
import org.eclipse.jpt.common.utility.internal.iterable.SubIterableWrapper;
import org.eclipse.jpt.common.utility.internal.iterable.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.TypeKind;
import org.eclipse.jpt.jaxb.core.context.XmlRegistry;
import org.eclipse.jpt.jaxb.core.context.java.JavaClass;
import org.eclipse.jpt.jaxb.core.context.java.JavaClassMapping;
import org.eclipse.jpt.jaxb.core.context.java.JavaEnum;
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.jaxbindex.JaxbIndexResource;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;

/**
 * the context model root
 */
public abstract class AbstractJaxbContextRoot
		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 JavaType objects */
	protected final Map<String, JavaType> types;
	
	
	public AbstractJaxbContextRoot(JaxbProject jaxbProject) {
		super(null);  // the JAXB project is not really a "parent"...
		if (jaxbProject == null) {
			throw new NullPointerException();
		}
		this.jaxbProject = jaxbProject;
		this.packages = new Hashtable<String, JaxbPackage>();
		this.types = new Hashtable<String, JavaType>();
		initialize();
	}
	
	
	@Override
	public JaxbContextRoot getContextRoot() {
		return this;
	}
	
	@Override
	protected boolean requiresParent() {
		return false;
	}
	
	protected void initialize() {
		
		// process packages with annotations first
		for (String pkg : calculateInitialPackageNames()) {
			this.packages.put(pkg, buildPackage(pkg));
		}
		
		// keep set of total types for remaining package initialization
		Set<String> totalTypeNames = new HashSet<String>();
		
		// process types with annotations and in jaxb.index files
		for (JavaResourceAbstractType resourceType : calculateInitialTypes()) {
			totalTypeNames.add(resourceType.getTypeBinding().getQualifiedName());
			addType_(buildType(resourceType));
		}
		
		// once all classes have been processed, add packages
		for (String pkg : calculatePackageNames(totalTypeNames)) {
			if (! this.packages.containsKey(pkg)) {
				this.packages.put(pkg, buildPackage(pkg));
			}
		}
	}
	
	@Override
	public void synchronizeWithResourceModel() {
		super.synchronizeWithResourceModel();
		for (JaxbPackage each : getPackages()) {
			each.synchronizeWithResourceModel();
		}
		for (JavaType each : getJavaTypes()) {
			each.synchronizeWithResourceModel();
		}
	}
	
	@Override
	public void update() {
		super.update();
		
		// keep a master list of these so that objects are updated only once
		final Set<String> packagesToUpdate = CollectionTools.<String>set();
		final Set<String> typesToUpdate = CollectionTools.<String>set();
		
		// keep a (shrinking) running list of these so that we know which ones we do eventually need to remove
		final Set<String> packagesToRemove = CollectionTools.set(this.packages.keySet());
		final Set<String> typesToRemove = CollectionTools.set(this.types.keySet());
		
		// keep a master list of all types that we've processed so we don't process them again
		final Set<String> totalTypes = CollectionTools.<String>set();
		
		// keep an running list of types that we need to scan for further referenced types
		final Set<String> typesToScan = CollectionTools.<String>set();
		
		// process packages with annotations first
		for (String pkg : calculateInitialPackageNames()) {
			if (this.packages.containsKey(pkg)) {
				packagesToUpdate.add(pkg);
				packagesToRemove.remove(pkg);
			}
			else {
				this.addPackage(this.buildPackage(pkg));
			}
		}
		
		// calculate initial types (annotated or listed in jaxb.index files)
		final Set<JavaResourceAbstractType> resourceTypesToProcess = calculateInitialTypes();
		
		// store set of types that are referenced (and should therefore be default mapped)
		final Set<JavaResourceAbstractType> referencedTypes = new HashSet<JavaResourceAbstractType>();
		
		// while there are resource types to process or types to scan, continue to do so
		while (! resourceTypesToProcess.isEmpty() || ! typesToScan.isEmpty()) {
			for (JavaResourceAbstractType resourceType : new SnapshotCloneIterable<JavaResourceAbstractType>(resourceTypesToProcess)) {
				String className = resourceType.getTypeBinding().getQualifiedName();
				typesToRemove.remove(className);
				totalTypes.add(className);
				typesToScan.add(className);
				processType(resourceType, typesToUpdate, referencedTypes.contains(resourceType));
				resourceTypesToProcess.remove(resourceType);
			}
			
			for (String typeToScan : new SnapshotCloneIterable<String>(typesToScan)) {
				JavaType jaxbType = getJavaType(typeToScan);
				if (jaxbType != null) {
					for (String referencedTypeName : jaxbType.getReferencedXmlTypeNames()) {
						if (! StringTools.isBlank(referencedTypeName) && ! totalTypes.contains(referencedTypeName)) {
							JavaResourceAbstractType referencedType = getJaxbProject().getJavaResourceType(referencedTypeName);
							if (referencedType != null) {
								resourceTypesToProcess.add(referencedType);
								referencedTypes.add(referencedType);
							}
						}
					}
				}
				typesToScan.remove(typeToScan);
			}
		}
		
		// once all classes have been processed, add packages
		for (String pkg : calculatePackageNames(totalTypes)) {
			if (this.packages.containsKey(pkg)) {
				packagesToUpdate.add(pkg);
				packagesToRemove.remove(pkg);
			}
			else {
				this.addPackage(this.buildPackage(pkg));
			}
		}
		
		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 presence of package annotations
	 */
	protected Set<String> calculateInitialPackageNames() {
		return CollectionTools.set(
				new TransformationIterable<JavaResourcePackage, String>(
						getJaxbProject().getAnnotatedJavaResourcePackages()) {
					@Override
					protected String transform(JavaResourcePackage o) {
						return o.getName();
					}
				});
	}
	
	/**
	 * calculate set of packages that can be determined from type names
	 */
	protected Set<String> calculatePackageNames(Set<String> typeNames) {
		Set<String> packageNames = CollectionTools.<String>set();
		for (String typeName : typeNames) {
			JavaType jaxbType = this.types.get(typeName);
			if (jaxbType != null) {
				packageNames.add(jaxbType.getTypeName().getPackageName());
			}
		}
		return packageNames;
	}
	
	/*
	 * Calculate set of initial types
	 * This should be:
	 * - all resource types with @XmlType, @XmlRootElement, or @XmlJavaTypeAdapter
	 * - all resource classes with @XmlRegistry
	 * - all resource enums with @XmlEnum
	 * - all types listed in jaxb.index files.
	 */
	protected Set<JavaResourceAbstractType> calculateInitialTypes() {
		Set<JavaResourceAbstractType> set = CollectionTools.set(
				new FilteringIterable<JavaResourceAbstractType>(
						getJaxbProject().getJavaSourceResourceTypes()) {
					@Override
					protected boolean accept(JavaResourceAbstractType o) {
						if (o.getKind() == JavaResourceAbstractType.Kind.TYPE) {
							if (o.getAnnotation(JAXB.XML_REGISTRY) != null) {
								return true;
							}
						}
						if (o.getKind() == JavaResourceAbstractType.Kind.ENUM) {
							if (o.getAnnotation(JAXB.XML_ENUM) != null) {
								return true;
							}
						}
						return o.getAnnotation(JAXB.XML_TYPE) != null
								|| o.getAnnotation(JAXB.XML_ROOT_ELEMENT) != null
								|| o.getAnnotationsSize(JAXB.XML_JAVA_TYPE_ADAPTER) > 0;
					}
				});
		CollectionTools.addAll(
				set,
				new FilteringIterable<JavaResourceAbstractType>(
						new TransformationIterable<String, JavaResourceAbstractType>(
								new CompositeIterable<String>(
										new TransformationIterable<JaxbIndexResource, Iterable<String>>(getJaxbProject().getJaxbIndexResources()) {
											@Override
											protected Iterable<String>transform(JaxbIndexResource o) {
												return o.getFullyQualifiedClassNames();
											}
										})) {
							@Override
							protected JavaResourceAbstractType transform(String o) {
								return getJaxbProject().getJavaResourceType(o);
							}
						},
						NotNullFilter.<JavaResourceAbstractType>instance()));
		return set;
	}
	
	protected void processType(JavaResourceAbstractType resourceType, Set<String> typesToUpdate, boolean defaultMapped) {
		TypeKind jaxbTypeKind = calculateJaxbTypeKind(resourceType);
		String className = resourceType.getTypeBinding().getQualifiedName();
		
		if (this.types.containsKey(className)) {
			JavaType type = this.types.get(className);
			if (type.getKind() == jaxbTypeKind) {
				typesToUpdate.add(className);
				type.setDefaultMapped(defaultMapped);
				return;
			}
			else {
				this.removeType(className); // this will remove a type of another kind
			}
		}
		
		JavaType type = buildType(resourceType);
		type.setDefaultMapped(defaultMapped);
		this.addType(type);
	}
	
	protected TypeKind calculateJaxbTypeKind(JavaResourceAbstractType resourceType) {
		if (resourceType.getKind() == JavaResourceAbstractType.Kind.ENUM) {
			return TypeKind.ENUM;
		}
		// else is of kind TYPE
		else {
			return TypeKind.CLASS;
		}
	}
	
	protected JavaType buildType(JavaResourceAbstractType resourceType) {
		TypeKind kind = calculateJaxbTypeKind(resourceType);
		if (kind == TypeKind.ENUM) {
			return buildJaxbEnum((JavaResourceEnum) resourceType);
		}
		else {
			return buildJaxbClass((JavaResourceType) resourceType);
		}
	}
	
	
	// ***** 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 (ObjectTools.equals(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<JavaType> getJavaTypes() {
		return new LiveCloneIterable<JavaType>(this.types.values());
	}
	
	public int getJavaTypesSize() {
		return this.types.size();
	}
	
	public JavaType getJavaType(String typeName) {
		return typeName == null ? null : this.types.get(typeName);
	}
	
	protected void addType_(JavaType type) {
		this.types.put(type.getTypeName().getFullyQualifiedName(), type);
	}
	
	protected void addType(JavaType type) {
		if (this.types.containsKey(type.getTypeName().getFullyQualifiedName())) {
			throw new IllegalArgumentException("Type with that name already exists."); //$NON-NLS-1$
		}
		addType_(type);
		fireItemAdded(JAVA_TYPES_COLLECTION, type);
	}
	
	protected void removeType(JavaType type) {
		removeType(type.getTypeName().getFullyQualifiedName());
	}
	
	protected void removeType(String typeName) {
		if (! this.types.containsKey(typeName)) {
			throw new IllegalArgumentException("No type with that name exists."); //$NON-NLS-1$
		}
		JavaType removedType = this.types.remove(typeName);
		fireItemRemoved(JAVA_TYPES_COLLECTION, removedType);
	}
	
	public Iterable<JavaType> getJavaTypes(final JaxbPackage jaxbPackage) {
		return new FilteringIterable<JavaType>(getJavaTypes()) {
			@Override
			protected boolean accept(JavaType o) {
				return o.getTypeName().getPackageName().equals(jaxbPackage.getName());
			}
		};
	}
	
	public Iterable<JavaClass> getJavaClasses() {
		return new SubIterableWrapper<JavaType, JavaClass>(
				new FilteringIterable<JavaType>(getJavaTypes()) {
					@Override
					protected boolean accept(JavaType o) {
						return o.getKind() == TypeKind.CLASS;
					}
				});
	}
	
	public Iterable<JavaClass> getJavaClasses(JaxbPackage jaxbPackage) {
		return new SubIterableWrapper<JavaType, JavaClass>(
				new FilteringIterable<JavaType>(getJavaTypes(jaxbPackage)) {
					@Override
					protected boolean accept(JavaType o) {
						return o.getKind() == TypeKind.CLASS;
					}
				});
	}
	
	public Iterable<JavaEnum> getJavaEnums() {
		return new SubIterableWrapper<JavaType, JavaEnum>(
				new FilteringIterable<JavaType>(getJavaTypes()) {
					@Override
					protected boolean accept(JavaType o) {
						return o.getKind() == TypeKind.ENUM;
					}
				});
	}
	
	public Iterable<JavaEnum> getJavaEnums(JaxbPackage jaxbPackage) {
		return new SubIterableWrapper<JavaType, JavaEnum>(
				new FilteringIterable<JavaType>(getJavaTypes(jaxbPackage)) {
					@Override
					protected boolean accept(JavaType o) {
						return o.getKind() == TypeKind.ENUM;
					}
				});
	}
	
	
	protected JavaClass buildJaxbClass(JavaResourceType resourceType) {
		return this.getFactory().buildJaxbClass(this, resourceType);
	}
	
	protected JavaEnum buildJaxbEnum(JavaResourceEnum resourceEnum) {
		return this.getFactory().buildJaxbEnum(this, resourceEnum);
	}
	
	public Iterable<XmlRegistry> getXmlRegistries(JaxbPackage jaxbPackage) {
		return new FilteringIterable<XmlRegistry>(
				new TransformationIterable<JavaClass, XmlRegistry>(getJavaClasses(jaxbPackage)) {
					@Override
					protected XmlRegistry transform(JavaClass o) {
						return o.getXmlRegistry();
					}
				},
				NotNullFilter.INSTANCE);
	}
	
	public JavaTypeMapping getTypeMapping(String typeName) {
		JavaType type = getJavaType(typeName);
		return (type == null) ? null : type.getMapping();
	}
	
	public JavaClassMapping getClassMapping(String typeName) {
		JavaType type = getJavaType(typeName);
		return (type == null || (type.getKind() != TypeKind.CLASS)) ? 
				null : ((JavaClass) type).getMapping();
	}
	
	
	@Override
    public void stateChanged() {
		super.stateChanged();
		// forward to JAXB project
		this.jaxbProject.stateChanged();
    }
	
	
	// **************** validation ********************************************
	
	@Override
	public void validate(List<IMessage> messages, IReporter reporter) {
		super.validate(messages, reporter);
		for (JaxbPackage pkg : this.packages.values()) {
			pkg.validate(messages, reporter);
		}
		for (JavaType type : this.types.values()) {
			type.validate(messages, reporter);
		}
	}
}

Back to the top