Skip to content

Instantly share code, notes, and snippets.

@dblevins
Created August 14, 2009 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dblevins/168153 to your computer and use it in GitHub Desktop.
Save dblevins/168153 to your computer and use it in GitHub Desktop.
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.util;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
/**
* Propagates the InvocationContext so that anyone with access to
* the InvocationContext can see the caller's context and propogate
* state forward for the entire call stack. With this, no one with
* access to the InvocationContext should ever need a thread local.
*
* This is the one thread local to make all other thread locals unnecessary.
*
* This interceptor should be installed as a global interceptor and
* positioned to be the first interceptor executed.
*
* Anyone downstream of this interceptor can make a call like this
* to get access the an infinite amout of state up the stack.
*
* InvocationContext caller = (InvocationContext) invocationContext.getContextData().get("caller");
*
* With the "caller" InvocationContext you can move specific state
* forward for quick access.
*
* // Move the fooState to the current InvocationContext
* Object state = caller.getContextData().get("fooState");
* invocationContext.getContextData().put("fooState", oldContext);
*
* You can also look infinitely back the invocation chain for
* state set in a previous InvocationContext.
*
* Object fooState = null;
* for (InvocationContext context = invocationContext;
* fooState == null && context != null;
* context = (InvocationContext) context.getContextData().get("caller")) {
*
* fooState = context.getContextData().get("fooState");
* }
*
*
* Same approach as above, but using a simple recursive method
*
*
* public Object get(InvocationContext context, String property) {
* if (context == null) return null;
* Map<String,Object> data = context.getContextData();
* Object value = data.get(property);
* if (value != null) return value;
* return get((InvocationContext) data.get("caller"), property);
* }
*
* @author David Blevins
*/
public class InvocationContextPropagator {
private final static ThreadLocal<InvocationContext> context = new ThreadLocal<InvocationContext>();
@AroundInvoke
public Object intercept(InvocationContext newContext) throws Exception {
// Get the previous InvocationContext
InvocationContext oldContext = context.get();
try {
// Now anyone can get the old context without the thread local
newContext.getContextData().put("caller", oldContext);
// Track the newContext for our purposes
context.set(newContext);
// Call the method
return newContext.proceed();
} finally {
// restore the calling context
context.set(oldContext);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment