You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ga...@apache.org on 2009/12/16 20:12:17 UTC

svn commit: r891387 - in /geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi: BundleClassLoader.java BundleDescription.java DictionaryMap.java

Author: gawor
Date: Wed Dec 16 19:12:17 2009
New Revision: 891387

URL: http://svn.apache.org/viewvc?rev=891387&view=rev
Log:
Improved BundleClassLoader to deletage META-INF resource lookups to wired bundles. Might come useful in some cases

Added:
    geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java   (with props)
Modified:
    geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleClassLoader.java
    geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleDescription.java

Modified: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleClassLoader.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleClassLoader.java?rev=891387&r1=891386&r2=891387&view=diff
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleClassLoader.java (original)
+++ geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleClassLoader.java Wed Dec 16 19:12:17 2009
@@ -21,21 +21,45 @@
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleReference;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
 
 /**
+ * ClassLoader for a {@link Bundle}. 
+ * <br/>
+ * In OSGi, resource lookup on resources in the <i>META-INF</i> directory using {@link Bundle#getResource(String)} or 
+ * {@link Bundle#getResources(String)} does not return the resources found in the wired bundles of the bundle 
+ * (wired via <i>Import-Package</i> or <i>DynamicImport-Package</i>). This class loader implementation provides 
+ * {@link #getResource(String) and {@link #getResources(String)} methods that do delegate such resource lookups to
+ * the wired bundles. 
+ * 
  * @version $Rev$ $Date$
  */
 public class BundleClassLoader extends ClassLoader implements BundleReference {
 
+    private final static String META_INF_1 = "META-INF/";
+    private final static String META_INF_2 = "/META-INF/";
+    
     private final Bundle bundle;
+    private boolean searchWiredBundles;
 
     public BundleClassLoader(Bundle bundle) {
+        this(bundle, true);
+    }
+    
+    public BundleClassLoader(Bundle bundle, boolean searchWiredBundles) {
         this.bundle = bundle;
+        this.searchWiredBundles = searchWiredBundles;
     }
 
     @Override
@@ -59,20 +83,110 @@
 
     @Override
     public URL getResource(String name) {
-        return bundle.getResource(name);
+        URL resource = bundle.getResource(name);
+        if (resource == null && isMetaInfResource(name)) {
+            LinkedHashSet<Bundle> wiredBundles = getWiredBundles();
+            Iterator<Bundle> iterator = wiredBundles.iterator();
+            while (iterator.hasNext() && resource == null) {                
+                resource = iterator.next().getResource(name);
+            }
+        }
+        return resource;
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public Enumeration<URL> getResources(String name) throws IOException {
-        Enumeration<URL> e = (Enumeration<URL>)bundle.getResources(name);
-        if (e == null) {
-            return Collections.enumeration(Collections.EMPTY_LIST);
+        Enumeration<URL> e = (Enumeration<URL>) bundle.getResources(name);
+        if (isMetaInfResource(name)) {
+            ArrayList<URL> allResources = new ArrayList<URL>();
+            addToList(allResources, e);
+            LinkedHashSet<Bundle> wiredBundles = getWiredBundles();
+            for (Bundle wiredBundle : wiredBundles) {
+                Enumeration<URL> resources = wiredBundle.getResources(name);
+                addToList(allResources, resources);
+            }
+            return Collections.enumeration(allResources);            
         } else {
-            return e;
+            if (e == null) {
+                return Collections.enumeration(Collections.EMPTY_LIST);
+            } else {
+                return e;
+            }
         }
     }
 
+    public void setSearchWiredBundles(boolean search) {
+        searchWiredBundles = search;
+    }
+    
+    public boolean getSearchWiredBundles() {
+        return searchWiredBundles;
+    }
+    
+    private boolean isMetaInfResource(String name) {
+        return searchWiredBundles && name != null && (name.startsWith(META_INF_1) || name.startsWith(META_INF_2));
+    }
+    
+    private LinkedHashSet<Bundle> getWiredBundles() {
+        ServiceReference reference = bundle.getBundleContext().getServiceReference(PackageAdmin.class.getName());
+        PackageAdmin packageAdmin = (PackageAdmin) bundle.getBundleContext().getService(reference);
+        
+        BundleDescription description = new BundleDescription(bundle.getHeaders());
+        
+        // handle static wire via Import-Package
+        List<BundleDescription.Package> imports = description.getExternalImports();
+        LinkedHashSet<Bundle> wiredBundles = new LinkedHashSet<Bundle>();
+        for (BundleDescription.Package packageImport : imports) {
+            ExportedPackage[] exports = packageAdmin.getExportedPackages(packageImport.getName());
+            Bundle wiredBundle = getWiredBundle(exports);
+            if (wiredBundle != null) {
+                wiredBundles.add(wiredBundle);
+            }
+        }
+                
+        // handle dynamic wire via DynamicImport-Package
+        if (!description.getDynamicImportPackage().isEmpty()) {
+            for (Bundle b : bundle.getBundleContext().getBundles()) {
+                if (!wiredBundles.contains(b)) {
+                    ExportedPackage[] exports = packageAdmin.getExportedPackages(b);
+                    Bundle wiredBundle = getWiredBundle(exports); 
+                    if (wiredBundle != null) {
+                        wiredBundles.add(wiredBundle);
+                    }
+                }
+            }
+        }
+        
+        bundle.getBundleContext().ungetService(reference);
+        
+        return wiredBundles;
+    }
+    
+    private Bundle getWiredBundle(ExportedPackage[] exports) {
+        if (exports != null) {
+            for (ExportedPackage exportedPackage : exports) {
+                Bundle[] importingBundles = exportedPackage.getImportingBundles();
+                if (importingBundles != null) {
+                    for (Bundle importingBundle : importingBundles) {
+                        if (importingBundle == bundle) {
+                            return exportedPackage.getExportingBundle();
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    private void addToList(List<URL> list, Enumeration<URL> enumeration) {
+        if (enumeration != null) {
+            while (enumeration.hasMoreElements()) {
+                list.add(enumeration.nextElement());
+            }
+        }
+    }
+    
     /**
      * Return the bundle instance backing this classloader.
      *

Modified: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleDescription.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleDescription.java?rev=891387&r1=891386&r2=891387&view=diff
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleDescription.java (original)
+++ geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/BundleDescription.java Wed Dec 16 19:12:17 2009
@@ -19,6 +19,7 @@
 package org.apache.geronimo.kernel.osgi;
 
 import java.util.ArrayList;
+import java.util.Dictionary;
 import java.util.List;
 import java.util.Map;
 
@@ -32,6 +33,10 @@
 
     private Map headers;
     
+    public BundleDescription(Dictionary dictionary) {
+        this.headers = new DictionaryMap(dictionary);
+    }
+    
     public BundleDescription(Map headers) {
         this.headers = headers;
     }
@@ -100,6 +105,20 @@
         return required;
     }
     
+    /**
+     * Returns a list of packages that are listed in <i>DynamicImport-Package</i> header.
+     */
+    public List<Package> getDynamicImportPackage() {
+        String headerValue = (String) headers.get(Constants.DYNAMICIMPORT_PACKAGE);
+        List<Package> imports = new ArrayList<Package>();
+        List<HeaderElement> elements = HeaderParser.parseHeader(headerValue);
+        for (HeaderElement element : elements) {
+            Package p = new Package(element.getName(), element.getAttributes(), element.getDirectives());
+            imports.add(p);
+        }
+        return imports;
+    }
+    
     public static class Package {
     
         private String name;
@@ -124,6 +143,13 @@
             return directives;
         }       
         
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("Name: ").append(name);
+            builder.append(", Attributes: ").append(attributes);
+            builder.append(", Directives: ").append(directives);
+            return builder.toString();
+        }
     }
-    
+        
 }

Added: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java?rev=891387&view=auto
==============================================================================
--- geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java (added)
+++ geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java Wed Dec 16 19:12:17 2009
@@ -0,0 +1,74 @@
+/**
+ * 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.geronimo.kernel.osgi;
+
+import java.util.AbstractMap;
+import java.util.Dictionary;
+import java.util.Set;
+
+/**
+ * Simple wrapper that exposes {@link Dictionary} class as a {@link Map}. 
+ * 
+ * @version $Rev$, $Date$
+ */
+public class DictionaryMap extends AbstractMap {
+
+    private final Dictionary dictionary;
+
+    public DictionaryMap(Dictionary dictionary) {
+        this.dictionary = dictionary;
+    }
+
+    @Override
+    public Object get(Object key) {
+        return dictionary.get(key);
+    }
+
+    @Override
+    public Object put(Object key, Object value) {
+        return dictionary.put(key, value);
+    }
+
+    @Override
+    public Object remove(Object key) {
+        return dictionary.remove(key);
+    }
+
+    @Override
+    public int size() {
+        return dictionary.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return dictionary.isEmpty();
+    }
+
+    @Override
+    public Set entrySet() {
+        // TODO: implement 
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Set keySet() {
+        // TODO: implement 
+        throw new UnsupportedOperationException();
+    }
+}

Propchange: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/server/trunk/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/osgi/DictionaryMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain