KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ungoverned > oscar > OSGiSelectionPolicy


1 /*
2  * Oscar - An implementation of the OSGi framework.
3  * Copyright (c) 2004, Richard S. Hall
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of the ungoverned.org nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * Contact: Richard S. Hall (heavy@ungoverned.org)
33  * Contributor(s):
34  *
35 **/

36 package org.ungoverned.oscar;
37
38 import java.net.MalformedURLException JavaDoc;
39 import java.net.URL JavaDoc;
40 import java.security.*;
41 import java.security.cert.Certificate JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.Map JavaDoc;
45
46 import org.osgi.framework.Bundle;
47 import org.osgi.framework.PackagePermission;
48 import org.ungoverned.moduleloader.Module;
49 import org.ungoverned.moduleloader.ModuleEvent;
50 import org.ungoverned.moduleloader.ModuleListener;
51 import org.ungoverned.moduleloader.search.ImportSearchPolicy;
52 import org.ungoverned.moduleloader.search.SelectionPolicy;
53 import org.ungoverned.moduleloader.search.CompatibilityPolicy;
54
55 public class OSGiSelectionPolicy implements SelectionPolicy, ModuleListener
56 {
57     private Oscar m_oscar = null;
58     private Map JavaDoc m_resolvedPackageMap = new HashMap JavaDoc();
59     private Map JavaDoc m_resolvedModuleMap = new HashMap JavaDoc();
60
61     public OSGiSelectionPolicy(Oscar oscar)
62     {
63         m_oscar = oscar;
64     }
65
66     /**
67      * Selects a single module to resolve the specified import
68      * from the array of compatible candidate modules. If the import
69      * target has not been resolved before, then this selection policy
70      * chooses the module that exports the newest version of the
71      * import target. If the import target has been resolved already,
72      * then the same module that was chosen before is chosen again.
73      * This ensures that all modules use the same version of all
74      * exported classes, as described in the OSGi specification.
75      * @param module the module that is importing the target.
76      * @param identifier the identifier of the import target.
77      * @param version the version number of the import target.
78      * @param candidates array of compatible candidate modules from which to choose.
79      * @param compatPolicy the compatibility policy that is being used.
80      * @return the selected module or <tt>null</tt> if no module
81      * can be selected.
82     **/

83     public synchronized Module select(Module module, Object JavaDoc identifier,
84         Object JavaDoc v, Module[] candidates, CompatibilityPolicy compatPolicy)
85     {
86         String JavaDoc pkgName = (String JavaDoc) identifier;
87         int[] version = (int[]) v;
88
89         // See if a module was already selected to resolve this package.
90
Module selModule = (Module) m_resolvedPackageMap.get(pkgName);
91
92         // If no module was previously selected to resolve the package,
93
// then try to choose one now.
94
if (selModule == null)
95         {
96             int[] selVersion = version;
97             Bundle selBundle = null;
98
99             // Examine all exported instances of the package and
100
// choose the one with the newest version number. If
101
// there is more than one source for the newest version,
102
// then select the package coming from the bundle with
103
// the with the smallest bundle ID.
104
for (int i = 0; i < candidates.length; i++)
105             {
106                 // Get the bundle associated with the module.
107
long id = BundleInfo.getBundleIdFromModuleId(candidates[i].getId());
108                 if (id < 0)
109                 {
110                     // Ignore modules for which there is no bundle.
111
continue;
112                 }
113
114                 BundleImpl bundle = (BundleImpl) m_oscar.getBundle(id);
115
116                 // The bundle may be uninstalled, so just ignore that case.
117
if (bundle == null)
118                 {
119                     continue;
120                 }
121
122                 // Ignore the package if its bundle is not resolved,
123
// active, or installed.
124
if ((bundle.getState() != Bundle.RESOLVED)
125                     && (bundle.getState() != Bundle.ACTIVE)
126                     && (bundle.getState() != Bundle.INSTALLED))
127                 {
128                     continue;
129                 }
130
131                 // If the security manager is set, then check if the
132
// exporting bundle is allowed to export the package,
133
// unless the bundle is the system bundle.
134
if ((System.getSecurityManager() != null) && (bundle.getBundleId() != 0))
135                 {
136                     URL JavaDoc url = null;
137                     try
138                     {
139                         url = new URL JavaDoc(bundle.getInfo().getLocation());
140                     }
141                     catch (MalformedURLException JavaDoc ex)
142                     {
143                         // For safety, ignore if we can't get its
144
// location URL.
145
continue;
146                     }
147                     try
148                     {
149                         AccessController.doPrivileged(
150                             new CheckExportPrivileged(url, pkgName));
151                     }
152                     catch (PrivilegedActionException ex)
153                     {
154                         // If we are here, then most likely the security
155
// check failed, so ignore this package.
156
continue;
157                     }
158                 }
159
160                 int[] tmpVersion = (int[])
161                     ImportSearchPolicy.getExportVersion(candidates[i], pkgName);
162
163                 // If this is the first match, then just select it.
164
if ((selModule == null) &&
165                     (compatPolicy.compare(pkgName, tmpVersion, pkgName, selVersion) >= 0))
166                 {
167                     selModule = candidates[i];
168                     selVersion = tmpVersion;
169                     selBundle = bundle;
170                 }
171                 // If the current export package version is greater
172
// than the selected export package version, then
173
// record it instead.
174
else if (compatPolicy.compare(pkgName, tmpVersion, pkgName, selVersion) > 0)
175                 {
176                     selModule = candidates[i];
177                     selVersion = tmpVersion;
178                     selBundle = bundle;
179                 }
180                 // If the current export package version is equal to
181
// the selected export package version, but has a lower
182
// bundle ID, then record it instead.
183
else if ((compatPolicy.compare(pkgName, tmpVersion, pkgName, selVersion) == 0)
184                     && (bundle.getBundleId() < selBundle.getBundleId()))
185                 {
186                     selModule = candidates[i];
187                     selVersion = tmpVersion;
188                     selBundle = bundle;
189                 }
190             }
191
192             m_resolvedPackageMap.put(pkgName, selModule);
193             m_resolvedModuleMap.put(selModule, selModule);
194         }
195         // See if the previously selected export module satisfies
196
// the current request, otherwise return null.
197
else
198         {
199             int[] selVersion = (int[])
200                 ImportSearchPolicy.getExportVersion(selModule, pkgName);
201             Module tmpModule = selModule;
202             selModule = null;
203             if (compatPolicy.isCompatible(pkgName, selVersion, pkgName, version))
204             {
205                 selModule = tmpModule;
206             }
207         }
208
209         return selModule;
210     }
211
212     public void moduleAdded(ModuleEvent event)
213     {
214     }
215
216     public void moduleReset(ModuleEvent event)
217     {
218         moduleRemoved(event);
219     }
220
221     public synchronized void moduleRemoved(ModuleEvent event)
222     {
223 // TODO: Synchronization?
224
// If the module that was removed was chosen for
225
// exporting packages, then flush it from our
226
// data structures.
227
if (m_resolvedModuleMap.get(event.getModule()) != null)
228         {
229             // Remove from module map.
230
m_resolvedModuleMap.remove(event.getModule());
231             // Remove each exported package from package map.
232
Iterator JavaDoc iter = m_resolvedPackageMap.entrySet().iterator();
233             while (iter.hasNext())
234             {
235                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
236                 if (entry.getValue() == event.getModule())
237                 {
238                     iter.remove();
239                 }
240             }
241         }
242     }
243
244     /**
245      * This simple class is used to perform the privileged action of
246      * checking if a bundle has permission to export a package.
247     **/

248     private static class CheckExportPrivileged implements PrivilegedExceptionAction
249     {
250         private URL JavaDoc m_url = null;
251         private String JavaDoc m_pkgName = null;
252
253         public CheckExportPrivileged(URL JavaDoc url, String JavaDoc pkgName)
254         {
255             m_url = url;
256             m_pkgName = pkgName;
257         }
258
259         public Object JavaDoc run() throws Exception JavaDoc
260         {
261             // Get permission collection for code source; we cannot
262
// call AccessController.checkPermission() directly since
263
// the bundle's code is not on the access context yet and
264
// might never be if it is only a library bundle, for example.
265
CodeSource cs = new CodeSource(m_url, (Certificate JavaDoc[]) null);
266             PermissionCollection pc = Policy.getPolicy().getPermissions(cs);
267             PackagePermission perm = new PackagePermission(
268                 m_pkgName, PackagePermission.EXPORT);
269             if (!pc.implies(perm))
270             {
271                 throw new AccessControlException("access denied " + perm);
272             }
273
274             return null;
275         }
276     }
277 }
Popular Tags