summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/java/impl/ClassLoaderModelResolver.java
blob: bb7ae3f29dd19913dfa4e2a3653a35fc96a6fdf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * 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;
    }

}