001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.services.ejb.remote;
019:
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: import javax.ejb.EJBHome;
024: import javax.naming.Context;
025: import javax.naming.NamingException;
026: import javax.rmi.PortableRemoteObject;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.sape.carbon.core.component.ComponentConfiguration;
032: import org.sape.carbon.core.component.lifecycle.Configurable;
033: import org.sape.carbon.core.config.InvalidConfigurationException;
034:
035: import org.sape.carbon.services.ejb.EnterpriseBeanConfiguration;
036: import org.sape.carbon.services.ejb.HomeFactoryClassCastException;
037: import org.sape.carbon.services.ejb.HomeFactoryClassNotFoundException;
038: import org.sape.carbon.services.ejb.HomeFactoryException;
039: import org.sape.carbon.services.ejb.HomeFactoryNamingException;
040:
041: /**
042: * <p>The functional implementation of the Remote Home Factory functional interface.<br>
043: *
044: * The following list summarizes the key entites involved in using this servive
045: * <ul>
046: * <li>Configuration Interface {@link org.sape.carbon.services.ejb.remote.RemoteHomeFactoryConfiguration}
047: * <li>Functional Interface {@link org.sape.carbon.services.ejb.remote.RemoteHomeFactory}
048: * </ul>
049: * </p>
050: *
051: * @see org.sape.carbon.services.ejb.remote.RemoteHomeFactory
052: * @see org.sape.carbon.services.ejb.remote.RemoteHomeFactoryConfiguration
053: * @see org.sape.carbon.services.ejb.EnterpriseBeanConfiguration
054: * @see org.sape.carbon.services.ejb.HomeFactoryConfiguration
055: * @since carbon 1.0
056: * @author Erik M Gottesman, June 2002
057: * @version $Revision: 1.17 $($Author: dvoet $ / $Date: 2003/11/05 17:45:16 $)
058: * @stereotype implementationClass
059: */
060: public class RemoteHomeFactoryImpl implements Configurable,
061: RemoteHomeFactory {
062:
063: /**
064: * Provides a handle to Apache-commons logger
065: */
066: private Log log = LogFactory.getLog(this .getClass());
067:
068: /**
069: * Used for performing comparisons/null-checks on configuration data
070: */
071: private static final String EMPTY_STRING = "";
072:
073: private RemoteHomeFactoryConfiguration configuration;
074:
075: /**
076: * A private <code>Map</code> object used to store the lookup details of
077: * EJBs associated with this home factory component
078: */
079: private Map ejbMap;
080:
081: /**
082: * A private <code>Map</code> object used for caching the home interfaces of
083: * EJBs associated with this home factory component
084: */
085: private Map homeCache = new HashMap();
086:
087: /**
088: * @see RemoteHomeFactory
089: */
090: public EJBHome lookup(String logicalName)
091: throws HomeFactoryException {
092:
093: Context context = null;
094:
095: try {
096: context = this .configuration.getInitialContextFactory()
097: .getContext();
098:
099: return lookup(logicalName, context);
100:
101: } catch (NamingException ne) {
102: throw new HomeFactoryNamingException(this .getClass(),
103: "javax.naming.NamingException occurred for EJB name = "
104: + "'" + logicalName + "'", ne);
105:
106: } finally {
107: if (context != null) {
108: try {
109: context.close();
110: } catch (NamingException ne) {
111: log
112: .debug("Caught naming exception closing context: "
113: + ne);
114: }
115: }
116: }
117:
118: }
119:
120: /**
121: * @see RemoteHomeFactory
122: */
123: public EJBHome lookup(String logicalName, String principal,
124: String credentials) throws HomeFactoryException {
125:
126: Context context = null;
127:
128: try {
129: Map securityInfo = new HashMap();
130: securityInfo.put(Context.SECURITY_PRINCIPAL, principal);
131: securityInfo.put(Context.SECURITY_CREDENTIALS, credentials);
132: context = this .configuration.getInitialContextFactory()
133: .getContext(securityInfo);
134:
135: return lookup(logicalName, context);
136:
137: } catch (NamingException ne) {
138: throw new HomeFactoryNamingException(this .getClass(),
139: "javax.naming.NamingException occurred for EJB name = "
140: + "'" + logicalName + "'", ne);
141:
142: } finally {
143: if (context != null) {
144: try {
145: context.close();
146: } catch (NamingException ne) {
147: log
148: .debug("Caught naming exception closing context: "
149: + ne);
150: }
151: }
152: }
153: }
154:
155: /**
156: * @see RemoteHomeFactory
157: */
158: public EJBHome lookup(String logicalName, Context context)
159: throws HomeFactoryException {
160:
161: if (log.isTraceEnabled()) {
162: log.trace("Performing lookup for EJB with logical name: "
163: + logicalName);
164: }
165:
166: // Define local variables
167: EJBHome ejbHome = null;
168:
169: EnterpriseBeanConfiguration ejbDetails = (EnterpriseBeanConfiguration) this .ejbMap
170: .get(logicalName);
171:
172: if (ejbDetails == null) {
173: throw new HomeFactoryNamingException(this .getClass(),
174: "Unable to retrieve configuration details for EJB name = '"
175: + logicalName + "'");
176: }
177:
178: if (ejbDetails.isCacheable()) {
179:
180: if (log.isTraceEnabled()) {
181: log
182: .trace("Checking home cache for EJB: "
183: + logicalName);
184: }
185:
186: /*
187: * Assumption: a compound key has not been implemented for caching
188: * a home interface in multiple security contexts
189: */
190: ejbHome = (EJBHome) homeCache.get(logicalName);
191: }
192:
193: if (ejbHome == null) {
194:
195: // Get the JNDI Initial Context and lookup the JNDI bean name.
196: Object homeObject = null;
197:
198: try {
199: homeObject = context.lookup(logicalName);
200: } catch (NamingException ne) {
201: throw new HomeFactoryNamingException(this .getClass(),
202: "javax.naming.NamingException occurred for EJB name = '"
203: + logicalName + "'", ne);
204: }
205:
206: // Find home, first check if it uses RMI-IIOP or RMI-JRMP
207: if (this .configuration.isRmiIiop()) {
208:
209: /*
210: * For RMI-IIOP, convert the remote reference from the more
211: * general type, Object, to the more specific type (as specified
212: * via the Config service).
213: */
214:
215: Class homeClass;
216:
217: String homeInterfaceClassName = ejbDetails
218: .getHomeInterface();
219:
220: try {
221: // Get the name of the class that defines the home interface
222:
223: // Get the home interface class
224: homeClass = Class.forName(homeInterfaceClassName);
225:
226: // Narrow the EJB home reference accordingly
227: ejbHome = (EJBHome) PortableRemoteObject.narrow(
228: homeObject, homeClass);
229: } catch (ClassNotFoundException cnfe) {
230: throw new HomeFactoryClassNotFoundException(this
231: .getClass(),
232: "Unable to obtain class: for name = '"
233: + homeInterfaceClassName + "'",
234: cnfe);
235: } catch (ClassCastException cce) {
236: throw new HomeFactoryClassCastException(
237: this .getClass(),
238: "java.lang.ClassCastException "
239: + "occurred while attempting to narrow the EJB home "
240: + "reference - logical name = '"
241: + logicalName + "'", cce);
242: }
243:
244: } else {
245:
246: // For Java RMI, simply downcast the home object to EJBHome
247: try {
248: ejbHome = (EJBHome) homeObject;
249: } catch (ClassCastException cce) {
250: throw new HomeFactoryClassCastException(
251: this .getClass(),
252: "java.lang.ClassCastException "
253: + " occurred while attempting to downcast the EJB home "
254: + "reference - logical name = '"
255: + logicalName + "'", cce);
256: }
257: }
258:
259: /*
260: * If the EJB is declared as cacheable, store a reference to its
261: * home interface in order to expedite future lookups
262: */
263: if (ejbDetails.isCacheable()) {
264:
265: if (log.isTraceEnabled()) {
266: log.trace("Adding EJB: " + logicalName
267: + " to the home interface cache");
268: }
269:
270: cacheHome(logicalName, ejbHome);
271: }
272: }
273:
274: // Return the EJBHome object to the caller
275: return ejbHome;
276: }
277:
278: /**
279: * Configures the component. This is preceded and followed by the suspend
280: * and resume operations if they are available on the component.
281: * @param configuration A HomeFactoryConfiguration instance
282: */
283: public void configure(ComponentConfiguration configuration) {
284:
285: try {
286: this .configuration = (RemoteHomeFactoryConfiguration) configuration;
287: } catch (ClassCastException cce) {
288: throw new InvalidConfigurationException(this .getClass(),
289: configuration.getConfigurationName(),
290: "ConfigurationInterface",
291: "Configuration interface must be of type "
292: + RemoteHomeFactoryConfiguration.class
293: .getName());
294: }
295:
296: EnterpriseBeanConfiguration ejbs[];
297:
298: ejbs = (EnterpriseBeanConfiguration[]) this .configuration
299: .getEnterpriseBean();
300:
301: this .ejbMap = new HashMap(ejbs.length);
302:
303: /*
304: * Build the internal data structures that will be used to hold
305: * EJB configuration details and (optionally) cached home interfaces
306: */
307: for (int i = 0; i < ejbs.length; i++) {
308:
309: /*
310: * Perform a check to ensure that the home interface is specified
311: * in configuration if RMI-IIOP is to be used
312: */
313: if (this .configuration.isRmiIiop() == true
314: && (ejbs[i].getHomeInterface().equals(EMPTY_STRING) || ejbs[i]
315: .getHomeInterface() == null)) {
316:
317: throw new InvalidConfigurationException(
318: this .getClass(),
319: configuration.getConfigurationName(),
320: "Home interface for EJB "
321: + ejbs[i]
322: + "must be specified if RMI-IIOP is enabled");
323: }
324:
325: this .ejbMap.put(ejbs[i].getLogicalName(), ejbs[i]);
326: }
327: }
328:
329: /**
330: * @see RemoteHomeFactory
331: */
332: public EnterpriseBeanConfiguration getEJBDetails(String logicalName) {
333: return (EnterpriseBeanConfiguration) this .ejbMap
334: .get(logicalName);
335: }
336:
337: /**
338: * <p>Associates the home interface object of a locally deployed EJB
339: * with a logical name (usually its JNDI name), and caches it to
340: * decrease the cost of subsequent JNDI lookups</p>
341: * @param logicalName a String representation of the EJB's logical name
342: * in JNDI
343: * @param ejbHome the home interface object of a remotely deployed EJB
344: */
345: protected void cacheHome(String logicalName, EJBHome ejbHome) {
346: this.homeCache.put(logicalName, ejbHome);
347: }
348: }
|