Added: 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/MethodUtils.java
URL: 
http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/MethodUtils.java?rev=1617141&view=auto
==============================================================================
--- 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/MethodUtils.java 
(added)
+++ 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/MethodUtils.java 
Sun Aug 10 18:25:10 2014
@@ -0,0 +1,1334 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.util;
+
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p> Utility reflection methods focussed on methods in general rather than 
properties in particular. </p>
+ *
+ * <h3>Known Limitations</h3>
+ * <h4>Accessing Public Methods In A Default Access Superclass</h4>
+ * <p>There is an issue when invoking public methods contained in a default 
access superclass.
+ * Reflection locates these methods fine and correctly assigns them as public.
+ * However, an <code>IllegalAccessException</code> is thrown if the method is 
invoked.</p>
+ *
+ * <p><code>MethodUtils</code> contains a workaround for this situation. 
+ * It will attempt to call <code>setAccessible</code> on this method.
+ * If this call succeeds, then the method can be invoked as normal.
+ * This call will only succeed when the application has sufficient security 
privilages. 
+ * If this call fails then a warning will be logged and the method may 
fail.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey Fran&#231;ois
+ * @author Gregor Ra&#253;man
+ * @author Jan Sorensen
+ * @author Robert Burrell Donkin
+ */
+
+public class MethodUtils {
+
+    // --------------------------------------------------------- Private 
Methods
+    
+    /** 
+     * Only log warning about accessibility work around once.
+     * <p>
+     * Note that this is broken when this class is deployed via a shared
+     * classloader in a container, as the warning message will be emitted
+     * only once, not once per webapp. However making the warning appear
+     * once per webapp means having a map keyed by context classloader
+     * which introduces nasty memory-leak problems. As this warning is
+     * really optional we can ignore this problem; only one of the webapps
+     * will get the warning in its logs but that should be good enough.
+     */
+    private static boolean loggedAccessibleWarning = false;
+    
+    /** 
+     * Indicates whether methods should be cached for improved performance.
+     * <p>
+     * Note that when this class is deployed via a shared classloader in
+     * a container, this will affect all webapps. However making this
+     * configurable per webapp would mean having a map keyed by context 
classloader
+     * which may introduce memory-leak problems.
+     */
+    private static boolean CACHE_METHODS = true;
+
+    /** An empty class array */
+    private static final Class[] EMPTY_CLASS_PARAMETERS = new Class[0];
+    /** An empty object array */
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than <code>invokeExactMethod()</code>.
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeMethod(Object object,String methodName,Object [] args)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param arg use this argument
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeMethod(object, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod(Object object,String methodName,Object 
[] args)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeMethod(Object object,String methodName,Object [] 
args,Class[] parameterTypes)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+        int arguments = args.length;
+        Class[] parameterTypes = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeMethod(object, methodName, args, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link 
+     * #invokeExactMethod(Object object,String methodName,Object [] 
args,Class[] parameterTypes)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+                throws
+                    NoSuchMethodException,
+                    IllegalAccessException,
+                    InvocationTargetException {
+                    
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+
+        Method method = getMatchingAccessibleMethod(
+                object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on object: " + 
object.getClass().getName());
+        }
+        return method.invoke(object, args);
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter type matches exactly the object
+     * type.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeExactMethod(Object object,String methodName,Object [] 
args)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param arg use this argument
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeExactMethod(object, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the object
+     * types.</p>
+     *
+     * <p> This uses reflection to invoke the method obtained from a call to
+     * <code>getAccessibleMethod()</code>.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+        int arguments = args.length;
+        Class[] parameterTypes = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeExactMethod(object, methodName, args, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the parameter
+     * types given.</p>
+     *
+     * <p>This uses reflection to invoke the method obtained from a call to
+     * <code>getAccessibleMethod()</code>.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+                
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }
+
+        Method method = getAccessibleMethod(
+                object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on object: " + 
object.getClass().getName());
+        }
+        return method.invoke(object, args);
+
+    }
+
+    /**
+     * <p>Invoke a static method whose parameter types match exactly the 
parameter
+     * types given.</p>
+     *
+     * <p>This uses reflection to invoke the method obtained from a call to
+     * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+                
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }
+
+        Method method = getAccessibleMethod(
+                objectClass,
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on class: " + objectClass.getName());
+        }
+        return method.invoke(null, args);
+
+    }
+
+    /**
+     * <p>Invoke a named static method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod(Object, String, Object[], Class[])}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeStaticMethod(Class objectClass,String methodName,Object 
[] args)}.
+     * </p>
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param arg use this argument
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeStaticMethod (objectClass, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a named static method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod(Object object,String methodName,Object 
[] args)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeStaticMethod(Class objectClass,String methodName,Object 
[] args,Class[] parameterTypes)}.
+     * </p>
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+        int arguments = args.length;
+        Class[] parameterTypes = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeStaticMethod (objectClass, methodName, args, 
parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Invoke a named static method whose parameter type matches the object 
type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link 
+     * #invokeExactStaticMethod(Class objectClass,String methodName,Object [] 
args,Class[] parameterTypes)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a 
<code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+                throws
+                    NoSuchMethodException,
+                    IllegalAccessException,
+                    InvocationTargetException {
+                    
+        if (parameterTypes == null) {
+            parameterTypes = EMPTY_CLASS_PARAMETERS;
+        }        
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+
+        Method method = getMatchingAccessibleMethod(
+                objectClass,
+                methodName,
+                parameterTypes);
+        if (method == null) {
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on class: " + objectClass.getName());
+        }
+        return method.invoke(null, args);
+    }
+
+
+    /**
+     * <p>Invoke a static method whose parameter type matches exactly the 
object
+     * type.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeExactStaticMethod(Class objectClass,String 
methodName,Object [] args)}.
+     * </p>
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param arg use this argument
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeExactStaticMethod (objectClass, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a static method whose parameter types match exactly the object
+     * types.</p>
+     *
+     * <p> This uses reflection to invoke the method obtained from a call to
+     * {@link #getAccessibleMethod(Class, String, Class[])}.</p>
+     *
+     * @param objectClass invoke static method on this class
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @return The value returned by the invoked method
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactStaticMethod(
+            Class objectClass,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        if (args == null) {
+            args = EMPTY_OBJECT_ARRAY;
+        }  
+        int arguments = args.length;
+        Class[] parameterTypes = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeExactStaticMethod(objectClass, methodName, args, 
parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) with given name and a single parameter.  If no such method
+     * can be found, return <code>null</code>.
+     * Basically, a convenience wrapper that constructs a <code>Class</code>
+     * array for you.</p>
+     *
+     * @param clazz get method from this class
+     * @param methodName get method with this name
+     * @param parameterType taking this type of parameter
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(
+            Class clazz,
+            String methodName,
+            Class parameterType) {
+
+        Class[] parameterTypes = {parameterType};
+        return getAccessibleMethod(clazz, methodName, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) with given name and parameters.  If no such method
+     * can be found, return <code>null</code>.
+     * This is just a convenient wrapper for
+     * {@link #getAccessibleMethod(Method method)}.</p>
+     *
+     * @param clazz get method from this class
+     * @param methodName get method with this name
+     * @param parameterTypes with these parameters types
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(
+            Class clazz,
+            String methodName,
+            Class[] parameterTypes) {
+
+        try {
+            MethodDescriptor md = new MethodDescriptor(clazz, methodName, 
parameterTypes, true);
+            Method method =  getAccessibleMethod
+                    (clazz, clazz.getMethod(methodName, parameterTypes));
+            return method;
+        } catch (NoSuchMethodException e) {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified Method.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param method The method that we wish to call
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(Method method) {
+
+        // Make sure we have a method to check
+        if (method == null) {
+            return (null);
+        }
+
+        return getAccessibleMethod(method.getDeclaringClass(), method);
+
+    }
+
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified Method.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param clazz The class of the object
+     * @param method The method that we wish to call
+     * @return The accessible method
+     */
+    public static Method getAccessibleMethod(Class clazz, Method method) {
+
+        // Make sure we have a method to check
+        if (method == null) {
+            return (null);
+        }
+
+        // If the requested method is not public we cannot call it
+        if (!Modifier.isPublic(method.getModifiers())) {
+            return (null);
+        }
+
+        boolean sameClass = true;
+        if (clazz == null) {
+            clazz = method.getDeclaringClass();
+        } else {
+            sameClass = clazz.equals(method.getDeclaringClass());
+            if (!method.getDeclaringClass().isAssignableFrom(clazz)) {
+                throw new IllegalArgumentException(clazz.getName() +
+                        " is not assignable from " + 
method.getDeclaringClass().getName());
+            }
+        }
+
+        // If the class is public, we are done
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            if (!sameClass && 
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
+                setMethodAccessible(method); // Default access superclass 
workaround
+            }
+            return (method);
+        }
+
+        String methodName      = method.getName();
+        Class[] parameterTypes = method.getParameterTypes();
+
+        // Check the implemented interfaces and subinterfaces
+        method =
+                getAccessibleMethodFromInterfaceNest(clazz,
+                        methodName,
+                        parameterTypes);
+
+        // Check the superclass chain
+        if (method == null) {
+            method = getAccessibleMethodFromSuperclass(clazz,
+                        methodName,
+                        parameterTypes);
+        }
+
+        return (method);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) by scanning through the superclasses. If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param clazz Class to be checked
+     * @param methodName Method name of the method we wish to call
+     * @param parameterTypes The parameter type signatures
+     */
+    private static Method getAccessibleMethodFromSuperclass
+            (Class clazz, String methodName, Class[] parameterTypes) {
+
+        Class parentClazz = clazz.getSuperclass();
+        while (parentClazz != null) {
+            if (Modifier.isPublic(parentClazz.getModifiers())) {
+                try {
+                    return parentClazz.getMethod(methodName, parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    return null;
+                }
+            }
+            parentClazz = parentClazz.getSuperclass();
+        }
+        return null;
+    }
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified method, by scanning through
+     * all implemented interfaces and subinterfaces.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * <p> There isn't any good reason why this method must be private.
+     * It is because there doesn't seem any reason why other classes should
+     * call this rather than the higher level methods.</p>
+     *
+     * @param clazz Parent class for the interfaces to be checked
+     * @param methodName Method name of the method we wish to call
+     * @param parameterTypes The parameter type signatures
+     */
+    private static Method getAccessibleMethodFromInterfaceNest
+            (Class clazz, String methodName, Class[] parameterTypes) {
+
+        Method method = null;
+
+        // Search up the superclass chain
+        for (; clazz != null; clazz = clazz.getSuperclass()) {
+
+            // Check the implemented interfaces of the parent class
+            Class[] interfaces = clazz.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++) {
+
+                // Is this interface public?
+                if (!Modifier.isPublic(interfaces[i].getModifiers())) {
+                    continue;
+                }
+
+                // Does the method exist on this interface?
+                try {
+                    method = interfaces[i].getDeclaredMethod(methodName,
+                            parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    /* Swallow, if no method is found after the loop then this
+                     * method returns null.
+                     */
+                }
+                if (method != null) {
+                    return method;
+                }
+
+                // Recursively check our parent interfaces
+                method =
+                        getAccessibleMethodFromInterfaceNest(interfaces[i],
+                                methodName,
+                                parameterTypes);
+                if (method != null) {
+                    return method;
+                }
+
+            }
+
+        }
+
+        // If we found a method return it
+        if (method != null) {
+            return (method);
+        }
+
+        // We did not find anything
+        return (null);
+
+    }
+
+    /**
+     * <p>Find an accessible method that matches the given name and has 
compatible parameters.
+     * Compatible parameters mean that every method parameter is assignable 
from 
+     * the given parameters.
+     * In other words, it finds a method with the given name 
+     * that will take the parameters given.<p>
+     *
+     * <p>This method is slightly undeterminstic since it loops 
+     * through methods names and return the first matching method.</p>
+     * 
+     * <p>This method is used by 
+     * {@link 
+     * #invokeMethod(Object object,String methodName,Object [] args,Class[] 
parameterTypes)}.
+     *
+     * <p>This method can match primitive parameter by passing in wrapper 
classes.
+     * For example, a <code>Boolean</code> will match a primitive 
<code>boolean</code>
+     * parameter.
+     *
+     * @param clazz find method in this class
+     * @param methodName find method with this name
+     * @param parameterTypes find method with compatible parameters 
+     * @return The accessible method
+     */
+    public static Method getMatchingAccessibleMethod(
+                                                Class clazz,
+                                                String methodName,
+                                                Class[] parameterTypes) {
+        // trace logging
+        Log log = LogFactory.getLog(MethodUtils.class);
+        if (log.isTraceEnabled()) {
+            log.trace("Matching name=" + methodName + " on " + clazz);
+        }
+        MethodDescriptor md = new MethodDescriptor(clazz, methodName, 
parameterTypes, false);
+        
+        // see if we can find the method directly
+        // most of the time this works and it's much faster
+        try {
+            Method method = clazz.getMethod(methodName, parameterTypes);
+            if (log.isTraceEnabled()) {
+                log.trace("Found straight match: " + method);
+                log.trace("isPublic:" + 
Modifier.isPublic(method.getModifiers()));
+            }
+            
+            setMethodAccessible(method); // Default access superclass 
workaround
+
+            return method;
+            
+        } catch (NoSuchMethodException e) { /* SWALLOW */ }
+        
+        // search through all methods 
+        int paramSize = parameterTypes.length;
+        Method bestMatch = null;
+        Method[] methods = clazz.getMethods();
+        float bestMatchCost = Float.MAX_VALUE;
+        float myCost = Float.MAX_VALUE;
+        for (int i = 0, size = methods.length; i < size ; i++) {
+            if (methods[i].getName().equals(methodName)) {
+                // log some trace information
+                if (log.isTraceEnabled()) {
+                    log.trace("Found matching name:");
+                    log.trace(methods[i]);
+                }                
+                
+                // compare parameters
+                Class[] methodsParams = methods[i].getParameterTypes();
+                int methodParamSize = methodsParams.length;
+                if (methodParamSize == paramSize) {          
+                    boolean match = true;
+                    for (int n = 0 ; n < methodParamSize; n++) {
+                        if (log.isTraceEnabled()) {
+                            log.trace("Param=" + parameterTypes[n].getName());
+                            log.trace("Method=" + methodsParams[n].getName());
+                        }
+                        if (!isAssignmentCompatible(methodsParams[n], 
parameterTypes[n])) {
+                            if (log.isTraceEnabled()) {
+                                log.trace(methodsParams[n] + " is not 
assignable from " 
+                                            + parameterTypes[n]);
+                            }    
+                            match = false;
+                            break;
+                        }
+                    }
+                    
+                    if (match) {
+                        // get accessible version of method
+                        Method method = getAccessibleMethod(clazz, methods[i]);
+                        if (method != null) {
+                            if (log.isTraceEnabled()) {
+                                log.trace(method + " accessible version of " 
+                                            + methods[i]);
+                            }
+                            setMethodAccessible(method); // Default access 
superclass workaround
+                            myCost = 
getTotalTransformationCost(parameterTypes,method.getParameterTypes());
+                            if ( myCost < bestMatchCost ) {
+                               bestMatch = method;
+                               bestMatchCost = myCost;
+                            }
+                        }
+                        
+                        log.trace("Couldn't find accessible method.");
+                    }
+                }
+            }
+        }
+        if ( bestMatch == null ){
+            // didn't find a match
+               log.trace("No match found.");
+        }
+        
+        return bestMatch;                                        
+    }
+
+    public static <T> Constructor<T> getMatchingAccessibleConstructor(
+                                                Class<T> clazz,
+                                                Class[] parameterTypes) {
+        // trace logging
+        Log log = LogFactory.getLog(MethodUtils.class);
+        MethodDescriptor md = new MethodDescriptor(clazz, "dummy", 
parameterTypes, false);
+        
+        // see if we can find the method directly
+        // most of the time this works and it's much faster
+        try {
+            Constructor<T> constructor = clazz.getConstructor(parameterTypes);
+            if (log.isTraceEnabled()) {
+                log.trace("Found straight match: " + constructor);
+                log.trace("isPublic:" + 
Modifier.isPublic(constructor.getModifiers()));
+            }
+            
+            setMethodAccessible(constructor); // Default access superclass 
workaround
+
+            return constructor;
+            
+        } catch (NoSuchMethodException e) { /* SWALLOW */ }
+        
+        // search through all methods 
+        int paramSize = parameterTypes.length;
+        Constructor<T> bestMatch = null;
+        Constructor<?>[] constructors = clazz.getConstructors();
+        float bestMatchCost = Float.MAX_VALUE;
+        float myCost = Float.MAX_VALUE;
+        for (int i = 0, size = constructors.length; i < size ; i++) {
+            // compare parameters
+            Class[] methodsParams = constructors[i].getParameterTypes();
+            int methodParamSize = methodsParams.length;
+            if (methodParamSize == paramSize) {          
+                boolean match = true;
+                for (int n = 0 ; n < methodParamSize; n++) {
+                    if (log.isTraceEnabled()) {
+                        log.trace("Param=" + parameterTypes[n].getName());
+                        log.trace("Method=" + methodsParams[n].getName());
+                    }
+                    if (!isAssignmentCompatible(methodsParams[n], 
parameterTypes[n])) {
+                        if (log.isTraceEnabled()) {
+                            log.trace(methodsParams[n] + " is not assignable 
from " 
+                                        + parameterTypes[n]);
+                        }    
+                        match = false;
+                        break;
+                    }
+                }
+                
+                if (match) {
+                    // get accessible version of method
+                    Constructor<T> cons = (Constructor<T>)constructors[i];
+                    myCost = 
getTotalTransformationCost(parameterTypes,cons.getParameterTypes());
+                    if ( myCost < bestMatchCost ) {
+                       bestMatch = cons;
+                       bestMatchCost = myCost;
+                    }
+                }
+            }
+        }
+        if ( bestMatch == null ){
+            // didn't find a match
+               log.trace("No match found.");
+        }
+        
+        return bestMatch;                                        
+    }
+
+    /**
+     * Try to make the method accessible
+     * @param method The source arguments
+     */
+    private static void setMethodAccessible(Object method) {
+        try {
+            //
+            // XXX Default access superclass workaround
+            //
+            // When a public class has a default access superclass
+            // with public methods, these methods are accessible.
+            // Calling them from compiled code works fine.
+            //
+            // Unfortunately, using reflection to invoke these methods
+            // seems to (wrongly) to prevent access even when the method
+            // modifer is public.
+            //
+            // The following workaround solves the problem but will only
+            // work from sufficiently privilages code. 
+            //
+            // Better workarounds would be greatfully accepted.
+            //
+            if (method instanceof Method) {
+                ((Method)method).setAccessible(true);
+            } else if (method instanceof Constructor) {
+                ((Constructor)method).setAccessible(true);
+            } else {
+                throw new RuntimeException("invalid parameter");
+            }
+            
+        } catch (SecurityException se) {
+            // log but continue just in case the method.invoke works anyway
+            Log log = LogFactory.getLog(MethodUtils.class);
+            if (!loggedAccessibleWarning) {
+                boolean vulnerableJVM = false;
+                try {
+                    String specVersion = 
System.getProperty("java.specification.version");
+                    if (specVersion.charAt(0) == '1' && 
+                            (specVersion.charAt(2) == '0' ||
+                             specVersion.charAt(2) == '1' ||
+                             specVersion.charAt(2) == '2' ||
+                             specVersion.charAt(2) == '3')) {
+                             
+                        vulnerableJVM = true;
+                    }
+                } catch (SecurityException e) {
+                    // don't know - so display warning
+                    vulnerableJVM = true;
+                }
+                if (vulnerableJVM) {
+                    log.warn(
+                        "Current Security Manager restricts use of workarounds 
for reflection bugs "
+                        + " in pre-1.4 JVMs.");
+                }
+                loggedAccessibleWarning = true;
+            }
+            log.debug("Cannot setAccessible on method. Therefore cannot use 
jvm access bug workaround.", se);
+        }
+    }
+
+    /**
+     * Returns the sum of the object transformation cost for each class in the 
source
+     * argument list.
+     * @param srcArgs The source arguments
+     * @param destArgs The destination arguments
+     * @return The total transformation cost
+     */
+    private static float getTotalTransformationCost(Class[] srcArgs, Class[] 
destArgs) {
+
+        float totalCost = 0.0f;
+        for (int i = 0; i < srcArgs.length; i++) {
+            Class srcClass, destClass;
+            srcClass = srcArgs[i];
+            destClass = destArgs[i];
+            totalCost += getObjectTransformationCost(srcClass, destClass);
+        }
+
+        return totalCost;
+    }
+    
+    /**
+     * Gets the number of steps required needed to turn the source class into 
the 
+     * destination class. This represents the number of steps in the object 
hierarchy 
+     * graph.
+     * @param srcClass The source class
+     * @param destClass The destination class
+     * @return The cost of transforming an object
+     */
+    private static float getObjectTransformationCost(Class srcClass, Class 
destClass) {
+        float cost = 0.0f;
+        while (destClass != null && !destClass.equals(srcClass)) {
+            if (destClass.isInterface() && 
isAssignmentCompatible(destClass,srcClass)) {
+                // slight penalty for interface match. 
+                // we still want an exact match to override an interface 
match, but  
+                // an interface match should override anything where we have 
to get a 
+                // superclass.
+                cost += 0.25f;
+                break;
+            }
+            cost++;
+            destClass = destClass.getSuperclass();
+        }
+
+        /*
+         * If the destination class is null, we've travelled all the way up to 
+         * an Object match. We'll penalize this by adding 1.5 to the cost.
+         */
+        if (destClass == null) {
+            cost += 1.5f;
+        }
+
+        return cost;
+    }
+    
+    
+    /**
+     * <p>Determine whether a type can be used as a parameter in a method 
invocation.
+     * This method handles primitive conversions correctly.</p>
+     *
+     * <p>In order words, it will match a <code>Boolean</code> to a 
<code>boolean</code>,
+     * a <code>Long</code> to a <code>long</code>,
+     * a <code>Float</code> to a <code>float</code>,
+     * a <code>Integer</code> to a <code>int</code>,
+     * and a <code>Double</code> to a <code>double</code>.
+     * Now logic widening matches are allowed.
+     * For example, a <code>Long</code> will not match a <code>int</code>.
+     *
+     * @param parameterType the type of parameter accepted by the method
+     * @param parameterization the type of parameter being tested 
+     *
+     * @return true if the assignement is compatible.
+     */
+    public static final boolean isAssignmentCompatible(Class parameterType, 
Class parameterization) {
+        // try plain assignment
+        if (parameterType.isAssignableFrom(parameterization)) {
+            return true;
+        }
+        
+        if (parameterType.isPrimitive()) {
+            // this method does *not* do widening - you must specify exactly
+            // is this the right behaviour?
+            Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);
+            if (parameterWrapperClazz != null) {
+                return parameterWrapperClazz.equals(parameterization);
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Gets the wrapper object class for the given primitive type class.
+     * For example, passing <code>boolean.class</code> returns 
<code>Boolean.class</code>
+     * @param primitiveType the primitive type class for which a match is to 
be found
+     * @return the wrapper type associated with the given primitive 
+     * or null if no match is found
+     */
+    public static Class getPrimitiveWrapper(Class primitiveType) {
+        // does anyone know a better strategy than comparing names?
+        if (boolean.class.equals(primitiveType)) {
+            return Boolean.class;
+        } else if (float.class.equals(primitiveType)) {
+            return Float.class;
+        } else if (long.class.equals(primitiveType)) {
+            return Long.class;
+        } else if (int.class.equals(primitiveType)) {
+            return Integer.class;
+        } else if (short.class.equals(primitiveType)) {
+            return Short.class;
+        } else if (byte.class.equals(primitiveType)) {
+            return Byte.class;
+        } else if (double.class.equals(primitiveType)) {
+            return Double.class;
+        } else if (char.class.equals(primitiveType)) {
+            return Character.class;
+        } else {
+            
+            return null;
+        }
+    }
+
+    /**
+     * Gets the class for the primitive type corresponding to the primitive 
wrapper class given.
+     * For example, an instance of <code>Boolean.class</code> returns a 
<code>boolean.class</code>. 
+     * @param wrapperType the 
+     * @return the primitive type class corresponding to the given wrapper 
class,
+     * null if no match is found
+     */
+    public static Class getPrimitiveType(Class wrapperType) {
+        // does anyone know a better strategy than comparing names?
+        if (Boolean.class.equals(wrapperType)) {
+            return boolean.class;
+        } else if (Float.class.equals(wrapperType)) {
+            return float.class;
+        } else if (Long.class.equals(wrapperType)) {
+            return long.class;
+        } else if (Integer.class.equals(wrapperType)) {
+            return int.class;
+        } else if (Short.class.equals(wrapperType)) {
+            return short.class;
+        } else if (Byte.class.equals(wrapperType)) {
+            return byte.class;
+        } else if (Double.class.equals(wrapperType)) {
+            return double.class;
+        } else if (Character.class.equals(wrapperType)) {
+            return char.class;
+        } else {
+            Log log = LogFactory.getLog(MethodUtils.class);
+            if (log.isDebugEnabled()) {
+                log.debug("Not a known primitive wrapper class: " + 
wrapperType);
+            }
+            return null;
+        }
+    }
+    
+    /**
+     * Find a non primitive representation for given primitive class.
+     *
+     * @param clazz the class to find a representation for, not null
+     * @return the original class if it not a primitive. Otherwise the wrapper 
class. Not null
+     */
+    public static Class toNonPrimitiveClass(Class clazz) {
+        if (clazz.isPrimitive()) {
+            Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
+            // the above method returns 
+            if (primitiveClazz != null) {
+                return primitiveClazz;
+            } else {
+                return clazz;
+            }
+        } else {
+            return clazz;
+        }
+    }
+    
+
+    /**
+     * Represents the key to looking up a Method by reflection.
+     */
+    private static class MethodDescriptor {
+        private Class cls;
+        private String methodName;
+        private Class[] paramTypes;
+        private boolean exact;
+        private int hashCode;
+
+        /**
+         * The sole constructor.
+         *
+         * @param cls  the class to reflect, must not be null
+         * @param methodName  the method name to obtain
+         * @param paramTypes the array of classes representing the paramater 
types
+         * @param exact whether the match has to be exact.
+         */
+        public MethodDescriptor(Class cls, String methodName, Class[] 
paramTypes, boolean exact) {
+            if (cls == null) {
+                throw new IllegalArgumentException("Class cannot be null");
+            }
+            if (methodName == null) {
+                throw new IllegalArgumentException("Method Name cannot be 
null");
+            }
+            if (paramTypes == null) {
+                paramTypes = EMPTY_CLASS_PARAMETERS;
+            }
+
+            this.cls = cls;
+            this.methodName = methodName;
+            this.paramTypes = paramTypes;
+            this.exact= exact;
+
+            this.hashCode = methodName.length();
+        }
+        /**
+         * Checks for equality.
+         * @param obj object to be tested for equality
+         * @return true, if the object describes the same Method.
+         */
+        public boolean equals(Object obj) {
+            if (!(obj instanceof MethodDescriptor)) {
+                return false;
+            }
+            MethodDescriptor md = (MethodDescriptor)obj;
+
+            return (
+                exact == md.exact &&
+                methodName.equals(md.methodName) &&
+                cls.equals(md.cls) &&
+                java.util.Arrays.equals(paramTypes, md.paramTypes)
+            );
+        }
+        /**
+         * Returns the string length of method name. I.e. if the
+         * hashcodes are different, the objects are different. If the
+         * hashcodes are the same, need to use the equals method to
+         * determine equality.
+         * @return the string length of method name.
+         */
+        public int hashCode() {
+            return hashCode;
+        }
+    }
+}

Modified: 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/SAXHelper.java
URL: 
http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/SAXHelper.java?rev=1617141&r1=1617140&r2=1617141&view=diff
==============================================================================
--- 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/SAXHelper.java 
(original)
+++ 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/SAXHelper.java 
Sun Aug 10 18:25:10 2014
@@ -23,6 +23,9 @@ import java.io.StringReader;
 import java.lang.reflect.Method;
 
 import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
@@ -89,4 +92,72 @@ public final class SAXHelper {
     public static Document readSAXDocument(InputStream inp) throws 
DocumentException {
         return getSAXReader().read(inp);
     }
+    
+    private static final EntityResolver IGNORING_ENTITY_RESOLVER = new 
EntityResolver() {
+        @Override
+        public InputSource resolveEntity(String publicId, String systemId)
+                throws SAXException, IOException {
+            return new InputSource(new StringReader(""));
+        }
+    };
+
+    private static void trySetSAXFeature(DocumentBuilderFactory 
documentBuilderFactory, String feature, boolean enabled) {
+        try {
+            documentBuilderFactory.setFeature(feature, enabled);
+        } catch (Exception e) {
+            logger.log(POILogger.INFO, "SAX Feature unsupported", feature, e);
+        }
+    }
+    private static void trySetXercesSecurityManager(DocumentBuilderFactory 
documentBuilderFactory) {
+        // Try built-in JVM one first, standalone if not
+        for (String securityManagerClassName : new String[] {
+                "com.sun.org.apache.xerces.internal.util.SecurityManager",
+                "org.apache.xerces.util.SecurityManager"
+        }) {
+            try {
+                Object mgr = 
Class.forName(securityManagerClassName).newInstance();
+                Method setLimit = 
mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
+                setLimit.invoke(mgr, 4096);
+                
documentBuilderFactory.setAttribute("http://apache.org/xml/properties/security-manager";,
 mgr);
+                // Stop once one can be setup without error
+                return;
+            } catch (Exception e) {
+                logger.log(POILogger.INFO, "SAX Security Manager could not be 
setup", e);
+            }
+        }
+    }
+    
+    private static final ThreadLocal<DocumentBuilder> documentBuilder = new 
ThreadLocal<DocumentBuilder>() {
+        @Override
+        protected DocumentBuilder initialValue() {
+            DocumentBuilderFactory factory = 
DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            factory.setValidating(false);
+            trySetSAXFeature(factory, XMLConstants.FEATURE_SECURE_PROCESSING, 
true);
+            trySetXercesSecurityManager(factory);
+            try {
+                return factory.newDocumentBuilder();
+            } catch (ParserConfigurationException e) {
+                throw new IllegalStateException("cannot create a 
DocumentBuilder", e);
+            }
+        }
+
+        @Override
+        public DocumentBuilder get() {
+            DocumentBuilder documentBuilder = super.get();
+            documentBuilder.reset();
+            documentBuilder.setEntityResolver(IGNORING_ENTITY_RESOLVER);
+            return documentBuilder;
+        }
+    };
+    
+    /**
+     * Parses the given stream via the default (sensible)
+     * SAX Reader
+     * @param inp Stream to read the XML data from
+     * @return the SAX processed Document 
+     */
+    public static org.w3c.dom.Document readSAXDocumentW3C(InputStream inp) 
throws IOException, SAXException {
+        return documentBuilder.get().parse(inp);
+    }
 }

Added: 
poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/XmlSort.java
URL: 
http://svn.apache.org/viewvc/poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/XmlSort.java?rev=1617141&view=auto
==============================================================================
--- poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/XmlSort.java 
(added)
+++ poi/branches/xml_signature/src/ooxml/java/org/apache/poi/util/XmlSort.java 
Sun Aug 10 18:25:10 2014
@@ -0,0 +1,221 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Comparator;
+
+import javax.xml.namespace.QName;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+
+/**
+ */
+public final class XmlSort
+{
+    /**
+     * Receives an XML element instance and sorts the children of this
+     * element in lexicographical (by default) order.
+     *
+     * @param args An array in which the first item is a
+     * path to the XML instance file and the second item (optional) is
+     * an XPath inside the document identifying the element to be sorted
+     */
+    public static void main(String[] args)
+    {
+        if (args.length < 1 || args.length > 2)
+        {
+            System.out.println("    java XmlSort <XML_File> [<XPath>]");
+            return;
+        }
+        File f = new File(args[0]);
+        try
+        {
+            XmlObject docInstance = XmlObject.Factory.parse(f);
+            XmlObject element = null;
+            if (args.length > 1)
+            {
+                String xpath = args[1];
+                XmlObject[] result = docInstance.selectPath(xpath);
+                if (result.length == 0)
+                {
+                    System.out.println("ERROR: XPath \"" + xpath + "\" did not 
return any results");
+                }
+                else if (result.length > 1)
+                {
+                    System.out.println("ERROR: XPath \"" + xpath + "\" 
returned more than one " +
+                        "node (" + result.length + ")");
+                }
+                else
+                    element = result[0];
+            }
+            else
+            {
+                // Navigate to the root element
+                XmlCursor c = docInstance.newCursor();
+                c.toFirstChild();
+                element = c.getObject();
+                c.dispose();
+            }
+            if (element != null)
+                sort(element, new QNameComparator(QNameComparator.ASCENDING));
+            System.out.println(docInstance.xmlText());
+        }
+        catch (IOException ioe)
+        {
+            System.out.println("ERROR: Could not open file: \"" + args[0] + 
"\": " +
+                ioe.getMessage());
+        }
+        catch (XmlException xe)
+        {
+            System.out.println("ERROR: Could not parse file: \"" + args[0] + 
"\": " +
+                xe.getMessage());
+        }
+    }
+
+    /**
+     * Sorts the children of <code>element</code> according to the order 
indicated by the
+     * comparator.
+     * @param element the element whose content is to be sorted. Only element 
children are sorted,
+     * attributes are not touched. When elements are reordered, all the text, 
comments and PIs
+     * follow the element that they come immediately after.
+     * @param comp a comparator that is to be used when comparing the 
<code>QName</code>s of two
+     * elements. See {@link 
org.apache.xmlbeans.samples.cursor.XmlSort.QNameComparator} for a simple
+     * implementation that compares two elements based on the value of their 
QName, but more
+     * complicated implementations are possible, for instance, ones that 
compare two elements based
+     * on the value of a specifc attribute etc.
+     * @throws IllegalArgumentException if the input <code>XmlObject</code> 
does not represent
+     * an element
+     */
+    public static void sort(XmlObject element, Comparator<XmlCursor> comp)
+    {
+        XmlCursor headCursor = element.newCursor();
+        if (!headCursor.isStart())
+            throw new IllegalStateException("The element parameter must point 
to a STARTDOC");
+        // We use insertion sort to minimize the number of swaps, because each 
swap means
+        // moving a part of the document
+        /* headCursor points to the beginning of the list of the already 
sorted items and
+           listCursor points to the beginning of the list of unsorted items
+           At the beginning, headCursor points to the first element and 
listCursor points to the
+           second element. The algorithm ends when listCursor cannot be moved 
to the "next"
+           element in the unsorted list, i.e. the unsorted list becomes empty 
*/
+        boolean moved = headCursor.toFirstChild();
+        if (!moved)
+        {
+            // Cursor was not moved, which means that the given element has no 
children and
+            // therefore there is nothing to sort
+            return;
+        }
+        XmlCursor listCursor = headCursor.newCursor();
+        boolean moreElements = listCursor.toNextSibling();
+        while (moreElements)
+        {
+            moved = false;
+            // While we can move the head of the unsorted list, it means that 
there are still
+            // items (elements) that need to be sorted
+            while (headCursor.comparePosition(listCursor) < 0)
+            {
+                if (comp.compare(headCursor, listCursor) > 0)
+                {
+                    // We have found the position in the sorted list, insert 
the element and the
+                    // text following the element in the current position
+                    /*
+                     * Uncomment this code to cause the text before the 
element to move along
+                     * with the element, rather than the text after the 
element. Notice that this
+                     * is more difficult to do, because the cursor's "type" 
refers to the position
+                     * to the right of the cursor, so to get the type of the 
token to the left, the
+                     * cursor needs to be first moved to the left (previous 
token)
+                     *
+                    headCursor.toPrevToken();
+                    while (headCursor.isComment() || headCursor.isProcinst() 
|| headCursor.isText())
+                        headCursor.toPrevToken();
+                    headCursor.toNextToken();
+                    listCursor.toPrevToken();
+                    while (listCursor.isComment() || listCursor.isProcinst() 
|| listCursor.isText())
+                        listCursor.toPrevToken();
+                    listCursor.toNextToken();
+                    while (!listCursor.isStart())
+                        listCursor.moveXml(headCursor);
+                    listCursor.moveXml(headCursor);
+                    */
+                    // Move the element
+                    listCursor.moveXml(headCursor);
+                    // Move the text following the element
+                    while (!listCursor.isStart() && !listCursor.isEnd())
+                        listCursor.moveXml(headCursor);
+                    moreElements = listCursor.isStart();
+                    moved = true;
+                    break;
+                }
+                headCursor.toNextSibling();
+            }
+            if (!moved)
+            {
+                // Because during the move of a fragment of XML, the 
listCursor is also moved, in
+                // case we didn't need to move XML (the new element to be 
inserted happened to
+                // be the last one in order), we need to move this cursor
+                moreElements = listCursor.toNextSibling();
+            }
+            // Reposition the head of the sorted list
+            headCursor.toParent();
+            headCursor.toFirstChild();
+        }
+    }
+
+    /**
+     * Implements a <code>java.util.Comparator</code> for comparing 
<code>QName</code>values.
+     * The namespace URIs are compared first and if they are equal, the local 
parts are compared.
+     * <p/>
+     * The constructor accepts an argument indicating whether the comparison 
order is the same as
+     * the lexicographic order of the strings or the reverse.
+     */
+    public static final class QNameComparator implements Comparator
+    {
+        public static final int ASCENDING = 1;
+        public static final int DESCENDING = 2;
+
+        private int order;
+
+        public QNameComparator(int order)
+        {
+            this.order = order;
+            if (order != ASCENDING && order != DESCENDING)
+                throw new IllegalArgumentException("Please specify one of 
ASCENDING or DESCENDING "+
+                    "comparison orders");
+        }
+
+        public int compare(Object o, Object o1)
+        {
+            XmlCursor cursor1 = (XmlCursor) o;
+            XmlCursor cursor2 = (XmlCursor) o1;
+            QName qname1 = cursor1.getName();
+            QName qname2 = cursor2.getName();
+            int qnameComparisonRes = 
qname1.getNamespaceURI().compareTo(qname2.getNamespaceURI());
+            if (qnameComparisonRes == 0)
+                return order == ASCENDING ?
+                    qname1.getLocalPart().compareTo(qname2.getLocalPart()) :
+                    -qname1.getLocalPart().compareTo(qname2.getLocalPart());
+            else
+                return order == ASCENDING ? qnameComparisonRes : 
-qnameComparisonRes;
+        }
+    }
+}
+ 
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to