Author: dblevins
Date: Mon Jun 11 14:56:24 2007
New Revision: 546300
URL: http://svn.apache.org/viewvc?view=rev&rev=546300
Log:
Preliminary support for embedded jpa enhancement (still does not work for
surefire as it has classloader seperation)
Added:
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EmbeddedJpaEnhancher.java
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/jpa.enhancer
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/AgentExtention.java
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/ResourceFinder.java
Modified:
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/Agent.java
Added:
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EmbeddedJpaEnhancher.java
URL:
http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EmbeddedJpaEnhancher.java?view=auto&rev=546300
==============================================================================
---
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EmbeddedJpaEnhancher.java
(added)
+++
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EmbeddedJpaEnhancher.java
Mon Jun 11 14:56:24 2007
@@ -0,0 +1,70 @@
+/**
+ * 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.openejb.config;
+
+import org.apache.openejb.javaagent.AgentExtention;
+import org.apache.openejb.core.TemporaryClassLoader;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.AppInfo;
+import org.apache.openejb.OpenEJBException;
+import org.apache.xbean.finder.ResourceFinder;
+
+import javax.naming.NamingException;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.ClassFileTransformer;
+import java.io.IOException;
+import java.io.File;
+import java.net.URL;
+import java.util.Map;
+import java.util.List;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class EmbeddedJpaEnhancher implements AgentExtention {
+ public void premain(String agentArgs, Instrumentation instrumentation) {
+ ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
+
+ ClassLoader appClassLoader = new TemporaryClassLoader(classLoader);
+ AppModule appModule = new AppModule(appClassLoader,
classLoader.toString());
+
+ // Persistence Units via META-INF/persistence.xml
+ try {
+ ResourceFinder finder = new ResourceFinder("", appClassLoader);
+ List<URL> persistenceUrls =
finder.findAll("META-INF/persistence.xml");
+ appModule.getAltDDs().put("persistence.xml", persistenceUrls);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot load persistence-units
from 'META-INF/persistence.xml' : " + e.getMessage(), e);
+ }
+
+ try {
+ ConfigurationFactory configFactory = new ConfigurationFactory();
+ AppInfo appInfo = configFactory.configureApplication(appModule);
+
+ Assembler assembler =
SystemInstance.get().getComponent(Assembler.class);
+ if (assembler == null) {
+ assembler = new Assembler();
+ }
+
+ assembler.createApplication(appInfo);
+ assembler.destroyApplication(appInfo.jarPath);
+ } catch (Exception e) {
+ throw new IllegalStateException("Enhancement failed: "+
e.getMessage(), e);
+ }
+ }
+}
Added:
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/jpa.enhancer
URL:
http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/jpa.enhancer?view=auto&rev=546300
==============================================================================
---
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/jpa.enhancer
(added)
+++
incubator/openejb/trunk/openejb3/container/openejb-core/src/main/resources/META-INF/org.apache.openejb.javaagent.AgentExtention/jpa.enhancer
Mon Jun 11 14:56:24 2007
@@ -0,0 +1 @@
+org.apache.openejb.config.EmbeddedJpaEnhancher
Modified:
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/Agent.java
URL:
http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/Agent.java?view=diff&rev=546300&r1=546299&r2=546300
==============================================================================
---
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/Agent.java
(original)
+++
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/Agent.java
Mon Jun 11 14:56:24 2007
@@ -18,9 +18,18 @@
package org.apache.openejb.javaagent;
import java.lang.instrument.Instrumentation;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
import java.lang.reflect.ReflectPermission;
import java.lang.reflect.Field;
import java.security.Permission;
+import java.security.ProtectionDomain;
+import java.net.URL;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+import java.io.IOException;
public class Agent {
private static final Permission ACCESS_PERMISSION = new
ReflectPermission("suppressAccessChecks");
@@ -32,6 +41,43 @@
Agent.agentArgs = agentArgs;
Agent.instrumentation = instrumentation;
initialized = true;
+// System.out.println("Agent startup");
+
+// ClassFileTransformer transformer = new SurefireTransformer();
+// instrumentation.addTransformer(transformer);
+
+ ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
+ executeExtentions(classLoader, agentArgs, instrumentation);
+ }
+
+ private static void executeExtentions(ClassLoader classLoader, String
agentArgs, Instrumentation instrumentation) {
+ try {
+ ResourceFinder finder = new ResourceFinder("META-INF",
classLoader);
+ Map<String, Class> extentions =
finder.mapAvailableImplementations(AgentExtention.class);
+// System.out.println("Agents found: " + extentions.size());
+ List<String> resourcesNotLoaded = finder.getResourcesNotLoaded();
+ for (String className : resourcesNotLoaded) {
+ System.out.println("Agent not loaded: " + className);
+ }
+
+
+ for (Map.Entry<String, Class> entry : extentions.entrySet()) {
+ AgentExtention extention = null;
+ try {
+ extention = (AgentExtention)
entry.getValue().newInstance();
+ } catch (Throwable e) {
+ new RuntimeException("AgentExtention instantiation failed:
AgentExtention(name="+entry.getKey()+", class="+entry.getValue().getName()+")",
e).printStackTrace();
+ }
+
+ try {
+ extention.premain(agentArgs, instrumentation);
+ } catch (Throwable e) {
+ new RuntimeException("AgentExtention premain failed:
AgentExtention(name="+entry.getKey()+", class="+entry.getValue().getName()+")",
e).printStackTrace();
+ }
+ }
+ } catch (IOException e) {
+ new RuntimeException("Failed searching for AgentExtentions:
"+e.getMessage(), e).printStackTrace();
+ }
}
public static synchronized String getAgentArgs() {
@@ -70,6 +116,19 @@
new IllegalStateException("Unable to initialize agent",
e).printStackTrace();
}
initialized = true;
+ }
+ }
+
+ private static class SurefireTransformer implements ClassFileTransformer {
+ private boolean surefirePathEnhanced;
+
+ public byte[] transform(ClassLoader loader, String className, Class<?>
classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
+ if (!surefirePathEnhanced &&
loader.getClass().getName().equals("org.apache.maven.surefire.booter.IsolatedClassLoader")){
+ surefirePathEnhanced = true;
+ executeExtentions(loader, agentArgs, instrumentation);
+ }
+
+ return classfileBuffer;
}
}
}
Added:
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/AgentExtention.java
URL:
http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/AgentExtention.java?view=auto&rev=546300
==============================================================================
---
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/AgentExtention.java
(added)
+++
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/AgentExtention.java
Mon Jun 11 14:56:24 2007
@@ -0,0 +1,26 @@
+/**
+ * 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.openejb.javaagent;
+
+import java.lang.instrument.Instrumentation;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface AgentExtention {
+ public void premain(String agentArgs, Instrumentation instrumentation);
+}
Added:
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/ResourceFinder.java
URL:
http://svn.apache.org/viewvc/incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/ResourceFinder.java?view=auto&rev=546300
==============================================================================
---
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/ResourceFinder.java
(added)
+++
incubator/openejb/trunk/openejb3/container/openejb-javaagent/src/main/java/org/apache/openejb/javaagent/ResourceFinder.java
Mon Jun 11 14:56:24 2007
@@ -0,0 +1,1073 @@
+/**
+ * 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.openejb.javaagent;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.JarURLConnection;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+
+/**
+ * Note: This class is a copy of the xbean-finder ResourceFinder class. Any
changes should
+ * be make to the xbean-finder source first and then copied to this class.
Also, this class
+ * should be kept in sync with the xbean-finder code.
+ * @author David Blevins
+ */
+public class ResourceFinder {
+
+ private final URL[] urls;
+ private final String path;
+ private final ClassLoader classLoader;
+ private final List<String> resourcesNotLoaded = new ArrayList<String>();
+
+ public ResourceFinder(URL... urls) {
+ this(null, Thread.currentThread().getContextClassLoader(), urls);
+ }
+
+ public ResourceFinder(String path) {
+ this(path, Thread.currentThread().getContextClassLoader(), null);
+ }
+
+ public ResourceFinder(String path, URL... urls) {
+ this(path, Thread.currentThread().getContextClassLoader(), urls);
+ }
+
+ public ResourceFinder(String path, ClassLoader classLoader) {
+ this(path, classLoader, null);
+ }
+
+ public ResourceFinder(String path, ClassLoader classLoader, URL... urls) {
+ if (path == null){
+ path = "";
+ } else if (path.length() > 0 && !path.endsWith("/")) {
+ path += "/";
+ }
+ this.path = path;
+
+ if (classLoader == null) {
+ classLoader = Thread.currentThread().getContextClassLoader();
+ }
+ this.classLoader = classLoader;
+
+ System.out.println("ResourceFinder urls = " + urls);
+
+ for (int i = 0; urls != null && i < urls.length; i++) {
+ URL url = urls[i];
+ System.out.println("url.toExternalForm() = " +
url.toExternalForm());
+ if (url == null || isDirectory(url) ||
url.getProtocol().equals("jar")) {
+ continue;
+ }
+ try {
+ urls[i] = new URL("jar", "", -1, url.toString() + "!/");
+ } catch (MalformedURLException e) {
+ }
+ }
+ this.urls = (urls == null || urls.length == 0)? null : urls;
+ }
+
+ private static boolean isDirectory(URL url) {
+ String file = url.getFile();
+ return (file.length() > 0 && file.charAt(file.length() - 1) == '/');
+ }
+
+ /**
+ * Returns a list of resources that could not be loaded in the last
invoked findAvailable* or
+ * mapAvailable* methods.
+ * <p/>
+ * The list will only contain entries of resources that match the
requirements
+ * of the last invoked findAvailable* or mapAvailable* methods, but were
unable to be
+ * loaded and included in their results.
+ * <p/>
+ * The list returned is unmodifiable and the results of this method will
change
+ * after each invocation of a findAvailable* or mapAvailable* methods.
+ * <p/>
+ * This method is not thread safe.
+ */
+ public List<String> getResourcesNotLoaded() {
+ return Collections.unmodifiableList(resourcesNotLoaded);
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ public URL find(String uri) throws IOException {
+ String fullUri = path + uri;
+
+ URL resource = getResource(fullUri);
+ if (resource == null) {
+ throw new IOException("Could not find resource '" + fullUri + "'");
+ }
+
+ return resource;
+ }
+
+ public List<URL> findAll(String uri) throws IOException {
+ String fullUri = path + uri;
+
+ Enumeration<URL> resources = getResources(fullUri);
+ List<URL> list = new ArrayList();
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ list.add(url);
+ }
+ return list;
+ }
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find String
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Reads the contents of the URL as a [EMAIL PROTECTED] String}'s and
returns it.
+ *
+ * @param uri
+ * @return a stringified content of a resource
+ * @throws java.io.IOException if a resource pointed out by the uri param
could not be find
+ * @see ClassLoader#getResource(String)
+ */
+ public String findString(String uri) throws IOException {
+ String fullUri = path + uri;
+
+ URL resource = getResource(fullUri);
+ if (resource == null) {
+ throw new IOException("Could not find a resource in : " + fullUri);
+ }
+
+ return readContents(resource);
+ }
+
+ /**
+ * Reads the contents of the found URLs as a list of [EMAIL PROTECTED]
String}'s and returns them.
+ *
+ * @param uri
+ * @return a list of the content of each resource URL found
+ * @throws java.io.IOException if any of the found URLs are unable to be
read.
+ */
+ public List<String> findAllStrings(String uri) throws IOException {
+ String fulluri = path + uri;
+
+ List<String> strings = new ArrayList<String>();
+
+ Enumeration<URL> resources = getResources(fulluri);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ String string = readContents(url);
+ strings.add(string);
+ }
+ return strings;
+ }
+
+ /**
+ * Reads the contents of the found URLs as a Strings and returns them.
+ * Individual URLs that cannot be read are skipped and added to the
+ * list of 'resourcesNotLoaded'
+ *
+ * @param uri
+ * @return a list of the content of each resource URL found
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public List<String> findAvailableStrings(String uri) throws IOException {
+ resourcesNotLoaded.clear();
+ String fulluri = path + uri;
+
+ List<String> strings = new ArrayList<String>();
+
+ Enumeration<URL> resources = getResources(fulluri);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ try {
+ String string = readContents(url);
+ strings.add(string);
+ } catch (IOException notAvailable) {
+ resourcesNotLoaded.add(url.toExternalForm());
+ }
+ }
+ return strings;
+ }
+
+ /**
+ * Reads the contents of all non-directory URLs immediately under the
specified
+ * location and returns them in a map keyed by the file name.
+ * <p/>
+ * Any URLs that cannot be read will cause an exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/serializables/one
+ * META-INF/serializables/two
+ * META-INF/serializables/three
+ * META-INF/serializables/four/foo.txt
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAvailableStrings("serializables");
+ * map.contains("one"); // true
+ * map.contains("two"); // true
+ * map.contains("three"); // true
+ * map.contains("four"); // false
+ *
+ * @param uri
+ * @return a list of the content of each resource URL found
+ * @throws java.io.IOException if any of the urls cannot be read
+ */
+ public Map<String, String> mapAllStrings(String uri) throws IOException {
+ Map<String, String> strings = new HashMap<String, String>();
+ Map<String, URL> resourcesMap = getResourcesMap(uri);
+ for (Iterator iterator = resourcesMap.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String name = (String) entry.getKey();
+ URL url = (URL) entry.getValue();
+ String value = readContents(url);
+ strings.put(name, value);
+ }
+ return strings;
+ }
+
+ /**
+ * Reads the contents of all non-directory URLs immediately under the
specified
+ * location and returns them in a map keyed by the file name.
+ * <p/>
+ * Individual URLs that cannot be read are skipped and added to the
+ * list of 'resourcesNotLoaded'
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/serializables/one
+ * META-INF/serializables/two # not readable
+ * META-INF/serializables/three
+ * META-INF/serializables/four/foo.txt
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAvailableStrings("serializables");
+ * map.contains("one"); // true
+ * map.contains("two"); // false
+ * map.contains("three"); // true
+ * map.contains("four"); // false
+ *
+ * @param uri
+ * @return a list of the content of each resource URL found
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public Map<String, String> mapAvailableStrings(String uri) throws
IOException {
+ resourcesNotLoaded.clear();
+ Map<String, String> strings = new HashMap<String, String>();
+ Map<String, URL> resourcesMap = getResourcesMap(uri);
+ for (Iterator iterator = resourcesMap.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String name = (String) entry.getKey();
+ URL url = (URL) entry.getValue();
+ try {
+ String value = readContents(url);
+ strings.put(name, value);
+ } catch (IOException notAvailable) {
+ resourcesNotLoaded.add(url.toExternalForm());
+ }
+ }
+ return strings;
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find Class
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Executes [EMAIL PROTECTED] #findString(String)} assuming the contents
URL found is the name of
+ * a class that should be loaded and returned.
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException
+ * @throws ClassNotFoundException
+ */
+ public Class findClass(String uri) throws IOException,
ClassNotFoundException {
+ String className = findString(uri);
+ return (Class) classLoader.loadClass(className);
+ }
+
+ /**
+ * Executes findAllStrings assuming the strings are
+ * the names of a classes that should be loaded and returned.
+ * <p/>
+ * Any URL or class that cannot be loaded will cause an exception to be
thrown.
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException
+ * @throws ClassNotFoundException
+ */
+ public List<Class> findAllClasses(String uri) throws IOException,
ClassNotFoundException {
+ List<Class> classes = new ArrayList<Class>();
+ List<String> strings = findAllStrings(uri);
+ for (String className : strings) {
+ Class clazz = classLoader.loadClass(className);
+ classes.add(clazz);
+ }
+ return classes;
+ }
+
+ /**
+ * Executes findAvailableStrings assuming the strings are
+ * the names of a classes that should be loaded and returned.
+ * <p/>
+ * Any class that cannot be loaded will be skipped and placed in the
+ * 'resourcesNotLoaded' collection.
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public List<Class> findAvailableClasses(String uri) throws IOException {
+ resourcesNotLoaded.clear();
+ List<Class> classes = new ArrayList<Class>();
+ List<String> strings = findAvailableStrings(uri);
+ for (String className : strings) {
+ try {
+ Class clazz = classLoader.loadClass(className);
+ classes.add(clazz);
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(className);
+ }
+ }
+ return classes;
+ }
+
+ /**
+ * Executes mapAllStrings assuming the value of each entry in the
+ * map is the name of a class that should be loaded.
+ * <p/>
+ * Any class that cannot be loaded will be cause an exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/xmlparsers/xerces
+ * META-INF/xmlparsers/crimson
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAvailableStrings("xmlparsers");
+ * map.contains("xerces"); // true
+ * map.contains("crimson"); // true
+ * Class xercesClass = map.get("xerces");
+ * Class crimsonClass = map.get("crimson");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException
+ * @throws ClassNotFoundException
+ */
+ public Map<String, Class> mapAllClasses(String uri) throws IOException,
ClassNotFoundException {
+ Map<String, Class> classes = new HashMap<String, Class>();
+ Map<String, String> map = mapAllStrings(uri);
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ String className = (String) entry.getValue();
+ Class clazz = classLoader.loadClass(className);
+ classes.put(string, clazz);
+ }
+ return classes;
+ }
+
+ /**
+ * Executes mapAvailableStrings assuming the value of each entry in the
+ * map is the name of a class that should be loaded.
+ * <p/>
+ * Any class that cannot be loaded will be skipped and placed in the
+ * 'resourcesNotLoaded' collection.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/xmlparsers/xerces
+ * META-INF/xmlparsers/crimson
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAvailableStrings("xmlparsers");
+ * map.contains("xerces"); // true
+ * map.contains("crimson"); // true
+ * Class xercesClass = map.get("xerces");
+ * Class crimsonClass = map.get("crimson");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public Map<String, Class> mapAvailableClasses(String uri) throws
IOException {
+ resourcesNotLoaded.clear();
+ Map<String, Class> classes = new HashMap<String, Class>();
+ Map<String, String> map = mapAvailableStrings(uri);
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ String className = (String) entry.getValue();
+ try {
+ Class clazz = classLoader.loadClass(className);
+ classes.put(string, clazz);
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(className);
+ }
+ }
+ return classes;
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find Implementation
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Assumes the class specified points to a file in the classpath that
contains
+ * the name of a class that implements or is a subclass of the specfied
class.
+ * <p/>
+ * Any class that cannot be loaded will be cause an exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/java.io.InputStream # contains the classname
org.acme.AcmeInputStream
+ * META-INF/java.io.OutputStream
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Class clazz = finder.findImplementation(java.io.InputStream.class);
+ * clazz.getName(); // returns "org.acme.AcmeInputStream"
+ *
+ * @param interfase a superclass or interface
+ * @return
+ * @throws java.io.IOException if the URL cannot be read
+ * @throws ClassNotFoundException if the class found is not loadable
+ * @throws ClassCastException if the class found is not assignable to
the specified superclass or interface
+ */
+ public Class findImplementation(Class interfase) throws IOException,
ClassNotFoundException {
+ String className = findString(interfase.getName());
+ Class impl = classLoader.loadClass(className);
+ if (!interfase.isAssignableFrom(impl)) {
+ throw new ClassCastException("Class not of type: " +
interfase.getName());
+ }
+ return impl;
+ }
+
+ /**
+ * Assumes the class specified points to a file in the classpath that
contains
+ * the name of a class that implements or is a subclass of the specfied
class.
+ * <p/>
+ * Any class that cannot be loaded or assigned to the specified interface
will be cause
+ * an exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/java.io.InputStream # contains the classname
org.acme.AcmeInputStream
+ * META-INF/java.io.InputStream # contains the classname
org.widget.NeatoInputStream
+ * META-INF/java.io.InputStream # contains the classname
com.foo.BarInputStream
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List classes = finder.findAllImplementations(java.io.InputStream.class);
+ * classes.contains("org.acme.AcmeInputStream"); // true
+ * classes.contains("org.widget.NeatoInputStream"); // true
+ * classes.contains("com.foo.BarInputStream"); // true
+ *
+ * @param interfase a superclass or interface
+ * @return
+ * @throws java.io.IOException if the URL cannot be read
+ * @throws ClassNotFoundException if the class found is not loadable
+ * @throws ClassCastException if the class found is not assignable to
the specified superclass or interface
+ */
+ public List<Class> findAllImplementations(Class interfase) throws
IOException, ClassNotFoundException {
+ List<Class> implementations = new ArrayList<Class>();
+ List<String> strings = findAllStrings(interfase.getName());
+ for (String className : strings) {
+ Class impl = classLoader.loadClass(className);
+ if (!interfase.isAssignableFrom(impl)) {
+ throw new ClassCastException("Class not of type: " +
interfase.getName());
+ }
+ implementations.add(impl);
+ }
+ return implementations;
+ }
+
+ /**
+ * Assumes the class specified points to a file in the classpath that
contains
+ * the name of a class that implements or is a subclass of the specfied
class.
+ * <p/>
+ * Any class that cannot be loaded or are not assignable to the specified
class will be
+ * skipped and placed in the 'resourcesNotLoaded' collection.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/java.io.InputStream # contains the classname
org.acme.AcmeInputStream
+ * META-INF/java.io.InputStream # contains the classname
org.widget.NeatoInputStream
+ * META-INF/java.io.InputStream # contains the classname
com.foo.BarInputStream
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List classes = finder.findAllImplementations(java.io.InputStream.class);
+ * classes.contains("org.acme.AcmeInputStream"); // true
+ * classes.contains("org.widget.NeatoInputStream"); // true
+ * classes.contains("com.foo.BarInputStream"); // true
+ *
+ * @param interfase a superclass or interface
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public List<Class> findAvailableImplementations(Class interfase) throws
IOException {
+ resourcesNotLoaded.clear();
+ List<Class> implementations = new ArrayList<Class>();
+ List<String> strings = findAvailableStrings(interfase.getName());
+ for (String className : strings) {
+ try {
+ Class impl = classLoader.loadClass(className);
+ if (interfase.isAssignableFrom(impl)) {
+ implementations.add(impl);
+ } else {
+ resourcesNotLoaded.add(className);
+ }
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(className);
+ }
+ }
+ return implementations;
+ }
+
+ /**
+ * Assumes the class specified points to a directory in the classpath that
holds files
+ * containing the name of a class that implements or is a subclass of the
specfied class.
+ * <p/>
+ * Any class that cannot be loaded or assigned to the specified interface
will be cause
+ * an exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/java.net.URLStreamHandler/jar
+ * META-INF/java.net.URLStreamHandler/file
+ * META-INF/java.net.URLStreamHandler/http
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAllImplementations(java.net.URLStreamHandler.class);
+ * Class jarUrlHandler = map.get("jar");
+ * Class fileUrlHandler = map.get("file");
+ * Class httpUrlHandler = map.get("http");
+ *
+ * @param interfase a superclass or interface
+ * @return
+ * @throws java.io.IOException if the URL cannot be read
+ * @throws ClassNotFoundException if the class found is not loadable
+ * @throws ClassCastException if the class found is not assignable to
the specified superclass or interface
+ */
+ public Map<String, Class> mapAllImplementations(Class interfase) throws
IOException, ClassNotFoundException {
+ Map<String, Class> implementations = new HashMap<String, Class>();
+ Map<String, String> map = mapAllStrings(interfase.getName());
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ String className = (String) entry.getValue();
+ Class impl = classLoader.loadClass(className);
+ if (!interfase.isAssignableFrom(impl)) {
+ throw new ClassCastException("Class not of type: " +
interfase.getName());
+ }
+ implementations.put(string, impl);
+ }
+ return implementations;
+ }
+
+ /**
+ * Assumes the class specified points to a directory in the classpath that
holds files
+ * containing the name of a class that implements or is a subclass of the
specfied class.
+ * <p/>
+ * Any class that cannot be loaded or are not assignable to the specified
class will be
+ * skipped and placed in the 'resourcesNotLoaded' collection.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/java.net.URLStreamHandler/jar
+ * META-INF/java.net.URLStreamHandler/file
+ * META-INF/java.net.URLStreamHandler/http
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Map map = finder.mapAllImplementations(java.net.URLStreamHandler.class);
+ * Class jarUrlHandler = map.get("jar");
+ * Class fileUrlHandler = map.get("file");
+ * Class httpUrlHandler = map.get("http");
+ *
+ * @param interfase a superclass or interface
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public Map<String, Class> mapAvailableImplementations(Class interfase)
throws IOException {
+ resourcesNotLoaded.clear();
+ Map<String, Class> implementations = new HashMap<String, Class>();
+ Map<String, String> map = mapAvailableStrings(interfase.getName());
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ String className = (String) entry.getValue();
+ try {
+ Class impl = classLoader.loadClass(className);
+ if (interfase.isAssignableFrom(impl)) {
+ implementations.put(string, impl);
+ } else {
+ resourcesNotLoaded.add(className);
+ }
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(className);
+ }
+ }
+ return implementations;
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find Properties
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Finds the corresponding resource and reads it in as a properties file
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/widget.properties
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * Properties widgetProps = finder.findProperties("widget.properties");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if the URL cannot be read or is not in
properties file format
+ */
+ public Properties findProperties(String uri) throws IOException {
+ String fulluri = path + uri;
+
+ URL resource = getResource(fulluri);
+ if (resource == null) {
+ throw new IOException("Could not find command in : " + fulluri);
+ }
+
+ return loadProperties(resource);
+ }
+
+ /**
+ * Finds the corresponding resources and reads them in as a properties
files
+ * <p/>
+ * Any URL that cannot be read in as a properties file will cause an
exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/app.properties
+ * META-INF/app.properties
+ * META-INF/app.properties
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List<Properties> appProps = finder.findAllProperties("app.properties");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if the URL cannot be read or is not in
properties file format
+ */
+ public List<Properties> findAllProperties(String uri) throws IOException {
+ String fulluri = path + uri;
+
+ List<Properties> properties = new ArrayList<Properties>();
+
+ Enumeration<URL> resources = getResources(fulluri);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ Properties props = loadProperties(url);
+ properties.add(props);
+ }
+ return properties;
+ }
+
+ /**
+ * Finds the corresponding resources and reads them in as a properties
files
+ * <p/>
+ * Any URL that cannot be read in as a properties file will be added to the
+ * 'resourcesNotLoaded' collection.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/app.properties
+ * META-INF/app.properties
+ * META-INF/app.properties
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List<Properties> appProps =
finder.findAvailableProperties("app.properties");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public List<Properties> findAvailableProperties(String uri) throws
IOException {
+ resourcesNotLoaded.clear();
+ String fulluri = path + uri;
+
+ List<Properties> properties = new ArrayList<Properties>();
+
+ Enumeration<URL> resources = getResources(fulluri);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ try {
+ Properties props = loadProperties(url);
+ properties.add(props);
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(url.toExternalForm());
+ }
+ }
+ return properties;
+ }
+
+ /**
+ * Finds the corresponding resources and reads them in as a properties
files
+ * <p/>
+ * Any URL that cannot be read in as a properties file will cause an
exception to be thrown.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/jdbcDrivers/oracle.properties
+ * META-INF/jdbcDrivers/mysql.props
+ * META-INF/jdbcDrivers/derby
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List<Properties> driversList =
finder.findAvailableProperties("jdbcDrivers");
+ * Properties oracleProps = driversList.get("oracle.properties");
+ * Properties mysqlProps = driversList.get("mysql.props");
+ * Properties derbyProps = driversList.get("derby");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if the URL cannot be read or is not in
properties file format
+ */
+ public Map<String, Properties> mapAllProperties(String uri) throws
IOException {
+ Map<String, Properties> propertiesMap = new HashMap<String,
Properties>();
+ Map<String, URL> map = getResourcesMap(uri);
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ URL url = (URL) entry.getValue();
+ Properties properties = loadProperties(url);
+ propertiesMap.put(string, properties);
+ }
+ return propertiesMap;
+ }
+
+ /**
+ * Finds the corresponding resources and reads them in as a properties
files
+ * <p/>
+ * Any URL that cannot be read in as a properties file will be added to the
+ * 'resourcesNotLoaded' collection.
+ * <p/>
+ * Example classpath:
+ * <p/>
+ * META-INF/jdbcDrivers/oracle.properties
+ * META-INF/jdbcDrivers/mysql.props
+ * META-INF/jdbcDrivers/derby
+ * <p/>
+ * ResourceFinder finder = new ResourceFinder("META-INF/");
+ * List<Properties> driversList =
finder.findAvailableProperties("jdbcDrivers");
+ * Properties oracleProps = driversList.get("oracle.properties");
+ * Properties mysqlProps = driversList.get("mysql.props");
+ * Properties derbyProps = driversList.get("derby");
+ *
+ * @param uri
+ * @return
+ * @throws java.io.IOException if classLoader.getResources throws an
exception
+ */
+ public Map<String, Properties> mapAvailableProperties(String uri) throws
IOException {
+ resourcesNotLoaded.clear();
+ Map<String, Properties> propertiesMap = new HashMap<String,
Properties>();
+ Map<String, URL> map = getResourcesMap(uri);
+ for (Iterator iterator = map.entrySet().iterator();
iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String string = (String) entry.getKey();
+ URL url = (URL) entry.getValue();
+ try {
+ Properties properties = loadProperties(url);
+ propertiesMap.put(string, properties);
+ } catch (Exception notAvailable) {
+ resourcesNotLoaded.add(url.toExternalForm());
+ }
+ }
+ return propertiesMap;
+ }
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Map Resources
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ public Map<String, URL> getResourcesMap(String uri) throws IOException {
+ String basePath = path + uri;
+
+ Map<String, URL> resources = new HashMap<String, URL>();
+ if (!basePath.endsWith("/")) {
+ basePath += "/";
+ }
+ Enumeration<URL> urls = getResources(basePath);
+
+ while (urls.hasMoreElements()) {
+ URL location = urls.nextElement();
+
+ try {
+ if (location.getProtocol().equals("jar")) {
+
+ readJarEntries(location, basePath, resources);
+
+ } else if (location.getProtocol().equals("file")) {
+
+ readDirectoryEntries(location, resources);
+
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ return resources;
+ }
+
+ private static void readDirectoryEntries(URL location, Map<String, URL>
resources) throws MalformedURLException {
+ File dir = new File(location.getPath());
+ if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ for (File file : files) {
+ if (!file.isDirectory()) {
+ String name = file.getName();
+ URL url = file.toURL();
+ resources.put(name, url);
+ }
+ }
+ }
+ }
+
+ private static void readJarEntries(URL location, String basePath,
Map<String, URL> resources) throws IOException {
+ JarURLConnection conn = (JarURLConnection) location.openConnection();
+ JarFile jarfile = null;
+ jarfile = conn.getJarFile();
+
+ Enumeration<JarEntry> entries = jarfile.entries();
+ while (entries != null && entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+
+ if (entry.isDirectory() || !name.startsWith(basePath) ||
name.length() == basePath.length()) {
+ continue;
+ }
+
+ name = name.substring(basePath.length());
+
+ if (name.contains("/")) {
+ continue;
+ }
+
+ URL resource = new URL(location, name);
+ resources.put(name, resource);
+ }
+ }
+
+ private Properties loadProperties(URL resource) throws IOException {
+ InputStream in = resource.openStream();
+
+ BufferedInputStream reader = null;
+ try {
+ reader = new BufferedInputStream(in);
+ Properties properties = new Properties();
+ properties.load(reader);
+
+ return properties;
+ } finally {
+ try {
+ in.close();
+ reader.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ private String readContents(URL resource) throws IOException {
+ InputStream in = resource.openStream();
+ BufferedInputStream reader = null;
+ StringBuffer sb = new StringBuffer();
+
+ try {
+ reader = new BufferedInputStream(in);
+
+ int b = reader.read();
+ while (b != -1) {
+ sb.append((char) b);
+ b = reader.read();
+ }
+
+ return sb.toString().trim();
+ } finally {
+ try {
+ in.close();
+ reader.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ private URL getResource(String fullUri) {
+ if (urls == null){
+ return classLoader.getResource(fullUri);
+ }
+ return findResource(fullUri, urls);
+ }
+
+ private Enumeration<URL> getResources(String fulluri) throws IOException {
+ if (urls == null) {
+ System.out.println("fulluri: " + fulluri);
+ return classLoader.getResources(fulluri);
+ }
+ Vector<URL> resources = new Vector();
+ for (URL url : urls) {
+ URL resource = findResource(fulluri, url);
+ if (resource != null){
+ resources.add(resource);
+ }
+ }
+ return resources.elements();
+ }
+
+ private URL findResource(String resourceName, URL... search) {
+ for (int i = 0; i < search.length; i++) {
+ URL currentUrl = search[i];
+ if (currentUrl == null) {
+ continue;
+ }
+ JarFile jarFile = null;
+ try {
+ String protocol = currentUrl.getProtocol();
+ if (protocol.equals("jar")) {
+ /*
+ * If the connection for currentUrl or resURL is
+ * used, getJarFile() will throw an exception if the
+ * entry doesn't exist.
+ */
+ URL jarURL = ((JarURLConnection)
currentUrl.openConnection()).getJarFileURL();
+ try {
+ JarURLConnection juc = (JarURLConnection) new
URL("jar", "", jarURL.toExternalForm() + "!/").openConnection();
+ jarFile = juc.getJarFile();
+ } catch (IOException e) {
+ // Don't look for this jar file again
+ search[i] = null;
+ throw e;
+ }
+
+ String entryName;
+ if (currentUrl.getFile().endsWith("!/")) {
+ entryName = resourceName;
+ } else {
+ String file = currentUrl.getFile();
+ int sepIdx = file.lastIndexOf("!/");
+ if (sepIdx == -1) {
+ // Invalid URL, don't look here again
+ search[i] = null;
+ continue;
+ }
+ sepIdx += 2;
+ StringBuffer sb = new StringBuffer(file.length() -
sepIdx + resourceName.length());
+ sb.append(file.substring(sepIdx));
+ sb.append(resourceName);
+ entryName = sb.toString();
+ }
+ if (entryName.equals("META-INF/") &&
jarFile.getEntry("META-INF/MANIFEST.MF") != null){
+ return targetURL(currentUrl, "META-INF/MANIFEST.MF");
+ }
+ if (jarFile.getEntry(entryName) != null) {
+ return targetURL(currentUrl, resourceName);
+ }
+ } else if (protocol.equals("file")) {
+ String baseFile = currentUrl.getFile();
+ String host = currentUrl.getHost();
+ int hostLength = 0;
+ if (host != null) {
+ hostLength = host.length();
+ }
+ StringBuffer buf = new StringBuffer(2 + hostLength +
baseFile.length() + resourceName.length());
+
+ if (hostLength > 0) {
+ buf.append("//").append(host);
+ }
+ // baseFile always ends with '/'
+ buf.append(baseFile);
+ String fixedResName = resourceName;
+ // Do not create a UNC path, i.e. \\host
+ while (fixedResName.startsWith("/") ||
fixedResName.startsWith("\\")) {
+ fixedResName = fixedResName.substring(1);
+ }
+ buf.append(fixedResName);
+ String filename = buf.toString();
+ File file = new File(filename);
+ if (file.exists()) {
+ return targetURL(currentUrl, fixedResName);
+ }
+ } else {
+ URL resourceURL = targetURL(currentUrl, resourceName);
+ URLConnection urlConnection = resourceURL.openConnection();
+
+ try {
+ urlConnection.getInputStream().close();
+ } catch (SecurityException e) {
+ return null;
+ }
+ // HTTP can return a stream on a non-existent file
+ // So check for the return code;
+ if (!resourceURL.getProtocol().equals("http")) {
+ return resourceURL;
+ }
+
+ int code = ((HttpURLConnection)
urlConnection).getResponseCode();
+ if (code >= 200 && code < 300) {
+ return resourceURL;
+ }
+ }
+ } catch (MalformedURLException e) {
+ // Keep iterating through the URL list
+ } catch (IOException e) {
+ } catch (SecurityException e) {
+ }
+ }
+ return null;
+ }
+
+ private URL targetURL(URL base, String name) throws MalformedURLException {
+ StringBuffer sb = new StringBuffer(base.getFile().length() +
name.length());
+ sb.append(base.getFile());
+ sb.append(name);
+ String file = sb.toString();
+ return new URL(base.getProtocol(), base.getHost(), base.getPort(),
file, null);
+ }
+}