Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 72368 invoked from network); 28 Aug 2006 06:15:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 28 Aug 2006 06:15:20 -0000 Received: (qmail 14286 invoked by uid 500); 28 Aug 2006 06:15:20 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 14228 invoked by uid 500); 28 Aug 2006 06:15:19 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 14217 invoked by uid 99); 28 Aug 2006 06:15:19 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Aug 2006 23:15:19 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 27 Aug 2006 23:15:16 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id F3D281A981D; Sun, 27 Aug 2006 23:14:55 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r437551 [2/2] - in /geronimo/xbean/trunk: ./ xbean-classloader/ xbean-classloader/src/ xbean-classloader/src/main/java/org/apache/xbean/classloader/ xbean-classloader/src/main/java/org/apache/xbean/server/classloader/ xbean-classloader/src/... Date: Mon, 28 Aug 2006 06:14:50 -0000 To: scm@geronimo.apache.org From: adc@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060828061455.F3D281A981D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,107 @@ +/** + * 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.xbean.classloader; + +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.Arrays; + + +/** + * The NamedClassLoader is a simple extension to URLClassLoader that adds a name and a destroy method that cleans up + * the commons logging and JavaVM caches of the classloader. + * + * @author Dain Sundstrom + * @version $Id$ + * @since 2.0 + */ +public class NamedClassLoader extends URLClassLoader implements DestroyableClassLoader { + private final String name; + private boolean destroyed = false; + + /** + * Creates a named class loader with no parents. + * @param name the name of this class loader + * @param urls the urls from which this class loader will classes and resources + */ + public NamedClassLoader(String name, URL[] urls) { + super(urls); + this.name = name; + } + + /** + * Creates a named class loader as a child of the specified parent. + * @param name the name of this class loader + * @param urls the urls from which this class loader will classes and resources + * @param parent the parent of this class loader + */ + public NamedClassLoader(String name, URL[] urls, ClassLoader parent) { + super(urls, parent); + this.name = name; + } + + /** + * Creates a named class loader as a child of the specified parent and using the specified URLStreamHandlerFactory + * for accessing the urls.. + * @param name the name of this class loader + * @param urls the urls from which this class loader will classes and resources + * @param parent the parent of this class loader + * @param factory the URLStreamHandlerFactory used to access the urls + */ + public NamedClassLoader(String name, URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { + super(urls, parent, factory); + this.name = name; + } + + /** + * Check if this classloader has been destroyed + * @return + */ + public synchronized boolean isDestroyed() { + return destroyed; + } + + /** + * {@inheritDoc} + */ + public void destroy() { + synchronized(this) { + if (destroyed) return; + destroyed = true; + } + ClassLoaderUtil.destroy(this); + } + + /** + * Gets the name of this class loader. + * @return the name of this class loader + */ + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + public String toString() { + return "[" + getClass().getName() + ":" + + " name=" + getName() + + " urls=" + Arrays.asList(getURLs()) + + "]"; + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/NamedClassLoader.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,83 @@ +/** + * 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.xbean.classloader; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Collection; +import java.util.NoSuchElementException; + +/** + * @version $Rev$ $Date$ + */ +public class ResourceEnumeration implements Enumeration { + private Iterator iterator; + private final String resourceName; + private Object next; + + public ResourceEnumeration(Collection resourceLocations, String resourceName) { + this.iterator = resourceLocations.iterator(); + this.resourceName = resourceName; + } + + public boolean hasMoreElements() { + fetchNext(); + return (next != null); + } + + public Object nextElement() { + fetchNext(); + + // save next into a local variable and clear the next field + Object next = this.next; + this.next = null; + + // if we didn't have a next throw an exception + if (next == null) { + throw new NoSuchElementException(); + } + return next; + } + + private void fetchNext() { + if (iterator == null) { + return; + } + if (next != null) { + return; + } + + try { + while (iterator.hasNext()) { + ResourceLocation resourceLocation = (ResourceLocation) iterator.next(); + ResourceHandle resourceHandle = resourceLocation.getResourceHandle(resourceName); + if (resourceHandle != null) { + next = resourceHandle.getUrl(); + return; + } + } + // no more elements + // clear the iterator so it can be GCed + iterator = null; + } catch (IllegalStateException e) { + // Jar file was closed... this means the resource finder was destroyed + // clear the iterator so it can be GCed + iterator = null; + throw e; + } + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceEnumeration.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,55 @@ +/** + * 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.xbean.classloader; + +import java.net.URL; +import java.util.Enumeration; + +/** + * Abstraction of resource searching policy. Given resource name, the resource + * finder performs implementation-specific lookup, and, if it is able to locate + * the resource, returns the {@link AbstractResourceHandle handle(s)} or URL(s) of it. + * + * @version $Rev$ $Date$ + */ +public interface ResourceFinder { + /** + * Find the resource by name and return URL of it if found. + * + * @param name the resource name + * @return resource URL or null if resource was not found + */ + public URL findResource(String name); + + /** + * Find all resources with given name and return enumeration of their URLs. + * + * @param name the resource name + * @return enumeration of resource URLs (possibly empty). + */ + public Enumeration findResources(String name); + + /** + * Get the resource by name and, if found, open connection to it and return + * the {@link AbstractResourceHandle handle} of it. + * + * @param name the resource name + * @return resource handle or null if resource was not found + */ + public ResourceHandle getResource(String name); + +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceFinder.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,97 @@ +/** + * 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.xbean.classloader; + +import java.net.URL; +import java.io.InputStream; +import java.io.IOException; +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.security.cert.Certificate; + +/** + * This is a handle (a connection) to some resource, which may + * be a class, native library, text file, image, etc. Handles are returned + * by a ResourceFinder. A resource handle allows easy access to the resource data + * (using methods {@link #getInputStream} or {@link #getBytes}) as well as + * access resource metadata, such as attributes, certificates, etc. + *

+ * As soon as the handle is no longer in use, it should be explicitly + * {@link #close}d, similarly to I/O streams. + * + * @version $Rev$ $Date$ + */ +public interface ResourceHandle { + /** + * Return the name of the resource. The name is a "/"-separated path + * name that identifies the resource. + */ + String getName(); + + /** + * Returns the URL of the resource. + */ + URL getUrl(); + + /** + * Does this resource refer to a directory. Directory resources are commly used + * as the basis for a URL in client application. A directory resource has 0 bytes for it's content. + */ + boolean isDirectory(); + + /** + * Returns the CodeSource URL for the class or resource. + */ + URL getCodeSourceUrl(); + + /** + * Returns and InputStream for reading this resource data. + */ + InputStream getInputStream() throws IOException; + + /** + * Returns the length of this resource data, or -1 if unknown. + */ + int getContentLength(); + + /** + * Returns this resource data as an array of bytes. + */ + byte[] getBytes() throws IOException; + + /** + * Returns the Manifest of the JAR file from which this resource + * was loaded, or null if none. + */ + Manifest getManifest() throws IOException; + + /** + * Return the Certificates of the resource, or null if none. + */ + Certificate[] getCertificates(); + + /** + * Return the Attributes of the resource, or null if none. + */ + Attributes getAttributes() throws IOException; + + /** + * Closes a connection to the resource indentified by this handle. Releases + * any I/O objects associated with the handle. + */ + void close(); +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceHandle.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,32 @@ +/** + * 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.xbean.classloader; + +import java.util.jar.Manifest; +import java.io.IOException; +import java.net.URL; + +/** + * This is a location which is searched by + * @version $Rev$ $Date$ + */ +public interface ResourceLocation { + URL getCodeSource(); + ResourceHandle getResourceHandle(String resourceName); + Manifest getManifest() throws IOException; + void close(); +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ResourceLocation.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,41 @@ +/** + * 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.xbean.classloader; + +import org.springframework.beans.factory.FactoryBean; + +/** + * A factory bean to expose the current thread context class loader. + * + * * @org.apache.xbean.XBean namespace="http://xbean.apache.org/schemas/classloader" + * element="threadContextClassLoader" description="References the ClassLoader of the current thread context" + * @version $Revision$ + */ +public class ThreadContextClassLoaderFactoryBean implements FactoryBean { + + public Object getObject() throws Exception { + return Thread.currentThread().getContextClassLoader(); + } + + public Class getObjectType() { + return ClassLoader.class; + } + + public boolean isSingleton() { + return true; + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/ThreadContextClassLoaderFactoryBean.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,63 @@ +/** + * 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.xbean.classloader; + +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * @version $Rev$ $Date$ + */ +public final class UnionEnumeration implements Enumeration { + private final LinkedList enumerations = new LinkedList(); + + public UnionEnumeration(List enumerations) { + this.enumerations.addAll(enumerations); + } + + public UnionEnumeration(Enumeration first, Enumeration second) { + if (first == null) throw new NullPointerException("first is null"); + if (second == null) throw new NullPointerException("second is null"); + + enumerations.add(first); + enumerations.add(second); + } + + public boolean hasMoreElements() { + while (!enumerations.isEmpty()) { + Enumeration enumeration = (Enumeration) enumerations.getFirst(); + if (enumeration.hasMoreElements()) { + return true; + } + enumerations.removeFirst(); + } + return false; + } + + public Object nextElement() { + while (!enumerations.isEmpty()) { + Enumeration enumeration = (Enumeration) enumerations.getFirst(); + if (enumeration.hasMoreElements()) { + return enumeration.nextElement(); + } + enumerations.removeFirst(); + } + throw new NoSuchElementException(); + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UnionEnumeration.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,296 @@ +/** + * 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.xbean.classloader; + +import java.io.File; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.jar.JarFile; + +/** + * @version $Rev$ $Date$ + */ +public class UrlResourceFinder implements ResourceFinder { + private final Object lock = new Object(); + + private final LinkedHashSet urls = new LinkedHashSet(); + private final LinkedHashMap classPath = new LinkedHashMap(); + private final LinkedHashSet watchedFiles = new LinkedHashSet(); + + private boolean destroyed = false; + + public UrlResourceFinder() { + } + + public UrlResourceFinder(URL[] urls) { + addUrls(urls); + } + + public void destroy() { + synchronized (lock) { + if (destroyed) { + return; + } + destroyed = true; + urls.clear(); + for (Iterator iterator = classPath.values().iterator(); iterator.hasNext();) { + ResourceLocation resourceLocation = (ResourceLocation) iterator.next(); + resourceLocation.close(); + } + classPath.clear(); + } + } + + public ResourceHandle getResource(String resourceName) { + synchronized (lock) { + if (destroyed) { + return null; + } + for (Iterator iterator = getClassPath().entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + ResourceLocation resourceLocation = (ResourceLocation) entry.getValue(); + ResourceHandle resourceHandle = resourceLocation.getResourceHandle(resourceName); + if (resourceHandle != null && !resourceHandle.isDirectory()) { + return resourceHandle; + } + } + } + return null; + } + + public URL findResource(String resourceName) { + synchronized (lock) { + if (destroyed) { + return null; + } + for (Iterator iterator = getClassPath().entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = (Map.Entry) iterator.next(); + ResourceLocation resourceLocation = (ResourceLocation) entry.getValue(); + ResourceHandle resourceHandle = resourceLocation.getResourceHandle(resourceName); + if (resourceHandle != null) { + return resourceHandle.getUrl(); + } + } + } + return null; + } + + public Enumeration findResources(String resourceName) { + synchronized (lock) { + return new ResourceEnumeration(new ArrayList(getClassPath().values()), resourceName); + } + } + + public void addUrl(URL url) { + addUrls(Collections.singletonList(url)); + } + + public URL[] getUrls() { + synchronized (lock) { + return (URL[]) urls.toArray(new URL[urls.size()]); + } + } + + /** + * Adds an array of urls to the end of this class loader. + * @param urls the URLs to add + */ + protected void addUrls(URL[] urls) { + addUrls(Arrays.asList(urls)); + } + + /** + * Adds a list of urls to the end of this class loader. + * @param urls the URLs to add + */ + protected void addUrls(List urls) { + synchronized (lock) { + if (destroyed) { + throw new IllegalStateException("UrlResourceFinder has been destroyed"); + } + + boolean shouldRebuild = this.urls.addAll(urls); + if (shouldRebuild) { + rebuildClassPath(); + } + } + } + + private LinkedHashMap getClassPath() { + assert Thread.holdsLock(lock): "This method can only be called while holding the lock"; + + for (Iterator iterator = watchedFiles.iterator(); iterator.hasNext();) { + File file = (File) iterator.next(); + if (file.canRead()) { + rebuildClassPath(); + break; + } + } + + return classPath; + } + + /** + * Rebuilds the entire class path. This class is called when new URLs are added or one of the watched files + * becomes readable. This method will not open jar files again, but will add any new entries not alredy open + * to the class path. If any file based url is does not exist, we will watch for that file to appear. + */ + private void rebuildClassPath() { + assert Thread.holdsLock(lock): "This method can only be called while holding the lock"; + + // copy all of the existing locations into a temp map and clear the class path + Map existingJarFiles = new LinkedHashMap(classPath); + classPath.clear(); + + LinkedList locationStack = new LinkedList(urls); + try { + while (!locationStack.isEmpty()) { + URL url = (URL) locationStack.removeFirst(); + + // Skip any duplicate urls in the claspath + if (classPath.containsKey(url)) { + continue; + } + + // Check is this URL has already been opened + ResourceLocation resourceLocation = (ResourceLocation) existingJarFiles.remove(url); + + // If not opened, cache the url and wrap it with a resource location + if (resourceLocation == null) { + try { + File file = cacheUrl(url); + resourceLocation = createResourceLocation(url, file); + } catch (FileNotFoundException e) { + // if this is a file URL, the file doesn't exist yet... watch to see if it appears later + if ("file".equals(url.getProtocol())) { + File file = new File(url.getPath()); + watchedFiles.add(file); + continue; + + } + } catch (IOException ignored) { + // can't seem to open the file... this is most likely a bad jar file + // so don't keep a watch out for it because that would require lots of checking + // Dain: We may want to review this decision later + continue; + } + } + + // add the jar to our class path + classPath.put(resourceLocation.getCodeSource(), resourceLocation); + + // push the manifest classpath on the stack (make sure to maintain the order) + List manifestClassPath = getManifestClassPath(resourceLocation); + locationStack.addAll(0, manifestClassPath); + } + } catch (Error e) { + destroy(); + throw e; + } + + for (Iterator iterator = existingJarFiles.values().iterator(); iterator.hasNext();) { + ResourceLocation resourceLocation = (ResourceLocation) iterator.next(); + resourceLocation.close(); + } + } + + protected File cacheUrl(URL url) throws IOException { + if (!"file".equals(url.getProtocol())) { + // download the jar + throw new Error("Only local file jars are supported " + url); + } + + File file = new File(url.getPath()); + if (!file.exists()) { + throw new FileNotFoundException(file.getAbsolutePath()); + } + if (!file.canRead()) { + throw new IOException("File is not readable: " + file.getAbsolutePath()); + } + return file; + } + + protected ResourceLocation createResourceLocation(URL codeSource, File cacheFile) throws IOException { + if (!cacheFile.exists()) { + throw new FileNotFoundException(cacheFile.getAbsolutePath()); + } + if (!cacheFile.canRead()) { + throw new IOException("File is not readable: " + cacheFile.getAbsolutePath()); + } + + ResourceLocation resourceLocation = null; + if (cacheFile.isDirectory()) { + // DirectoryResourceLocation will only return "file" URLs within this directory + // do not user the DirectoryResourceLocation for non file based urls + resourceLocation = new DirectoryResourceLocation(cacheFile); + } else { + resourceLocation = new JarResourceLocation(codeSource, new JarFile(cacheFile)); + } + return resourceLocation; + } + + private List getManifestClassPath(ResourceLocation resourceLocation) { + try { + // get the manifest, if possible + Manifest manifest = resourceLocation.getManifest(); + if (manifest == null) { + // some locations don't have a manifest + return Collections.EMPTY_LIST; + } + + // get the class-path attribute, if possible + String manifestClassPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); + if (manifestClassPath == null) { + return Collections.EMPTY_LIST; + } + + // build the urls... + // the class-path attribute is space delimited + URL codeSource = resourceLocation.getCodeSource(); + LinkedList classPathUrls = new LinkedList(); + for (StringTokenizer tokenizer = new StringTokenizer(manifestClassPath, " "); tokenizer.hasMoreTokens();) { + String entry = tokenizer.nextToken(); + try { + // the class path entry is relative to the resource location code source + URL entryUrl = new URL(codeSource, entry); + classPathUrls.addLast(entryUrl); + } catch (MalformedURLException ignored) { + // most likely a poorly named entry + } + } + return classPathUrls; + } catch (IOException ignored) { + // error opening the manifest + return Collections.EMPTY_LIST; + } + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/main/java/org/apache/xbean/classloader/UrlResourceFinder.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,32 @@ +/** + * 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.xbean.classloader; + +import java.net.URL; + +/** + * Test the JarFileClassLoader. + * + * @author Dain Sundstrom + * @version $Id$ + * @since 2.0 + */ +public class JarFileClassLoaderTest extends MultiParentClassLoaderTest { + protected MultiParentClassLoader createClassLoader(String name, URL[] urls, ClassLoader[] parents) { + return new JarFileClassLoader(name, urls, parents); + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/JarFileClassLoaderTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,360 @@ +/** + * 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.xbean.classloader; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.SortedSet; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +import junit.framework.TestCase; +import net.sf.cglib.core.DefaultGeneratorStrategy; +import net.sf.cglib.core.NamingPolicy; +import net.sf.cglib.core.Predicate; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.NoOp; + +/** + * Tests the MultiParentClassLoader including classloading and resource loading. + * @author Dain Sundstrom + * @version $Id$ + * @since 2.0 + */ +public class MultiParentClassLoaderTest extends TestCase { + private static final String CLASS_NAME = "TestClass"; + private static final String ENTRY_NAME = "foo"; + private static final String ENTRY_VALUE = "bar"; + private File[] files; + private static final String NON_EXISTANT_RESOURCE = "non-existant-resource"; + private static final String NON_EXISTANT_CLASS = "NonExistant.class"; + private URLClassLoader[] parents; + private File myFile; + private MultiParentClassLoader classLoader; + private static final String NAME = "my test class loader"; + + /** + * Verify that the test jars are valid. + * @throws Exception if a problem occurs + */ + public void testTestJars() throws Exception { + for (int i = 0; i < files.length; i++) { + File file = files[i]; + JarFile jarFile = new JarFile(files[i]); + String urlString = "jar:" + file.toURL() + "!/" + ENTRY_NAME; + URL url = new URL(files[i].toURL(), urlString); + assertStreamContains(ENTRY_VALUE + i, url.openStream()); + jarFile.close(); + + URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { file.toURL() } ); + // clazz shared by all + Class clazz = urlClassLoader.loadClass(CLASS_NAME); + assertNotNull(clazz); + assertTrue(SortedSet.class.isAssignableFrom(clazz)); + + // clazz specific to this jar + clazz = urlClassLoader.loadClass(CLASS_NAME + i); + assertNotNull(clazz); + assertTrue(SortedSet.class.isAssignableFrom(clazz)); + + // resource shared by all jars + InputStream in = urlClassLoader.getResourceAsStream(ENTRY_NAME ); + assertStreamContains("Should have found value from parent " + i, ENTRY_VALUE + i, in); + + // resource specific to this jar + in = urlClassLoader.getResourceAsStream(ENTRY_NAME + i); + assertStreamContains("Should have found value from parent " + i, ENTRY_VALUE + i + ENTRY_VALUE, in); + } + } + + /** + * Verify the get name method returns the name provided to the constructor. + */ + public void testGetName() { + assertEquals(NAME, classLoader.getName()); + } + + /** + * Verufy that the getParents method returns a different array from the one passed to the constructor and that the + * parents are in the same order. + */ + public void testGetParents() { + ClassLoader[] actualParents = classLoader.getParents(); + assertNotSame(parents, actualParents); + assertEquals(parents.length, actualParents.length); + for (int i = 0; i < actualParents.length; i++) { + assertEquals(parents[i], actualParents[i]); + } + } + + /** + * Test loadClass loads in preference of the parents, in order, and then the local urls. + * @throws Exception if a problem occurs + */ + public void testLoadClass() throws Exception { + // load class specific to my class loader + Class clazz = classLoader.loadClass(CLASS_NAME + 33); + assertNotNull(clazz); + assertTrue(SortedSet.class.isAssignableFrom(clazz)); + assertEquals(classLoader, clazz.getClassLoader()); + + // load class specific to each parent class loader + for (int i = 0; i < parents.length; i++) { + URLClassLoader parent = parents[i]; + clazz = classLoader.loadClass(CLASS_NAME + i); + assertNotNull(clazz); + assertTrue(SortedSet.class.isAssignableFrom(clazz)); + assertEquals(parent, clazz.getClassLoader()); + } + + // class shared by all class loaders + clazz = classLoader.loadClass(CLASS_NAME); + assertNotNull(clazz); + assertTrue(SortedSet.class.isAssignableFrom(clazz)); + assertEquals(parents[0], clazz.getClassLoader()); + } + + /** + * Test that an attempt to load a non-existant class causes a ClassNotFoundException. + */ + public void testLoadNonExistantClass() { + try { + classLoader.loadClass(NON_EXISTANT_CLASS); + fail("loadClass should have thrown a ClassNotFoundException"); + } catch (ClassNotFoundException e) { + // expected + } + } + + /** + * Test getResourceAsStream loads in preference of the parents, in order, and then the local urls. + * @throws Exception if a problem occurs + */ + public void testGetResourceAsStream() throws Exception { + InputStream in = classLoader.getResourceAsStream(ENTRY_NAME + 33); + assertStreamContains("Should have found value from my file", ENTRY_VALUE + 33 + ENTRY_VALUE, in); + + for (int i = 0; i < parents.length; i++) { + in = classLoader.getResourceAsStream(ENTRY_NAME + i); + assertStreamContains("Should have found value from parent " + i, ENTRY_VALUE + i + ENTRY_VALUE, in); + } + + in = classLoader.getResourceAsStream(ENTRY_NAME); + assertStreamContains("Should have found value from first parent", ENTRY_VALUE + 0, in); + } + + /** + * Test getResourceAsStream returns null when attempt is made to loade a non-existant resource. + * @throws Exception if a problem occurs + */ + public void testGetNonExistantResourceAsStream() throws Exception { + InputStream in = classLoader.getResourceAsStream(NON_EXISTANT_RESOURCE); + assertNull(in); + } + + /** + * Test getResource loads in preference of the parents, in order, and then the local urls. + * @throws Exception if a problem occurs + */ + public void testGetResource() throws Exception { + URL resource = classLoader.getResource(ENTRY_NAME + 33); + assertURLContains("Should have found value from my file", ENTRY_VALUE + 33 + ENTRY_VALUE, resource); + + for (int i = 0; i < parents.length; i++) { + resource = classLoader.getResource(ENTRY_NAME + i); + assertURLContains("Should have found value from parent " + i, ENTRY_VALUE + i + ENTRY_VALUE, resource); + } + + resource = classLoader.getResource(ENTRY_NAME); + assertURLContains("Should have found value from first parent", ENTRY_VALUE + 0, resource); + } + + /** + * Test getResource returns null when attempt is made to loade a non-existant resource. + * @throws Exception if a problem occurs + */ + public void testGetNonExistantResource() throws Exception { + URL resource = classLoader.getResource(NON_EXISTANT_RESOURCE); + assertNull(resource); + } + + /** + * Test getResource returns an enumeration in preference of the parents, in order, and then the local urls. + * @throws Exception if a problem occurs + */ + public void testGetResources() throws Exception { + Enumeration resources = classLoader.getResources(ENTRY_NAME); + assertNotNull(resources); + assertTrue(resources.hasMoreElements()); + + // there should be one entry for each parent + for (int i = 0; i < parents.length; i++) { + URL resource = (URL) resources.nextElement(); + assertURLContains("Should have found value from parent " + i, ENTRY_VALUE + i, resource); + } + + // and one entry from my url + assertTrue(resources.hasMoreElements()); + URL resource = (URL) resources.nextElement(); + assertURLContains("Should have found value from my file", ENTRY_VALUE + 33, resource); + } + + /** + * Test getResources returns an empty enumeration when attempt is made to loade a non-existant resource. + * @throws Exception if a problem occurs + */ + public void testGetNonExistantResources() throws Exception { + Enumeration resources = classLoader.getResources(NON_EXISTANT_RESOURCE); + assertNotNull(resources); + assertFalse(resources.hasMoreElements()); + } + + private void assertStreamContains(String expectedValue, InputStream in) throws IOException { + assertStreamContains(null, expectedValue, in); + } + + private void assertStreamContains(String message, String expectedValue, InputStream in) throws IOException { + String entryValue; + try { + StringBuffer stringBuffer = new StringBuffer(); + byte[] bytes = new byte[4000]; + for (int count = in.read(bytes); count != -1; count = in.read(bytes)) { + stringBuffer.append(new String(bytes, 0, count)); + } + entryValue = stringBuffer.toString(); + } finally { + in.close(); + } + assertEquals(message, expectedValue, entryValue); + } + + private void assertURLContains(String message, String expectedValue, URL resource) throws IOException { + InputStream in; + assertNotNull(resource); + in = resource.openStream(); + assertStreamContains(message, expectedValue, in); + } + + private static void assertFileExists(File file) { + assertTrue("File should exist: " + file, file.canRead()); + } + + private static void assertFileNotExists(File file) { + assertTrue("File should not exist: " + file, !file.canRead()); + } + + protected void setUp() throws Exception { + super.setUp(); + files = new File[3]; + for (int i = 0; i < files.length; i++) { + files[i] = createJarFile(i); + } + + parents = new URLClassLoader[3]; + for (int i = 0; i < parents.length; i++) { + parents[i] = new URLClassLoader(new URL[]{files[i].toURL()}); + } + + myFile = createJarFile(33); + classLoader = createClassLoader(NAME, new URL[]{myFile.toURL()}, parents); + } + + /** + * Creates the class loader to test. + * @param name the name of the classloader + * @param urls the urls to load classes and resources from + * @param parents the parents of the class loader + * @return the class loader to test + */ + protected MultiParentClassLoader createClassLoader(String name, URL[] urls, ClassLoader[] parents) { + return new MultiParentClassLoader(name, urls, parents); + } + + private static File createJarFile(int i) throws IOException { + File file = File.createTempFile("test-" + i + "-", ".jar"); + + FileOutputStream out = new FileOutputStream(file); + JarOutputStream jarOut = new JarOutputStream(out); + + // common class shared by everyone + jarOut.putNextEntry(new JarEntry(CLASS_NAME + ".class")); + jarOut.write(createClass(CLASS_NAME)); + + // class only available in this jar + jarOut.putNextEntry(new JarEntry(CLASS_NAME + i + ".class")); + jarOut.write(createClass(CLASS_NAME + i)); + + // common resource shared by everyone + jarOut.putNextEntry(new JarEntry(ENTRY_NAME)); + jarOut.write((ENTRY_VALUE + i).getBytes()); + + // resource only available in this jar + jarOut.putNextEntry(new JarEntry(ENTRY_NAME + i)); + jarOut.write((ENTRY_VALUE + i + ENTRY_VALUE).getBytes()); + + jarOut.close(); + out.close(); + + assertFileExists(file); + return file; + } + + private static byte[] createClass(final String name) { + Enhancer enhancer = new Enhancer(); + enhancer.setNamingPolicy(new NamingPolicy() { + public String getClassName(String prefix, String source, Object key, Predicate names) { + return name; + } + }); + enhancer.setClassLoader(new URLClassLoader(new URL[0])); + enhancer.setSuperclass(Object.class); + enhancer.setInterfaces(new Class[]{SortedSet.class}); + enhancer.setCallbackTypes(new Class[]{NoOp.class}); + enhancer.setUseFactory(false); + ByteCode byteCode = new ByteCode(); + enhancer.setStrategy(byteCode); + enhancer.createClass(); + + return byteCode.getByteCode(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + for (int i = 0; i < files.length; i++) { + files[i].delete(); + } + } + + private static class ByteCode extends DefaultGeneratorStrategy { + private byte[] byteCode; + + public byte[] transform(byte[] byteCode) { + this.byteCode = byteCode; + return byteCode; + } + + public byte[] getByteCode() { + return byteCode; + } + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/MultiParentClassLoaderTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java?rev=437551&view=auto ============================================================================== --- geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java (added) +++ geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java Sun Aug 27 23:14:47 2006 @@ -0,0 +1,487 @@ +/** + * 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.xbean.classloader; + +import java.net.URL; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileNotFoundException; + +import junit.framework.TestCase; + +/** + * @version $Rev$ $Date$ + */ +public class UrlResourceFinderTest extends TestCase { + private File basedir = new File(System.getProperty("basedir")); + private File jarFile; + private Manifest manifest; + private Attributes resourceAttributes; + private File alternateJarFile; + private File testResource; + + /** + * There are 2 "jars" with a "resource" inside. Make sure the enumeration has exactly 2 elements and + * that hasMoreElements() doesn't advance the iterator. + * + * @throws Exception + */ + public void testResourceEnumeration() throws Exception { + URL jar1 = new File(basedir, "src/test-data/resourceFinderTest/jar1/").toURL(); + URL jar2 = new File(basedir, "src/test-data/resourceFinderTest/jar2/").toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar1, jar2}); + + Enumeration enumeration = resourceFinder.findResources("resource"); + + // resource1 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource1 = (URL) enumeration.nextElement(); + assertNotNull(resource1); + assertEquals("resource1", toString(resource1.openStream())); + + // resource2 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource2 = (URL) enumeration.nextElement(); + assertNotNull(resource2); + assertEquals("resource2", toString(resource2.openStream())); + assertFalse(enumeration.hasMoreElements()); + } + + public void testDirectoryResource() throws Exception { + URL jar = new File(basedir, "src/test-data/resourceFinderTest/jar1/").toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + + ResourceHandle resource = resourceFinder.getResource("resource"); + assertNotNull(resource); + + // handle.getBytes() + assertEquals("resource1", new String(resource.getBytes())); + + // handle.getInputStream() + assertEquals("resource1", toString(resource.getInputStream())); + + // handle.getUrl() + URL url = resource.getUrl(); + assertEquals("resource1", toString(url.openStream())); + + // copy the url and verify we can still get the data + URL copyUrl = new URL(url.toExternalForm()); + assertEquals("resource1", toString(copyUrl.openStream())); + + // resourceFinder.findResource + URL directUrl = resourceFinder.findResource("resource"); + assertEquals("resource1", toString(directUrl.openStream())); + assertEquals("resource1", toString(new URL(directUrl.toExternalForm()).openStream())); + + // handle.getContentLength() + assertEquals("resource1".length(), resource.getContentLength()); + + // handle.getName() + assertEquals("resource", resource.getName()); + + // handle.getAttributes() + assertNull(resource.getAttributes()); + + // handle.getManifest() + assertNull(resource.getManifest()); + } + + public void testJarResource() throws Exception { + URL jar = jarFile.toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + + ResourceHandle resource = resourceFinder.getResource("resource"); + assertNotNull(resource); + + // handle.getBytes() + assertEquals("resource3", new String(resource.getBytes())); + + // handle.getInputStream() + assertEquals("resource3", toString(resource.getInputStream())); + + // handle.getUrl() + URL url = resource.getUrl(); + assertEquals("resource3", toString(url.openStream())); + + // copy the url and verify we can still get the data + URL copyUrl = new URL(url.toExternalForm()); + assertEquals("resource3", toString(copyUrl.openStream())); + + // resourceFinder.findResource + URL directUrl = resourceFinder.findResource("resource"); + assertEquals("resource3", toString(directUrl.openStream())); + assertEquals("resource3", toString(new URL(directUrl.toExternalForm()).openStream())); + + // handle.getContentLength() + assertEquals("resource3".length(), resource.getContentLength()); + + // handle.getName() + assertEquals("resource", resource.getName()); + + // handle.getAttributes() + assertEquals(resourceAttributes, resource.getAttributes()); + + // handle.getManifest() + assertEquals(manifest, resource.getManifest()); + } + + public void testAddURL() throws Exception { + URL jar1 = new File(basedir, "src/test-data/resourceFinderTest/jar1/").toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar1}); + + Enumeration enumeration = resourceFinder.findResources("resource"); + + // resource1 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource1 = (URL) enumeration.nextElement(); + assertNotNull(resource1); + assertEquals("resource1", toString(resource1.openStream())); + assertFalse(enumeration.hasMoreElements()); + + // addUrl + URL jar2 = new File(basedir, "src/test-data/resourceFinderTest/jar2/").toURL(); + resourceFinder.addUrl(jar2); + + // getResource should find the first jar only + ResourceHandle resource = resourceFinder.getResource("resource"); + assertNotNull(resource); + assertEquals("resource1", new String(resource.getBytes())); + + // findResource should find the first jar only + resource1 = resourceFinder.findResource("resource"); + assertEquals("resource1", toString(resource1.openStream())); + + // findResouces should see both jars + enumeration = resourceFinder.findResources("resource"); + + // resource1 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + resource1 = (URL) enumeration.nextElement(); + assertNotNull(resource1); + assertEquals("resource1", toString(resource1.openStream())); + assertTrue(enumeration.hasMoreElements()); + + // resource2 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource2 = (URL) enumeration.nextElement(); + assertNotNull(resource2); + assertEquals("resource2", toString(resource2.openStream())); + assertFalse(enumeration.hasMoreElements()); + } + + public void testConcurrentAddURL() throws Exception { + URL jar1 = new File(basedir, "src/test-data/resourceFinderTest/jar1/").toURL(); + URL jar2 = new File(basedir, "src/test-data/resourceFinderTest/jar2/").toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar1, jar2}); + + Enumeration enumeration = resourceFinder.findResources("resource"); + + // resource1 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource1 = (URL) enumeration.nextElement(); + assertNotNull(resource1); + assertEquals("resource1", toString(resource1.openStream())); + assertTrue(enumeration.hasMoreElements()); + + // + // addURL + // + URL newJar = jarFile.toURL(); + resourceFinder.addUrl(newJar); + + // new resources should be available + // getResource should find the first jar only + ResourceHandle jar3Resouce = resourceFinder.getResource("jar3"); + assertNotNull(jar3Resouce); + assertEquals("jar3", new String(jar3Resouce.getBytes())); + + // findResource should find the first jar only + URL jar3Url = resourceFinder.findResource("jar3"); + assertEquals("jar3", toString(jar3Url.openStream())); + + // + // enumeration from above should still be valid, but only see the resources available at the time it was created + // + + // resource2 + assertTrue(enumeration.hasMoreElements()); + assertTrue(enumeration.hasMoreElements()); + URL resource2 = (URL) enumeration.nextElement(); + assertNotNull(resource2); + assertEquals("resource2", toString(resource2.openStream())); + assertFalse(enumeration.hasMoreElements()); + } + + public void testDirectoryDestroy() throws Exception { + URL jar = new File(basedir, "src/test-data/resourceFinderTest/jar1/").toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + assertDestroyed(resourceFinder, "resource1", null); + } + + public void testJarDestroy() throws Exception { + URL jar = jarFile.toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + assertDestroyed(resourceFinder, "resource3", manifest); + } + + public void testUrlCopy() throws Exception { + URL jar = jarFile.toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + + // get the resource + URL resource = resourceFinder.findResource("resource"); + assertNotNull(resource); + assertEquals("resource3", toString(resource.openStream())); + + // copy resource with string + URL stringCopy = new URL(resource.toExternalForm()); + assertEquals("resource3", toString(stringCopy.openStream())); + + // copy resource perserving the url handler + URL handlerCopy = new URL(resource, resource.toExternalForm()); + assertEquals("resource3", toString(handlerCopy.openStream())); + + // access the other resource using the original url as a starting point + URL other = new URL(resource, "jar3"); + assertEquals("jar3", toString(other.openStream())); + } + + public void testUrlAccess() throws Exception { + URL jar = jarFile.toURL(); + UrlResourceFinder resourceFinder = new UrlResourceFinder(new URL[]{jar}); + + // get geronimo url from the resource finder + URL geronimoUrl = resourceFinder.findResource("resource"); + assertNotNull(geronimoUrl); + assertEquals("resource3", toString(geronimoUrl.openStream())); + + // get a system url by copying the url by string + URL systemUrl = new URL(geronimoUrl.toExternalForm()); + assertEquals("resource3", toString(systemUrl.openStream())); + + // verify both can see the jar3 file withing the jar file + assertEquals("jar3", toString(new URL(systemUrl, "jar3").openStream())); + assertEquals("jar3", toString(new URL(geronimoUrl, "jar3").openStream())); + + // verify both can see the jar3 file withing the jar file using a full url spec + String mainEntry = "jar:" + jarFile.toURL().toExternalForm() + "!/jar3"; + assertEquals("jar3", toString(new URL(systemUrl, mainEntry).openStream())); + assertEquals("jar3", toString(new URL(geronimoUrl, mainEntry).openStream())); + + // verify both throw a FileNotFoundExcetion for an unknown file + try { + new URL(systemUrl, "unknown").openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + try { + new URL(geronimoUrl, "unknown").openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + + // verify both can see the alternate jar + String alternateEntry = "jar:" + alternateJarFile.toURL().toExternalForm() + "!/jar4"; + assertEquals("jar4", toString(new URL(systemUrl, alternateEntry).openStream())); + assertEquals("jar4", toString(new URL(geronimoUrl, alternateEntry).openStream())); + + // verify both throw a FileNotFoundExcetion for an unknown entry in the alternate file + String alternateUnknownEntry = "jar:" + alternateJarFile.toURL().toExternalForm() + "!/unknown"; + try { + new URL(systemUrl, alternateUnknownEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + try { + new URL(geronimoUrl, alternateUnknownEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + + // verify both work an excepton for a non-jar entry + assertEquals("testResource", toString(new URL(systemUrl, testResource.toURL().toExternalForm()).openStream())); + assertEquals("testResource", toString(new URL(geronimoUrl, testResource.toURL().toExternalForm()).openStream())); + + // verify both fail for a spec without a !/ + String badEntry = "jar:" + alternateJarFile.toURL().toExternalForm(); + try { + new URL(systemUrl, badEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (MalformedURLException expected) { + } + try { + new URL(geronimoUrl, badEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (MalformedURLException expected) { + } + + // verify both throw FileNotFoundException for a nested jar file + badEntry = "jar:" + alternateJarFile.toURL().toExternalForm() + "!/foo.jar!/bar"; + try { + new URL(systemUrl, badEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + try { + new URL(geronimoUrl, badEntry).openStream(); + fail("Expected a FileNotFoundException"); + } catch (FileNotFoundException expected) { + } + } + + public void assertDestroyed(UrlResourceFinder resourceFinder, String resourceValue, Manifest expectedManifest) throws Exception { + ResourceHandle resource = resourceFinder.getResource("resource"); + assertNotNull(resource); + assertEquals(resourceValue, new String(resource.getBytes())); + + // handle.getUrl() + URL url = resource.getUrl(); + assertEquals(resourceValue, toString(url.openStream())); + + // copy the url and verify we can still get the data + URL copyUrl = new URL(url.toExternalForm()); + assertEquals(resourceValue, toString(copyUrl.openStream())); + + // resourceFinder.findResource + URL directUrl = resourceFinder.findResource("resource"); + assertEquals(resourceValue, toString(directUrl.openStream())); + URL directUrlCopy = new URL(directUrl.toExternalForm()); + assertEquals(resourceValue, toString(directUrlCopy.openStream())); + + // destroy + resourceFinder.destroy(); + + // getResource always returns null + assertNull(resourceFinder.getResource("resource")); + + // findResource always returns null + assertNull(resourceFinder.findResource("resource")); + + // findResources always returns an empty enumeration + assertFalse(resourceFinder.findResources("resource").hasMoreElements()); + + // existing url may not work + try { + assertEquals(resourceValue, toString(url.openStream())); + } catch (IllegalStateException expected) { + } catch (IOException expected) { + } + try { + assertEquals(resourceValue, toString(directUrl.openStream())); + } catch (IllegalStateException expected) { + } catch (IOException expected) { + } + + // the copied urls will work since they are proviced by the vm + assertEquals(resourceValue, toString(copyUrl.openStream())); + assertEquals(resourceValue, toString(directUrlCopy.openStream())); + + // existing resource handle may not work since the location was closed + assertEquals("resource", resource.getName()); + try { + if (expectedManifest != null) { + assertEquals(expectedManifest.getAttributes("resource"), resource.getAttributes()); + } + } catch (IllegalStateException expected) { + } + try { + assertEquals(expectedManifest, resource.getManifest()); + } catch (IllegalStateException expected) { + } + try { + assertEquals(resourceValue, toString(resource.getUrl().openStream())); + } catch (IllegalStateException expected) { + } + try { + assertEquals(resourceValue, toString(resource.getInputStream())); + } catch (IllegalStateException expected) { + } catch (IOException expected) { + } + try { + assertEquals(resourceValue, new String(resource.getBytes())); + } catch (IllegalStateException expected) { + } catch (IOException expected) { + } + } + + protected void setUp() throws Exception { + super.setUp(); + + // + // Build a simple Jar file to test with + // + manifest = new Manifest(); + Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + mainAttributes.putValue("food", "nacho"); + resourceAttributes = new Attributes(); + resourceAttributes.putValue("drink", "margarita"); + manifest.getEntries().put("resource", resourceAttributes); + + File targetDir = new File(basedir, "target"); + jarFile = new File(targetDir, "resourceFinderTest.jar"); + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile), manifest); + jarOutputStream.putNextEntry(new ZipEntry("resource")); + jarOutputStream.write("resource3".getBytes()); + jarOutputStream.putNextEntry(new ZipEntry("jar3")); + jarOutputStream.write("jar3".getBytes()); + IoUtil.close(jarOutputStream); + + alternateJarFile = new File(targetDir, "alternate.jar"); + System.out.println(alternateJarFile.getAbsolutePath()); + jarOutputStream = new JarOutputStream(new FileOutputStream(alternateJarFile), manifest); + jarOutputStream.putNextEntry(new ZipEntry("resource")); + jarOutputStream.write("resource4".getBytes()); + jarOutputStream.putNextEntry(new ZipEntry("jar4")); + jarOutputStream.write("jar4".getBytes()); + IoUtil.close(jarOutputStream); + + testResource = new File(targetDir, "testResource"); + FileOutputStream fileOutputStream = new FileOutputStream(testResource); + fileOutputStream.write("testResource".getBytes()); + IoUtil.close(fileOutputStream); + } + + protected void tearDown() throws Exception { + jarFile.delete(); + super.tearDown(); + } + + private static String toString(InputStream in) throws IOException { + try { + byte[] bytes = IoUtil.getBytes(in); + String string = new String(bytes); + return string; + } finally { + IoUtil.close(in); + } + } +} Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java ------------------------------------------------------------------------------ svn:keywords = Date Revision Id Author Propchange: geronimo/xbean/trunk/xbean-classloader/src/test/java/org/apache/xbean/classloader/UrlResourceFinderTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: geronimo/xbean/trunk/xbean-server/pom.xml URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-server/pom.xml?rev=437551&r1=437550&r2=437551&view=diff ============================================================================== --- geronimo/xbean/trunk/xbean-server/pom.xml (original) +++ geronimo/xbean/trunk/xbean-server/pom.xml Sun Aug 27 23:14:47 2006 @@ -34,36 +34,42 @@ XBean :: Server - + org.apache.xbean xbean-spring ${pom.version} - + + + org.apache.xbean + xbean-classloader + ${pom.version} + + org.apache.xbean xbean-kernel ${pom.version} - + mx4j mx4j true - + commons-logging commons-logging - + cglib cglib-nodep test - + Modified: geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/deployer/FileDeployer.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/deployer/FileDeployer.java?rev=437551&r1=437550&r2=437551&view=diff ============================================================================== --- geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/deployer/FileDeployer.java (original) +++ geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/deployer/FileDeployer.java Sun Aug 27 23:14:47 2006 @@ -23,7 +23,7 @@ import org.apache.xbean.kernel.ServiceFactory; import org.apache.xbean.kernel.ServiceRegistrationException; import org.apache.xbean.kernel.StringServiceName; -import org.apache.xbean.server.classloader.NamedClassLoader; +import org.apache.xbean.classloader.NamedClassLoader; import org.apache.xbean.server.spring.configuration.SpringConfigurationServiceFactory; import org.apache.xbean.spring.context.ResourceXmlApplicationContext; import org.apache.xbean.spring.context.SpringApplicationContext; Modified: geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/spring/configuration/ClassLoaderXmlPreprocessor.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/spring/configuration/ClassLoaderXmlPreprocessor.java?rev=437551&r1=437550&r2=437551&view=diff ============================================================================== --- geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/spring/configuration/ClassLoaderXmlPreprocessor.java (original) +++ geronimo/xbean/trunk/xbean-server/src/main/java/org/apache/xbean/server/spring/configuration/ClassLoaderXmlPreprocessor.java Sun Aug 27 23:14:47 2006 @@ -21,7 +21,7 @@ import java.util.List; import java.util.ListIterator; -import org.apache.xbean.server.classloader.JarFileClassLoader; +import org.apache.xbean.classloader.JarFileClassLoader; import org.apache.xbean.server.repository.Repository; import org.apache.xbean.server.spring.loader.SpringLoader; import org.apache.xbean.spring.context.SpringApplicationContext; Modified: geronimo/xbean/trunk/xbean-server/src/test/java/org/apache/xbean/server/spring/loader/SpringLoaderTest.java URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-server/src/test/java/org/apache/xbean/server/spring/loader/SpringLoaderTest.java?rev=437551&r1=437550&r2=437551&view=diff ============================================================================== --- geronimo/xbean/trunk/xbean-server/src/test/java/org/apache/xbean/server/spring/loader/SpringLoaderTest.java (original) +++ geronimo/xbean/trunk/xbean-server/src/test/java/org/apache/xbean/server/spring/loader/SpringLoaderTest.java Sun Aug 27 23:14:47 2006 @@ -39,10 +39,9 @@ import org.apache.xbean.kernel.KernelFactory; import org.apache.xbean.kernel.ServiceName; import org.apache.xbean.kernel.StringServiceName; -import org.apache.xbean.server.classloader.MultiParentClassLoader; +import org.apache.xbean.classloader.MultiParentClassLoader; import org.apache.xbean.server.repository.FileSystemRepository; import org.apache.xbean.server.spring.configuration.ClassLoaderXmlPreprocessor; -import org.apache.xbean.server.spring.configuration.SpringConfigurationServiceFactory; import org.apache.xbean.spring.context.SpringApplicationContext; /**