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.rmi.RemoteException;
021: import java.util.ArrayList;
022: import java.util.Collection;
023:
024: import org.apache.openejb.DeploymentInfo;
025: import org.apache.openejb.ProxyInfo;
026: import org.apache.openejb.RpcContainer;
027: import org.apache.openejb.client.EJBHomeProxyHandle;
028: import org.apache.openejb.client.EJBObjectProxyHandle;
029: import org.apache.openejb.client.EJBRequest;
030: import org.apache.openejb.client.EJBResponse;
031: import org.apache.openejb.client.RequestMethodConstants;
032: import org.apache.openejb.client.ResponseCodes;
033: import org.apache.openejb.client.ThrowableArtifact;
034: import org.apache.openejb.loader.SystemInstance;
035: import org.apache.openejb.spi.SecurityService;
036: import org.apache.openejb.util.LogCategory;
037: import org.apache.openejb.util.Logger;
038:
039: class EjbRequestHandler {
040: public static final ServerSideResolver SERVER_SIDE_RESOLVER = new ServerSideResolver();
041:
042: private static final Logger logger = Logger.getInstance(
043: LogCategory.OPENEJB_SERVER_REMOTE.createChild("ejb"),
044: "org.apache.openejb.server.util.resources");
045: private final EjbDaemon daemon;
046:
047: private final ClusterableRequestHandler clusterableRequestHandler;
048:
049: EjbRequestHandler(EjbDaemon daemon) {
050: this .daemon = daemon;
051:
052: clusterableRequestHandler = newClusterableRequestHandler();
053: }
054:
055: protected BasicClusterableRequestHandler newClusterableRequestHandler() {
056: return new BasicClusterableRequestHandler();
057: }
058:
059: public void processRequest(ObjectInputStream in,
060: ObjectOutputStream out) {
061: // Setup the client proxy replacement to replace
062: // the proxies with the IntraVM proxy implementations
063: EJBHomeProxyHandle.resolver.set(SERVER_SIDE_RESOLVER);
064: EJBObjectProxyHandle.resolver.set(SERVER_SIDE_RESOLVER);
065:
066: EJBRequest req = new EJBRequest();
067: EJBResponse res = new EJBResponse();
068:
069: try {
070: req.readExternal(in);
071: } catch (Throwable t) {
072: replyWithFatalError(out, t,
073: "Error caught during request processing");
074: return;
075: }
076:
077: CallContext call = null;
078: DeploymentInfo di = null;
079: RpcContainer c = null;
080:
081: try {
082: di = this .daemon.getDeployment(req);
083: } catch (RemoteException e) {
084: replyWithFatalError(out, e, "No such deployment");
085: return;
086: /*
087: logger.warn( req + "No such deployment: "+e.getMessage());
088: res.setResponse( EJB_SYS_EXCEPTION, e);
089: res.writeExternal( out );
090: return;
091: */
092: } catch (Throwable t) {
093: replyWithFatalError(out, t,
094: "Unkown error occured while retrieving deployment");
095: return;
096: }
097:
098: // Need to set this for deserialization of the body
099: ClassLoader classLoader = di.getBeanClass().getClassLoader();
100: Thread.currentThread().setContextClassLoader(classLoader);
101:
102: try {
103: req.getBody().readExternal(in);
104: } catch (Throwable t) {
105: replyWithFatalError(out, t,
106: "Error caught during request processing");
107: return;
108: }
109:
110: try {
111: call = CallContext.getCallContext();
112: call.setEJBRequest(req);
113: call.setDeploymentInfo(di);
114: } catch (Throwable t) {
115: replyWithFatalError(out, t,
116: "Unable to set the thread context for this request");
117: return;
118: }
119:
120: SecurityService securityService = SystemInstance.get()
121: .getComponent(SecurityService.class);
122: try {
123: Object clientIdentity = req.getClientIdentity();
124: if (clientIdentity != null)
125: securityService.associate(clientIdentity);
126: } catch (Throwable t) {
127: replyWithFatalError(out, t,
128: "Security system failed to associate thread with the thread");
129: return;
130: }
131:
132: try {
133: switch (req.getRequestMethod()) {
134: // Remote interface methods
135: case RequestMethodConstants.EJB_OBJECT_BUSINESS_METHOD:
136: doEjbObject_BUSINESS_METHOD(req, res);
137: updateServer(req, res);
138: break;
139:
140: // Home interface methods
141: case RequestMethodConstants.EJB_HOME_CREATE:
142: doEjbHome_CREATE(req, res);
143: updateServer(req, res);
144: break;
145:
146: // Home interface methods
147: case RequestMethodConstants.EJB_HOME_METHOD:
148: doEjbHome_METHOD(req, res);
149: updateServer(req, res);
150: break;
151:
152: case RequestMethodConstants.EJB_HOME_FIND:
153: doEjbHome_FIND(req, res);
154: updateServer(req, res);
155: break;
156:
157: // javax.ejb.EJBObject methods
158: case RequestMethodConstants.EJB_OBJECT_GET_EJB_HOME:
159: doEjbObject_GET_EJB_HOME(req, res);
160: updateServer(req, res);
161: break;
162:
163: case RequestMethodConstants.EJB_OBJECT_GET_HANDLE:
164: doEjbObject_GET_HANDLE(req, res);
165: updateServer(req, res);
166: break;
167:
168: case RequestMethodConstants.EJB_OBJECT_GET_PRIMARY_KEY:
169: doEjbObject_GET_PRIMARY_KEY(req, res);
170: updateServer(req, res);
171: break;
172:
173: case RequestMethodConstants.EJB_OBJECT_IS_IDENTICAL:
174: doEjbObject_IS_IDENTICAL(req, res);
175: updateServer(req, res);
176: break;
177:
178: case RequestMethodConstants.EJB_OBJECT_REMOVE:
179: doEjbObject_REMOVE(req, res);
180: break;
181:
182: // javax.ejb.EJBHome methods
183: case RequestMethodConstants.EJB_HOME_GET_EJB_META_DATA:
184: doEjbHome_GET_EJB_META_DATA(req, res);
185: updateServer(req, res);
186: break;
187:
188: case RequestMethodConstants.EJB_HOME_GET_HOME_HANDLE:
189: doEjbHome_GET_HOME_HANDLE(req, res);
190: updateServer(req, res);
191: break;
192:
193: case RequestMethodConstants.EJB_HOME_REMOVE_BY_HANDLE:
194: doEjbHome_REMOVE_BY_HANDLE(req, res);
195: break;
196:
197: case RequestMethodConstants.EJB_HOME_REMOVE_BY_PKEY:
198: doEjbHome_REMOVE_BY_PKEY(req, res);
199: break;
200: }
201:
202: } catch (org.apache.openejb.InvalidateReferenceException e) {
203: res.setResponse(ResponseCodes.EJB_SYS_EXCEPTION,
204: new ThrowableArtifact(e.getRootCause()));
205: } catch (org.apache.openejb.ApplicationException e) {
206: res.setResponse(ResponseCodes.EJB_APP_EXCEPTION,
207: new ThrowableArtifact(e.getRootCause()));
208: } catch (org.apache.openejb.SystemException e) {
209: res.setResponse(ResponseCodes.EJB_ERROR,
210: new ThrowableArtifact(e.getRootCause()));
211:
212: logger
213: .fatal(
214: req
215: + ": OpenEJB encountered an unknown system error in container: ",
216: e);
217: } catch (java.lang.Throwable t) {
218: // todo this causes the response to be written twice but the code below
219: replyWithFatalError(out, t, "Unknown error in container");
220: return;
221: } finally {
222: if (logger.isDebugEnabled()) {
223: try {
224: logger.debug("EJB REQUEST: " + req
225: + " -- RESPONSE: " + res);
226: } catch (Exception justInCase) {
227: }
228: }
229: try {
230: res.writeExternal(out);
231: } catch (java.io.IOException ie) {
232: logger.fatal(
233: "Couldn't write EjbResponse to output stream",
234: ie);
235: }
236: securityService.disassociate();
237: call.reset();
238: EJBHomeProxyHandle.resolver.set(null);
239: EJBObjectProxyHandle.resolver.set(null);
240:
241: }
242: }
243:
244: protected void updateServer(EJBRequest req, EJBResponse res) {
245: CallContext callContext = CallContext.getCallContext();
246: DeploymentInfo deploymentInfo = callContext.getDeploymentInfo();
247: clusterableRequestHandler
248: .updateServer(deploymentInfo, req, res);
249: }
250:
251: protected void doEjbObject_BUSINESS_METHOD(EJBRequest req,
252: EJBResponse res) throws Exception {
253:
254: CallContext call = CallContext.getCallContext();
255: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
256: .getContainer();
257:
258: Object result = c.invoke(req.getDeploymentId(), req
259: .getInterfaceClass(), req.getMethodInstance(), req
260: .getMethodParameters(), req.getPrimaryKey());
261:
262: res.setResponse(ResponseCodes.EJB_OK, result);
263: }
264:
265: protected void doEjbHome_METHOD(EJBRequest req, EJBResponse res)
266: throws Exception {
267:
268: CallContext call = CallContext.getCallContext();
269: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
270: .getContainer();
271:
272: Object result = c.invoke(req.getDeploymentId(), req
273: .getInterfaceClass(), req.getMethodInstance(), req
274: .getMethodParameters(), req.getPrimaryKey());
275:
276: res.setResponse(ResponseCodes.EJB_OK, result);
277: }
278:
279: protected void doEjbHome_CREATE(EJBRequest req, EJBResponse res)
280: throws Exception {
281:
282: CallContext call = CallContext.getCallContext();
283: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
284: .getContainer();
285:
286: Object result = c.invoke(req.getDeploymentId(), req
287: .getInterfaceClass(), req.getMethodInstance(), req
288: .getMethodParameters(), req.getPrimaryKey());
289:
290: if (result instanceof ProxyInfo) {
291: ProxyInfo info = (ProxyInfo) result;
292: res.setResponse(ResponseCodes.EJB_OK, info.getPrimaryKey());
293: } else {
294:
295: result = new RemoteException(
296: "The bean is not EJB compliant. The bean should be created or and exception should be thrown.");
297: logger
298: .error(req
299: + "The bean is not EJB compliant. The bean should be created or and exception should be thrown.");
300: res.setResponse(ResponseCodes.EJB_SYS_EXCEPTION,
301: new ThrowableArtifact((Throwable) result));
302: }
303: }
304:
305: protected void doEjbHome_FIND(EJBRequest req, EJBResponse res)
306: throws Exception {
307:
308: CallContext call = CallContext.getCallContext();
309: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
310: .getContainer();
311:
312: Object result = c.invoke(req.getDeploymentId(), req
313: .getInterfaceClass(), req.getMethodInstance(), req
314: .getMethodParameters(), req.getPrimaryKey());
315:
316: /* Multiple instances found */
317: if (result instanceof Collection) {
318:
319: Object[] primaryKeys = ((Collection) result).toArray();
320:
321: for (int i = 0; i < primaryKeys.length; i++) {
322: ProxyInfo proxyInfo = ((ProxyInfo) primaryKeys[i]);
323: if (proxyInfo == null) {
324: primaryKeys[i] = null;
325: } else {
326: primaryKeys[i] = proxyInfo.getPrimaryKey();
327: }
328: }
329:
330: res.setResponse(ResponseCodes.EJB_OK_FOUND_COLLECTION,
331: primaryKeys);
332:
333: } else if (result instanceof java.util.Enumeration) {
334:
335: java.util.Enumeration resultAsEnum = (java.util.Enumeration) result;
336: java.util.List<Object> listOfPKs = new ArrayList<Object>();
337: while (resultAsEnum.hasMoreElements()) {
338: ProxyInfo proxyInfo = ((ProxyInfo) resultAsEnum
339: .nextElement());
340: if (proxyInfo == null) {
341: listOfPKs.add(null);
342: } else {
343: listOfPKs.add(proxyInfo.getPrimaryKey());
344: }
345: }
346:
347: res.setResponse(ResponseCodes.EJB_OK_FOUND_ENUMERATION,
348: listOfPKs.toArray(new Object[listOfPKs.size()]));
349: /* Single instance found */
350: } else if (result instanceof ProxyInfo) {
351: ProxyInfo proxyInfo = ((ProxyInfo) result);
352: result = proxyInfo.getPrimaryKey();
353: res.setResponse(ResponseCodes.EJB_OK_FOUND, result);
354: } else if (result == null) {
355: res.setResponse(ResponseCodes.EJB_OK_FOUND, null);
356: } else {
357:
358: final String message = "The bean is not EJB compliant. "
359: + "The finder method ["
360: + req.getMethodInstance().getName()
361: + "] is declared "
362: + "to return neither Collection nor the Remote Interface, "
363: + "but [" + result.getClass().getName() + "]";
364: result = new RemoteException(message);
365: logger.error(req + " " + message);
366: res.setResponse(ResponseCodes.EJB_SYS_EXCEPTION, result);
367: }
368: }
369:
370: protected void doEjbObject_GET_EJB_HOME(EJBRequest req,
371: EJBResponse res) throws Exception {
372: checkMethodAuthorization(req, res);
373: }
374:
375: protected void doEjbObject_GET_HANDLE(EJBRequest req,
376: EJBResponse res) throws Exception {
377: checkMethodAuthorization(req, res);
378: }
379:
380: protected void doEjbObject_GET_PRIMARY_KEY(EJBRequest req,
381: EJBResponse res) throws Exception {
382: checkMethodAuthorization(req, res);
383: }
384:
385: protected void doEjbObject_IS_IDENTICAL(EJBRequest req,
386: EJBResponse res) throws Exception {
387: checkMethodAuthorization(req, res);
388: }
389:
390: protected void doEjbObject_REMOVE(EJBRequest req, EJBResponse res)
391: throws Exception {
392:
393: CallContext call = CallContext.getCallContext();
394: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
395: .getContainer();
396:
397: Object result = c.invoke(req.getDeploymentId(), req
398: .getInterfaceClass(), req.getMethodInstance(), req
399: .getMethodParameters(), req.getPrimaryKey());
400:
401: res.setResponse(ResponseCodes.EJB_OK, null);
402: }
403:
404: protected void doEjbHome_GET_EJB_META_DATA(EJBRequest req,
405: EJBResponse res) throws Exception {
406: checkMethodAuthorization(req, res);
407: }
408:
409: protected void doEjbHome_GET_HOME_HANDLE(EJBRequest req,
410: EJBResponse res) throws Exception {
411: checkMethodAuthorization(req, res);
412: }
413:
414: protected void doEjbHome_REMOVE_BY_HANDLE(EJBRequest req,
415: EJBResponse res) throws Exception {
416:
417: CallContext call = CallContext.getCallContext();
418: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
419: .getContainer();
420:
421: Object result = c.invoke(req.getDeploymentId(), req
422: .getInterfaceClass(), req.getMethodInstance(), req
423: .getMethodParameters(), req.getPrimaryKey());
424:
425: res.setResponse(ResponseCodes.EJB_OK, null);
426: }
427:
428: protected void doEjbHome_REMOVE_BY_PKEY(EJBRequest req,
429: EJBResponse res) throws Exception {
430:
431: CallContext call = CallContext.getCallContext();
432: RpcContainer c = (RpcContainer) call.getDeploymentInfo()
433: .getContainer();
434:
435: Object result = c.invoke(req.getDeploymentId(), req
436: .getInterfaceClass(), req.getMethodInstance(), req
437: .getMethodParameters(), req.getPrimaryKey());
438:
439: res.setResponse(ResponseCodes.EJB_OK, null);
440: }
441:
442: protected void checkMethodAuthorization(EJBRequest req,
443: EJBResponse res) throws Exception {
444: res.setResponse(ResponseCodes.EJB_OK, null);
445: // SecurityService sec = SystemInstance.get().getComponent(SecurityService.class);
446: // CallContext caller = CallContext.getCallContext();
447: // DeploymentInfo di = caller.getDeploymentInfo();
448: //
449: // if (sec.isCallerAuthorized(req.getMethodInstance(), null)) {
450: // res.setResponse(ResponseCodes.EJB_OK, null);
451: // } else {
452: // logger.info(req + "Unauthorized Access by Principal Denied");
453: // res.setResponse(ResponseCodes.EJB_APP_EXCEPTION, new ThrowableArtifact(new EJBAccessException("Unauthorized Access by Principal Denied")));
454: // }
455: }
456:
457: private void replyWithFatalError(ObjectOutputStream out,
458: Throwable error, String message) {
459: logger.fatal(message, error);
460: RemoteException re = new RemoteException(
461: "The server has encountered a fatal error: " + message
462: + " " + error, error);
463: EJBResponse res = new EJBResponse();
464: res.setResponse(ResponseCodes.EJB_ERROR, new ThrowableArtifact(
465: re));
466: try {
467: res.writeExternal(out);
468: } catch (java.io.IOException ie) {
469: logger.error("Failed to write to EJBResponse", ie);
470: }
471: }
472: }
|