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.extender.internal.activator;
18  
19  import org.osgi.framework.Bundle;
20  import org.osgi.framework.BundleContext;
21  import org.springframework.osgi.io.internal.resolver.DependencyResolver;
22  import org.springframework.osgi.io.internal.resolver.ImportedBundle;
23  import org.springframework.osgi.io.internal.resolver.PackageAdminResolver;
24  import org.springframework.osgi.util.OsgiBundleUtils;
25  import org.springframework.util.Assert;
26  
27  /**
28   * Simple utility class for checking the Spring compatibility between two
29   * different bundles.
30   * 
31   * <p/> To escape bundle resolving (which can be difficult as the packages can
32   * be spread across multiple bundles), this class simply does class loading and
33   * the checks the compatibility between them. Since the bundles are all wired
34   * between them, the same Spring version should be used all over.
35   * 
36   * @author Costin Leau
37   * 
38   */
39  class SpringTypeCompatibilityChecker {
40  
41  	/** Spring class used for loading */
42  	private static Class SPRING_TYPE = Assert.class;
43  	/** hold a direct reference since it's a mandatory platform service */
44  	private final DependencyResolver dependencyResolver;
45  
46  
47  	SpringTypeCompatibilityChecker(BundleContext bundleContext) {
48  		// use PackageAdminResolver
49  		dependencyResolver = new PackageAdminResolver(bundleContext);
50  	}
51  
52  	/**
53  	 * Returns the type compatibility between the given bundle and the Spring
54  	 * types used by the current version of Spring-DM. If the given bundle does
55  	 * not import Spring, then true is returned (the bundle is considered
56  	 * compatible).
57  	 * 
58  	 * @param bundle
59  	 * @return
60  	 */
61  	boolean checkCompatibility(Bundle bundle) {
62  		Assert.notNull(bundle);
63  
64  		Boolean typeComparison = isTypeAvailable(bundle, SPRING_TYPE);
65  
66  		if (typeComparison != null) {
67  			return typeComparison.booleanValue();
68  		}
69  		// check the imported bundles
70  		else {
71  			ImportedBundle[] importedBundles = dependencyResolver.getImportedBundles(bundle);
72  			return checkImportedBundles(importedBundles);
73  		}
74  	}
75  
76  	/**
77  	 * Check the Spring compatibility with the given imported bundles.
78  	 * 
79  	 * @param importedBundles
80  	 * @return
81  	 */
82  	private boolean checkImportedBundles(ImportedBundle[] importedBundles) {
83  		for (int i = 0; i < importedBundles.length; i++) {
84  			Bundle bundle = importedBundles[i].getBundle();
85  			// minor optimization (exclude system bundle)
86  			if (!OsgiBundleUtils.isSystemBundle(bundle)) {
87  				Boolean comparsion = isTypeAvailable(bundle, SPRING_TYPE);
88  				if (comparsion != null) {
89  					return comparsion.booleanValue();
90  				}
91  			}
92  		}
93  		// no Spring type found, the bundles are compatible
94  		return true;
95  	}
96  
97  	/**
98  	 * Returns a boolean representing the comparison result if the given type is
99  	 * found in the given bundle or null otherwise.
100 	 * 
101 	 * @param bundle
102 	 * @param type
103 	 * @return
104 	 */
105 	private static Boolean isTypeAvailable(Bundle bundle, Class type) {
106 		try {
107 			Class newType = bundle.loadClass(type.getName());
108 			return Boolean.valueOf(type.equals(newType));
109 		}
110 		catch (ClassNotFoundException cnfe) {
111 			// class is not available
112 			return null;
113 		}
114 	}
115 
116 	/**
117 	 * Utility method used for finding bundles that load a specific type. This
118 	 * should be used if the PackageAdmin is not available.
119 	 * 
120 	 * @param context
121 	 * @param type
122 	 * @return
123 	 */
124 	static Bundle findOriginatingBundle(BundleContext context, Class type) {
125 		Bundle[] bundles = context.getBundles();
126 		for (int i = 0; i < bundles.length; i++) {
127 			Bundle bundle = bundles[i];
128 			Boolean isAvailable = isTypeAvailable(bundle, type);
129 			if (isAvailable != null && isAvailable.booleanValue()) {
130 				return bundle;
131 			}
132 		}
133 
134 		return null;
135 	}
136 }