001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.wrap;
024:
025: import java.lang.reflect.InvocationHandler;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Proxy;
028: import java.util.ArrayList;
029: import java.util.Arrays;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Map;
035: import java.util.Set;
036:
037: /**
038: * Wraps Jsel object such as the underlying object becomes garbage collection
039: * eligible and will be transparently restored from the database and source files
040: * on demand
041: * @author Pavel Vlasov
042: * @version $Revision: 1.2 $
043: */
044: public abstract class WrapperHandler implements InvocationHandler {
045: private Object proxy;
046:
047: /**
048: * Subclasses can add more classes to wrap.
049: */
050: protected Collection classesToWrap = new ArrayList();
051:
052: private static Map interfaceMap = new HashMap();
053:
054: public WrapperHandler(Object master) {
055: proxy = Proxy.newProxyInstance(master.getClass()
056: .getClassLoader(),
057: getClassInterfaces(master.getClass()), this );
058:
059: classesToWrap.add(Collection.class);
060: classesToWrap.add(Map.class);
061: }
062:
063: public Object getProxy() {
064: return proxy;
065: }
066:
067: public Object invoke(Object proxy, Method method, Object[] args)
068: throws Throwable {
069: Object[] unwrappedArgs;
070: if (args != null && args.length != 0) {
071: unwrappedArgs = new Object[args.length];
072: for (int i = 0; i < unwrappedArgs.length; i++) {
073: unwrappedArgs[i] = args[i];
074: if (Proxy.isProxyClass(args[i].getClass())) {
075: InvocationHandler handler = Proxy
076: .getInvocationHandler(proxy);
077: if (handler instanceof WrapperHandler) {
078: unwrappedArgs[i] = ((WrapperHandler) handler)
079: .getMaster();
080: if (unwrappedArgs[i] == null) {
081: throw new IllegalStateException(
082: "Unwrapped object is null for parameter "
083: + i + " in method "
084: + method);
085: }
086: }
087: }
088: }
089: } else {
090: unwrappedArgs = args;
091: }
092:
093: Object master = getMaster();
094: if (master == null) {
095: throw new NullPointerException("Master object is null");
096: }
097:
098: Object ret = method.invoke(master, unwrappedArgs);
099:
100: return wrap(ret, classesToWrap);
101: }
102:
103: /**
104: * Convenience method.
105: * @param toWrap Object to wrap
106: * @param classesToWrap collection of classes that shall be wrapped. Wrappable is always wrapped. Can be null.
107: * @return Proxy object for toWrap if toWrap is either Wrappable or instance of one of classes from classesToWrap,
108: * toWrap otherwise
109: * @throws Throwable
110: */
111: public static Object wrap(Object toWrap, Collection classesToWrap)
112: throws Throwable {
113: if (toWrap instanceof Wrappable) {
114: return ((Wrappable) toWrap).getProxy();
115: }
116:
117: if (classesToWrap != null) {
118: Iterator it = classesToWrap.iterator();
119: while (it.hasNext()) {
120: if (((Class) it.next()).isInstance(toWrap)) {
121: return new StrongWrapperHandler(toWrap).getProxy();
122: }
123: }
124: }
125:
126: return toWrap;
127: }
128:
129: public static Object wrap(Object toWrap) throws Throwable {
130: return wrap(toWrap, null);
131: }
132:
133: protected abstract Object getMaster() throws Throwable;
134:
135: /**
136: * @param sourceClass
137: * @return all interfaces implemented by this class
138: */
139: public static Class[] getClassInterfaces(Class sourceClass) {
140: synchronized (interfaceMap) {
141: Class[] ret = (Class[]) interfaceMap.get(sourceClass);
142: if (ret == null) {
143: Set set = new HashSet();
144: getClassInterfaces(sourceClass, set);
145: ret = (Class[]) new ArrayList(set)
146: .toArray(new Class[set.size()]);
147: interfaceMap.put(sourceClass, ret);
148: }
149: return ret;
150: }
151: }
152:
153: /**
154: * @param sourceClass
155: */
156: private static void getClassInterfaces(Class sourceClass,
157: Collection set) {
158: if (sourceClass != null) {
159: Class[] interfaces = sourceClass.getInterfaces();
160: for (int i = 0; interfaces != null && i < interfaces.length; i++) {
161: getClassInterfaces(interfaces[i]);
162: }
163: getClassInterfaces(sourceClass.getSuperclass(), set);
164: set.addAll(Arrays.asList(interfaces));
165: }
166: }
167: }
|