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 [27/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/ResolverUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ResolverUtil.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ResolverUtil.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ResolverUtil.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,466 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * 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;
+
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * <p>ResolverUtil is used to locate classes that are available in the/a class path and meet
+ * arbitrary conditions. The two most common conditions are that a class implements/extends
+ * another class, or that is it annotated with a specific annotation. However, through the use
+ * of the {@link Test} class it is possible to search using arbitrary conditions.</p>
+ *
+ * <p>A ClassLoader is used to locate all locations (directories and jar files) in the class
+ * path that contain classes within certain packages, and then to load those classes and
+ * check them. By default the ClassLoader returned by
+ * {@code Thread.currentThread().getContextClassLoader()} is used, but this can be overridden
+ * by calling {@link #setClassLoader(ClassLoader)} prior to invoking any of the {@code find()}
+ * methods.</p>
+ *
+ * <p>General searches are initiated by calling the
+ * {@link #find(ResolverUtil.Test, String...)} ()} method and supplying
+ * a package name and a Test instance. This will cause the named package <b>and all sub-packages</b>
+ * to be scanned for classes that meet the test. There are also utility methods for the common
+ * use cases of scanning multiple packages for extensions of particular classes, or classes
+ * annotated with a specific annotation.</p>
+ *
+ * <p>The standard usage pattern for the ResolverUtil class is as follows:</p>
+ *
+ *<pre>
+ *ResolverUtil<ActionBean> resolver = new ResolverUtil<ActionBean>();
+ *resolver.findImplementation(ActionBean.class, pkg1, pkg2);
+ *resolver.find(new CustomTest(), pkg1);
+ *resolver.find(new CustomTest(), pkg2);
+ *Collection<ActionBean> beans = resolver.getClasses();
+ *</pre>
+ *
+ * <p>This class was copied from Stripes - http://stripes.mc4j.org/confluence/display/stripes/Home
+ * </p>
+ *
+ * @author Tim Fennell
+ */
+public class ResolverUtil<T> {
+ /** An instance of Log to use for logging in this class. */
+ private static final Logger LOG = LoggerFactory.getLogger(ResolverUtil.class);
+
+ /**
+ * A simple interface that specifies how to test classes to determine if they
+ * are to be included in the results produced by the ResolverUtil.
+ */
+ public static interface Test {
+ /**
+ * Will be called repeatedly with candidate classes. Must return True if a class
+ * is to be included in the results, false otherwise.
+ */
+ boolean matches(Class type);
+
+ boolean matches(URL resource);
+
+ boolean doesMatchClass();
+ boolean doesMatchResource();
+ }
+
+ public static abstract class ClassTest implements Test {
+ public boolean matches(URL resource) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean doesMatchClass() {
+ return true;
+ }
+ public boolean doesMatchResource() {
+ return false;
+ }
+ }
+
+ public static abstract class ResourceTest implements Test {
+ public boolean matches(Class cls) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean doesMatchClass() {
+ return false;
+ }
+ public boolean doesMatchResource() {
+ return true;
+ }
+ }
+
+ /**
+ * A Test that checks to see if each class is assignable to the provided class. Note
+ * that this test will match the parent type itself if it is presented for matching.
+ */
+ public static class IsA extends ClassTest {
+ private Class parent;
+
+ /** Constructs an IsA test using the supplied Class as the parent class/interface. */
+ public IsA(Class parentType) { this.parent = parentType; }
+
+ /** Returns true if type is assignable to the parent type supplied in the constructor. */
+ public boolean matches(Class type) {
+ return type != null && parent.isAssignableFrom(type);
+ }
+
+ @Override public String toString() {
+ return "is assignable to " + parent.getSimpleName();
+ }
+ }
+
+ /**
+ * A Test that checks to see if each class name ends with the provided suffix.
+ */
+ public static class NameEndsWith extends ClassTest {
+ private String suffix;
+
+ /** Constructs a NameEndsWith test using the supplied suffix. */
+ public NameEndsWith(String suffix) { this.suffix = suffix; }
+
+ /** Returns true if type name ends with the suffix supplied in the constructor. */
+ public boolean matches(Class type) {
+ return type != null && type.getName().endsWith(suffix);
+ }
+
+ @Override public String toString() {
+ return "ends with the suffix " + suffix;
+ }
+ }
+
+ /**
+ * A Test that checks to see if each class is annotated with a specific annotation. If it
+ * is, then the test returns true, otherwise false.
+ */
+ public static class AnnotatedWith extends ClassTest {
+ private Class<? extends Annotation> annotation;
+
+ /** Construts an AnnotatedWith test for the specified annotation type. */
+ public AnnotatedWith(Class<? extends Annotation> annotation) { this.annotation = annotation; }
+
+ /** Returns true if the type is annotated with the class provided to the constructor. */
+ public boolean matches(Class type) {
+ return type != null && type.isAnnotationPresent(annotation);
+ }
+
+ @Override public String toString() {
+ return "annotated with @" + annotation.getSimpleName();
+ }
+ }
+
+ public static class NameIs extends ResourceTest {
+ private String name;
+
+ public NameIs(String name) { this.name = "/" + name; }
+
+ public boolean matches(URL resource) {
+ return (resource.getPath().endsWith(name));
+ }
+
+ @Override public String toString() {
+ return "named " + name;
+ }
+ }
+
+ /** The set of matches being accumulated. */
+ private Set<Class<? extends T>> classMatches = new HashSet<Class<?extends T>>();
+
+ /** The set of matches being accumulated. */
+ private Set<URL> resourceMatches = new HashSet<URL>();
+
+ /**
+ * The ClassLoader to use when looking for classes. If null then the ClassLoader returned
+ * by Thread.currentThread().getContextClassLoader() will be used.
+ */
+ private ClassLoader classloader;
+
+ /**
+ * Provides access to the classes discovered so far. If no calls have been made to
+ * any of the {@code find()} methods, this set will be empty.
+ *
+ * @return the set of classes that have been discovered.
+ */
+ public Set<Class<? extends T>> getClasses() {
+ return classMatches;
+ }
+
+ public Set<URL> getResources() {
+ return resourceMatches;
+ }
+
+
+ /**
+ * Returns the classloader that will be used for scanning for classes. If no explicit
+ * ClassLoader has been set by the calling, the context class loader will be used.
+ *
+ * @return the ClassLoader that will be used to scan for classes
+ */
+ public ClassLoader getClassLoader() {
+ return classloader == null ? Thread.currentThread().getContextClassLoader() : classloader;
+ }
+
+ /**
+ * Sets an explicit ClassLoader that should be used when scanning for classes. If none
+ * is set then the context classloader will be used.
+ *
+ * @param classloader a ClassLoader to use when scanning for classes
+ */
+ public void setClassLoader(ClassLoader classloader) { this.classloader = classloader; }
+
+ /**
+ * Attempts to discover classes that are assignable to the type provided. In the case
+ * that an interface is provided this method will collect implementations. In the case
+ * of a non-interface class, subclasses will be collected. Accumulated classes can be
+ * accessed by calling {@link #getClasses()}.
+ *
+ * @param parent the class of interface to find subclasses or implementations of
+ * @param packageNames one or more package names to scan (including subpackages) for classes
+ */
+ public void findImplementations(Class parent, String... packageNames) {
+ if (packageNames == null) return;
+
+ Test test = new IsA(parent);
+ for (String pkg : packageNames) {
+ findInPackage(test, pkg);
+ }
+ }
+
+ /**
+ * Attempts to discover classes who's name ends with the provided suffix. Accumulated classes can be
+ * accessed by calling {@link #getClasses()}.
+ *
+ * @param suffix The class name suffix to match
+ * @param packageNames one or more package names to scan (including subpackages) for classes
+ */
+ public void findSuffix(String suffix, String... packageNames) {
+ if (packageNames == null) return;
+
+ Test test = new NameEndsWith(suffix);
+ for (String pkg : packageNames) {
+ findInPackage(test, pkg);
+ }
+ }
+
+ /**
+ * Attempts to discover classes that are annotated with to the annotation. Accumulated
+ * classes can be accessed by calling {@link #getClasses()}.
+ *
+ * @param annotation the annotation that should be present on matching classes
+ * @param packageNames one or more package names to scan (including subpackages) for classes
+ */
+ public void findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
+ if (packageNames == null) return;
+
+ Test test = new AnnotatedWith(annotation);
+ for (String pkg : packageNames) {
+ findInPackage(test, pkg);
+ }
+ }
+
+ public void findNamedResource(String name, String... pathNames) {
+ if (pathNames == null) return;
+
+ Test test = new NameIs(name);
+ for (String pkg : pathNames) {
+ findInPackage(test, pkg);
+ }
+ }
+
+ /**
+ * Attempts to discover classes that pass the test. Accumulated
+ * classes can be accessed by calling {@link #getClasses()}.
+ *
+ * @param test the test to determine matching classes
+ * @param packageNames one or more package names to scan (including subpackages) for classes
+ */
+ public void find(Test test, String... packageNames) {
+ if (packageNames == null) return;
+
+ for (String pkg : packageNames) {
+ findInPackage(test, pkg);
+ }
+ }
+
+ /**
+ * Scans for classes starting at the package provided and descending into subpackages.
+ * Each class is offered up to the Test as it is discovered, and if the Test returns
+ * true the class is retained. Accumulated classes can be fetched by calling
+ * {@link #getClasses()}.
+ *
+ * @param test an instance of {@link Test} that will be used to filter classes
+ * @param packageName the name of the package from which to start scanning for
+ * classes, e.g. {@code net.sourceforge.stripes}
+ */
+ public void findInPackage(Test test, String packageName) {
+ packageName = packageName.replace('.', '/');
+ ClassLoader loader = getClassLoader();
+ Enumeration<URL> urls;
+
+ try {
+ urls = loader.getResources(packageName);
+ }
+ catch (IOException ioe) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn("Could not read package: " + packageName, ioe);
+ }
+ return;
+ }
+
+ while (urls.hasMoreElements()) {
+ try {
+ String urlPath = urls.nextElement().getFile();
+ urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+ // If it's a file in a directory, trim the stupid file: spec
+ if ( urlPath.startsWith("file:") ) {
+ urlPath = urlPath.substring(5);
+ }
+
+ // Else it's in a JAR, grab the path to the jar
+ if (urlPath.indexOf('!') > 0) {
+ urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+ }
+
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+ }
+ File file = new File(urlPath);
+ if ( file.isDirectory() ) {
+ loadImplementationsInDirectory(test, packageName, file);
+ }
+ else {
+ loadImplementationsInJar(test, packageName, file);
+ }
+ }
+ catch (IOException ioe) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn("could not read entries", ioe);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Finds matches in a physical directory on a filesystem. Examines all
+ * files within a directory - if the File object is not a directory, and ends with <i>.class</i>
+ * the file is loaded and tested to see if it is acceptable according to the Test. Operates
+ * recursively to find classes within a folder structure matching the package structure.
+ *
+ * @param test a Test used to filter the classes that are discovered
+ * @param parent the package name up to this directory in the package hierarchy. E.g. if
+ * /classes is in the classpath and we wish to examine files in /classes/org/apache then
+ * the values of <i>parent</i> would be <i>org/apache</i>
+ * @param location a File object representing a directory
+ */
+ private void loadImplementationsInDirectory(Test test, String parent, File location) {
+ File[] files = location.listFiles();
+ StringBuilder builder = null;
+
+ for (File file : files) {
+ builder = new StringBuilder(100);
+ builder.append(parent).append("/").append(file.getName());
+ String packageOrClass = ( parent == null ? file.getName() : builder.toString() );
+
+ if (file.isDirectory()) {
+ loadImplementationsInDirectory(test, packageOrClass, file);
+ }
+ else if (isTestApplicable(test, file.getName())) {
+ addIfMatching(test, packageOrClass);
+ }
+ }
+ }
+
+ private boolean isTestApplicable(Test test, String path) {
+ return test.doesMatchResource() || path.endsWith(".class") && test.doesMatchClass();
+ }
+
+ /**
+ * Finds matching classes within a jar files that contains a folder structure
+ * matching the package structure. If the File is not a JarFile or does not exist a warning
+ * will be logged, but no error will be raised.
+ *
+ * @param test a Test used to filter the classes that are discovered
+ * @param parent the parent package under which classes must be in order to be considered
+ * @param jarfile the jar file to be examined for classes
+ */
+ private void loadImplementationsInJar(Test test, String parent, File jarfile) {
+
+ try {
+ JarEntry entry;
+ JarInputStream jarStream = new JarInputStream(new FileInputStream(jarfile));
+
+ while ( (entry = jarStream.getNextJarEntry() ) != null) {
+ String name = entry.getName();
+ if (!entry.isDirectory() && name.startsWith(parent) && isTestApplicable(test, name)) {
+ addIfMatching(test, name);
+ }
+ }
+ }
+ catch (IOException ioe) {
+ LOG.error("Could not search jar file '" + jarfile + "' for classes matching criteria: " +
+ test + " due to an IOException", ioe);
+ }
+ }
+
+ /**
+ * Add the class designated by the fully qualified class name provided to the set of
+ * resolved classes if and only if it is approved by the Test supplied.
+ *
+ * @param test the test used to determine if the class matches
+ * @param fqn the fully qualified name of a class
+ */
+ protected void addIfMatching(Test test, String fqn) {
+ try {
+ ClassLoader loader = getClassLoader();
+ if (test.doesMatchClass()) {
+ String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
+ }
+
+ Class type = loader.loadClass(externalName);
+ if (test.matches(type) ) {
+ classMatches.add( (Class<T>) type);
+ }
+ }
+ if (test.doesMatchResource()) {
+ URL url = loader.getResource(fqn);
+ if (url == null) {
+ url = loader.getResource(fqn.substring(1));
+ }
+ if (url != null && test.matches(url)) {
+ resourceMatches.add(url);
+ }
+ }
+ }
+ catch (Throwable t) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn("Could not examine class '" + fqn + "' due to a " +
+ t.getClass().getName() + " with message: " + t.getMessage());
+ }
+ }
+ }
+}
\ No newline at end of file
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/TextParseUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/TextParseUtil.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/TextParseUtil.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/TextParseUtil.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2002-2006,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;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.conversion.impl.XWorkConverter;
+import org.apache.struts2.xwork2.inject.Container;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+
+
+/**
+ * Utility class for text parsing.
+ *
+ * @author Jason Carreira
+ * @author Rainer Hermanns
+ * @author tm_jee
+ *
+ * @version $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $ $Id: TextParseUtil.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ */
+public class TextParseUtil {
+
+ private static final int MAX_RECURSION = 1;
+
+ /**
+ * Converts all instances of ${...}, and %{...} in <code>expression</code> to the value returned
+ * by a call to {@link ValueStack#findValue(java.lang.String)}. If an item cannot
+ * be found on the stack (null is returned), then the entire variable ${...} is not
+ * displayed, just as if the item was on the stack but returned an empty string.
+ *
+ * @param expression an expression that hasn't yet been translated
+ * @return the parsed expression
+ */
+ public static String translateVariables(String expression, ValueStack stack) {
+ return translateVariables(new char[]{'$', '%'}, expression, stack, String.class, null).toString();
+ }
+
+
+ /**
+ * Function similarly as {@link #translateVariables(char, String, ValueStack)}
+ * except for the introduction of an additional <code>evaluator</code> that allows
+ * the parsed value to be evaluated by the <code>evaluator</code>. The <code>evaluator</code>
+ * could be null, if it is it will just be skipped as if it is just calling
+ * {@link #translateVariables(char, String, ValueStack)}.
+ *
+ * <p/>
+ *
+ * A typical use-case would be when we need to URL Encode the parsed value. To do so
+ * we could just supply a URLEncodingEvaluator for example.
+ *
+ * @param expression
+ * @param stack
+ * @param evaluator The parsed Value evaluator (could be null).
+ * @return the parsed (and possibly evaluated) variable String.
+ */
+ public static String translateVariables(String expression, ValueStack stack, ParsedValueEvaluator evaluator) {
+ return translateVariables(new char[]{'$', '%'}, expression, stack, String.class, evaluator).toString();
+ }
+
+ /**
+ * Converts all instances of ${...} in <code>expression</code> to the value returned
+ * by a call to {@link ValueStack#findValue(java.lang.String)}. If an item cannot
+ * be found on the stack (null is returned), then the entire variable ${...} is not
+ * displayed, just as if the item was on the stack but returned an empty string.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @return Translated variable String
+ */
+ public static String translateVariables(char open, String expression, ValueStack stack) {
+ return translateVariables(open, expression, stack, String.class, null).toString();
+ }
+
+ /**
+ * Converted object from variable translation.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @param asType
+ * @return Converted object from variable translation.
+ */
+ public static Object translateVariables(char open, String expression, ValueStack stack, Class asType) {
+ return translateVariables(open, expression, stack, asType, null);
+ }
+
+ /**
+ * Converted object from variable translation.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @param asType
+ * @param evaluator
+ * @return Converted object from variable translation.
+ */
+ public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
+ return translateVariables(new char[]{open} , expression, stack, asType, evaluator, MAX_RECURSION);
+ }
+
+ /**
+ * Converted object from variable translation.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @param asType
+ * @param evaluator
+ * @return Converted object from variable translation.
+ */
+ public static Object translateVariables(char[] openChars, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
+ return translateVariables(openChars, expression, stack, asType, evaluator, MAX_RECURSION);
+ }
+
+ /**
+ * Converted object from variable translation.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @param asType
+ * @param evaluator
+ * @return Converted object from variable translation.
+ */
+ public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator, int maxLoopCount) {
+ return translateVariables(new char[]{open}, expression, stack, asType, evaluator, maxLoopCount);
+ }
+
+ /**
+ * Converted object from variable translation.
+ *
+ * @param open
+ * @param expression
+ * @param stack
+ * @param asType
+ * @param evaluator
+ * @return Converted object from variable translation.
+ */
+ public static Object translateVariables(char[] openChars, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator, int maxLoopCount) {
+ // deal with the "pure" expressions first!
+ //expression = expression.trim();
+ Object result = expression;
+ for (char open : openChars) {
+ int loopCount = 1;
+ int pos = 0;
+
+ //this creates an implicit StringBuffer and shouldn't be used in the inner loop
+ final String lookupChars = open + "{";
+
+ while (true) {
+ int start = expression.indexOf(lookupChars, pos);
+ if (start == -1) {
+ pos = 0;
+ loopCount++;
+ start = expression.indexOf(lookupChars);
+ }
+ if (loopCount > maxLoopCount) {
+ // translateVariables prevent infinite loop / expression recursive evaluation
+ break;
+ }
+ int length = expression.length();
+ int x = start + 2;
+ int end;
+ char c;
+ int count = 1;
+ while (start != -1 && x < length && count != 0) {
+ c = expression.charAt(x++);
+ if (c == '{') {
+ count++;
+ } else if (c == '}') {
+ count--;
+ }
+ }
+ end = x - 1;
+
+ if ((start != -1) && (end != -1) && (count == 0)) {
+ String var = expression.substring(start + 2, end);
+
+ Object o = stack.findValue(var, asType);
+ if (evaluator != null) {
+ o = evaluator.evaluate(o);
+ }
+
+
+ String left = expression.substring(0, start);
+ String right = expression.substring(end + 1);
+ String middle = null;
+ if (o != null) {
+ middle = o.toString();
+ if (StringUtils.isEmpty(left)) {
+ result = o;
+ } else {
+ result = left.concat(middle);
+ }
+
+ if (StringUtils.isNotEmpty(right)) {
+ result = result.toString().concat(right);
+ }
+
+ expression = left.concat(middle).concat(right);
+ } else {
+ // the variable doesn't exist, so don't display anything
+ expression = left.concat(right);
+ result = expression;
+ }
+ pos = (left != null && left.length() > 0 ? left.length() - 1: 0) +
+ (middle != null && middle.length() > 0 ? middle.length() - 1: 0) +
+ 1;
+ pos = Math.max(pos, 1);
+ } else {
+ break;
+ }
+ }
+ }
+
+ XWorkConverter conv = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(XWorkConverter.class);
+ return conv.convertValue(stack.getContext(), result, asType);
+ }
+
+ /**
+ * Returns a set from comma delimted Strings.
+ * @param s The String to parse.
+ * @return A set from comma delimted Strings.
+ */
+ public static Set<String> commaDelimitedStringToSet(String s) {
+ Set<String> set = new HashSet<String>();
+ String[] split = s.split(",");
+ for (String aSplit : split) {
+ String trimmed = aSplit.trim();
+ if (trimmed.length() > 0)
+ set.add(trimmed);
+ }
+ return set;
+ }
+
+
+ /**
+ * A parsed value evaluator for {@link TextParseUtil}. It could be supplied by
+ * calling {@link TextParseUtil#translateVariables(char, String, ValueStack, Class, ParsedValueEvaluator)}.
+ *
+ * <p/>
+ *
+ * By supplying this <code>ParsedValueEvaluator</code>, the parsed value
+ * (parsed against the value stack) value will be
+ * given to <code>ParsedValueEvaluator</code> to be evaluated before the
+ * translateVariable process goes on.
+ *
+ * <p/>
+ *
+ * A typical use-case would be to have a custom <code>ParseValueEvaluator</code>
+ * to URL Encode the parsed value.
+ *
+ * @author tm_jee
+ *
+ * @version $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $ $Id: TextParseUtil.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ */
+ public static interface ParsedValueEvaluator {
+
+ /**
+ * Evaluated the value parsed by Ognl value stack.
+ *
+ * @param parsedValue - value parsed by ognl value stack
+ * @return return the evaluted value.
+ */
+ Object evaluate(Object parsedValue);
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/URLUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/URLUtil.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/URLUtil.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/URLUtil.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+/**
+ * Helper class to extract file paths from different urls
+ */
+public class URLUtil {
+
+ /**
+ * Prefix for Jar files in JBoss Virtual File System
+ */
+ public static final String JBOSS5_VFS = "vfs";
+ public static final String JBOSS5_VFSZIP = "vfszip";
+ public static final String JBOSS5_VFSMEMORY = "vfsmemory";
+ public static final String JBOSS5_VFSFILE = "vfsfile";
+
+ private static final Pattern JAR_PATTERN = Pattern.compile("^(jar:|wsjar:|zip:|vfsfile:|code-source:)?(file:)?(.*?)(\\!/|\\.jar/)(.*)");
+ private static final int JAR_FILE_PATH = 3;
+
+ /**
+ * Convert URLs to URLs with "file" protocol
+ * @param url URL to convert to a jar url
+ * @return a URL to a file, or null if the URL external form cannot be parsed
+ */
+ public static URL normalizeToFileProtocol(URL url) {
+ String fileName = url.toExternalForm();
+ Matcher jarMatcher = JAR_PATTERN.matcher(fileName);
+ try {
+ if (isJBoss5Url(url)){
+ return new URL("file", null, fileName.substring(fileName.indexOf(":") + 1));
+ } else if (jarMatcher.matches()) {
+ String path = jarMatcher.group(JAR_FILE_PATH);
+ return new URL("file", "", path);
+ } else {
+ //it is not a jar or zip file
+ return null;
+ }
+ } catch (MalformedURLException e) {
+ //can this ever happen?
+ return null;
+ }
+ }
+
+ /**
+ * Verify That the given String is in valid URL format.
+ * @param url The url string to verify.
+ * @return a boolean indicating whether the URL seems to be incorrect.
+ */
+ public static boolean verifyUrl(String url) {
+ if (url == null) {
+ return false;
+ }
+
+ if (url.startsWith("https://")) {
+ // URL doesn't understand the https protocol, hack it
+ url = "http://" + url.substring(8);
+ }
+
+ try {
+ new URL(url);
+
+ return true;
+ } catch (MalformedURLException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Check if given URL is matching Jar pattern for different servers
+ * @param fileUrl
+ * @return
+ */
+ public static boolean isJarURL(URL fileUrl) {
+ Matcher jarMatcher = URLUtil.JAR_PATTERN.matcher(fileUrl.getPath());
+ return jarMatcher.matches();
+ }
+
+ /**
+ * Check if given URL is pointing to JBoss 5 VFS resource
+ * @param fileUrl
+ * @return
+ */
+ public static boolean isJBoss5Url(URL fileUrl) {
+ final String protocol = fileUrl.getProtocol();
+ return JBOSS5_VFSZIP.equals(protocol) || JBOSS5_VFSMEMORY.equals(protocol) || JBOSS5_VFS.equals(protocol)
+ || ("true".equals(System.getProperty("jboss.vfs.forceVfsJar")) && JBOSS5_VFSFILE.equals(protocol));
+ }
+
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStack.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStack.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStack.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStack.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2002-2007,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;
+
+import java.util.Map;
+
+/**
+ * ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When
+ * evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the
+ * earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending
+ * on the expression being evaluated).
+ */
+public interface ValueStack {
+
+ public static final String VALUE_STACK = "org.apache.struts2.xwork2.util.ValueStack.ValueStack";
+
+ public static final String REPORT_ERRORS_ON_NO_PROP = "org.apache.struts2.xwork2.util.ValueStack.ReportErrorsOnNoProp";
+
+ /**
+ * Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings.
+ *
+ * @return the context.
+ */
+ public abstract Map<String, Object> getContext();
+
+ /**
+ * Sets the default type to convert to if no type is provided when getting a value.
+ *
+ * @param defaultType the new default type
+ */
+ public abstract void setDefaultType(Class defaultType);
+
+ /**
+ * Set a override map containing <code>key -> values</code> that takes precedent when doing find operations on the ValueStack.
+ * <p/>
+ * See the unit test for ValueStackTest for examples.
+ *
+ * @param overrides overrides map.
+ */
+ public abstract void setExprOverrides(Map<Object, Object> overrides);
+
+ /**
+ * Gets the override map if anyone exists.
+ *
+ * @return the override map, <tt>null</tt> if not set.
+ */
+ public abstract Map<Object, Object> getExprOverrides();
+
+ /**
+ * Get the CompoundRoot which holds the objects pushed onto the stack
+ *
+ * @return the root
+ */
+ public abstract CompoundRoot getRoot();
+
+ /**
+ * Attempts to set a property on a bean in the stack with the given expression using the default search order.
+ *
+ * @param expr the expression defining the path to the property to be set.
+ * @param value the value to be set into the named property
+ */
+ public abstract void setValue(String expr, Object value);
+
+ /**
+ * Attempts to set a property on a bean in the stack with the given expression using the default search order.
+ *
+ * @param expr the expression defining the path to the property to be set.
+ * @param value the value to be set into the named property
+ * @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
+ * the given name.
+ */
+ public abstract void setValue(String expr, Object value, boolean throwExceptionOnFailure);
+
+ public abstract String findString(String expr);
+ public abstract String findString(String expr, boolean throwExceptionOnFailure);
+
+ /**
+ * Find a value by evaluating the given expression against the stack in the default search order.
+ *
+ * @param expr the expression giving the path of properties to navigate to find the property value to return
+ * @return the result of evaluating the expression
+ */
+ public abstract Object findValue(String expr);
+
+ public abstract Object findValue(String expr, boolean throwExceptionOnFailure);
+
+ /**
+ * Find a value by evaluating the given expression against the stack in the default search order.
+ *
+ * @param expr the expression giving the path of properties to navigate to find the property value to return
+ * @param asType the type to convert the return value to
+ * @return the result of evaluating the expression
+ */
+ public abstract Object findValue(String expr, Class asType);
+ public abstract Object findValue(String expr, Class asType, boolean throwExceptionOnFailure);
+
+ /**
+ * Get the object on the top of the stack <b>without</b> changing the stack.
+ *
+ * @return the object on the top.
+ * @see CompoundRoot#peek()
+ */
+ public abstract Object peek();
+
+ /**
+ * Get the object on the top of the stack and <b>remove</b> it from the stack.
+ *
+ * @return the object on the top of the stack
+ * @see CompoundRoot#pop()
+ */
+ public abstract Object pop();
+
+ /**
+ * Put this object onto the top of the stack
+ *
+ * @param o the object to be pushed onto the stack
+ * @see CompoundRoot#push(Object)
+ */
+ public abstract void push(Object o);
+
+ /**
+ * Sets an object on the stack with the given key
+ * so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)}
+ *
+ * @param key the key
+ * @param o the object
+ */
+ public abstract void set(String key, Object o);
+
+ /**
+ * Get the number of objects in the stack
+ *
+ * @return the number of objects in the stack
+ */
+ public abstract int size();
+
+}
\ No newline at end of file
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStackFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStackFactory.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStackFactory.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/ValueStackFactory.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2007,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;
+
+/**
+ * Factory that creates a value stack, defaulting to the OgnlValueStackFactory
+ */
+public interface ValueStackFactory {
+
+ /**
+ * Get a new instance of {@link ValueStack}
+ *
+ * @return a new {@link ValueStack}.
+ */
+ ValueStack createValueStack();
+
+ /**
+ * Get a new instance of {@link ValueStack}
+ *
+ * @param stack an existing stack to include.
+ * @return a new {@link ValueStack}.
+ */
+ ValueStack createValueStack(ValueStack stack);
+
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardHelper.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardHelper.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardHelper.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardHelper.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,463 @@
+/*
+ * $Id: WildcardHelper.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ *
+ * Copyright 2003-2004 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;
+
+import java.util.Map;
+
+/**
+ * This class is an utility class that perform wilcard-patterns matching and
+ * isolation taken from Apache Cocoon.
+ *
+ * @version $Rev: 1209415 $ $Date: 2005-05-07 12:11:38 -0400 (Sat, 07 May 2005)
+ * $
+ */
+public class WildcardHelper implements PatternMatcher<int[]> {
+ /**
+ * The int representing '*' in the pattern <code>int []</code>.
+ */
+ protected static final int MATCH_FILE = -1;
+
+ /**
+ * The int representing '**' in the pattern <code>int []</code>.
+ */
+ protected static final int MATCH_PATH = -2;
+
+ /**
+ * The int representing begin in the pattern <code>int []</code>.
+ */
+ protected static final int MATCH_BEGIN = -4;
+
+ /**
+ * The int representing end in pattern <code>int []</code>.
+ */
+ protected static final int MATCH_THEEND = -5;
+
+ /**
+ * The int value that terminates the pattern <code>int []</code>.
+ */
+ protected static final int MATCH_END = -3;
+
+ /**
+ * Determines if the pattern contains any * characters
+ *
+ * @param pattern The pattern
+ * @return True if no wildcards are found
+ */
+ public boolean isLiteral(String pattern) {
+ return (pattern == null || pattern.indexOf('*') == -1);
+ }
+
+ /**
+ * <p> Translate the given <code>String</code> into a <code>int []</code>
+ * representing the pattern matchable by this class. <br> This function
+ * translates a <code>String</code> into an int array converting the
+ * special '*' and '\' characters. <br> Here is how the conversion
+ * algorithm works:</p>
+ *
+ * <ul>
+ *
+ * <li>The '*' character is converted to MATCH_FILE, meaning that zero or
+ * more characters (excluding the path separator '/') are to be
+ * matched.</li>
+ *
+ * <li>The '**' sequence is converted to MATCH_PATH, meaning that zero or
+ * more characters (including the path separator '/') are to be
+ * matched.</li>
+ *
+ * <li>The '\' character is used as an escape sequence ('\*' is translated
+ * in '*', not in MATCH_FILE). If an exact '\' character is to be matched
+ * the source string must contain a '\\'. sequence.</li>
+ *
+ * </ul>
+ *
+ * <p>When more than two '*' characters, not separated by another
+ * character, are found their value is considered as '**' (MATCH_PATH).
+ * <br> The array is always terminated by a special value (MATCH_END).
+ * <br> All MATCH* values are less than zero, while normal characters are
+ * equal or greater.</p>
+ *
+ * @param data The string to translate.
+ * @return The encoded string as an int array, terminated by the MATCH_END
+ * value (don't consider the array length).
+ * @throws NullPointerException If data is null.
+ */
+ public int[] compilePattern(String data) {
+ // Prepare the arrays
+ int[] expr = new int[data.length() + 2];
+ char[] buff = data.toCharArray();
+
+ // Prepare variables for the translation loop
+ int y = 0;
+ boolean slash = false;
+
+ // Must start from beginning
+ expr[y++] = MATCH_BEGIN;
+
+ if (buff.length > 0) {
+ if (buff[0] == '\\') {
+ slash = true;
+ } else if (buff[0] == '*') {
+ expr[y++] = MATCH_FILE;
+ } else {
+ expr[y++] = buff[0];
+ }
+
+ // Main translation loop
+ for (int x = 1; x < buff.length; x++) {
+ // If the previous char was '\' simply copy this char.
+ if (slash) {
+ expr[y++] = buff[x];
+ slash = false;
+
+ // If the previous char was not '\' we have to do a bunch of
+ // checks
+ } else {
+ // If this char is '\' declare that and continue
+ if (buff[x] == '\\') {
+ slash = true;
+
+ // If this char is '*' check the previous one
+ } else if (buff[x] == '*') {
+ // If the previous character als was '*' match a path
+ if (expr[y - 1] <= MATCH_FILE) {
+ expr[y - 1] = MATCH_PATH;
+ } else {
+ expr[y++] = MATCH_FILE;
+ }
+ } else {
+ expr[y++] = buff[x];
+ }
+ }
+ }
+ }
+
+ // Must match end at the end
+ expr[y] = MATCH_THEEND;
+
+ return expr;
+ }
+
+ /**
+ * Match a pattern agains a string and isolates wildcard replacement into
+ * a <code>Stack</code>.
+ *
+ * @param map The map to store matched values
+ * @param data The string to match
+ * @param expr The compiled wildcard expression
+ * @return True if a match
+ * @throws NullPointerException If any parameters are null
+ */
+ public boolean match(Map<String, String> map, String data, int[] expr) {
+ if (map == null) {
+ throw new NullPointerException("No map provided");
+ }
+
+ if (data == null) {
+ throw new NullPointerException("No data provided");
+ }
+
+ if (expr == null) {
+ throw new NullPointerException("No pattern expression provided");
+ }
+
+ char[] buff = data.toCharArray();
+
+ // Allocate the result buffer
+ char[] rslt = new char[expr.length + buff.length];
+
+ // The previous and current position of the expression character
+ // (MATCH_*)
+ int charpos = 0;
+
+ // The position in the expression, input, translation and result arrays
+ int exprpos = 0;
+ int buffpos = 0;
+ int rsltpos = 0;
+ int offset = -1;
+
+ // The matching count
+ int mcount = 0;
+
+ // We want the complete data be in {0}
+ map.put(Integer.toString(mcount), data);
+
+ // First check for MATCH_BEGIN
+ boolean matchBegin = false;
+
+ if (expr[charpos] == MATCH_BEGIN) {
+ matchBegin = true;
+ exprpos = ++charpos;
+ }
+
+ // Search the fist expression character (except MATCH_BEGIN - already
+ // skipped)
+ while (expr[charpos] >= 0) {
+ charpos++;
+ }
+
+ // The expression charater (MATCH_*)
+ int exprchr = expr[charpos];
+
+ while (true) {
+ // Check if the data in the expression array before the current
+ // expression character matches the data in the input buffer
+ if (matchBegin) {
+ if (!matchArray(expr, exprpos, charpos, buff, buffpos)) {
+ return (false);
+ }
+
+ matchBegin = false;
+ } else {
+ offset = indexOfArray(expr, exprpos, charpos, buff, buffpos);
+
+ if (offset < 0) {
+ return (false);
+ }
+ }
+
+ // Check for MATCH_BEGIN
+ if (matchBegin) {
+ if (offset != 0) {
+ return (false);
+ }
+
+ matchBegin = false;
+ }
+
+ // Advance buffpos
+ buffpos += (charpos - exprpos);
+
+ // Check for END's
+ if (exprchr == MATCH_END) {
+ if (rsltpos > 0) {
+ map.put(Integer.toString(++mcount),
+ new String(rslt, 0, rsltpos));
+ }
+
+ // Don't care about rest of input buffer
+ return (true);
+ } else if (exprchr == MATCH_THEEND) {
+ if (rsltpos > 0) {
+ map.put(Integer.toString(++mcount),
+ new String(rslt, 0, rsltpos));
+ }
+
+ // Check that we reach buffer's end
+ return (buffpos == buff.length);
+ }
+
+ // Search the next expression character
+ exprpos = ++charpos;
+
+ while (expr[charpos] >= 0) {
+ charpos++;
+ }
+
+ int prevchr = exprchr;
+
+ exprchr = expr[charpos];
+
+ // We have here prevchr == * or **.
+ offset =
+ (prevchr == MATCH_FILE)
+ ? indexOfArray(expr, exprpos, charpos, buff, buffpos)
+ : lastIndexOfArray(expr, exprpos, charpos, buff, buffpos);
+
+ if (offset < 0) {
+ return (false);
+ }
+
+ // Copy the data from the source buffer into the result buffer
+ // to substitute the expression character
+ if (prevchr == MATCH_PATH) {
+ while (buffpos < offset) {
+ rslt[rsltpos++] = buff[buffpos++];
+ }
+ } else {
+ // Matching file, don't copy '/'
+ while (buffpos < offset) {
+ if (buff[buffpos] == '/') {
+ return (false);
+ }
+
+ rslt[rsltpos++] = buff[buffpos++];
+ }
+ }
+
+ map.put(Integer.toString(++mcount), new String(rslt, 0, rsltpos));
+ rsltpos = 0;
+ }
+ }
+
+ /**
+ * Get the offset of a part of an int array within a char array. <br> This
+ * method return the index in d of the first occurrence after dpos of that
+ * part of array specified by r, starting at rpos and terminating at
+ * rend.
+ *
+ * @param r The array containing the data that need to be matched in
+ * d.
+ * @param rpos The index of the first character in r to look for.
+ * @param rend The index of the last character in r to look for plus 1.
+ * @param d The array of char that should contain a part of r.
+ * @param dpos The starting offset in d for the matching.
+ * @return The offset in d of the part of r matched in d or -1 if that was
+ * not found.
+ */
+ protected int indexOfArray(int[] r, int rpos, int rend, char[] d, int dpos) {
+ // Check if pos and len are legal
+ if (rend < rpos) {
+ throw new IllegalArgumentException("rend < rpos");
+ }
+
+ // If we need to match a zero length string return current dpos
+ if (rend == rpos) {
+ return (d.length); //?? dpos?
+ }
+
+ // If we need to match a 1 char length string do it simply
+ if ((rend - rpos) == 1) {
+ // Search for the specified character
+ for (int x = dpos; x < d.length; x++) {
+ if (r[rpos] == d[x]) {
+ return (x);
+ }
+ }
+ }
+
+ // Main string matching loop. It gets executed if the characters to
+ // match are less then the characters left in the d buffer
+ while (((dpos + rend) - rpos) <= d.length) {
+ // Set current startpoint in d
+ int y = dpos;
+
+ // Check every character in d for equity. If the string is matched
+ // return dpos
+ for (int x = rpos; x <= rend; x++) {
+ if (x == rend) {
+ return (dpos);
+ }
+
+ if (r[x] != d[y++]) {
+ break;
+ }
+ }
+
+ // Increase dpos to search for the same string at next offset
+ dpos++;
+ }
+
+ // The remaining chars in d buffer were not enough or the string
+ // wasn't matched
+ return (-1);
+ }
+
+ /**
+ * Get the offset of a last occurance of an int array within a char array.
+ * <br> This method return the index in d of the last occurrence after
+ * dpos of that part of array specified by r, starting at rpos and
+ * terminating at rend.
+ *
+ * @param r The array containing the data that need to be matched in
+ * d.
+ * @param rpos The index of the first character in r to look for.
+ * @param rend The index of the last character in r to look for plus 1.
+ * @param d The array of char that should contain a part of r.
+ * @param dpos The starting offset in d for the matching.
+ * @return The offset in d of the last part of r matched in d or -1 if
+ * that was not found.
+ */
+ protected int lastIndexOfArray(int[] r, int rpos, int rend, char[] d,
+ int dpos) {
+ // Check if pos and len are legal
+ if (rend < rpos) {
+ throw new IllegalArgumentException("rend < rpos");
+ }
+
+ // If we need to match a zero length string return current dpos
+ if (rend == rpos) {
+ return (d.length); //?? dpos?
+ }
+
+ // If we need to match a 1 char length string do it simply
+ if ((rend - rpos) == 1) {
+ // Search for the specified character
+ for (int x = d.length - 1; x > dpos; x--) {
+ if (r[rpos] == d[x]) {
+ return (x);
+ }
+ }
+ }
+
+ // Main string matching loop. It gets executed if the characters to
+ // match are less then the characters left in the d buffer
+ int l = d.length - (rend - rpos);
+
+ while (l >= dpos) {
+ // Set current startpoint in d
+ int y = l;
+
+ // Check every character in d for equity. If the string is matched
+ // return dpos
+ for (int x = rpos; x <= rend; x++) {
+ if (x == rend) {
+ return (l);
+ }
+
+ if (r[x] != d[y++]) {
+ break;
+ }
+ }
+
+ // Decrease l to search for the same string at next offset
+ l--;
+ }
+
+ // The remaining chars in d buffer were not enough or the string
+ // wasn't matched
+ return (-1);
+ }
+
+ /**
+ * Matches elements of array r from rpos to rend with array d, starting
+ * from dpos. <br> This method return true if elements of array r from
+ * rpos to rend equals elements of array d starting from dpos to
+ * dpos+(rend-rpos).
+ *
+ * @param r The array containing the data that need to be matched in
+ * d.
+ * @param rpos The index of the first character in r to look for.
+ * @param rend The index of the last character in r to look for.
+ * @param d The array of char that should start from a part of r.
+ * @param dpos The starting offset in d for the matching.
+ * @return true if array d starts from portion of array r.
+ */
+ protected boolean matchArray(int[] r, int rpos, int rend, char[] d, int dpos) {
+ if ((d.length - dpos) < (rend - rpos)) {
+ return (false);
+ }
+
+ for (int i = rpos; i < rend; i++) {
+ if (r[i] != d[dpos++]) {
+ return (false);
+ }
+ }
+
+ return (true);
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardUtil.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardUtil.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/WildcardUtil.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 Yahoo, Inc. All rights reserved.
+ *
+ * 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;
+
+import java.util.regex.Pattern;
+
+/**
+ * Helper class to convert wildcard expression to regular expression
+ */
+public class WildcardUtil {
+
+ /**
+ * Convert wildcard pattern to Pattern
+ * @param pattern String containing wildcard pattern
+ * @return compiled regular expression as a Pattern
+ */
+ public static Pattern compileWildcardPattern(String pattern) {
+ StringBuilder buf = new StringBuilder(pattern);
+
+ for (int i=buf.length()-1; i>=0; i--)
+ {
+ char c = buf.charAt(i);
+ if (c == '*' && (i == 0 || buf.charAt(i-1) != '\\'))
+ {
+ buf.insert(i+1, '?');
+ buf.insert(i, '.');
+ }
+ else if (c == '*')
+ {
+ i--; // skip backslash, too
+ }
+ else if (needsBackslashToBeLiteralInRegex(c))
+ {
+ buf.insert(i, '\\');
+ }
+ }
+
+ return Pattern.compile(buf.toString());
+ }
+
+ /**
+ * @param c character to test
+ * @return true if the given character must be escaped to be a literal
+ * inside a regular expression.
+ */
+
+ private static final String theSpecialRegexCharList = ".[]\\?*+{}|()^$";
+
+ public static boolean needsBackslashToBeLiteralInRegex(
+ char c)
+ {
+ return (theSpecialRegexCharList.indexOf(c) >= 0);
+ }
+
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkList.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkList.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkList.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkList.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2002-2006,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;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ObjectFactory;
+import org.apache.struts2.xwork2.XWorkException;
+import org.apache.struts2.xwork2.conversion.impl.XWorkConverter;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * A simple list that guarantees that inserting and retrieving objects will always work regardless
+ * of the current size of the list. Upon insertion, type conversion is also performed if necessary.
+ * Empty beans will be created to fill the gap between the current list size and the requested index
+ * using ObjectFactory's {@link ObjectFactory#buildBean(Class,java.util.Map) buildBean} method.
+ *
+ * @author Patrick Lightbody
+ */
+public class XWorkList extends ArrayList {
+ private static final Logger LOG = LoggerFactory.getLogger(XWorkConverter.class);
+
+ private Class clazz;
+ private XWorkConverter conv;
+
+ private ObjectFactory objectFactory;
+
+ public XWorkList(ObjectFactory fac, XWorkConverter conv, Class clazz) {
+ this.conv = conv;
+ this.clazz = clazz;
+ this.objectFactory = fac;
+ }
+
+ public XWorkList(ObjectFactory fac, XWorkConverter conv, Class clazz, int initialCapacity) {
+ super(initialCapacity);
+ this.clazz = clazz;
+ this.conv = conv;
+ this.objectFactory = fac;
+ }
+
+ /**
+ * Inserts the specified element at the specified position in this list. Shifts the element
+ * currently at that position (if any) and any subsequent elements to the right (adds one to
+ * their indices).
+ * <p/>
+ * This method is guaranteed to work since it will create empty beans to fill the gap between
+ * the current list size and the requested index to enable the element to be set. This method
+ * also performs any necessary type conversion.
+ *
+ * @param index index at which the specified element is to be inserted.
+ * @param element element to be inserted.
+ */
+ @Override
+ public void add(int index, Object element) {
+ if (index >= this.size()) {
+ get(index);
+ }
+
+ element = convert(element);
+
+ super.add(index, element);
+ }
+
+ /**
+ * Appends the specified element to the end of this list.
+ * <p/>
+ * This method performs any necessary type conversion.
+ *
+ * @param element element to be appended to this list.
+ * @return <tt>true</tt> (as per the general contract of Collection.add).
+ */
+ @Override
+ public boolean add(Object element) {
+ element = convert(element);
+
+ return super.add(element);
+ }
+
+ /**
+ * Appends all of the elements in the specified Collection to the end of this list, in the order
+ * that they are returned by the specified Collection's Iterator. The behavior of this
+ * operation is undefined if the specified Collection is modified while the operation is in
+ * progress. (This implies that the behavior of this call is undefined if the specified
+ * Collection is this list, and this list is nonempty.)
+ * <p/>
+ * This method performs any necessary type conversion.
+ *
+ * @param c the elements to be inserted into this list.
+ * @return <tt>true</tt> if this list changed as a result of the call.
+ * @throws NullPointerException if the specified collection is null.
+ */
+ @Override
+ public boolean addAll(Collection c) {
+ if (c == null) {
+ throw new NullPointerException("Collection to add is null");
+ }
+
+ for (Object aC : c) {
+ add(aC);
+ }
+
+ return true;
+ }
+
+ /**
+ * Inserts all of the elements in the specified Collection into this list, starting at the
+ * specified position. Shifts the element currently at that position (if any) and any
+ * subsequent elements to the right (increases their indices). The new elements will appear in
+ * the list in the order that they are returned by the specified Collection's iterator.
+ * <p/>
+ * This method is guaranteed to work since it will create empty beans to fill the gap between
+ * the current list size and the requested index to enable the element to be set. This method
+ * also performs any necessary type conversion.
+ *
+ * @param index index at which to insert first element from the specified collection.
+ * @param c elements to be inserted into this list.
+ * @return <tt>true</tt> if this list changed as a result of the call.
+ */
+ @Override
+ public boolean addAll(int index, Collection c) {
+ if (c == null) {
+ throw new NullPointerException("Collection to add is null");
+ }
+
+ boolean trim = false;
+
+ if (index >= this.size()) {
+ trim = true;
+ }
+
+ for (Iterator it = c.iterator(); it.hasNext(); index++) {
+ add(index, it.next());
+ }
+
+ if (trim) {
+ remove(this.size() - 1);
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the element at the specified position in this list.
+ * <p/>
+ * An object is guaranteed to be returned since it will create empty beans to fill the gap
+ * between the current list size and the requested index.
+ *
+ * @param index index of element to return.
+ * @return the element at the specified position in this list.
+ */
+ @Override
+ public synchronized Object get(int index) {
+ while (index >= this.size()) {
+ try {
+ //todo
+ this.add(objectFactory.buildBean(clazz, null)); //ActionContext.getContext().getContextMap()));
+ } catch (Exception e) {
+ throw new XWorkException(e);
+ }
+ }
+
+ return super.get(index);
+ }
+
+ /**
+ * Replaces the element at the specified position in this list with the specified element.
+ * <p/>
+ * This method is guaranteed to work since it will create empty beans to fill the gap between
+ * the current list size and the requested index to enable the element to be set. This method
+ * also performs any necessary type conversion.
+ *
+ * @param index index of element to replace.
+ * @param element element to be stored at the specified position.
+ * @return the element previously at the specified position.
+ */
+ @Override
+ public Object set(int index, Object element) {
+ if (index >= this.size()) {
+ get(index);
+ }
+
+ element = convert(element);
+
+ return super.set(index, element);
+ }
+
+ private Object convert(Object element) {
+ if ((element != null) && !clazz.isAssignableFrom(element.getClass())) {
+ // convert to correct type
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Converting from " + element.getClass().getName() + " to " + clazz.getName());
+ }
+
+ Map<String, Object> context = ActionContext.getContext().getContextMap();
+ element = conv.convertValue(context, null, null, null, element, clazz);
+ }
+
+ return element;
+ }
+
+ @Override
+ public boolean contains(Object element) {
+ element = convert(element);
+
+ return super.contains(element);
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkTestCaseHelper.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkTestCaseHelper.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkTestCaseHelper.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/XWorkTestCaseHelper.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2002-2006,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;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.config.Configuration;
+import org.apache.struts2.xwork2.config.ConfigurationException;
+import org.apache.struts2.xwork2.config.providers.XWorkConfigurationProvider;
+import org.apache.struts2.xwork2.config.providers.XmlConfigurationProvider;
+import org.apache.struts2.xwork2.inject.Container;
+import org.apache.struts2.xwork2.inject.ContainerBuilder;
+import org.apache.struts2.xwork2.util.location.LocatableProperties;
+import org.apache.struts2.xwork2.config.ConfigurationManager;
+import org.apache.struts2.xwork2.config.ConfigurationProvider;
+import org.apache.struts2.xwork2.config.ContainerProvider;
+
+/**
+ * Generic test setup methods to be used with any unit testing framework.
+ */
+public class XWorkTestCaseHelper {
+
+ public static ConfigurationManager setUp() throws Exception {
+ ConfigurationManager configurationManager = new ConfigurationManager();
+ configurationManager.addContainerProvider(new XWorkConfigurationProvider());
+ Configuration config = configurationManager.getConfiguration();
+ Container container = config.getContainer();
+
+ // Reset the value stack
+ ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
+ stack.getContext().put(ActionContext.CONTAINER, container);
+ ActionContext.setContext(new ActionContext(stack.getContext()));
+
+ // clear out localization
+ LocalizedTextUtil.reset();
+
+
+ //ObjectFactory.setObjectFactory(container.getInstance(ObjectFactory.class));
+ return configurationManager;
+ }
+
+ public static ConfigurationManager loadConfigurationProviders(ConfigurationManager configurationManager,
+ ConfigurationProvider... providers) {
+ try {
+ tearDown(configurationManager);
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot clean old configuration", e);
+ }
+ configurationManager = new ConfigurationManager();
+ configurationManager.addContainerProvider(new ContainerProvider() {
+ public void destroy() {}
+ public void init(Configuration configuration) throws ConfigurationException {}
+ public boolean needsReload() { return false; }
+
+ public void register(ContainerBuilder builder,
+ LocatableProperties props) throws ConfigurationException {
+ builder.setAllowDuplicates(true);
+ }
+
+ });
+ configurationManager.addContainerProvider(new XWorkConfigurationProvider());
+ for (ConfigurationProvider prov : providers) {
+ if (prov instanceof XmlConfigurationProvider) {
+ ((XmlConfigurationProvider)prov).setThrowExceptionOnDuplicateBeans(false);
+ }
+ configurationManager.addContainerProvider(prov);
+ }
+ Container container = configurationManager.getConfiguration().getContainer();
+
+ // Reset the value stack
+ ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
+ stack.getContext().put(ActionContext.CONTAINER, container);
+ ActionContext.setContext(new ActionContext(stack.getContext()));
+
+ return configurationManager;
+ }
+
+ public static void tearDown(ConfigurationManager configurationManager) throws Exception {
+
+ // clear out configuration
+ if (configurationManager != null) {
+ configurationManager.destroyConfiguration();
+ configurationManager = null;
+ }
+ ActionContext.setContext(null);
+ }
+}
\ No newline at end of file
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/FileResourceStore.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/FileResourceStore.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/FileResourceStore.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/FileResourceStore.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2006,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.classloader;
+
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * Reads a class from disk
+ * class taken from Apache JCI
+ */
+public final class FileResourceStore implements ResourceStore {
+ private static final Logger LOG = LoggerFactory.getLogger(FileResourceStore.class);
+ private final File root;
+
+ public FileResourceStore(final File pFile) {
+ root = pFile;
+ }
+
+ public byte[] read(final String pResourceName) {
+ FileInputStream fis = null;
+ try {
+ File file = getFile(pResourceName);
+ byte[] data = new byte[(int) file.length()];
+ fis = new FileInputStream(file);
+ fis.read(data);
+
+ return data;
+ } catch (Exception e) {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unable to read file [#0]", e, pResourceName);
+ return null;
+ } finally {
+ closeQuietly(fis);
+ }
+ }
+
+ public void write(final String pResourceName, final byte[] pData) {
+
+ }
+
+ private void closeQuietly(InputStream is) {
+ try {
+ if (is != null)
+ is.close();
+ } catch (IOException e) {
+ if (LOG.isErrorEnabled())
+ LOG.error("Unable to close file input stream", e);
+ }
+ }
+
+ private File getFile(final String pResourceName) {
+ final String fileName = pResourceName.replace('/', File.separatorChar);
+ return new File(root, fileName);
+ }
+
+ public String toString() {
+ return this.getClass().getName() + root.toString();
+ }
+}
Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/JarResourceStore.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/JarResourceStore.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/JarResourceStore.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/util/classloader/JarResourceStore.java Fri Dec 2 16:33:03 2011
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-2006,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.classloader;
+
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.io.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Read resources from a jar file
+ */
+public class JarResourceStore implements ResourceStore {
+ private static final Logger LOG = LoggerFactory.getLogger(JarResourceStore.class);
+
+ private final File file;
+
+ public JarResourceStore(File file) {
+ this.file = file;
+ }
+
+ public void write(String pResourceName, byte[] pResourceData) {
+ }
+
+ public byte[] read(String pResourceName) {
+ InputStream in = null;
+ try {
+ ZipFile jarFile = new ZipFile(file);
+ ZipEntry entry = jarFile.getEntry(pResourceName);
+
+ //read into byte array
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ in = jarFile.getInputStream(entry);
+ copy(in, out);
+
+ return out.toByteArray();
+ } catch (Exception e) {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Unable to read file [#0] from [#1]", e, pResourceName, file.getName());
+ return null;
+ } finally {
+ closeQuietly(in);
+ }
+ }
+
+ public static long copy(InputStream input, OutputStream output)
+ throws IOException {
+ byte[] buffer = new byte[1024 * 4];
+ long count = 0;
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ private void closeQuietly(InputStream is) {
+ try {
+ if (is != null)
+ is.close();
+ } catch (IOException e) {
+ if (LOG.isErrorEnabled())
+ LOG.error("Unable to close input stream", e);
+ }
+ }
+}