View Javadoc

1   /*
2    * The SmartWeb Framework
3    * Copyright (C) 2004-2006
4    *
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18   *
19   * For further informations on the SmartWeb Framework please visit
20   *
21   *                        http://smartweb.sourceforge.net
22   */
23  package net.smartlab.web;
24  
25  import java.lang.reflect.InvocationHandler;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.Proxy;
29  import java.rmi.RemoteException;
30  import java.util.Collections;
31  import java.util.HashMap;
32  import java.util.Map;
33  import java.util.TreeMap;
34  
35  import javax.ejb.EJBHome;
36  import javax.naming.Context;
37  import javax.naming.InitialContext;
38  import javax.naming.NamingException;
39  import javax.rmi.PortableRemoteObject;
40  
41  import org.apache.commons.logging.Log;
42  import org.apache.commons.logging.LogFactory;
43  
44  /**
45   * This class works as a <strong>Business Delegate</strong> for Session Enterprise Java Beans.
46   * @author   rlogiacco
47   * @uml.dependency   supplier="net.smartlab.web.EnterpriseDomain"
48   */
49  public class EnterpriseDomainBuilder extends Domain {
50  
51  	/**
52  	 * Provides logging capabilities to the builder.
53  	 */
54  	private final static Log logger = LogFactory.getLog(EnterpriseDomainBuilder.class);
55  	
56  	protected final static Map primitives = new TreeMap();
57  	static {
58  		primitives.put("boolean", boolean.class);
59  		primitives.put("byte", byte.class);
60  		primitives.put("short", short.class);
61  		primitives.put("int", int.class);
62  		primitives.put("long", long.class);
63  		primitives.put("float", float.class);
64  		primitives.put("double", double.class);
65  		primitives.put("char", char.class);
66  	}
67  
68  	/**
69  	 * Associating map for EJB homes. Home objects are cached here for single
70  	 * JNDI lookup, but should be checked for bindings update.
71  	 */
72  	private final static Map homes = Collections.synchronizedMap(new HashMap());
73  
74  
75  	/**
76  	 * @TODO documentation
77  	 * @param name
78  	 * @param type
79  	 * @return
80  	 */
81  	public static Object getInstance(String name, Class type) {
82  		return EnterpriseDomainBuilder.getInstance(name, type, null, null);
83  	}
84  
85  	/**
86  	 * @TODO documentation
87  	 * @param name
88  	 * @param type
89  	 * @param params
90  	 * @return
91  	 */
92  	public static Object getInstance(String name, Class type, Object[] params) {
93  		return EnterpriseDomainBuilder.getInstance(name, type, null, params);
94  	}
95  
96  	/**
97  	 * TODO documentation
98  	 * 
99  	 * @param name
100 	 * @param type
101 	 * @param context
102 	 * @return
103 	 */
104 	public static Object getInstance(String name, Class type, Context context) {
105 		return EnterpriseDomainBuilder.getInstance(name, type, context, null);
106 	}
107 
108 	/**
109 	 * TODO documentation
110 	 * 
111 	 * @param name
112 	 * @param type
113 	 * @param context
114 	 * @param params
115 	 * @return
116 	 */
117 	public static Object getInstance(String name, Class type, Context context, Object[] params) {
118 		HomeWrapper wrapper = (HomeWrapper)homes.get(name);
119 		if (wrapper == null) {
120 			// home not found
121 			try {
122 				if (context == null) {
123 					context = new InitialContext();
124 					logger.debug("no context specified");
125 				}
126 				Object home = context.lookup(name);
127 				if (home instanceof EJBHome) {
128 					home = PortableRemoteObject.narrow(home, EJBHome.class);
129 				}
130 				wrapper = new HomeWrapper(home);
131 				homes.put(name, wrapper);
132 			} catch (NamingException ne) {
133 				logger.error("lookup(" + name + ") - error", ne);
134 				return null;
135 			}
136 		} else {
137 			if (System.currentTimeMillis() - wrapper.getLastCheck() > 60000) {
138 				homes.remove(name);
139 			}
140 		}
141 		try {
142 			Class[] paramTypes = null;
143 			if (params != null) {
144 				paramTypes = new Class[params.length];
145 				for (int i = 0; i < paramTypes.length; i++) {
146 					paramTypes[i] = params[i].getClass();
147 				}
148 			}
149 			Object ejb = wrapper.getHome().getClass().getDeclaredMethod("create", paramTypes).invoke(wrapper.getHome(),
150 					params);
151 			return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {type},
152 					new EnterpriseDomainWrapper(ejb));
153 		} catch (Exception e) {
154 			homes.remove(name);
155 			logger.error("ejb home class instantiation failed", e);
156 			return null;
157 		}
158 	}
159 
160 
161 	private static class EnterpriseDomainWrapper implements InvocationHandler {
162 
163 		/**
164 		 * Logger for this class
165 		 */
166 		private static final Log logger = LogFactory.getLog(EnterpriseDomain.class);
167 
168 		/**
169 		 * TODO documentation Comment for <code>ejb</code>
170 		 */
171 		private Object ejb;
172 
173 
174 		/**
175 		 * TODO documentation
176 		 * 
177 		 * @param ejb
178 		 */
179 		private EnterpriseDomainWrapper(Object ejb) {
180 			this.ejb = ejb;
181 		}
182 
183 		/**
184 		 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
185 		 *      java.lang.reflect.Method, java.lang.Object[])
186 		 */
187 		public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
188 			if (logger.isDebugEnabled()) {
189 				logger.debug("invoke(" + ejb + ", " + method + ", " + params + ")");
190 			}
191 			Object result = null;
192 			try {
193 				if (ejb instanceof EnterpriseDomain.Remote) {
194 					String[] types = EnterpriseDomainWrapper.getNames(method.getParameterTypes());
195 					result = ((EnterpriseDomain.Remote)ejb).execute(method.getName(), params, types, EnterpriseDomain
196 							.getContext());
197 				} else {
198 					result = method.invoke(ejb, params);
199 				}
200 			} catch (RemoteException re) {
201 				if (re.detail instanceof InvocationTargetException) {
202 					// Exception thrown by the business tier
203 					throw ((InvocationTargetException)re.detail).getTargetException();
204 				} else {
205 					// Exception thrown by the communication layer
206 					throw re;
207 				}
208 			}
209 			if (logger.isDebugEnabled()) {
210 				logger.debug("invoke(" + ejb + ", " + method + ", " + params + ") - finish with result=" + result);
211 			}
212 			return result;
213 		}
214 
215 		/**
216 		 * Get the class names than can be used in remote reflection invocation.
217 		 * 
218 		 * @param paramTypes The method argument classes
219 		 * @return class names
220 		 */
221 		private static String[] getNames(Class[] paramTypes) {
222 			String[] paramNames = new String[paramTypes.length];
223 			for (int i = 0; i < paramTypes.length; i++) {
224 				paramNames[i] = paramTypes[i].getName();
225 			}
226 			return paramNames;
227 		}
228 	}
229 
230 	protected static class HomeWrapper {
231 
232 		private Object home;
233 
234 		private long lastCheck;
235 
236 
237 		private HomeWrapper(Object home) {
238 			this.home = home;
239 			this.lastCheck = System.currentTimeMillis();
240 		}
241 
242 		public long getLastCheck() {
243 			return lastCheck;
244 		}
245 
246 		public Object getHome() {
247 			return home;
248 		}
249 	}
250 }