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
020 package org.apache.xbean.osgi.bundle.util.equinox;
021
022 import java.io.IOException;
023 import java.net.URL;
024 import java.net.URLClassLoader;
025 import java.util.Enumeration;
026
027 import org.apache.xbean.osgi.bundle.util.BundleResourceHelper;
028 import org.apache.xbean.osgi.bundle.util.DelegatingBundle;
029 import org.apache.xbean.osgi.bundle.util.DelegatingBundleReference;
030 import org.osgi.framework.Bundle;
031 import 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 15:37:38 +0800 (Wed, 31 Aug 2011) $
041 */
042 public 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 }