Hi John,

While your example proxy solution is nice enough by itself, imo its way too 
much over-engineering for the issue at hand.
We're trying to get rid of the ContextClassLoader use for *only* the logging, 
not add more overhead to it!
And, in practice this solution wouldn't work for us anyway as there are other cross-context invocation usages where we *need* the ContextClassLoader of the caller, like when marshalling and unmarshalling complex PortletEvent payload (using JAXB) provided by the Portlet Application to be dispatched across potentially even other Portlet Applications (all this managed and coordinated from the Portal/container web app). The PortletContainer (we) know when to use the ContextClassLoader and when not. An all-encompassing proxy solution adds too much unnecessary overhead and actually blocks the usage of the real ContextClassLoader when its needed.

We just needed the least intrusive and most straightforward solution available 
and wrapping or patching CL simply doesn't fit that bill.

With kind regards,

Ate

John Bollinger wrote:
Mark Thomas wrote:
John Bollinger wrote:
See attached sample code for a class that would support this behavior.
Your attachment didn't make it through. Could you post it in-line?

Sure:

/*
 * 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 example;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <p>
 * A service class that assists in managing a "context" within an application or
 * service.  This version provides for creating dynamic proxies around objects
 * belonging to a particular context to ensure that those objects' methods are
 * invoked in that context.
 * </p><p>
 * Instances may be created and held on a one-per-context basis, but currently
 * there is no harm in having multiple managers for the same context.
 * Alternatively, {...@code ContextManager}s are lightweight, so they may be 
created
 * at need and released freely. Model usage:<br/>
 * <tt><pre>
 * ContextManager contextManager = ContextManager.forCurrentContext();
 * ...
 * void passRequestToForeignContext(RequestInterface request, ForeignContext 
context) {
 *      context.handleRequest(
 *          contextManager.createProxy(request, RequestInterface.class)
 *      );
 * }
 * </pre></tt>
 * </p>
 *
 * @author John C. Bollinger
 */
public class ContextManager {
/**
     * The context ClassLoader for the context managed by this ContextManager
     */
    private final ClassLoader contextClassLoader;
/**
     * Initializes a new ContextManager managing the context defined by the
     * specified context {...@code ClassLoader}
     *
     * @param contextClassLoader a {...@code ClassLoader} representing the 
context
* to be managed by this {...@code ContextManager} */
    public ContextManager(ClassLoader contextClassLoader) {
        this.contextClassLoader = contextClassLoader;
    }
/**
     * Creates and returns a {...@code ContextManger} for the current context
     *
     * @return a {...@code ContextManger} for the current context
     */
    public static ContextManager forCurrentContext() {
        return new 
ContextManager(Thread.currentThread().getContextClassLoader());
    }
/**
     * Creates a dynamic proxy object wrapping the provided object and ensuring
     * that all methods of the wrapped object (when invoked via the proxy) see
     * the appropriate context ClassLoader for the context managed by this
     * {...@code ContextManager}.  The proxy's class will implement the 
specified
     * interface(s) by delegating every method invocation to the wrapped object,
* setting the context ClassLoader before, and resetting it after. * * @param <T> an interface type that the proxy object will implement * @param object the object to be wrapped by the * @param iface a Class representing one of the interfaces the proxy's class
     *      must implement, and defining the formal type of the return value and
     *      the {...@code object} argument
     * @param additionalIfaces {...@code Class}es representing additional 
interfaces
     *      the proxy's class must implement
* * @return a proxy object wrapping the specified delegate object, and whose
     *      class implements all the specified interfaces
     */
    public <T> T createProxy(T object, Class<T> iface, Class<?>... 
additionalIfaces) {
        Class<?>[] interfaces;
/* * Could test to see whether the interfaces (iface and additionalIfaces)
         * are in fact interfaces (as opposed to normal classes).  Haven't 
tested
         * what happens if they are non-interface classes, but probably Proxy
         * will fail to create the proxy object.
* * Could also test whether they are null.
         */
if (additionalIfaces != null) {
            /*
             * Set up the full list of interface classes the proxy will 
implement.
             * iface comes first, then any additionalIfaces elements, in order.
             */
/*
             * Could test the additional interfaces here to make sure the
             * submitted object can successfully be cast to each type.  If the
             * object's class does not implement one of the interfaces then
             * runtime failures will occur when those interfaces' methods are
             * invoked on the proxy.
             */
interfaces = new Class[1 + additionalIfaces.length];
            interfaces[0] = iface;
            System.arraycopy(additionalIfaces, 0, interfaces, 1, 
additionalIfaces.length);
        } else {
            interfaces = new Class[] {iface};
        }
return iface.cast(Proxy.newProxyInstance(contextClassLoader, interfaces,
                new ContextManagingInvocationHandler(object, 
contextClassLoader)));
    }

    /**
     * An InvocationHandler wrapping a specified object and serving to present a
     * given context ClassLoader to that object on all method invocations.
     *
     * @author John C. Bollinger
     */
    private static class ContextManagingInvocationHandler implements 
InvocationHandler {

        /*
         * This class doesn't really need to be nested.  This version is nested
         * mainly for packaging purposes.
         */
/**
         * The ClassLoader to set as the current context ClassLoader when
         * delegating method invocations to the {...@link #wrappedObject}
         */
        private final ClassLoader contextClassLoader;
/**
         * The object to which all method invocations are delegated
         */
        private final Object wrappedObject;
/**
         * Initializes a new ContextManagingInvocationHandler that delegates
         * method invocations to the specified object while ensuring that the
         * current context ClassLoader is the specified one within the scope of
         * the invocation.
         *
         * @param wrappedObject the {...@code Object} to which method 
invocations
         *      should be delegated
         * @param contextClassLoader the {...@code ClassLoader} that should be 
the
         *      current context {...@code ClassLoader} within the scope of 
method
         *      invocations on the wrapped object
         */
        public ContextManagingInvocationHandler(Object wrappedObject,
                ClassLoader contextClassLoader) {
            this.contextClassLoader = contextClassLoader;
            this.wrappedObject = wrappedObject;
        }
/**
         * {...@inheritdoc}.  This implementation sets the context ClassLoader 
to the
         * configured one, delegates to the wrapped object, then restores the
* context ClassLoader to its value at method entry. *
         * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, 
java.lang.reflect.Method, java.lang.Object[])
         */
        public Object invoke(@SuppressWarnings("unused") Object proxy,
                Method method, Object[] args) throws Throwable {
            Thread currentThread = Thread.currentThread();
            ClassLoader currentContextClassLoader
                    = currentThread.getContextClassLoader();
try {
                currentThread.setContextClassLoader(contextClassLoader);
                return method.invoke(wrappedObject, args);
            } finally {
                currentThread.setContextClassLoader(currentContextClassLoader);
            }
        }
    }
}




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to