You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2011/12/02 17:33:45 UTC
svn commit: r1209569 [29/50] - in /struts/struts2/branches/STRUTS_3_X:
apps/blank/src/main/java/example/ apps/blank/src/test/java/example/
apps/jboss-blank/src/main/java/example/
apps/jboss-blank/src/test/java/example/ apps/mailreader/src/main/java/mai...
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/ResourceFinder.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/ResourceFinder.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/ResourceFinder.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/ResourceFinder.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,1153 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.finder;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.*;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+/**
+ * @author David Blevins
+ * @version $Rev: 1209415 $ $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $
+ */
+public class ResourceFinder {
+ private static final Logger LOG = LoggerFactory.getLogger(ResourceFinder.class);
+
+ private final URL[] urls;
+ private final String path;
+ private final ClassLoaderInterface classLoaderInterface;
+ private final List<String> resourcesNotLoaded = new ArrayList<String>();
+
+ public ResourceFinder(URL... urls) {
+ this(null, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), urls);
+ }
+
+ public ResourceFinder(String path) {
+ this(path, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), null);
+ }
+
+ public ResourceFinder(String path, URL... urls) {
+ this(path, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), urls);
+ }
+
+ public ResourceFinder(String path, ClassLoaderInterface classLoaderInterface) {
+ this(path, classLoaderInterface, null);
+ }
+
+ public ResourceFinder(String path, ClassLoaderInterface classLoaderInterface, URL... urls) {
+ if (path == null){
+ path = "";
+ } else if (path.length() > 0 && !path.endsWith("/")) {
+ path += "/";
+ }
+ this.path = path;
+
+ this.classLoaderInterface = classLoaderInterface == null ? new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()) : classLoaderInterface ;
+
+ for (int i = 0; urls != null && i < urls.length; i++) {
+ URL url = urls[i];
+ if (url == null || isDirectory(url) || "jar".equals(url.getProtocol())) {
+ 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;
+
+ return getResource(fullUri);
+ }
+
+ public List<URL> findAll(String uri) throws IOException {
+ String fullUri = path + uri;
+
+ Enumeration<URL> resources = getResources(fullUri);
+ List<URL> list = new ArrayList<URL>();
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ list.add(url);
+ }
+ return list;
+ }
+
+
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ //
+ // Find String
+ //
+ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ /**
+ * Reads the contents of the URL as a {@link String}'s and returns it.
+ *
+ * @param uri
+ * @return a stringified content of a resource
+ * @throws 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 {@link String}'s and returns them.
+ *
+ * @param uri
+ * @return a list of the content of each resource URL found
+ * @throws 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 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 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 (Map.Entry<String, URL> entry : resourcesMap.entrySet()) {
+ String name = entry.getKey();
+ 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 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 (Map.Entry<String, URL> entry : resourcesMap.entrySet()) {
+ String name = entry.getKey();
+ 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 {@link #findString(String)} assuming the contents URL found is the name of
+ * a class that should be loaded and returned.
+ *
+ * @param uri
+ * @return
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ public Class findClass(String uri) throws IOException, ClassNotFoundException {
+ String className = findString(uri);
+ return (Class) classLoaderInterface.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 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 = classLoaderInterface.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 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 = classLoaderInterface.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 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 (Map.Entry<String, String> entry : map.entrySet()) {
+ String string = entry.getKey();
+ String className = entry.getValue();
+ Class clazz = classLoaderInterface.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 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 (Map.Entry<String, String> entry : map.entrySet()) {
+ String string = entry.getKey();
+ String className = entry.getValue();
+ try {
+ Class clazz = classLoaderInterface.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 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 = classLoaderInterface.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 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 = classLoaderInterface.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 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 = classLoaderInterface.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 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 (Map.Entry<String, String> entry : map.entrySet()) {
+ String string = entry.getKey();
+ String className = entry.getValue();
+ Class impl = classLoaderInterface.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 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 (Map.Entry<String, String> entry : map.entrySet()) {
+ String string = entry.getKey();
+ String className = entry.getValue();
+ try {
+ Class impl = classLoaderInterface.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 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 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 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 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 (Map.Entry<String, URL> entry : map.entrySet()) {
+ String string = entry.getKey();
+ 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 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 (Map.Entry<String, URL> entry : map.entrySet()) {
+ String string = entry.getKey();
+ 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 ("jar".equals(location.getProtocol())) {
+
+ readJarEntries(location, basePath, resources);
+
+ } else if ("file".equals(location.getProtocol())) {
+
+ readDirectoryEntries(location, resources);
+
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ return resources;
+ }
+
+ /**
+ * Gets a list of subpckages from jars or dirs
+ */
+ public Set<String> findPackages(String uri) throws IOException {
+ String basePath = path + uri;
+
+ Set<String> resources = new HashSet<String>();
+ if (!basePath.endsWith("/")) {
+ basePath += "/";
+ }
+ Enumeration<URL> urls = getResources(basePath);
+
+ while (urls.hasMoreElements()) {
+ URL location = urls.nextElement();
+
+ try {
+ if ("jar".equals(location.getProtocol())) {
+
+ readJarDirectoryEntries(location, basePath, resources);
+
+ } else if ("file".equals(location.getProtocol())) {
+
+ readSubDirectories(new File(location.toURI()), uri, resources);
+
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ return convertPathsToPackages(resources);
+ }
+
+ /**
+ * Gets a list of subpckages from jars or dirs
+ */
+ public Map<URL, Set<String>> findPackagesMap(String uri) throws IOException {
+ String basePath = path + uri;
+
+ if (!basePath.endsWith("/")) {
+ basePath += "/";
+ }
+ Enumeration<URL> urls = getResources(basePath);
+ Map<URL, Set<String>> result = new HashMap<URL, Set<String>>();
+
+ while (urls.hasMoreElements()) {
+ URL location = urls.nextElement();
+
+ try {
+ if ("jar".equals(location.getProtocol())) {
+ Set<String> resources = new HashSet<String>();
+ readJarDirectoryEntries(location, basePath, resources);
+ result.put(location, convertPathsToPackages(resources));
+ } else if ("file".equals(location.getProtocol())) {
+ Set<String> resources = new HashSet<String>();
+ readSubDirectories(new File(location.toURI()), uri, resources);
+ result.put(location, convertPathsToPackages(resources));
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ return result;
+ }
+
+ private Set<String> convertPathsToPackages(Set<String> resources) {
+ Set<String> packageNames = new HashSet<String>(resources.size());
+ for(String resource : resources) {
+ packageNames.add(StringUtils.chomp(StringUtils.replace(resource, "/", "."), "."));
+ }
+
+ return packageNames;
+ }
+
+ private static void readDirectoryEntries(URL location, Map<String, URL> resources) throws MalformedURLException {
+ File dir = new File(URLDecoder.decode(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);
+ }
+ }
+ }
+ }
+
+ /**
+ * Reads subdirectories of a file. The output is a list of subdirectories, relative to the basepath
+ */
+ private static void readSubDirectories(File dir, String basePath, Set<String> resources) throws MalformedURLException {
+ if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ String name = file.getName();
+ String subName = StringUtils.chomp(basePath, "/") + "/" + name;
+ resources.add(subName);
+ readSubDirectories(file, subName, resources);
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+ //read directories in the jar that start with the basePath
+ private static void readJarDirectoryEntries(URL location, String basePath, Set<String> 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() && StringUtils.startsWith(name, basePath)) {
+ resources.add(name);
+ }
+ }
+ }
+
+ 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;
+ StringBuilder sb = new StringBuilder();
+
+ 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 classLoaderInterface.getResource(fullUri);
+ }
+ return findResource(fullUri, urls);
+ }
+
+ private Enumeration<URL> getResources(String fulluri) throws IOException {
+ if (urls == null) {
+ return classLoaderInterface.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 ("jar".equals(protocol)) {
+ /*
+ * 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;
+ StringBuilder sb = new StringBuilder(file.length() - sepIdx + resourceName.length());
+ sb.append(file.substring(sepIdx));
+ sb.append(resourceName);
+ entryName = sb.toString();
+ }
+ if ("META-INF/".equals(entryName) && 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 ("file".equals(protocol)) {
+ String baseFile = currentUrl.getFile();
+ String host = currentUrl.getHost();
+ int hostLength = 0;
+ if (host != null) {
+ hostLength = host.length();
+ }
+ StringBuilder buf = new StringBuilder(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);
+ File file2 = new File(URLDecoder.decode(filename));
+
+ if (file.exists() || file2.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 (!"http".equals(resourceURL.getProtocol())) {
+ 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 {
+ StringBuilder sb = new StringBuilder(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);
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/Test.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/Test.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/Test.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/Test.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.finder;
+
+/**
+ * This is the testing interface that is used to accept or reject resources.
+ */
+public interface Test<T> {
+ /**
+ * The test method.
+ *
+ * @param t The resource object to test.
+ * @return True if the resource should be accepted, false otherwise.
+ */
+ public boolean test(T t);
+}
\ No newline at end of file
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/UrlSet.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/UrlSet.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/UrlSet.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/finder/UrlSet.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.finder;
+
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.xwork2.util.URLUtil;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.ObjectUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * Use with ClassFinder to filter the Urls to be scanned, example:
+ * <pre>
+ * UrlSet urlSet = new UrlSet(classLoader);
+ * urlSet = urlSet.exclude(ClassLoader.getSystemClassLoader().getParent());
+ * urlSet = urlSet.excludeJavaExtDirs();
+ * urlSet = urlSet.excludeJavaEndorsedDirs();
+ * urlSet = urlSet.excludeJavaHome();
+ * urlSet = urlSet.excludePaths(System.getProperty("sun.boot.class.path", ""));
+ * urlSet = urlSet.exclude(".*?/JavaVM.framework/.*");
+ * urlSet = urlSet.exclude(".*?/activemq-(core|ra)-[\\d.]+.jar(!/)?");
+ * </pre>
+ * @author David Blevins
+ * @version $Rev: 1209415 $ $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $
+ */
+public class UrlSet {
+ private static final Logger LOG = LoggerFactory.getLogger(UrlSet.class);
+ private final Map<String,URL> urls;
+ private Set<String> protocols;
+
+
+ public UrlSet(ClassLoaderInterface classLoader) throws IOException {
+ this(getUrls(classLoader));
+ }
+
+ public UrlSet(ClassLoaderInterface classLoader, Set<String> protocols) throws IOException {
+ this(getUrls(classLoader, protocols));
+ this.protocols = protocols;
+ }
+
+ public UrlSet(URL... urls){
+ this(Arrays.asList(urls));
+ }
+ /**
+ * Ignores all URLs that are not "jar" or "file"
+ * @param urls
+ */
+ public UrlSet(Collection<URL> urls){
+ this.urls = new HashMap<String,URL>();
+ for (URL location : urls) {
+ try {
+// if (location.getProtocol().equals("file")) {
+// try {
+// // See if it's actually a jar
+// URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
+// JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
+// juc.getJarFile();
+// location = jarUrl;
+// } catch (IOException e) {
+// }
+// this.urls.put(location.toExternalForm(), location);
+// }
+ this.urls.put(location.toExternalForm(), location);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private UrlSet(Map<String, URL> urls) {
+ this.urls = urls;
+ }
+
+ public UrlSet include(UrlSet urlSet){
+ Map<String, URL> urls = new HashMap<String, URL>(this.urls);
+ urls.putAll(urlSet.urls);
+ return new UrlSet(urls);
+ }
+
+ public UrlSet exclude(UrlSet urlSet) {
+ Map<String, URL> urls = new HashMap<String, URL>(this.urls);
+ Map<String, URL> parentUrls = urlSet.urls;
+ for (String url : parentUrls.keySet()) {
+ urls.remove(url);
+ }
+ return new UrlSet(urls);
+ }
+
+ public UrlSet exclude(ClassLoaderInterface parent) throws IOException {
+ return exclude(new UrlSet(parent, this.protocols));
+ }
+
+ public UrlSet exclude(File file) throws MalformedURLException {
+ return exclude(relative(file));
+ }
+
+ public UrlSet exclude(String pattern) throws MalformedURLException {
+ return exclude(matching(pattern));
+ }
+
+ /**
+ * Calls excludePaths(System.getProperty("java.ext.dirs"))
+ * @return
+ * @throws MalformedURLException
+ */
+ public UrlSet excludeJavaExtDirs() throws MalformedURLException {
+ return excludePaths(System.getProperty("java.ext.dirs", ""));
+ }
+
+ /**
+ * Calls excludePaths(System.getProperty("java.endorsed.dirs"))
+ *
+ * @return
+ * @throws MalformedURLException
+ */
+ public UrlSet excludeJavaEndorsedDirs() throws MalformedURLException {
+ return excludePaths(System.getProperty("java.endorsed.dirs", ""));
+ }
+
+ public UrlSet excludeJavaHome() throws MalformedURLException {
+ String path = System.getProperty("java.home");
+ if (path != null) {
+
+ File java = new File(path);
+
+ if (path.matches("/System/Library/Frameworks/JavaVM.framework/Versions/[^/]+/Home")){
+ java = java.getParentFile();
+ }
+ return exclude(java);
+ } else {
+ return this;
+ }
+ }
+
+ public UrlSet excludePaths(String pathString) throws MalformedURLException {
+ String[] paths = pathString.split(File.pathSeparator);
+ UrlSet urlSet = this;
+ for (String path : paths) {
+ if (StringUtils.isNotEmpty(path)) {
+ File file = new File(path);
+ urlSet = urlSet.exclude(file);
+ }
+ }
+ return urlSet;
+ }
+
+ public UrlSet matching(String pattern) {
+ Map<String, URL> urls = new HashMap<String, URL>();
+ for (Map.Entry<String, URL> entry : this.urls.entrySet()) {
+ String url = entry.getKey();
+ if (url.matches(pattern)){
+ urls.put(url, entry.getValue());
+ }
+ }
+ return new UrlSet(urls);
+ }
+
+ /**
+ * Try to find a classes directory inside a war file add its normalized url to this set
+ */
+ public UrlSet includeClassesUrl(ClassLoaderInterface classLoaderInterface) throws IOException {
+ Enumeration<URL> rootUrlEnumeration = classLoaderInterface.getResources("");
+ while (rootUrlEnumeration.hasMoreElements()) {
+ URL url = rootUrlEnumeration.nextElement();
+ String externalForm = StringUtils.removeEnd(url.toExternalForm(), "/");
+ if (externalForm.endsWith(".war/WEB-INF/classes")) {
+ //if it is inside a war file, get the url to the file
+ externalForm = StringUtils.substringBefore(externalForm, "/WEB-INF/classes");
+ URL warUrl = new URL(externalForm);
+ URL normalizedUrl = URLUtil.normalizeToFileProtocol(warUrl);
+ URL finalUrl = (URL) ObjectUtils.defaultIfNull(normalizedUrl, warUrl);
+
+ Map<String, URL> newUrls = new HashMap<String, URL>(this.urls);
+ newUrls.put(finalUrl.toExternalForm(), finalUrl);
+ return new UrlSet(newUrls);
+ }
+ }
+
+ return this;
+ }
+
+ public UrlSet relative(File file) throws MalformedURLException {
+ String urlPath = file.toURL().toExternalForm();
+ Map<String, URL> urls = new HashMap<String, URL>();
+ for (Map.Entry<String, URL> entry : this.urls.entrySet()) {
+ String url = entry.getKey();
+ if (url.startsWith(urlPath) || url.startsWith("jar:"+urlPath)){
+ urls.put(url, entry.getValue());
+ }
+ }
+ return new UrlSet(urls);
+ }
+
+ public List<URL> getUrls() {
+ return new ArrayList<URL>(urls.values());
+ }
+
+ private static List<URL> getUrls(ClassLoaderInterface classLoader) throws IOException {
+ List<URL> list = new ArrayList<URL>();
+
+ //find jars
+ ArrayList<URL> urls = Collections.list(classLoader.getResources("META-INF"));
+
+ for (URL url : urls) {
+ if ("jar".equalsIgnoreCase(url.getProtocol())) {
+ String externalForm = url.toExternalForm();
+ //build a URL pointing to the jar, instead of the META-INF dir
+ url = new URL(StringUtils.substringBefore(externalForm, "META-INF"));
+ list.add(url);
+ } else if (LOG.isDebugEnabled())
+ LOG.debug("Ignoring URL [#0] because it is not a jar", url.toExternalForm());
+
+ }
+
+ //usually the "classes" dir
+ list.addAll(Collections.list(classLoader.getResources("")));
+ return list;
+ }
+
+ private static List<URL> getUrls(ClassLoaderInterface classLoader, Set<String> protocols) throws IOException {
+
+ if (protocols == null) {
+ return getUrls(classLoader);
+ }
+
+ List<URL> list = new ArrayList<URL>();
+
+ //find jars
+ ArrayList<URL> urls = Collections.list(classLoader.getResources("META-INF"));
+
+ for (URL url : urls) {
+ if (protocols.contains(url.getProtocol())) {
+ String externalForm = url.toExternalForm();
+ //build a URL pointing to the jar, instead of the META-INF dir
+ url = new URL(StringUtils.substringBefore(externalForm, "META-INF"));
+ list.add(url);
+ } else if (LOG.isDebugEnabled())
+ LOG.debug("Ignoring URL [#0] because it is not a valid protocol", url.toExternalForm());
+
+ }
+
+ //usually the "classes" dir
+ list.addAll(Collections.list(classLoader.getResources("")));
+ return list;
+ }
+
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Locatable.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Locatable.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Locatable.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Locatable.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.location;
+
+/**
+ * A interface that should be implemented by objects knowning their location (i.e. where they
+ * have been created from).
+ */
+public interface Locatable {
+ /**
+ * Get the location of this object
+ *
+ * @return the location
+ */
+ public Location getLocation();
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocatableProperties.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocatableProperties.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocatableProperties.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocatableProperties.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,76 @@
+package org.apache.struts2.xwork2.util.location;
+
+import org.apache.struts2.xwork2.util.PropertiesReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Properties implementation that remembers the location of each property. When
+ * loaded, a custom properties file parser is used to remember both the line number
+ * and preceeding comments for each property entry.
+ */
+public class LocatableProperties extends Properties implements Locatable {
+
+ Location location;
+ Map<String,Location> propLocations;
+
+ public LocatableProperties() {
+ this(null);
+ }
+
+ public LocatableProperties(Location loc) {
+ super();
+ this.location = loc;
+ this.propLocations = new HashMap<String,Location>();
+ }
+
+ @Override
+ public void load(InputStream in) throws IOException {
+ Reader reader = new InputStreamReader(in);
+ PropertiesReader pr = new PropertiesReader(reader);
+ while (pr.nextProperty()) {
+ String name = pr.getPropertyName();
+ String val = pr.getPropertyValue();
+ int line = pr.getLineNumber();
+ String desc = convertCommentsToString(pr.getCommentLines());
+
+ Location loc = new LocationImpl(desc, location.getURI(), line, 0);
+ setProperty(name, val, loc);
+ }
+ }
+
+ String convertCommentsToString(List<String> lines) {
+ StringBuilder sb = new StringBuilder();
+ if (lines != null && lines.size() > 0) {
+ for (String line : lines) {
+ sb.append(line).append('\n');
+ }
+ }
+ return sb.toString();
+ }
+
+ public Object setProperty(String key, String value, Object locationObj) {
+ Object obj = super.setProperty(key, value);
+ if (location != null) {
+ Location loc = LocationUtils.getLocation(locationObj);
+ propLocations.put(key, loc);
+ }
+ return obj;
+ }
+
+ public Location getPropertyLocation(String key) {
+ return propLocations.get(key);
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Located.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Located.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Located.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Located.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.location;
+
+/**
+ * Base class for location aware objects
+ */
+public abstract class Located implements Locatable {
+
+ protected Location location;
+
+ /**
+ * Get the location of this object
+ *
+ * @return the location
+ */
+ public Location getLocation() {
+ return location;
+ }
+
+ /**
+ * Set the location of this object
+ *
+ * @param loc the location
+ */
+ public void setLocation(Location loc) {
+ this.location = loc;
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Location.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Location.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Location.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/Location.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.location;
+
+import java.util.List;
+
+
+/**
+ * A location in a resource. The location is composed of the URI of the resource, and
+ * the line and column numbers within that resource (when available), along with a description.
+ * <p>
+ * Locations are mostly provided by {@link Locatable}s objects.
+ */
+public interface Location {
+
+ /**
+ * Constant for unknown locations.
+ */
+ public static final Location UNKNOWN = LocationImpl.UNKNOWN;
+
+ /**
+ * Get the description of this location
+ *
+ * @return the description (can be <code>null</code>)
+ */
+ String getDescription();
+
+ /**
+ * Get the URI of this location
+ *
+ * @return the URI (<code>null</code> if unknown).
+ */
+ String getURI();
+
+ /**
+ * Get the line number of this location
+ *
+ * @return the line number (<code>-1</code> if unknown)
+ */
+ int getLineNumber();
+
+ /**
+ * Get the column number of this location
+ *
+ * @return the column number (<code>-1</code> if unknown)
+ */
+ int getColumnNumber();
+
+ /**
+ * Gets a source code snippet with the default padding
+ *
+ * @param padding The amount of lines before and after the error to include
+ * @return A list of source lines
+ */
+ List<String> getSnippet(int padding);
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationAttributes.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationAttributes.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationAttributes.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationAttributes.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.location;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A class to handle location information stored in attributes.
+ * These attributes are typically setup using {@link LocationAttributes.Pipe}
+ * which augments the SAX stream with additional attributes, e.g.:
+ * <pre>
+ * <root xmlns:loc="http://struts.apache.org/xwork/location"
+ * loc:src="file://path/to/file.xml"
+ * loc:line="1" loc:column="1">
+ * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
+ * </root>
+ * </pre>
+ *
+ * @see LocationAttributes.Pipe
+ * @since 2.1.8
+ * @version $Id: LocationAttributes.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ */
+public class LocationAttributes {
+ /** Prefix for the location namespace */
+ public static final String PREFIX = "loc";
+ /** Namespace URI for location attributes */
+ public static final String URI = "http://struts.apache.org/xwork/location";
+
+ /** Attribute name for the location URI */
+ public static final String SRC_ATTR = "src";
+ /** Attribute name for the line number */
+ public static final String LINE_ATTR = "line";
+ /** Attribute name for the column number */
+ public static final String COL_ATTR = "column";
+
+ /** Attribute qualified name for the location URI */
+ public static final String Q_SRC_ATTR = "loc:src";
+ /** Attribute qualified name for the line number */
+ public static final String Q_LINE_ATTR = "loc:line";
+ /** Attribute qualified name for the column number */
+ public static final String Q_COL_ATTR = "loc:column";
+
+ // Private constructor, we only have static methods
+ private LocationAttributes() {
+ // Nothing
+ }
+
+ /**
+ * Add location attributes to a set of SAX attributes.
+ *
+ * @param locator the <code>Locator</code> (can be null)
+ * @param attrs the <code>Attributes</code> where locator information should be added
+ * @return Location enabled Attributes.
+ */
+ public static Attributes addLocationAttributes(Locator locator, Attributes attrs) {
+ if (locator == null || attrs.getIndex(URI, SRC_ATTR) != -1) {
+ // No location information known, or already has it
+ return attrs;
+ }
+
+ // Get an AttributeImpl so that we can add new attributes.
+ AttributesImpl newAttrs = attrs instanceof AttributesImpl ?
+ (AttributesImpl)attrs : new AttributesImpl(attrs);
+
+ newAttrs.addAttribute(URI, SRC_ATTR, Q_SRC_ATTR, "CDATA", locator.getSystemId());
+ newAttrs.addAttribute(URI, LINE_ATTR, Q_LINE_ATTR, "CDATA", Integer.toString(locator.getLineNumber()));
+ newAttrs.addAttribute(URI, COL_ATTR, Q_COL_ATTR, "CDATA", Integer.toString(locator.getColumnNumber()));
+
+ return newAttrs;
+ }
+
+ /**
+ * Returns the {@link Location} of an element (SAX flavor).
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @param description a description for the location (can be null)
+ * @return a {@link Location} object
+ */
+ public static Location getLocation(Attributes attrs, String description) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ if (src == null) {
+ return Location.UNKNOWN;
+ }
+
+ return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
+ }
+
+ /**
+ * Returns the location of an element (SAX flavor). If the location is to be kept
+ * into an object built from this element, consider using {@link #getLocation(Attributes, String)}
+ * and the {@link Locatable} interface.
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return a location string as defined by {@link Location}.
+ */
+ public static String getLocationString(Attributes attrs) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ if (src == null) {
+ return LocationUtils.UNKNOWN_STRING;
+ }
+
+ return src + ":" + attrs.getValue(URI, LINE_ATTR) + ":" + attrs.getValue(URI, COL_ATTR);
+ }
+
+ /**
+ * Returns the URI of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's URI or "<code>[unknown location]</code>" if <code>attrs</code>
+ * has no location information.
+ */
+ public static String getURI(Attributes attrs) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ return src != null ? src : LocationUtils.UNKNOWN_STRING;
+ }
+
+ /**
+ * Returns the line number of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's line number or <code>-1</code> if <code>attrs</code>
+ * has no location information.
+ */
+ public static int getLine(Attributes attrs) {
+ String line = attrs.getValue(URI, LINE_ATTR);
+ return line != null ? Integer.parseInt(line) : -1;
+ }
+
+ /**
+ * Returns the column number of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's column number or <code>-1</code> if <code>attrs</code>
+ * has no location information.
+ */
+ public static int getColumn(Attributes attrs) {
+ String col = attrs.getValue(URI, COL_ATTR);
+ return col != null ? Integer.parseInt(col) : -1;
+ }
+
+ /**
+ * Returns the {@link Location} of an element (DOM flavor).
+ *
+ * @param elem the element that holds the location information
+ * @param description a description for the location (if <code>null</code>, the element's name is used)
+ * @return a {@link Location} object
+ */
+ public static Location getLocation(Element elem, String description) {
+ Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ if (srcAttr == null) {
+ return Location.UNKNOWN;
+ }
+
+ return new LocationImpl(description == null ? elem.getNodeName() : description,
+ srcAttr.getValue(), getLine(elem), getColumn(elem));
+ }
+
+ /**
+ * Same as <code>getLocation(elem, null)</code>.
+ */
+ public static Location getLocation(Element elem) {
+ return getLocation(elem, null);
+ }
+
+
+ /**
+ * Returns the location of an element that has been processed by this pipe (DOM flavor).
+ * If the location is to be kept into an object built from this element, consider using
+ * {@link #getLocation(Element)} and the {@link Locatable} interface.
+ *
+ * @param elem the element that holds the location information
+ * @return a location string as defined by {@link Location}.
+ */
+ public static String getLocationString(Element elem) {
+ Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ if (srcAttr == null) {
+ return LocationUtils.UNKNOWN_STRING;
+ }
+
+ return srcAttr.getValue() + ":" + elem.getAttributeNS(URI, LINE_ATTR) + ":" + elem.getAttributeNS(URI, COL_ATTR);
+ }
+
+ /**
+ * Returns the URI of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's URI or "<code>[unknown location]</code>" if <code>elem</code>
+ * has no location information.
+ */
+ public static String getURI(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ return attr != null ? attr.getValue() : LocationUtils.UNKNOWN_STRING;
+ }
+
+ /**
+ * Returns the line number of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's line number or <code>-1</code> if <code>elem</code>
+ * has no location information.
+ */
+ public static int getLine(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, LINE_ATTR);
+ return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+ }
+
+ /**
+ * Returns the column number of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's column number or <code>-1</code> if <code>elem</code>
+ * has no location information.
+ */
+ public static int getColumn(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, COL_ATTR);
+ return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+ }
+
+ /**
+ * Remove the location attributes from a DOM element.
+ *
+ * @param elem the element to remove the location attributes from.
+ * @param recurse if <code>true</code>, also remove location attributes on descendant elements.
+ */
+ public static void remove(Element elem, boolean recurse) {
+ elem.removeAttributeNS(URI, SRC_ATTR);
+ elem.removeAttributeNS(URI, LINE_ATTR);
+ elem.removeAttributeNS(URI, COL_ATTR);
+ if (recurse) {
+ NodeList children = elem.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ remove((Element)child, recurse);
+ }
+ }
+ }
+ }
+
+ /**
+ * A SAX filter that adds the information available from the <code>Locator</code> as attributes.
+ * The purpose of having location as attributes is to allow this information to survive transformations
+ * of the document (an XSL could copy these attributes over) or conversion of SAX events to a DOM.
+ * <p>
+ * The location is added as 3 attributes in a specific namespace to each element.
+ * <pre>
+ * <root xmlns:loc="http://opensymphony.com/xwork/location"
+ * loc:src="file://path/to/file.xml"
+ * loc:line="1" loc:column="1">
+ * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
+ * </root>
+ * </pre>
+ * <strong>Note:</strong> Although this adds a lot of information to the serialized form of the document,
+ * the overhead in SAX events is not that big, as attribute names are interned, and all <code>src</code>
+ * attributes point to the same string.
+ *
+ * @see LocationAttributes
+ */
+ public static class Pipe implements ContentHandler {
+
+ private Locator locator;
+
+ private ContentHandler nextHandler;
+
+ /**
+ * Create a filter. It has to be chained to another handler to be really useful.
+ */
+ public Pipe() {
+ }
+
+ /**
+ * Create a filter that is chained to another handler.
+ * @param next the next handler in the chain.
+ */
+ public Pipe(ContentHandler next) {
+ nextHandler = next;
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ nextHandler.setDocumentLocator(locator);
+ }
+
+ public void startDocument() throws SAXException {
+ nextHandler.startDocument();
+ nextHandler.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
+ }
+
+ public void endDocument() throws SAXException {
+ endPrefixMapping(LocationAttributes.PREFIX);
+ nextHandler.endDocument();
+ }
+
+ public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+ // Add location attributes to the element
+ nextHandler.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
+ }
+
+ public void endElement(String arg0, String arg1, String arg2) throws SAXException {
+ nextHandler.endElement(arg0, arg1, arg2);
+ }
+
+ public void startPrefixMapping(String arg0, String arg1) throws SAXException {
+ nextHandler.startPrefixMapping(arg0, arg1);
+ }
+
+ public void endPrefixMapping(String arg0) throws SAXException {
+ nextHandler.endPrefixMapping(arg0);
+ }
+
+ public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
+ nextHandler.characters(arg0, arg1, arg2);
+ }
+
+ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+ nextHandler.ignorableWhitespace(arg0, arg1, arg2);
+ }
+
+ public void processingInstruction(String arg0, String arg1) throws SAXException {
+ nextHandler.processingInstruction(arg0, arg1);
+ }
+
+ public void skippedEntity(String arg0) throws SAXException {
+ nextHandler.skippedEntity(arg0);
+ }
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationImpl.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationImpl.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/location/LocationImpl.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.struts2.xwork2.util.location;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple immutable and serializable implementation of {@link Location}.
+ */
+public class LocationImpl implements Location, Serializable {
+ private final String uri;
+ private final int line;
+ private final int column;
+ private final String description;
+
+ // Package private: outside this package, use Location.UNKNOWN.
+ static final LocationImpl UNKNOWN = new LocationImpl(null, null, -1, -1);
+
+ /**
+ * Build a location for a given URI, with unknown line and column numbers.
+ *
+ * @param uri the resource URI
+ */
+ public LocationImpl(String description, String uri) {
+ this(description, uri, -1, -1);
+ }
+
+ /**
+ * Build a location for a given URI and line and column numbers.
+ *
+ * @param uri the resource URI
+ * @param line the line number (starts at 1)
+ * @param column the column number (starts at 1)
+ */
+ public LocationImpl(String description, String uri, int line, int column) {
+ if (uri == null || uri.length() == 0) {
+ this.uri = null;
+ this.line = -1;
+ this.column = -1;
+ } else {
+ this.uri = uri;
+ this.line = line;
+ this.column = column;
+ }
+
+ if (description != null && description.length() == 0) {
+ description = null;
+ }
+ this.description = description;
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param location the location to be copied
+ */
+ public LocationImpl(Location location) {
+ this(location.getDescription(), location.getURI(), location.getLineNumber(), location.getColumnNumber());
+ }
+
+ /**
+ * Create a location from an existing one, but with a different description
+ */
+ public LocationImpl(String description, Location location) {
+ this(description, location.getURI(), location.getLineNumber(), location.getColumnNumber());
+ }
+
+ /**
+ * Obtain a <code>LocationImpl</code> from a {@link Location}. If <code>location</code> is
+ * already a <code>LocationImpl</code>, it is returned, otherwise it is copied.
+ * <p>
+ * This method is useful when an immutable and serializable location is needed, such as in locatable
+ * exceptions.
+ *
+ * @param location the location
+ * @return an immutable and serializable version of <code>location</code>
+ */
+ public static LocationImpl get(Location location) {
+ if (location instanceof LocationImpl) {
+ return (LocationImpl)location;
+ } else if (location == null) {
+ return UNKNOWN;
+ } else {
+ return new LocationImpl(location);
+ }
+ }
+
+ /**
+ * Get the description of this location
+ *
+ * @return the description (can be <code>null</code>)
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Get the URI of this location
+ *
+ * @return the URI (<code>null</code> if unknown).
+ */
+ public String getURI() {
+ return this.uri;
+ }
+
+ /**
+ * Get the line number of this location
+ *
+ * @return the line number (<code>-1</code> if unknown)
+ */
+ public int getLineNumber() {
+ return this.line;
+ }
+
+ /**
+ * Get the column number of this location
+ *
+ * @return the column number (<code>-1</code> if unknown)
+ */
+ public int getColumnNumber() {
+ return this.column;
+ }
+
+ /**
+ * Gets a source code snippet with the default padding
+ *
+ * @param padding The amount of lines before and after the error to include
+ */
+ public List<String> getSnippet(int padding) {
+ List<String> snippet = new ArrayList<String>();
+ if (getLineNumber() > 0) {
+ try {
+ InputStream in = new URL(getURI()).openStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+ int lineno = 0;
+ int errno = getLineNumber();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lineno++;
+ if (lineno >= errno - padding && lineno <= errno + padding) {
+ snippet.add(line);
+ }
+ }
+ } catch (Exception ex) {
+ // ignoring as snippet not available isn't a big deal
+ }
+ }
+ return snippet;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof Location) {
+ Location other = (Location)obj;
+ return this.line == other.getLineNumber() && this.column == other.getColumnNumber()
+ && testEquals(this.uri, other.getURI())
+ && testEquals(this.description, other.getDescription());
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = line ^ column;
+ if (uri != null) hash ^= uri.hashCode();
+ if (description != null) hash ^= description.hashCode();
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return LocationUtils.toString(this);
+ }
+
+ /**
+ * Ensure serialized unknown location resolve to {@link Location#UNKNOWN}.
+ */
+ private Object readResolve() {
+ return this.equals(Location.UNKNOWN) ? Location.UNKNOWN : this;
+ }
+
+ private boolean testEquals(Object object1, Object object2) {
+ if (object1 == object2) {
+ return true;
+ }
+ if ((object1 == null) || (object2 == null)) {
+ return false;
+ }
+ return object1.equals(object2);
+ }
+}