| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.tuscany.sca.contribution.java.impl; |
| |
| import java.io.IOException; |
| import java.lang.ref.WeakReference; |
| import java.lang.reflect.Field; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Vector; |
| |
| import org.apache.tuscany.sca.contribution.Contribution; |
| import org.apache.tuscany.sca.contribution.Import; |
| import org.apache.tuscany.sca.contribution.java.JavaImport; |
| import org.apache.tuscany.sca.contribution.processor.ProcessorContext; |
| import org.apache.tuscany.sca.contribution.resolver.ClassReference; |
| import org.apache.tuscany.sca.contribution.resolver.DefaultDelegatingModelResolver; |
| import org.apache.tuscany.sca.contribution.resolver.ModelResolver; |
| import org.apache.tuscany.sca.core.FactoryExtensionPoint; |
| import org.apache.tuscany.sca.extensibility.ServiceDiscovery; |
| |
| /** |
| * A Model Resolver for ClassReferences. |
| * |
| * @version $Rev$ $Date$ |
| */ |
| public class ClassLoaderModelResolver extends URLClassLoader implements ModelResolver { |
| private WeakReference<Contribution> contribution; |
| private ProcessorContext context; |
| private Map<String, ModelResolver> importResolvers = new HashMap<String, ModelResolver>(); |
| |
| // a space to pass back the contribution that was used to resolve |
| // a class via an import |
| private Contribution contributionContainingClass; |
| |
| private static ClassLoader parentClassLoader(Contribution contribution) { |
| if (contribution.getClassLoader() != null) { |
| return contribution.getClassLoader(); |
| } |
| ClassLoader parentClassLoader = ServiceDiscovery.getInstance().getContextClassLoader(); |
| return parentClassLoader; |
| } |
| |
| private static URL[] getContributionURLs(final Contribution contribution) throws IOException { |
| if (contribution.getClassLoader() != null) { |
| // Do not include the contribution url |
| return new URL[0]; |
| } |
| List<URL> urls = new ArrayList<URL>(); |
| urls.add(new URL(contribution.getLocation())); |
| urls.addAll(ContributionHelper.getNestedJarUrls(contribution)); |
| return urls.toArray(new URL[urls.size()]); |
| } |
| |
| public ClassLoaderModelResolver(final Contribution contribution, FactoryExtensionPoint modelFactories) throws IOException { |
| super(getContributionURLs(contribution), parentClassLoader(contribution)); |
| this.contribution = new WeakReference<Contribution>(contribution); |
| // Index Java import resolvers by package name |
| Map<String, List<ModelResolver>> resolverMap = new HashMap<String, List<ModelResolver>>(); |
| for (Import import_: this.contribution.get().getImports()) { |
| if (import_ instanceof JavaImport) { |
| JavaImport javaImport = (JavaImport)import_; |
| List<ModelResolver> resolvers = resolverMap.get(javaImport.getPackage()); |
| if (resolvers == null) { |
| resolvers = new ArrayList<ModelResolver>(); |
| resolverMap.put(javaImport.getPackage(), resolvers); |
| } |
| resolvers.add(javaImport.getModelResolver()); |
| } |
| } |
| |
| // Create a delegating model resolver for each imported package |
| for (Map.Entry<String, List<ModelResolver>> entry: resolverMap.entrySet()) { |
| importResolvers.put(entry.getKey(), new DefaultDelegatingModelResolver(entry.getValue())); |
| } |
| } |
| |
| public void addModel(Object resolved, ProcessorContext context) { |
| throw new IllegalStateException(); |
| } |
| |
| public Object removeModel(Object resolved, ProcessorContext context) { |
| throw new IllegalStateException(); |
| } |
| |
| public <T> T resolveModel(Class<T> modelClass, T unresolved, ProcessorContext context) { |
| if (!(unresolved instanceof ClassReference)) { |
| return unresolved; |
| } |
| |
| try { |
| this.context = context; |
| contributionContainingClass = contribution.get(); |
| |
| // Load the class and return a class reference for it |
| String className = ((ClassReference)unresolved).getClassName(); |
| Class<?> clazz = Class.forName(className, false, this); |
| ClassReference classReference = new ClassReference(clazz); |
| classReference.setContributionContainingClass(contributionContainingClass); |
| contributionContainingClass = null; |
| return modelClass.cast(classReference); |
| |
| } catch (ClassNotFoundException e) { |
| return unresolved; |
| } finally { |
| contributionContainingClass = null; |
| } |
| } |
| |
| @Override |
| public URL findResource(String name) { |
| |
| //TODO delegate to the Java import resolvers |
| |
| URL url = super.findResource(name); |
| return url; |
| } |
| |
| @Override |
| public Enumeration<URL> findResources(String name) throws IOException { |
| |
| //TODO delegate to the Java import resolvers |
| //Enumeration<URL> importedResources; |
| |
| Enumeration<URL> resources = super.findResources(name); |
| List<URL> allResources = new ArrayList<URL>(); |
| //for (; importedResources.hasMoreElements(); ) { |
| // allResources.add(importedResources.nextElement()); |
| //} |
| for (; resources.hasMoreElements(); ) { |
| allResources.add(resources.nextElement()); |
| } |
| return Collections.enumeration(allResources); |
| } |
| |
| @Override |
| protected Class<?> findClass(String name) throws ClassNotFoundException { |
| |
| // Extract the package name |
| int d = name.lastIndexOf('.'); |
| String packageName; |
| if (d != -1) { |
| packageName = name.substring(0, d); |
| } else { |
| packageName = null; |
| } |
| |
| // First try to load the class using the Java import resolvers |
| ModelResolver importResolver = importResolvers.get(packageName); |
| if (importResolver != null) { |
| ClassReference classReference = importResolver.resolveModel(ClassReference.class, new ClassReference(name), context); |
| if (!classReference.isUnresolved()) { |
| contributionContainingClass = classReference.getContributionContainingClass(); |
| return classReference.getJavaClass(); |
| } |
| } |
| |
| // Next, try to load the class from the current contribution |
| Class<?> clazz = super.findClass(name); |
| return clazz; |
| } |
| |
| public void clear() { |
| contribution = null; |
| contributionContainingClass = null; |
| context = null; |
| importResolvers = null; |
| } |
| |
| } |