001: /*
002: * <copyright>
003: *
004: * Copyright 2001-2007 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.util;
028:
029: import java.lang.reflect.InvocationHandler;
030: import java.lang.reflect.Method;
031: import java.lang.reflect.Proxy;
032: import java.util.HashMap;
033: import java.util.Map;
034:
035: /**
036: * Reflection helper methods.
037: */
038: public final class Reflection {
039:
040: private Reflection() {
041: }
042:
043: /**
044: * Create a reflective proxy from one class to an interface with matching
045: * method names (but not necessarily an "instanceof").
046: * <p>
047: * For example, this utility method can be used to wrap class:<pre>
048: * public class Impl {
049: * public void foo() { .. }
050: * }
051: * </pre>
052: * as interface:<pre>
053: * public interface Service {
054: * void foo();
055: * }
056: * </pre>
057: * using:<pre>
058: * Impl x = new Impl();
059: * Service s = (Service) Reflection.makeProxy(x, Service.class);
060: * </pre>
061: * even though "x instanceof Service" is false. The only requirement is that
062: * Impl have all the methods defined in Service.
063: * <p>
064: * We primarily use this technique to avoid compile and classloader problems
065: * when importing/exporting services from/to an external Node container.
066: */
067: public static Object makeProxy(final Object from_obj,
068: final Class to_cl) throws Exception {
069: // validate
070: if (from_obj == null) {
071: throw new IllegalArgumentException("null from_obj");
072: }
073: if (to_cl == null || !to_cl.isInterface()) {
074: throw new IllegalArgumentException(
075: "to_class must be an interface, not " + to_cl);
076: }
077: final Class from_cl = from_obj.getClass();
078:
079: // create mapping of "to_cl" to our "from_cl"
080: //
081: // To help avoid confusion, we'll use "in/out" names instead of
082: // "to/from" names, since we're creating a reverse mapping
083: final Map mapping = new HashMap();
084: Method[] in_ma = to_cl.getMethods();
085: Method[] out_ma = from_cl.getMethods();
086: for (int i = 0; i < in_ma.length; i++) {
087: Method in_m = in_ma[i];
088: String in_name = in_m.getName();
089: int in_argc = in_m.getParameterTypes().length;
090: Method out_m = null;
091: for (int j = 0; j < out_ma.length; j++) {
092: Method oj_m = out_ma[j];
093: String oj_name = oj_m.getName();
094: if (!in_name.equals(oj_name))
095: continue;
096: int oj_argc = oj_m.getParameterTypes().length;
097: if (in_argc != oj_argc)
098: continue;
099: // assume no awkward polymorphism, e.g. no
100: // void foo(X x)
101: // void foo(Y y)
102: out_m = oj_m;
103: break;
104: }
105: if (out_m == null) {
106: throw new RuntimeException(
107: "Unable to find mapping from " + to_cl + " to "
108: + from_cl + " for method " + in_m);
109: }
110: mapping.put(in_m, out_m);
111: }
112:
113: // create method handler
114: InvocationHandler ih = new InvocationHandler() {
115: public Object invoke(Object proxy, Method in_m,
116: Object[] args) throws Throwable {
117: Method out_m = (Method) mapping.get(in_m);
118: if (out_m == null) {
119: throw new RuntimeException(
120: "Internal error, unable to map " + in_m
121: + " to " + from_cl + " method in "
122: + mapping);
123: }
124: return out_m.invoke(from_obj, args);
125: }
126: };
127:
128: // create proxy
129: Object ret = Proxy.newProxyInstance(to_cl.getClassLoader(),
130: new Class[] { to_cl }, ih);
131: return ret;
132: }
133: }
|