001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.server.ejbd;
017:
018: import java.io.ObjectInputStream;
019: import java.io.ObjectOutputStream;
020: import java.lang.reflect.Method;
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.HashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import javax.jms.ConnectionFactory;
029: import javax.naming.Context;
030: import javax.naming.NameClassPair;
031: import javax.naming.NameNotFoundException;
032: import javax.naming.NamingEnumeration;
033: import javax.naming.NamingException;
034: import javax.sql.DataSource;
035: import javax.xml.namespace.QName;
036:
037: import org.apache.openejb.DeploymentInfo;
038: import org.apache.openejb.Injection;
039: import org.apache.openejb.ProxyInfo;
040: import org.apache.openejb.client.CallbackMetaData;
041: import org.apache.openejb.client.DataSourceMetaData;
042: import org.apache.openejb.client.EJBMetaDataImpl;
043: import org.apache.openejb.client.HandlerChainMetaData;
044: import org.apache.openejb.client.HandlerMetaData;
045: import org.apache.openejb.client.InjectionMetaData;
046: import org.apache.openejb.client.JNDIRequest;
047: import org.apache.openejb.client.JNDIResponse;
048: import org.apache.openejb.client.NameClassPairEnumeration;
049: import org.apache.openejb.client.PortRefMetaData;
050: import org.apache.openejb.client.RequestMethodConstants;
051: import org.apache.openejb.client.ResponseCodes;
052: import org.apache.openejb.client.ThrowableArtifact;
053: import org.apache.openejb.client.WsMetaData;
054: import org.apache.openejb.core.ivm.BaseEjbProxyHandler;
055: import org.apache.openejb.core.ivm.naming.IvmContext;
056: import org.apache.openejb.core.webservices.HandlerChainData;
057: import org.apache.openejb.core.webservices.HandlerData;
058: import org.apache.openejb.core.webservices.PortAddress;
059: import org.apache.openejb.core.webservices.PortAddressRegistry;
060: import org.apache.openejb.core.webservices.PortRefData;
061: import org.apache.openejb.core.webservices.ServiceRefData;
062: import org.apache.openejb.loader.SystemInstance;
063: import org.apache.openejb.spi.ContainerSystem;
064: import org.apache.openejb.util.LogCategory;
065: import org.apache.openejb.util.Logger;
066: import org.apache.openejb.util.proxy.ProxyManager;
067: import org.omg.CORBA.ORB;
068:
069: class JndiRequestHandler {
070: private static final Logger logger = Logger.getInstance(
071: LogCategory.OPENEJB_SERVER_REMOTE.createChild("jndi"),
072: "org.apache.openejb.server.util.resources");
073:
074: private Context ejbJndiTree;
075: private Context clientJndiTree;
076: private Context deploymentsJndiTree;
077: private final ClusterableRequestHandler clusterableRequestHandler;
078:
079: JndiRequestHandler(EjbDaemon daemon) throws Exception {
080: ContainerSystem containerSystem = SystemInstance.get()
081: .getComponent(ContainerSystem.class);
082: ejbJndiTree = (Context) containerSystem.getJNDIContext()
083: .lookup("openejb/ejb");
084: deploymentsJndiTree = (Context) containerSystem
085: .getJNDIContext().lookup("openejb/Deployment");
086: try {
087: clientJndiTree = (Context) containerSystem.getJNDIContext()
088: .lookup("openejb/client");
089: } catch (NamingException e) {
090: }
091: clusterableRequestHandler = newClusterableRequestHandler();
092: }
093:
094: protected BasicClusterableRequestHandler newClusterableRequestHandler() {
095: return new BasicClusterableRequestHandler();
096: }
097:
098: public void processRequest(ObjectInputStream in,
099: ObjectOutputStream out) {
100: JNDIResponse res = new JNDIResponse();
101: JNDIRequest req = null;
102: try {
103: req = new JNDIRequest();
104: req.readExternal(in);
105: } catch (Throwable e) {
106: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
107: NamingException namingException = new NamingException(
108: "Could not read jndi request");
109: namingException.setRootCause(e);
110: res.setResult(new ThrowableArtifact(namingException));
111:
112: if (logger.isDebugEnabled()) {
113: try {
114: logger.debug("JNDI REQUEST: " + req
115: + " -- RESPONSE: " + res);
116: } catch (Exception justInCase) {
117: }
118: }
119:
120: try {
121: res.writeExternal(out);
122: } catch (java.io.IOException ie) {
123: logger.fatal(
124: "Couldn't write JndiResponse to output stream",
125: ie);
126: }
127: }
128:
129: try {
130: if (req.getRequestString().startsWith("/")) {
131: req.setRequestString(req.getRequestString()
132: .substring(1));
133: }
134: Context context = getContext(req);
135:
136: switch (req.getRequestMethod()) {
137: case RequestMethodConstants.JNDI_LOOKUP:
138: doLookup(req, res, context);
139: break;
140: case RequestMethodConstants.JNDI_LIST:
141: doList(req, res, context);
142: break;
143: }
144:
145: } catch (Throwable e) {
146: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
147: NamingException namingException = new NamingException(
148: "Unknown error in container");
149: namingException.setRootCause(e);
150: res.setResult(new ThrowableArtifact(namingException));
151: } finally {
152:
153: if (logger.isDebugEnabled()) {
154: try {
155: logger.debug("JNDI REQUEST: " + req
156: + " -- RESPONSE: " + res);
157: } catch (Exception justInCase) {
158: }
159: }
160:
161: try {
162: res.writeExternal(out);
163: } catch (Throwable e) {
164: logger.fatal(
165: "Couldn't write JndiResponse to output stream",
166: e);
167: }
168: }
169: }
170:
171: private Context getContext(JNDIRequest req) throws NamingException {
172: Context context;
173: if (req.getModuleId() != null
174: && req.getModuleId().equals("openejb/Deployment")) {
175: context = deploymentsJndiTree;
176: } else if (req.getModuleId() != null && clientJndiTree != null) {
177: context = (Context) clientJndiTree
178: .lookup(req.getModuleId());
179: } else {
180: context = ejbJndiTree;
181: }
182: return context;
183: }
184:
185: private void doLookup(JNDIRequest req, JNDIResponse res,
186: Context context) {
187: Object object;
188: String name = req.getRequestString();
189:
190: try {
191:
192: if (name.equals("comp/injections")) {
193:
194: //noinspection unchecked
195: List<Injection> injections = (List<Injection>) context
196: .lookup(name);
197: InjectionMetaData metaData = new InjectionMetaData();
198: for (Injection injection : injections) {
199: metaData.addInjection(injection.getTarget()
200: .getName(), injection.getName(), injection
201: .getJndiName());
202: }
203: res.setResponseCode(ResponseCodes.JNDI_INJECTIONS);
204: res.setResult(metaData);
205: return;
206: } else {
207: object = context.lookup(name);
208: }
209:
210: if (object instanceof Context) {
211: res.setResponseCode(ResponseCodes.JNDI_CONTEXT);
212: return;
213: } else if (object == null) {
214: throw new NullPointerException("lookup of '" + name
215: + "' returned null");
216: } else if (object instanceof DataSource
217: && object.getClass().getName().equals(
218: "org.apache.commons.dbcp.BasicDataSource")) {
219: try {
220: DbcpDataSource cf = new DbcpDataSource(object);
221: DataSourceMetaData dataSourceMetaData = new DataSourceMetaData(
222: cf.getDriverClassName(), cf.getUrl(), cf
223: .getUsername(), cf.getPassword());
224: res.setResponseCode(ResponseCodes.JNDI_DATA_SOURCE);
225: res.setResult(dataSourceMetaData);
226: } catch (Exception e) {
227: res.setResponseCode(ResponseCodes.JNDI_ERROR);
228: res.setResult(new ThrowableArtifact(e));
229: }
230: return;
231: } else if (object instanceof ConnectionFactory) {
232: res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
233: res.setResult(ConnectionFactory.class.getName());
234: return;
235: } else if (object instanceof ORB) {
236: res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
237: res.setResult(ORB.class.getName());
238: return;
239: }
240:
241: ServiceRefData serviceRef;
242: if (object instanceof ServiceRefData) {
243: serviceRef = (ServiceRefData) object;
244: } else {
245: serviceRef = ServiceRefData.getServiceRefData(object);
246: }
247:
248: if (serviceRef != null) {
249: WsMetaData serviceMetaData = new WsMetaData();
250:
251: // service class
252: String serviceClassName = null;
253: if (serviceRef.getServiceClass() != null) {
254: serviceClassName = serviceRef.getServiceClass()
255: .getName();
256: }
257: serviceMetaData.setServiceClassName(serviceClassName);
258:
259: // reference class
260: String referenceClassName = null;
261: if (serviceRef.getReferenceClass() != null) {
262: referenceClassName = serviceRef.getReferenceClass()
263: .getName();
264: }
265: serviceMetaData
266: .setReferenceClassName(referenceClassName);
267:
268: // set service qname
269: if (serviceRef.getServiceQName() != null) {
270: serviceMetaData.setServiceQName(serviceRef
271: .getServiceQName().toString());
272: }
273:
274: // get the port addresses for this service
275: PortAddressRegistry portAddressRegistry = SystemInstance
276: .get().getComponent(PortAddressRegistry.class);
277: Set<PortAddress> portAddresses = null;
278: if (portAddressRegistry != null) {
279: portAddresses = portAddressRegistry.getPorts(
280: serviceRef.getId(), serviceRef
281: .getServiceQName(),
282: referenceClassName);
283: }
284:
285: // resolve the wsdl url
286: if (serviceRef.getWsdlURL() != null) {
287: serviceMetaData.setWsdlUrl(serviceRef.getWsdlURL()
288: .toExternalForm());
289: }
290: if (portAddresses.size() == 1) {
291: PortAddress portAddress = portAddresses.iterator()
292: .next();
293: serviceMetaData.setWsdlUrl(portAddress.getAddress()
294: + "?wsdl");
295: }
296:
297: // add handler chains
298: for (HandlerChainData handlerChain : serviceRef
299: .getHandlerChains()) {
300: HandlerChainMetaData handlerChainMetaData = new HandlerChainMetaData();
301: handlerChainMetaData
302: .setServiceNamePattern(handlerChain
303: .getServiceNamePattern());
304: handlerChainMetaData
305: .setPortNamePattern(handlerChain
306: .getPortNamePattern());
307: handlerChainMetaData.getProtocolBindings().addAll(
308: handlerChain.getProtocolBindings());
309: for (HandlerData handler : handlerChain
310: .getHandlers()) {
311: HandlerMetaData handlerMetaData = new HandlerMetaData();
312: handlerMetaData.setHandlerClass(handler
313: .getHandlerClass().getName());
314: for (Method method : handler.getPostConstruct()) {
315: CallbackMetaData callbackMetaData = new CallbackMetaData();
316: callbackMetaData.setClassName(method
317: .getDeclaringClass().getName());
318: callbackMetaData
319: .setMethod(method.getName());
320: handlerMetaData.getPostConstruct().add(
321: callbackMetaData);
322: }
323: for (Method method : handler.getPreDestroy()) {
324: CallbackMetaData callbackMetaData = new CallbackMetaData();
325: callbackMetaData.setClassName(method
326: .getDeclaringClass().getName());
327: callbackMetaData
328: .setMethod(method.getName());
329: handlerMetaData.getPreDestroy().add(
330: callbackMetaData);
331: }
332: handlerChainMetaData.getHandlers().add(
333: handlerMetaData);
334: }
335: serviceMetaData.getHandlerChains().add(
336: handlerChainMetaData);
337: }
338:
339: // add port refs
340: Map<QName, PortRefMetaData> portsByQName = new HashMap<QName, PortRefMetaData>();
341: for (PortRefData portRef : serviceRef.getPortRefs()) {
342: PortRefMetaData portRefMetaData = new PortRefMetaData();
343: portRefMetaData.setQName(portRef.getQName());
344: portRefMetaData.setServiceEndpointInterface(portRef
345: .getServiceEndpointInterface());
346: portRefMetaData.setEnableMtom(portRef
347: .isEnableMtom());
348: portRefMetaData.getProperties().putAll(
349: portRef.getProperties());
350: portRefMetaData.getAddresses().addAll(
351: portRef.getAddresses());
352: if (portRef.getQName() != null) {
353: portsByQName.put(portRef.getQName(),
354: portRefMetaData);
355: }
356: serviceMetaData.getPortRefs().add(portRefMetaData);
357: }
358:
359: // add PortRefMetaData for any portAddress not added above
360: for (PortAddress portAddress : portAddresses) {
361: PortRefMetaData portRefMetaData = portsByQName
362: .get(portAddress.getPortQName());
363: if (portRefMetaData == null) {
364: portRefMetaData = new PortRefMetaData();
365: portRefMetaData.setQName(portAddress
366: .getPortQName());
367: portRefMetaData
368: .setServiceEndpointInterface(portAddress
369: .getServiceEndpointInterface());
370: portRefMetaData.getAddresses().add(
371: portAddress.getAddress());
372: serviceMetaData.getPortRefs().add(
373: portRefMetaData);
374: } else {
375: portRefMetaData.getAddresses().add(
376: portAddress.getAddress());
377: if (portRefMetaData
378: .getServiceEndpointInterface() == null) {
379: portRefMetaData
380: .setServiceEndpointInterface(portAddress
381: .getServiceEndpointInterface());
382: }
383: }
384: }
385:
386: res.setResponseCode(ResponseCodes.JNDI_WEBSERVICE);
387: res.setResult(serviceMetaData);
388: return;
389: }
390: } catch (NameNotFoundException e) {
391: res.setResponseCode(ResponseCodes.JNDI_NOT_FOUND);
392: return;
393: } catch (NamingException e) {
394: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
395: res.setResult(new ThrowableArtifact(e));
396: return;
397: }
398:
399: BaseEjbProxyHandler handler;
400: try {
401: handler = (BaseEjbProxyHandler) ProxyManager
402: .getInvocationHandler(object);
403: } catch (Exception e) {
404: // Not a proxy. See if it's serializable and send it
405: if (object instanceof java.io.Serializable) {
406: res.setResponseCode(ResponseCodes.JNDI_OK);
407: res.setResult(object);
408: return;
409: } else {
410: res
411: .setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
412: NamingException namingException = new NamingException(
413: "Expected an ejb proxy, found unknown object: type="
414: + object.getClass().getName()
415: + ", toString=" + object);
416: res.setResult(new ThrowableArtifact(namingException));
417: return;
418: }
419: }
420:
421: ProxyInfo proxyInfo = handler.getProxyInfo();
422: DeploymentInfo deployment = proxyInfo.getDeploymentInfo();
423: String deploymentID = deployment.getDeploymentID().toString();
424:
425: updateServer(req, res, proxyInfo);
426:
427: switch (proxyInfo.getInterfaceType()) {
428: case EJB_HOME: {
429: res.setResponseCode(ResponseCodes.JNDI_EJBHOME);
430: EJBMetaDataImpl metaData = new EJBMetaDataImpl(deployment
431: .getHomeInterface(), deployment
432: .getRemoteInterface(), deployment
433: .getPrimaryKeyClass(), deployment
434: .getComponentType().toString(), deploymentID, -1,
435: null);
436: res.setResult(metaData);
437: break;
438: }
439: case EJB_LOCAL_HOME: {
440: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
441: NamingException namingException = new NamingException(
442: "Not remotable: '"
443: + name
444: + "'. EJBLocalHome interfaces are not remotable as per the EJB specification.");
445: res.setResult(new ThrowableArtifact(namingException));
446: break;
447: }
448: case BUSINESS_REMOTE: {
449: res.setResponseCode(ResponseCodes.JNDI_BUSINESS_OBJECT);
450: EJBMetaDataImpl metaData = new EJBMetaDataImpl(null, null,
451: deployment.getPrimaryKeyClass(), deployment
452: .getComponentType().toString(),
453: deploymentID, -1, proxyInfo.getInterfaces());
454: metaData.setPrimaryKey(proxyInfo.getPrimaryKey());
455: res.setResult(metaData);
456: break;
457: }
458: case BUSINESS_LOCAL: {
459: String property = SystemInstance.get().getProperty(
460: "openejb.remotable.businessLocals", "false");
461: if (property.equalsIgnoreCase("true")) {
462: res.setResponseCode(ResponseCodes.JNDI_BUSINESS_OBJECT);
463: EJBMetaDataImpl metaData = new EJBMetaDataImpl(null,
464: null, deployment.getPrimaryKeyClass(),
465: deployment.getComponentType().toString(),
466: deploymentID, -1, proxyInfo.getInterfaces());
467: metaData.setPrimaryKey(proxyInfo.getPrimaryKey());
468: res.setResult(metaData);
469: } else {
470: res
471: .setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
472: NamingException namingException = new NamingException(
473: "Not remotable: '"
474: + name
475: + "'. Business Local interfaces are not remotable as per the EJB specification. To disable this restriction, set the system property 'openejb.remotable.businessLocals=true' in the server.");
476: res.setResult(new ThrowableArtifact(namingException));
477: }
478: break;
479: }
480: default: {
481: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
482: NamingException namingException = new NamingException(
483: "Not remotable: '" + name + "'.");
484: res.setResult(new ThrowableArtifact(namingException));
485: }
486: }
487:
488: }
489:
490: protected void updateServer(JNDIRequest req, JNDIResponse res,
491: ProxyInfo proxyInfo) {
492: clusterableRequestHandler.updateServer(proxyInfo
493: .getDeploymentInfo(), req, res);
494: }
495:
496: private void doList(JNDIRequest req, JNDIResponse res,
497: Context context) {
498: String name = req.getRequestString();
499: try {
500: NamingEnumeration<NameClassPair> namingEnumeration = context
501: .list(name);
502: if (namingEnumeration == null) {
503: res.setResponseCode(ResponseCodes.JNDI_OK);
504: res.setResult(null);
505: } else {
506: res.setResponseCode(ResponseCodes.JNDI_ENUMERATION);
507: ArrayList<NameClassPair> list = Collections
508: .list(namingEnumeration);
509: for (NameClassPair pair : list) {
510: if (pair.getClassName().equals(
511: IvmContext.class.getName())) {
512: pair.setClassName(javax.naming.Context.class
513: .getName());
514: }
515: }
516: res.setResult(new NameClassPairEnumeration(list));
517: }
518: } catch (NameNotFoundException e) {
519: res.setResponseCode(ResponseCodes.JNDI_NOT_FOUND);
520: return;
521: } catch (NamingException e) {
522: res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
523: res.setResult(new ThrowableArtifact(e));
524: return;
525: }
526: }
527:
528: public static class DbcpDataSource {
529: private final Object object;
530: private final Class clazz;
531:
532: public DbcpDataSource(Object object) {
533: clazz = object.getClass();
534: this .object = object;
535: }
536:
537: public java.lang.String getDriverClassName() throws Exception {
538: return (String) clazz.getMethod("getDriverClassName")
539: .invoke(object);
540: }
541:
542: public java.lang.String getPassword() throws Exception {
543: return (String) clazz.getMethod("getPassword").invoke(
544: object);
545: }
546:
547: public java.lang.String getUrl() throws Exception {
548: return (String) clazz.getMethod("getUrl").invoke(object);
549: }
550:
551: public java.lang.String getUsername() throws Exception {
552: return (String) clazz.getMethod("getUsername").invoke(
553: object);
554: }
555: }
556: }
|