package org.springframework.roo.classpath; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.file.monitor.FileMonitorService; import org.springframework.roo.file.monitor.event.FileDetails; import org.springframework.roo.metadata.MetadataIdentificationUtils; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaPackage; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.project.Dependency; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.PhysicalPath; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.project.maven.Pom; import org.springframework.roo.shell.NaturalOrderComparator; import org.springframework.roo.support.logging.HandlerUtils; import org.springframework.roo.support.util.FileUtils; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.logging.Logger; /** * Implementation of {@link TypeLocationService}. * <p> * For performance reasons automatically caches the queries. The cache is * invalidated on changes to the file system. * * @author Alan Stewart * @author Ben Alex * @author Stefan Schmidt * @author James Tyrrell * @author Paula Navarro * @author Sergio Clares * @since 1.1 */ @Component @Service public class TypeLocationServiceImpl implements TypeLocationService { private static final Logger LOGGER = HandlerUtils.getLogger(TypeLocationServiceImpl.class); // ------------ OSGi component attributes ---------------- private BundleContext context; private Map<ModuleFeatureName, ModuleFeature> moduleFeatures = new HashMap<ModuleFeatureName, ModuleFeature>(); protected void activate(final ComponentContext cContext) { context = cContext.getBundleContext(); } private static final Comparator<String> LENGTH_COMPARATOR = new Comparator<String>() { public int compare(final String key1, final String key2) { return Integer.valueOf(key1.length()).compareTo(key2.length()); } }; private static final String JAVA_FILES_ANT_PATH = "**" + File.separatorChar + "*.java"; /** * Returns all packages leading up to the given package, e.g. if the given * package is "com.foo.bar", returns ["com", "com.foo", "com.foo.bar"]. * * @param leafPackage the fully-qualified package to parse (required) * @return a non-<code>null</code> iterable */ static Set<String> getAllPackages(final String leafPackage) { final Set<String> discoveredPackages = new HashSet<String>(); final String[] typeSegments = leafPackage.split("\\."); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < typeSegments.length; i++) { final String typeSegment = typeSegments[i]; if (i > 0) { sb.append("."); } sb.append(typeSegment); discoveredPackages.add(sb.toString()); } return discoveredPackages; } /** * Returns the lowest-level package that contains the given number of types. * * @param typeCount the number of types to look for * @param typesByPackage maps package names to type names; a given type will * appear under all of its parent packages (required) * @return <code>null</code> if no package contains the given number of * types */ static String getLowestCommonPackage(final int typeCount, final Map<String, Collection<String>> typesByPackage) { final Map<String, Collection<String>> typesBySortedPackage = sortByKeyLength(typesByPackage); int longestPackage = 0; String topLevelPackage = null; for (final Entry<String, Collection<String>> entry : typesBySortedPackage.entrySet()) { final String thisPackage = entry.getKey(); final Collection<String> typesInPackage = entry.getValue(); if (typesInPackage.size() == typeCount && thisPackage.length() > longestPackage) { longestPackage = thisPackage.length(); topLevelPackage = thisPackage; } } return topLevelPackage; } static String getPackageFromType(final String typeName) { return typeName.substring(0, typeName.lastIndexOf('.')); } /** * Sorts the given string-keyed map by the length of its keys. * * @param <V> the type of the map's values * @param mapToSort the map to sort (not changed) * @return the sorted version of the map */ static <V> Map<String, V> sortByKeyLength(final Map<String, V> mapToSort) { final List<String> keys = new ArrayList<String>(mapToSort.keySet()); Collections.sort(keys, LENGTH_COMPARATOR); final Map<String, V> sortedMap = new LinkedHashMap<String, V>(); for (final String key : keys) { sortedMap.put(key, mapToSort.get(key)); } return sortedMap; } private FileManager fileManager; private FileMonitorService fileMonitorService; private MetadataService metadataService; private ProjectOperations projectOperations; private TypeCache typeCache; private TypeResolutionService typeResolutionService; private final Map<JavaType, Set<String>> annotationToMidMap = new HashMap<JavaType, Set<String>>(); private final Map<String, Set<String>> changeMap = new HashMap<String, Set<String>>(); private final Set<String> dirtyFiles = new HashSet<String>(); private final Set<String> discoveredTypes = new HashSet<String>(); private final Map<String, Set<Object>> typeCustomDataMap = new HashMap<String, Set<Object>>(); private final Map<Object, Set<String>> tagToMidMap = new HashMap<Object, Set<String>>(); private final Map<String, Set<JavaType>> typeAnnotationMap = new HashMap<String, Set<JavaType>>(); private void cacheType(final String fileCanonicalPath) { Validate.notBlank(fileCanonicalPath, "File canonical path required"); if (doesPathIndicateJavaType(fileCanonicalPath)) { final String id = getPhysicalTypeIdentifier(fileCanonicalPath); if (id != null && PhysicalTypeIdentifier.isValid(id)) { // Change to Java, so drop the cache final ClassOrInterfaceTypeDetails cid = lookupClassOrInterfaceTypeDetails(id); if (cid == null) { if (!getFileManager().exists(fileCanonicalPath)) { getTypeCache().removeType(id); final JavaType type = getTypeCache().getTypeDetails(id).getName(); updateChanges(type.getFullyQualifiedTypeName(), true); } return; } getTypeCache().cacheType(fileCanonicalPath, cid); updateAttributeCache(cid); updateChanges(cid.getName().getFullyQualifiedTypeName(), false); } } } private Set<String> discoverTypes() { // Retrieve a list of paths that have been discovered or modified since // the last invocation by this class for (final String change : getFileMonitorService().getDirtyFiles( TypeLocationServiceImpl.class.getName())) { if (doesPathIndicateJavaType(change)) { discoveredTypes.add(change); dirtyFiles.add(change); } } return discoveredTypes; } private boolean doesPathIndicateJavaType(final String fileCanonicalPath) { Validate.notBlank(fileCanonicalPath, "File canonical path required"); return fileCanonicalPath.endsWith(".java") && !fileCanonicalPath.endsWith("package-info.java") && JavaSymbolName.isLegalJavaName(getProposedJavaType(fileCanonicalPath)); } public Set<ClassOrInterfaceTypeDetails> findClassesOrInterfaceDetailsWithAnnotation( final JavaType... annotationsToDetect) { final List<ClassOrInterfaceTypeDetails> types = new ArrayList<ClassOrInterfaceTypeDetails>(); processTypesWithAnnotation(Arrays.asList(annotationsToDetect), new LocatedTypeCallback() { public void process(final ClassOrInterfaceTypeDetails located) { if (located != null) { types.add(located); } } }); Collections.sort(types, new NaturalOrderComparator<ClassOrInterfaceTypeDetails>() { @Override protected String stringify(final ClassOrInterfaceTypeDetails object) { return object.getName().getSimpleTypeName(); } }); return Collections.unmodifiableSet(new LinkedHashSet<ClassOrInterfaceTypeDetails>(types)); } public Set<ClassOrInterfaceTypeDetails> findClassesOrInterfaceDetailsWithTag(final Object tag) { Validate.notNull(tag, "Tag required"); final Set<ClassOrInterfaceTypeDetails> types = new LinkedHashSet<ClassOrInterfaceTypeDetails>(); processTypesWithTag(tag, new LocatedTypeCallback() { public void process(final ClassOrInterfaceTypeDetails located) { if (located != null) { types.add(located); } } }); return Collections.unmodifiableSet(types); } public Set<JavaType> findTypesWithAnnotation(final JavaType... annotationsToDetect) { return findTypesWithAnnotation(Arrays.asList(annotationsToDetect)); } public Set<JavaType> findTypesWithAnnotation(final List<JavaType> annotationsToDetect) { Validate.notNull(annotationsToDetect, "Annotations to detect required"); final Set<JavaType> types = new LinkedHashSet<JavaType>(); processTypesWithAnnotation(annotationsToDetect, new LocatedTypeCallback() { public void process(final ClassOrInterfaceTypeDetails located) { if (located != null) { types.add(located.getName()); } } }); return Collections.unmodifiableSet(types); } public List<JavaPackage> getPackagesForModule(Pom module) { List<JavaPackage> packages = new ArrayList<JavaPackage>(); for (JavaType type : getTypesForModule(module)) { if (!packages.contains(type.getPackage())) { packages.add(type.getPackage()); } } return packages; } public List<JavaPackage> getPackagesForModule(String moduleName) { return this.getPackagesForModule(getProjectOperations().getPomFromModuleName(moduleName)); } private String getParentPath(final JavaType javaType) { final String relativePath = javaType.getRelativeFileName(); for (final String typePath : discoverTypes()) { if (typePath.endsWith(relativePath)) { return StringUtils.removeEnd(typePath, relativePath); } } return null; } private PhysicalPath getPhysicalPath(final JavaType javaType) { Validate.notNull(javaType, "Java type required"); final String parentPath = getParentPath(javaType); if (parentPath == null) { return null; } for (final Pom pom : getProjectOperations().getPoms()) { for (final PhysicalPath physicalPath : pom.getPhysicalPaths()) { if (physicalPath.isSource()) { final String pathLocation = FileUtils.ensureTrailingSeparator(physicalPath.getLocationPath()); if (pathLocation.startsWith(parentPath)) { getTypeCache().cacheTypeAgainstModule(pom, javaType); return physicalPath; } } } } return null; } public String getPhysicalTypeCanonicalPath(final JavaType javaType, final LogicalPath path) { return getPhysicalTypeCanonicalPath(PhysicalTypeIdentifier.createIdentifier(javaType, path)); } public String getPhysicalTypeCanonicalPath(final String physicalTypeId) { final LogicalPath logicalPath = PhysicalTypeIdentifier.getPath(physicalTypeId); final JavaType javaType = PhysicalTypeIdentifier.getJavaType(physicalTypeId); final Pom pom = getProjectOperations().getPomFromModuleName(logicalPath.getModule()); final String canonicalFilePath = pom.getPathLocation(logicalPath.getPath()) + javaType.getRelativeFileName(); if (getFileManager().exists(canonicalFilePath)) { getTypeCache().cacheTypeAgainstModule(pom, javaType); getTypeCache().cacheFilePathAgainstTypeIdentifier(canonicalFilePath, physicalTypeId); } return canonicalFilePath; } public String getPhysicalTypeIdentifier(final JavaType type) { final PhysicalPath containingPhysicalPath = getPhysicalPath(type); if (containingPhysicalPath == null) { return null; } final LogicalPath logicalPath = containingPhysicalPath.getLogicalPath(); return PhysicalTypeIdentifier.createIdentifier(type, logicalPath); } public String getPhysicalTypeIdentifier(final String fileCanonicalPath) { Validate.notBlank(fileCanonicalPath, "File canonical path required"); if (!doesPathIndicateJavaType(fileCanonicalPath)) { return null; } String physicalTypeIdentifier = getTypeCache().getTypeIdFromTypeFilePath(fileCanonicalPath); if (physicalTypeIdentifier != null) { return physicalTypeIdentifier; } final String typeDirectory = FileUtils.getFirstDirectory(fileCanonicalPath); final String simpleTypeName = StringUtils.replace(fileCanonicalPath, typeDirectory + File.separator, "", 1).replace( ".java", ""); final JavaPackage javaPackage = getTypeResolutionService().getPackage(fileCanonicalPath); if (javaPackage == null) { return null; } final Pom module = getProjectOperations().getModuleForFileIdentifier(fileCanonicalPath); Validate.notNull(module, "The module for the file '" + fileCanonicalPath + "' could not be located"); final JavaType javaType = new JavaType(javaPackage.getFullyQualifiedPackageName() + "." + simpleTypeName, module.getModuleName()); getTypeCache().cacheTypeAgainstModule(module, javaType); String reducedPath = fileCanonicalPath.replace(javaType.getRelativeFileName(), ""); reducedPath = StringUtils.stripEnd(reducedPath, File.separator); for (final PhysicalPath physicalPath : module.getPhysicalPaths()) { if (physicalPath.getLocationPath().startsWith(reducedPath)) { final LogicalPath path = physicalPath.getLogicalPath(); physicalTypeIdentifier = MetadataIdentificationUtils.create(PhysicalTypeIdentifier.class.getName(), path.getName() + "?" + javaType.getFullyQualifiedTypeName()); break; } } getTypeCache().cacheFilePathAgainstTypeIdentifier(fileCanonicalPath, physicalTypeIdentifier); return physicalTypeIdentifier; } public List<String> getPotentialTopLevelPackagesForModule(final Pom module) { Validate.notNull(module, "Module required"); final Map<String, Set<String>> packageMap = new HashMap<String, Set<String>>(); final Set<String> moduleTypes = getTypesForModule(module.getPath()); final List<String> topLevelPackages = new ArrayList<String>(); if (moduleTypes.isEmpty()) { topLevelPackages.add(module.getGroupId()); return topLevelPackages; } for (final String typeName : moduleTypes) { final StringBuilder sb = new StringBuilder(); final String type = getPackageFromType(typeName); final String[] typeSegments = type.split("\\."); final Set<String> discoveredPackages = new HashSet<String>(); for (int i = 0; i < typeSegments.length; i++) { final String typeSegment = typeSegments[i]; if (i > 0) { sb.append("."); } sb.append(typeSegment); discoveredPackages.add(sb.toString()); } for (final String discoveredPackage : discoveredPackages) { if (!packageMap.containsKey(discoveredPackage)) { packageMap.put(discoveredPackage, new HashSet<String>()); } packageMap.get(discoveredPackage).add(typeName); } } int longestPackage = 0; for (final Map.Entry<String, Set<String>> entry : packageMap.entrySet()) { if (entry.getValue().size() == moduleTypes.size()) { topLevelPackages.add(entry.getKey()); if (entry.getKey().length() > longestPackage) { longestPackage = entry.getKey().length(); } } } return topLevelPackages; } private String getProposedJavaType(final String fileCanonicalPath) { Validate.notBlank(fileCanonicalPath, "File canonical path required"); // Determine the JavaType for this file String relativePath = ""; final Pom moduleForFileIdentifier = getProjectOperations().getModuleForFileIdentifier(fileCanonicalPath); if (moduleForFileIdentifier == null) { return relativePath; } for (final PhysicalPath physicalPath : moduleForFileIdentifier.getPhysicalPaths()) { final String moduleCanonicalPath = FileUtils.ensureTrailingSeparator(FileUtils.getCanonicalPath(physicalPath.getLocation())); if (fileCanonicalPath.startsWith(moduleCanonicalPath)) { relativePath = File.separator + StringUtils.replace(fileCanonicalPath, moduleCanonicalPath, "", 1); break; } } Validate.notBlank(relativePath, "Could not determine compilation unit name for file '%s'", fileCanonicalPath); Validate.isTrue(relativePath.startsWith(File.separator), "Relative path unexpectedly dropped the '%s' prefix (received '%s' from '%s')", File.separator, relativePath, fileCanonicalPath); relativePath = relativePath.substring(1); Validate.isTrue(relativePath.endsWith(".java"), "The relative path unexpectedly dropped the .java extension for file '%s'", fileCanonicalPath); relativePath = relativePath.substring(0, relativePath.lastIndexOf(".java")); return relativePath.replace(File.separatorChar, '.'); } public String getTopLevelPackageForModule(final Pom module) { if (StringUtils.isBlank(module.getModuleName())) { // Parent module or project package return module.getGroupId(); } else { //Module package return module.getGroupId().concat(".").concat(module.getArtifactId()); } } /** * Builds a map of a module's packages and all types anywhere within them, * e.g. if there's two types com.foo.bar.A and com.foo.baz.B, the map will * look like this: "com": {"com.foo.bar.A", "com.foo.baz.B"} "com.foo": * {"com.foo.bar.A", "com.foo.baz.B"}, "com.foo.bar": {"com.foo.bar.A"}, * "com.foo.baz": {"com.foo.baz.B"} All packages that directly contain a * type are added to the given set. * * @param typesInModule the Java types within the module in question * @param typePackages the set to which to add each type's package * @return a non-<code>null</code> map laid out as above */ @SuppressWarnings("unused") private Map<String, Collection<String>> getTypesByPackage(final Iterable<String> typesInModule, final Set<String> typePackages) { final Map<String, Collection<String>> typesByPackage = new HashMap<String, Collection<String>>(); for (final String typeName : typesInModule) { final String typePackage = getPackageFromType(typeName); typePackages.add(typePackage); for (final String discoveredPackage : getAllPackages(typePackage)) { if (typesByPackage.get(discoveredPackage) == null) { typesByPackage.put(discoveredPackage, new HashSet<String>()); } typesByPackage.get(discoveredPackage).add(typeName); } } return typesByPackage; } public ClassOrInterfaceTypeDetails getTypeDetails(final JavaType type) { return getTypeDetails(getPhysicalTypeIdentifier(type)); } public ClassOrInterfaceTypeDetails getTypeDetails(final String physicalTypeId) { if (StringUtils.isBlank(physicalTypeId)) { return null; } Validate.isTrue(PhysicalTypeIdentifier.isValid(physicalTypeId), "Metadata id '%s' is not a valid physical type id", physicalTypeId); updateTypeCache(); final ClassOrInterfaceTypeDetails cachedDetails = getTypeCache().getTypeDetails(physicalTypeId); if (cachedDetails != null) { return cachedDetails; } final PhysicalTypeMetadata physicalTypeMetadata = (PhysicalTypeMetadata) getMetadataService().get(physicalTypeId); if (physicalTypeMetadata == null) { return null; } return physicalTypeMetadata.getMemberHoldingTypeDetails(); } public LogicalPath getTypePath(final JavaType javaType) { final String physicalTypeId = getPhysicalTypeIdentifier(javaType); if (StringUtils.isBlank(physicalTypeId)) { return null; } return PhysicalTypeIdentifier.getPath(physicalTypeId); } public Collection<JavaType> getTypesForModule(final Pom module) { if ("pom".equals(module.getPackaging())) { return Collections.emptySet(); } final Set<String> typeNames = getTypesForModule(module.getPath()); final Collection<JavaType> javaTypes = new ArrayList<JavaType>(); for (final String typeName : typeNames) { javaTypes.add(new JavaType(typeName, module.getModuleName())); } return javaTypes; } public Set<String> getTypesForModule(final String modulePath) { Validate.notNull(modulePath, "Module path required"); return getTypeCache().getTypeNamesForModuleFilePath(modulePath); } public boolean hasTypeChanged(final String requestingClass, final JavaType javaType) { Validate.notNull(requestingClass, "Requesting class required"); Validate.notNull(javaType, "Java type required"); updateTypeCache(); Set<String> changesSinceLastRequest = changeMap.get(requestingClass); if (changesSinceLastRequest == null) { changesSinceLastRequest = new LinkedHashSet<String>(); for (final String typeIdentifier : getTypeCache().getAllTypeIdentifiers()) { changesSinceLastRequest.add(getTypeCache().getTypeDetails(typeIdentifier).getName() .getFullyQualifiedTypeName()); } changeMap.put(requestingClass, changesSinceLastRequest); } for (final String changedId : changesSinceLastRequest) { if (changedId.equals(javaType.getFullyQualifiedTypeName())) { changesSinceLastRequest.remove(changedId); return true; } } return false; } private void initTypeMap() { for (final Pom pom : getProjectOperations().getPoms()) { for (final PhysicalPath path : pom.getPhysicalPaths()) { if (path.isSource()) { final String allJavaFiles = FileUtils.ensureTrailingSeparator(path.getLocationPath()) + JAVA_FILES_ANT_PATH; for (final FileDetails file : getFileManager().findMatchingAntPath(allJavaFiles)) { cacheType(file.getCanonicalPath()); } } } } } public boolean isInProject(final JavaType javaType) { return javaType != null && !javaType.isCoreType() && getPhysicalPath(javaType) != null; } /** * Obtains the a fresh copy of the {@link ClassOrInterfaceTypeDetails} for * the given physical type. * * @param physicalTypeIdentifier to lookup (required) * @return the requested details (or <code>null</code> if unavailable) */ private ClassOrInterfaceTypeDetails lookupClassOrInterfaceTypeDetails( final String physicalTypeIdentifier) { final PhysicalTypeMetadata physicalTypeMetadata = (PhysicalTypeMetadata) getMetadataService().evictAndGet(physicalTypeIdentifier); if (physicalTypeMetadata == null) { return null; } return physicalTypeMetadata.getMemberHoldingTypeDetails(); } public void processTypesWithAnnotation(final List<JavaType> annotationsToDetect, final LocatedTypeCallback callback) { Validate.notNull(annotationsToDetect, "Annotations to detect required"); Validate.notNull(callback, "Callback required"); // If the cache doesn't yet contain the annotation to be found it should // be added for (final JavaType annotationType : annotationsToDetect) { if (!annotationToMidMap.containsKey(annotationType)) { annotationToMidMap.put(annotationType, new HashSet<String>()); } } // Before processing the call any changes to the project should be // processed and the cache updated accordingly updateTypeCache(); for (final JavaType annotationType : annotationsToDetect) { for (final String locatedMid : annotationToMidMap.get(annotationType)) { final ClassOrInterfaceTypeDetails located = getTypeCache().getTypeDetails(locatedMid); callback.process(located); } } } private void processTypesWithTag(final Object tag, final LocatedTypeCallback callback) { Validate.notNull(tag, "Tag required"); Validate.notNull(callback, "Callback required"); // If the cache doesn't yet contain the tag it should be added if (!tagToMidMap.containsKey(tag)) { tagToMidMap.put(tag, new HashSet<String>()); } // Before processing the call any changes to the project should be // processed and the cache updated accordingly updateTypeCache(); for (final String locatedMid : tagToMidMap.get(tag)) { final ClassOrInterfaceTypeDetails located = getTypeCache().getTypeDetails(locatedMid); callback.process(located); } } private void updateAttributeCache(final MemberHoldingTypeDetails cid) { Validate.notNull(cid, "Member holding type details required"); if (!typeAnnotationMap.containsKey(cid.getDeclaredByMetadataId())) { typeAnnotationMap.put(cid.getDeclaredByMetadataId(), new HashSet<JavaType>()); } if (!typeCustomDataMap.containsKey(cid.getDeclaredByMetadataId())) { typeCustomDataMap.put(cid.getDeclaredByMetadataId(), new HashSet<Object>()); } final Set<JavaType> previousAnnotations = typeAnnotationMap.get(cid.getDeclaredByMetadataId()); for (final JavaType previousAnnotation : previousAnnotations) { final Set<String> midSet = annotationToMidMap.get(previousAnnotation); if (midSet != null) { midSet.remove(cid.getDeclaredByMetadataId()); } } previousAnnotations.clear(); for (final AnnotationMetadata annotationMetadata : cid.getAnnotations()) { if (!annotationToMidMap.containsKey(annotationMetadata.getAnnotationType())) { annotationToMidMap.put(annotationMetadata.getAnnotationType(), new HashSet<String>()); } previousAnnotations.add(annotationMetadata.getAnnotationType()); annotationToMidMap.get(annotationMetadata.getAnnotationType()).add( cid.getDeclaredByMetadataId()); } final Set<Object> previousCustomDataSet = typeCustomDataMap.get(cid.getDeclaredByMetadataId()); for (final Object previousCustomData : previousCustomDataSet) { final Set<String> midSet = tagToMidMap.get(previousCustomData); if (midSet != null) { midSet.remove(cid.getDeclaredByMetadataId()); } } previousCustomDataSet.clear(); for (final Object customData : cid.getCustomData().keySet()) { if (!tagToMidMap.containsKey(customData)) { tagToMidMap.put(customData, new HashSet<String>()); } previousCustomDataSet.add(customData); tagToMidMap.get(customData).add(cid.getDeclaredByMetadataId()); } } private void updateChanges(final String typeName, final boolean remove) { Validate.notNull(typeName, "Type name required"); for (final String requestingClass : changeMap.keySet()) { if (remove) { changeMap.get(requestingClass).remove(typeName); } else { changeMap.get(requestingClass).add(typeName); } } } private void updateTypeCache() { if (getTypeCache().getAllTypeIdentifiers().isEmpty()) { initTypeMap(); } discoverTypes(); // Update the type cache for (final String change : dirtyFiles) { cacheType(change); } dirtyFiles.clear(); } public void addDependencies(ModuleFeatureName moduleFeatureName, final Collection<? extends Dependency> newDependencies) { for (String moduleName : getModuleNames(moduleFeatureName)) { getProjectOperations().addDependencies(moduleName, newDependencies); } } public void addModuleDependency(final String moduleName, final JavaType moduleJavaTypeToDependUpon) { if (moduleJavaTypeToDependUpon.getModule() != null) { getProjectOperations() .addModuleDependency(moduleName, moduleJavaTypeToDependUpon.getModule()); } else { ClassOrInterfaceTypeDetails details = getTypeDetails(moduleJavaTypeToDependUpon); if (details != null && details.getName().getModule() != null) { getProjectOperations().addModuleDependency(moduleName, details.getName().getModule()); } } } public void removeDependencies(ModuleFeatureName moduleFeatureName, final Collection<? extends Dependency> newDependencies) { for (String moduleName : getModuleNames(moduleFeatureName)) { getProjectOperations().removeDependencies(moduleName, newDependencies); } } @Override public Collection<Pom> getModules(ModuleFeatureName moduleFeatureName) { Validate.notNull(moduleFeatureName, "Module featured required"); List<Pom> modules = new ArrayList<Pom>(); ModuleFeature moduleFeature = getModuleFeature(moduleFeatureName); if (moduleFeature != null) { modules = moduleFeature.getModules(); } return modules; } @Override public Collection<String> getModuleNames(ModuleFeatureName moduleFeatureName) { Validate.notNull(moduleFeatureName, "Module featured required"); List<String> moduleNames = new ArrayList<String>(); ModuleFeature moduleFeature = getModuleFeature(moduleFeatureName); if (moduleFeature != null) { moduleNames = moduleFeature.getModuleNames(); } return moduleNames; } public boolean hasModuleFeature(Pom module, ModuleFeatureName moduleFeatureName) { Validate.notNull(moduleFeatureName, "Module featured required"); Validate.notNull(module, "Module required"); ModuleFeature moduleFeature = getModuleFeature(moduleFeatureName); if (moduleFeature != null) { return moduleFeature.hasModuleFeature(module); } return false; } public FileManager getFileManager() { if (fileManager == null) { // Get all Services implement FileManager interface try { ServiceReference<?>[] references = context.getAllServiceReferences(FileManager.class.getName(), null); for (ServiceReference<?> ref : references) { return (FileManager) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load FileManager on TypeLocationServiceImpl."); return null; } } else { return fileManager; } } public FileMonitorService getFileMonitorService() { if (fileMonitorService == null) { // Get all Services implement FileMonitorService interface try { ServiceReference<?>[] references = context.getAllServiceReferences(FileMonitorService.class.getName(), null); for (ServiceReference<?> ref : references) { return (FileMonitorService) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load FileMonitorService on TypeLocationServiceImpl."); return null; } } else { return fileMonitorService; } } public MetadataService getMetadataService() { if (metadataService == null) { // Get all Services implement MetadataService interface try { ServiceReference<?>[] references = context.getAllServiceReferences(MetadataService.class.getName(), null); for (ServiceReference<?> ref : references) { return (MetadataService) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MetadataService on TypeLocationServiceImpl."); return null; } } else { return metadataService; } } public ProjectOperations getProjectOperations() { if (projectOperations == null) { // Get all Services implement ProjectOperations interface try { ServiceReference<?>[] references = context.getAllServiceReferences(ProjectOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (ProjectOperations) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load ProjectOperations on TypeLocationServiceImpl."); return null; } } else { return projectOperations; } } public TypeCache getTypeCache() { if (typeCache == null) { // Get all Services implement TypeCache interface try { ServiceReference<?>[] references = context.getAllServiceReferences(TypeCache.class.getName(), null); for (ServiceReference<?> ref : references) { return (TypeCache) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load TypeCache on TypeLocationServiceImpl."); return null; } } else { return typeCache; } } public TypeResolutionService getTypeResolutionService() { if (typeResolutionService == null) { // Get all Services implement TypeResolutionService interface try { ServiceReference<?>[] references = context.getAllServiceReferences(TypeResolutionService.class.getName(), null); for (ServiceReference<?> ref : references) { return (TypeResolutionService) context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load TypeResolutionService on TypeLocationServiceImpl."); return null; } } else { return typeResolutionService; } } private ModuleFeature getModuleFeature(ModuleFeatureName moduleFeatureName) { if (moduleFeatures.containsKey(moduleFeatureName)) { return moduleFeatures.get(moduleFeatureName); } try { ServiceReference<?>[] references = context.getAllServiceReferences(ModuleFeature.class.getName(), null); for (ServiceReference<?> ref : references) { ModuleFeature moduleFeature = (ModuleFeature) context.getService(ref); if (moduleFeature.getName().equals(moduleFeatureName)) { moduleFeatures.put(moduleFeatureName, moduleFeature); return moduleFeature; } } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load ModuleFeature on TypeLocationServiceImpl."); return null; } } }