001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.xbean.osgi.bundle.util.equinox; 021 022import java.io.IOException; 023import java.net.URL; 024import java.net.URLClassLoader; 025import java.util.Enumeration; 026 027import org.apache.xbean.osgi.bundle.util.BundleResourceHelper; 028import org.apache.xbean.osgi.bundle.util.DelegatingBundle; 029import org.apache.xbean.osgi.bundle.util.DelegatingBundleReference; 030import org.osgi.framework.Bundle; 031import org.osgi.framework.BundleReference; 032 033/** 034 * ClassLoader for a {@link Bundle}. 035 * <br/> 036 * This ClassLoader implementation extends the {@link URLClassLoader} and converts resource "bundle" 037 * URLs (found in directories or embedded jar files) into regular <tt>jar</tt> URLs. 038 * This ClassLoader implementation will only work on Equinox framework. 039 * 040 * @version $Rev: 1163514 $ $Date: 2011-08-31 09:37:38 +0200 (Wed, 31 Aug 2011) $ 041 */ 042public class EquinoxBundleClassLoader extends URLClassLoader implements DelegatingBundleReference { 043 044 private final Bundle bundle; 045 private final BundleResourceHelper resourceHelper; 046 047 public EquinoxBundleClassLoader(Bundle bundle) { 048 this(bundle, 049 BundleResourceHelper.getSearchWiredBundles(true), 050 BundleResourceHelper.getConvertResourceUrls(true)); 051 } 052 053 public EquinoxBundleClassLoader(Bundle bundle, boolean searchWiredBundles, boolean convertResourceUrls) { 054 super(new URL[] {}); 055 this.bundle = bundle; 056 this.resourceHelper = new EquinoxBundleResourceHelper(bundle, searchWiredBundles, convertResourceUrls); 057 } 058 059 @Override 060 public String toString() { 061 return "[EquinoxBundleClassLoader] " + bundle; 062 } 063 064 @Override 065 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 066 Class clazz = bundle.loadClass(name); 067 if (resolve) { 068 resolveClass(clazz); 069 } 070 return clazz; 071 } 072 073 @Override 074 public URL getResource(String name) { 075 return resourceHelper.getResource(name); 076 } 077 078 @Override 079 public Enumeration<URL> findResources(String name) throws IOException { 080 return resourceHelper.getResources(name); 081 } 082 083 public void setSearchWiredBundles(boolean search) { 084 resourceHelper.setSearchWiredBundles(search); 085 } 086 087 public boolean getSearchWiredBundles() { 088 return resourceHelper.getSearchWiredBundles(); 089 } 090 091 public void setConvertResourceUrls(boolean convert) { 092 resourceHelper.setConvertResourceUrls(convert); 093 } 094 095 public boolean getConvertResourceUrls() { 096 return resourceHelper.getConvertResourceUrls(); 097 } 098 099 /** 100 * Return the bundle associated with this classloader. 101 * 102 * In most cases the bundle associated with the classloader is a regular framework bundle. 103 * However, in some cases the bundle associated with the classloader is a {@link DelegatingBundle}. 104 * In such cases, the <tt>unwrap</tt> parameter controls whether this function returns the 105 * {@link DelegatingBundle} instance or the main application bundle backing with the {@link DelegatingBundle}. 106 * 107 * @param unwrap If true and if the bundle associated with this classloader is a {@link DelegatingBundle}, 108 * this function will return the main application bundle backing with the {@link DelegatingBundle}. 109 * Otherwise, the bundle associated with this classloader is returned as is. 110 * @return The bundle associated with this classloader. 111 */ 112 public Bundle getBundle(boolean unwrap) { 113 if (unwrap && bundle instanceof DelegatingBundle) { 114 return ((DelegatingBundle) bundle).getMainBundle(); 115 } 116 return bundle; 117 } 118 119 /** 120 * Return the bundle associated with this classloader. 121 * 122 * This method calls {@link #getBundle(boolean) getBundle(true)} and therefore always returns a regular 123 * framework bundle. 124 * <br><br> 125 * Note: Some libraries use {@link BundleReference#getBundle()} to obtain a bundle for the given 126 * classloader and expect the returned bundle instance to be work with any OSGi API. Some of these API might 127 * not work if {@link DelegatingBundle} is returned. That is why this function will always return 128 * a regular framework bundle. See {@link #getBundle(boolean)} for more information. 129 * 130 * @return The bundle associated with this classloader. 131 */ 132 public Bundle getBundle() { 133 return getBundle(true); 134 } 135 136 @Override 137 public int hashCode() { 138 return bundle.hashCode(); 139 } 140 141 @Override 142 public boolean equals(Object other) { 143 if (other == this) { 144 return true; 145 } 146 if (other == null || !other.getClass().equals(getClass())) { 147 return false; 148 } 149 EquinoxBundleClassLoader otherBundleClassLoader = (EquinoxBundleClassLoader) other; 150 return this.bundle == otherBundleClassLoader.bundle; 151 } 152 153}