View Javadoc

1   /*
2    * Copyright 2006-2008 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.osgi.service.importer.support;
18  
19  import java.lang.reflect.Modifier;
20  import java.util.LinkedHashSet;
21  import java.util.Set;
22  
23  import org.aopalliance.aop.Advice;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.osgi.framework.Bundle;
27  import org.osgi.framework.BundleContext;
28  import org.osgi.framework.ServiceReference;
29  import org.springframework.osgi.context.internal.classloader.AopClassLoaderFactory;
30  import org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker;
31  import org.springframework.osgi.service.importer.support.internal.aop.ServiceStaticInterceptor;
32  import org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor;
33  import org.springframework.osgi.util.OsgiServiceReferenceUtils;
34  import org.springframework.osgi.util.OsgiStringUtils;
35  import org.springframework.osgi.util.internal.ClassUtils;
36  import org.springframework.util.ObjectUtils;
37  
38  /**
39   * @author Costin Leau
40   * 
41   */
42  class StaticServiceProxyCreator extends AbstractServiceProxyCreator {
43  
44  	private static final Log log = LogFactory.getLog(StaticServiceProxyCreator.class);
45  	/** greedy proxying mechanism */
46  	private final boolean greedyProxying;
47  	/** should greedy proxying consider just interfaces ? */
48  	private final boolean interfacesOnlyProxying;
49  
50  
51  	/**
52  	 * Constructs a new <code>StaticServiceProxyCreator</code> instance.
53  	 * 
54  	 * @param classes
55  	 * @param classLoader
56  	 * @param bundleContext
57  	 * @param iccl
58  	 * @param greedyProxying
59  	 */
60  	StaticServiceProxyCreator(Class[] classes, ClassLoader classLoader, BundleContext bundleContext,
61  			ImportContextClassLoader iccl, boolean greedyProxying) {
62  		super(classes, classLoader, bundleContext, iccl);
63  		this.greedyProxying = greedyProxying;
64  
65  		boolean onlyInterfaces = true;
66  
67  		// see if cglib is used or not
68  		for (int i = 0; i < classes.length; i++) {
69  			if (!classes[i].isInterface())
70  				onlyInterfaces = false;
71  		}
72  
73  		interfacesOnlyProxying = onlyInterfaces;
74  
75  		String msg = (interfacesOnlyProxying ? "NOT" : "");
76  
77  		if (log.isDebugEnabled())
78  			log.debug("Greedy proxying will " + msg + " consider exposed classes");
79  	}
80  
81  	ServiceInvoker createDispatcherInterceptor(ServiceReference reference) {
82  		return new ServiceStaticInterceptor(bundleContext, reference);
83  	}
84  
85  	Advice createServiceProviderTCCLAdvice(ServiceReference reference) {
86  		Bundle bundle = reference.getBundle();
87  		// if reference is dead already, it's impossible to provide the service
88  		// class loader
89  		if (bundle == null)
90  			return null;
91  
92  		return new ServiceTCCLInterceptor(AopClassLoaderFactory.getBundleClassLoaderFor(bundle));
93  	}
94  
95  	/**
96  	 * Apply 'greedy' proxying by discovering the exposed classes.
97  	 * 
98  	 * @param ref
99  	 * @return
100 	 */
101 	Class[] discoverProxyClasses(ServiceReference ref) {
102 		boolean trace = log.isTraceEnabled();
103 
104 		if (trace)
105 			log.trace("Generating greedy proxy for service " + OsgiStringUtils.nullSafeToString(ref));
106 
107 		String[] classNames = OsgiServiceReferenceUtils.getServiceObjectClasses(ref);
108 
109 		if (trace)
110 			log.trace("Discovered raw classes " + ObjectUtils.nullSafeToString(classNames));
111 
112 		// try to get as many classes as possible
113 		Class[] classes = ClassUtils.loadClasses(classNames, classLoader);
114 
115 		if (trace)
116 			log.trace("Visible classes are " + ObjectUtils.nullSafeToString(classes));
117 
118 		// exclude final classes
119 		classes = ClassUtils.excludeClassesWithModifier(classes, Modifier.FINAL);
120 
121 		if (trace)
122 			log.trace("Filtering out final classes; left out with " + ObjectUtils.nullSafeToString(classes));
123 
124 		// remove classes if needed
125 		if (interfacesOnlyProxying) {
126 			Set clazzes = new LinkedHashSet(classes.length);
127 			for (int classIndex = 0; classIndex < classes.length; classIndex++) {
128 				Class clazz = classes[classIndex];
129 				if (clazz.isInterface())
130 					clazzes.add(clazz);
131 			}
132 			if (trace)
133 				log.trace("Filtering out concrete classes; left out with " + clazzes);
134 
135 			classes = (Class[]) clazzes.toArray(new Class[clazzes.size()]);
136 		}
137 
138 		// remove class duplicates/parents
139 		classes = ClassUtils.removeParents(classes);
140 
141 		if (trace)
142 			log.trace("Filtering out parent classes; left out with " + classes);
143 
144 		return classes;
145 	}
146 
147 	Class[] getInterfaces(ServiceReference reference) {
148 		if (greedyProxying) {
149 			Class[] clazzes = discoverProxyClasses(reference);
150 			if (log.isTraceEnabled())
151 				log.trace("generating 'greedy' service proxy using classes " + ObjectUtils.nullSafeToString(clazzes)
152 						+ " over " + ObjectUtils.nullSafeToString(this.classes));
153 			return clazzes;
154 		}
155 		// no greedy proxy, return just the configured classes
156 		return classes;
157 	}
158 }