001: /**
002: * Speedo: an implementation of JDO compliant personality on top of JORM generic
003: * I/O sub-system.
004: * Copyright (C) 2001-2004 France Telecom R&D
005: *
006: * This library 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 library 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: * Release: 1.0
021: *
022: * Created on 2004-02-18
023: * @author fmillevi@yahoo.com
024: *
025: */package org.objectweb.speedo.j2eedo.web;
026:
027: import java.io.IOException;
028: import java.rmi.RemoteException;
029:
030: import javax.ejb.CreateException;
031: import javax.jdo.JDOException;
032: import javax.jdo.PersistenceManager;
033: import javax.jdo.PersistenceManagerFactory;
034: import javax.jdo.Transaction;
035: import javax.naming.InitialContext;
036: import javax.naming.NameNotFoundException;
037: import javax.naming.NamingException;
038: import javax.servlet.ServletException;
039: import javax.servlet.ServletOutputStream;
040: import javax.servlet.http.HttpServlet;
041: import javax.servlet.http.HttpServletRequest;
042: import javax.servlet.http.HttpServletResponse;
043: import javax.transaction.NotSupportedException;
044: import javax.transaction.Status;
045: import javax.transaction.SystemException;
046: import javax.transaction.UserTransaction;
047:
048: import org.objectweb.speedo.j2eedo.common.PMHolder;
049: import org.objectweb.speedo.j2eedo.bo.DatabaseImpl;
050: import org.objectweb.speedo.j2eedo.ejb.StoreServicesLocal;
051: import org.objectweb.speedo.j2eedo.ejb.StoreServicesLocalHome;
052: import org.objectweb.speedo.j2eedo.ejb.StoreServicesRemote;
053: import org.objectweb.speedo.j2eedo.ejb.StoreServicesRemoteHome;
054: import org.objectweb.util.monolog.Monolog;
055: import org.objectweb.util.monolog.api.BasicLevel;
056: import org.objectweb.util.monolog.api.Logger;
057:
058: /**
059: * is an extended of the former servlet MainServlet. This class implements the
060: * two methods used to execute the resquest through a Session Bean or directly
061: * from the {@link org.objectweb.speedo.j2eedo.bo.DatabaseImpl DataBaseImpl} class.</li>
062: * </ul>
063: *
064: * @author fmillevi@yahoo.com
065: *
066: */
067: public class ApplicationServlet extends HttpServlet {
068:
069: /**
070: * The constant <code>PARAMETER_ACTION</code> defines the HTTP
071: * requests paramater <b>"action"</b> use to know
072: * {@link org.objectweb.speedo.j2eedo.bo.DatabaseImpl#actionArray which action} to do.
073: */
074: final public static String PARAMETER_ACTION = "action";
075:
076: // define the class name parameter
077: /**
078: * The constant <code>WITHOUT_TRANSACTION_PARAMETER</code> is used
079: * to retrive the HTTP request parameter <b>"withoutTrans"</b> used by the servlet
080: * to know if a transaction must be start at the servlet level.
081: */
082: public final static String WITH_TRANSACTION_PARAMETER = "withTrans";
083: /**
084: * The constant <code>TYPE_CONTAINER_PARAMETER</code> is used
085: * to retrive the HTTP request parameter <b>"container"</b> used by the servlet
086: * to know if the action must be done through a Session Bean Container.
087: */
088: public final static String TYPE_CONTAINER_PARAMETER = "container";
089:
090: public final static String LOCAL_SESSION_BEAN_PARAMETER = "localsession";
091:
092: /**
093: * The constant <code>WITH_GETPM_PARAMETER</code> is used
094: * to retrive the HTTP request parameter <b>"withGetPM"</b> used by the servlet
095: * to know if the persistence manager must be get by the servelt.
096: */
097: public final static String JDOTX = "jdotx";
098:
099: private final static String PMF_JNDI_NAME = "speedo";
100:
101: protected static Logger logger = null;
102:
103: protected PersistenceManagerFactory persistenceManagerFactory = null;
104:
105: protected StoreServicesLocalHome lstoreServicesLH;
106: protected StoreServicesRemoteHome lstoreServicesRH;
107:
108: /**
109: * This servlet executes current request:<ul>
110: * <li>Gets the Persistence manager when required (false by default),</li>
111: * <li>Starts a local transaction when requested (false by default),</li>
112: * <li>Calls the dedicated action directly or through a Session Bean Container
113: * (direct call by default),</li>
114: * <li>Close the PM when initialized at the servlet level.</li>
115: * </ul>
116: * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest,
117: * javax.servlet.http.HttpServletResponse)
118: */
119: public void service(HttpServletRequest req, HttpServletResponse resp)
120: throws ServletException, IOException {
121: boolean withTransaction = getParameterValue(req,
122: WITH_TRANSACTION_PARAMETER, false);
123: boolean isJdoTx = getParameterValue(req, JDOTX, true);
124: boolean useSessionBean = getParameterValue(req,
125: TYPE_CONTAINER_PARAMETER, false);
126: boolean localSessionBean = getParameterValue(req,
127: LOCAL_SESSION_BEAN_PARAMETER, false);
128: String action = req
129: .getParameter(ApplicationServlet.PARAMETER_ACTION);
130: if (logger.isLoggable(BasicLevel.DEBUG)) {
131: logger.log(BasicLevel.DEBUG, "Invoke Servlet: "
132: + "\n\t-withTransaction=" + withTransaction
133: + " \n\t-isJdoTx=" + isJdoTx
134: + "\n\t-useSessionBean=" + useSessionBean
135: + "\n\t-localSessionBean=" + localSessionBean
136: + "\n\t-action=" + action);
137: }
138: UserTransaction jtatx = null;
139: PMHolder pmh = new PMHolder(persistenceManagerFactory);
140: Transaction jdotx = null;
141: if (withTransaction) {
142: if (isJdoTx && (!useSessionBean || localSessionBean)) {
143: logger.log(BasicLevel.DEBUG,
144: "fetch JDO PersistenceManager");
145: jdotx = pmh.getPersistenceManager()
146: .currentTransaction();
147: logger.log(BasicLevel.DEBUG,
148: "Begin JDO Transaction (local)");
149: jdotx.begin();
150: } else {
151: try {
152: jtatx = (UserTransaction) getObjectFromContext(
153: null, "java:comp/UserTransaction");
154: } catch (Exception e) {
155: logger
156: .log(
157: BasicLevel.ERROR,
158: "Cannot lookup java:comp/UserTransaction: ",
159: e);
160: throw new ServletException(e);
161: }
162: logger.log(BasicLevel.DEBUG, "Begin JTA Transaction");
163: try {
164: jtatx.begin();
165: } catch (Exception e) {
166: logger.log(BasicLevel.ERROR,
167: "Cannot begin JTA transaction", e);
168: throw new ServletException(e);
169: }
170: }
171: }
172: try {
173: if (useSessionBean) {
174: //The action will be done by the Session bean
175: if (localSessionBean) {
176: //Invoke the session bean through the local interface
177: logger.log(BasicLevel.DEBUG,
178: "Use local session bean");
179: StoreServicesLocal lstoreServices = null;
180: try {
181: lstoreServices = lstoreServicesLH.create();
182: } catch (CreateException e) {
183: logger
184: .log(
185: BasicLevel.ERROR,
186: "Error during the creation of Local Session",
187: e);
188: throw new ServletException(e);
189: }
190: try {
191: ServletOutputStream out = resp
192: .getOutputStream();
193: out.println(lstoreServices
194: .doAction(pmh, action));
195: } finally {
196: //release the session bean from the pool
197: lstoreServices.remove();
198: }
199: } else {
200: //Invoke the session bean through the Remote interface
201: logger.log(BasicLevel.DEBUG,
202: "Use remote session bean");
203: StoreServicesRemote lstoreServices = null;
204: try {
205: lstoreServices = lstoreServicesRH.create();
206: } catch (CreateException e) {
207: logger
208: .log(
209: BasicLevel.ERROR,
210: "Error during the creation of Local Session",
211: e);
212: throw new ServletException(e);
213: }
214: try {
215: ServletOutputStream out = resp
216: .getOutputStream();
217: out.println(lstoreServices.doAction(action));
218: } finally {
219: //release the session bean from the pool
220: lstoreServices.remove();
221: }
222: }
223: } else {
224: logger.log(BasicLevel.DEBUG, "Use direct call");
225: ServletOutputStream out = resp.getOutputStream();
226: String outStr = DatabaseImpl.instance.doAction(action,
227: false, pmh);
228: out.println(outStr);
229: }
230: if (jtatx != null) {
231: logger.log(BasicLevel.DEBUG,
232: "Commit the JTA Transaction");
233: jtatx.commit();
234: } else if (jdotx != null && jdotx.isActive()) {
235: logger.log(BasicLevel.DEBUG,
236: "Commit the local JDOTransactionItf");
237: jdotx.commit();
238: }
239: } catch (Exception e) {
240: if (jtatx != null) {
241: logger
242: .log(
243: BasicLevel.WARN,
244: "Rolling back the JTA Transaction due to an error: ",
245: e);
246: try {
247: jtatx.rollback();
248: } catch (Exception jtae) {
249: logger.log(BasicLevel.ERROR,
250: "Cannot rollback JTA transaction", jtae);
251: }
252: } else if (jdotx != null && jdotx.isActive()) {
253: logger
254: .log(
255: BasicLevel.WARN,
256: "Rolling back the JDO Transaction due to an error: ",
257: e);
258: jdotx.rollback();
259: } else {
260: logger
261: .log(BasicLevel.WARN, "An error has occured: ",
262: e);
263: }
264: throw new ServletException(e);
265: } finally {
266: if (jdotx != null) {
267: pmh.closePersistenceManager();
268: }
269: }
270: }
271:
272: public void init() throws ServletException {
273: super .init();
274:
275: // get the logger
276: logger = Monolog.initialize().getLogger(getClass().getName());
277:
278: //get the PersistenceManagerFactory
279: persistenceManagerFactory = (PersistenceManagerFactory) getObjectFromContext(
280: null, PMF_JNDI_NAME);
281:
282: try {
283: getStoreServicesRemoteHome();
284: } catch (ServletException e) {
285: logger.log(BasicLevel.WARN,
286: "No StoreServicesRemoteHome found: "
287: + e.getMessage());
288: }
289:
290: try {
291: getStoreServicesLocalHome();
292: } catch (ServletException e) {
293: logger.log(BasicLevel.WARN,
294: "No StoreServicesLocalHome found: "
295: + e.getMessage());
296: }
297: }
298:
299: /**
300: * get the StoreServicesLocalHome.
301: */
302: private StoreServicesLocalHome getStoreServicesLocalHome()
303: throws ServletException {
304: if (lstoreServicesLH == null) {
305: lstoreServicesLH = (StoreServicesLocalHome) getObjectFromContext(
306: null, "java:comp/env/ejb/StoreServicesHomeLocal");
307: }
308: return lstoreServicesLH;
309: }
310:
311: /**
312: * get the StoreServicesRemoteHome.
313: */
314: private StoreServicesRemoteHome getStoreServicesRemoteHome()
315: throws ServletException {
316: if (lstoreServicesRH == null) {
317: lstoreServicesRH = (StoreServicesRemoteHome) getObjectFromContext(
318: null, "ejb/storeService");
319: }
320: return lstoreServicesRH;
321: }
322:
323: /**
324: * Get an object from JNDI
325: * @param ictx is the InitialContext to use. If this parameter is null
326: * a new context is created and closed
327: * @param name is the JNDI name of the searched object
328: * @return the object (never null)
329: * @throws ServletException if the object cannot be found.
330: */
331: private static Object getObjectFromContext(InitialContext ictx,
332: String name) throws ServletException {
333: boolean hasToCloseContext = false;
334: if (ictx == null) {
335: try {
336: ictx = new InitialContext();
337: hasToCloseContext = true;
338: } catch (NamingException e) {
339: logger.log(BasicLevel.ERROR,
340: "Impossible to get the InitialContext: ", e);
341: throw new ServletException(
342: "Impossible to get the InitialContext: "
343: + e.getMessage());
344: }
345: }
346: try {
347: Object o = ictx.lookup(name);
348: if (o == null) {
349: throw new ServletException("'" + name
350: + "' has not been found from JNDI");
351: }
352: return o;
353: } catch (ServletException e) {
354: throw e;
355: } catch (NameNotFoundException e) {
356: logger.log(BasicLevel.WARN, "Impossible to find " + name
357: + ": " + e.getMessage());
358: return null;
359: } catch (Exception e) {
360: logger.log(BasicLevel.ERROR, "Impossible to find " + name
361: + ": ", e);
362: return null;
363: } finally {
364: if (hasToCloseContext && ictx != null) {
365: try {
366: ictx.close();
367: } catch (NamingException ne) {
368: }
369: }
370: }
371: }
372:
373: /**
374: * Get the value of a prameter from a HttpServletRequest instance
375: * @param req is the HttpServletRequest
376: * @param paramName is the name of the parameter
377: * @param defaultValue is the default value to return if the parameter
378: * is not defined in the HttpServletRequest
379: */
380: private static boolean getParameterValue(HttpServletRequest req,
381: String paramName, boolean defaultValue) {
382: try {
383: String val = req.getParameter(paramName);
384: return val == null ? defaultValue : Boolean.valueOf(val)
385: .booleanValue();
386: } catch (Exception e) {
387: return defaultValue;
388: }
389: }
390: }
|