001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * ---------------------------------------------------------
005: * ivata groupware may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * ---------------------------------------------------------
030: * $Log: PicoRequestProcessorImplementation.java,v $
031: * Revision 1.7 2005/10/14 14:25:15 colinmacleod
032: * Added createMaskForm to create and populate input mask and list forms
033: * for ivata masks.
034: *
035: * Revision 1.6 2005/10/11 18:57:05 colinmacleod
036: * Fixed some checkstyle and javadoc issues.
037: *
038: * Revision 1.5 2005/10/03 10:21:14 colinmacleod
039: * Fixed some style and javadoc issues.
040: *
041: * Revision 1.4 2005/10/02 10:29:05 colinmacleod
042: * Added logging.
043: * Added client session initialization.
044: *
045: * Revision 1.3 2005/09/29 14:17:03 colinmacleod
046: * Split UserGroupDO off from GroupDO.
047: * Moved UserGroupDO, Right classes to security subproject (from
048: * addressbook).
049: * Centralized user right handling into Rights and RightsImpl.
050: *
051: * Revision 1.2 2005/09/14 15:42:10 colinmacleod
052: * Removed unused local and class variables.
053: *
054: * Revision 1.1 2005/04/11 10:18:56 colinmacleod
055: * Added tiles support to request processor.
056: * Updated for new PicoContianerFactory singleton.
057: *
058: * ---------------------------------------------------------
059: */
060: package com.ivata.groupware.container.struts;
061:
062: import java.io.IOException;
063: import java.util.Map;
064: import java.util.Vector;
065:
066: import javax.servlet.ServletContext;
067: import javax.servlet.http.HttpServletRequest;
068: import javax.servlet.http.HttpServletResponse;
069: import javax.servlet.http.HttpSession;
070:
071: import org.apache.log4j.Logger;
072: import org.apache.struts.action.Action;
073: import org.apache.struts.action.ActionForm;
074: import org.apache.struts.action.ActionMapping;
075: import org.apache.struts.action.ActionServlet;
076: import org.apache.struts.config.FormBeanConfig;
077: import org.picocontainer.MutablePicoContainer;
078: import org.picocontainer.Parameter;
079: import org.picocontainer.PicoContainer;
080: import org.picocontainer.defaults.ConstantParameter;
081: import org.picocontainer.defaults.DefaultPicoContainer;
082: import org.sourceforge.clientsession.SessionManager;
083:
084: import com.ivata.groupware.admin.security.Security;
085: import com.ivata.groupware.admin.security.server.SecuritySession;
086: import com.ivata.groupware.container.PicoContainerFactory;
087: import com.ivata.mask.Mask;
088: import com.ivata.mask.MaskFactory;
089: import com.ivata.mask.field.FieldValueConvertorFactory;
090: import com.ivata.mask.persistence.PersistenceManager;
091: import com.ivata.mask.persistence.PersistenceSession;
092: import com.ivata.mask.util.StringHandling;
093: import com.ivata.mask.util.SystemException;
094: import com.ivata.mask.valueobject.ValueObject;
095: import com.ivata.mask.web.browser.Browser;
096: import com.ivata.mask.web.field.DefaultFieldWriterFactory;
097: import com.ivata.mask.web.field.FieldWriterFactory;
098: import com.ivata.mask.web.struts.InputMaskForm;
099: import com.ivata.mask.web.struts.ListForm;
100: import com.ivata.mask.web.struts.MaskForm;
101: import com.ivata.mask.web.struts.MaskRequestProcessorImplementation;
102:
103: /**
104: * <p>
105: * Overridden to extend the <code>createAction</code> and
106: * <code>createActionForm</code> methods. In this implementation, we use
107: * <code>PicoContainer</code> to actually perform the instantiation.
108: * </p>
109: *
110: * @since ivata groupware 0.10 (11-Mar-2005)
111: * @author Colin MacLeod
112: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
113: * @version $Revision: 1.7 $
114: */
115:
116: public class PicoRequestProcessorImplementation extends
117: MaskRequestProcessorImplementation {
118: /**
119: * Logger for this class.
120: */
121: private static final Logger logger = Logger
122: .getLogger(PicoRequestProcessorImplementation.class);
123: /**
124: * <p>
125: * Specifies the path to the mask config file, relative to the webapp root.
126: * </p>
127: */
128: public static final String MASKS_FILE_NAME = "/WEB-INF/ivataMasks.xml";
129:
130: /**
131: * <p>
132: * Get a valid persistence manager for the super class constructor.
133: * </p>
134: *
135: * @return valid Hibernate persistence manager from the default pico
136: * container.
137: * @throws SystemException If an instance of the pico container factory
138: * cannot be obtained.
139: */
140: static PersistenceManager getPersistenceManager()
141: throws SystemException {
142: if (logger.isDebugEnabled()) {
143: logger.debug("getPersistenceManager() - start");
144: }
145:
146: PicoContainer container = PicoContainerFactory.getInstance()
147: .getGlobalContainer();
148: PersistenceManager persistenceManager = (PersistenceManager) container
149: .getComponentInstance(PersistenceManager.class);
150: assert (persistenceManager != null);
151:
152: if (logger.isDebugEnabled()) {
153: logger
154: .debug("getPersistenceManager() - end - return value = "
155: + persistenceManager);
156: }
157: return persistenceManager;
158: }
159:
160: /**
161: * <p>
162: * Get a request processor implementation.
163: * </p>
164: *
165: * @return valid hibernate persistence manager from the default pico
166: * container.
167: */
168: static MaskRequestProcessorImplementation getRequestProcessorImplementation() {
169: if (logger.isDebugEnabled()) {
170: logger.debug("getRequestProcessorImplementation() - start");
171: }
172:
173: try {
174: MaskRequestProcessorImplementation implementation = (MaskRequestProcessorImplementation) PicoContainerFactory
175: .getInstance().instantiateOrOverride(
176: PicoRequestProcessorImplementation.class);
177: assert (implementation != null);
178:
179: if (logger.isDebugEnabled()) {
180: logger.debug("getRequestProcessorImplementation() "
181: + "- end - return value = " + implementation);
182: }
183: return implementation;
184: } catch (Exception e) {
185: logger.error("Cannot intantiate pico request processor "
186: + "implementation", e);
187: throw new RuntimeException(e);
188: }
189: }
190:
191: /**
192: * <copyDoc>Refer to {@link #PicoRequestProcessorImplementation}.</copyDoc>
193: */
194: private PersistenceManager persistenceManager;
195: /**
196: * <copyDoc>Refer to {@link
197: * PicoRequestProcessorImplementation#PicoRequestProcessorImplementation}.
198: * </copyDoc>
199: */
200: private Security security;
201:
202: /**
203: * <p>
204: * Initializes the mask factory, the value object locator and the the
205: * standard field value convertors.
206: * </p>
207: *
208: * @param securityParam Used to obtain a guest security session if the user
209: * is not logged in, or her session has timed out.
210: * @param maskFactoryParam {@inheritDoc}
211: * @param persistenceManagerParam {@inheritDoc}
212: * @param fieldValueConvertorFactory {@inheritDoc}
213: * @param sessionManager {@inheritDoc}
214: */
215: public PicoRequestProcessorImplementation(
216: final Security securityParam,
217: final MaskFactory maskFactoryParam,
218: final PersistenceManager persistenceManagerParam,
219: final FieldValueConvertorFactory fieldValueConvertorFactory,
220: final SessionManager sessionManager) {
221: super (maskFactoryParam, persistenceManagerParam,
222: fieldValueConvertorFactory, sessionManager);
223: this .security = securityParam;
224: this .persistenceManager = persistenceManagerParam;
225: }
226:
227: /**
228: * <p>
229: * Create an action. This method re-implemented to create an action in a
230: * <strong>PicoContainer</strong> friendly way.
231: * </p>
232: * @param request {@inheritDoc}
233: * @param response {@inheritDoc}
234: * @param mapping {@inheritDoc}
235: * @param servlet {@inheritDoc}. Used to write application
236: * scope attributes (in its servlet context).
237: * @param classNameParam {@inheritDoc}
238: * @param actionsParam {@inheritDoc}
239: * @return newly created action, or <code>null</code> if we can't create
240: * one.
241: * @throws IOException if the action cannot be created.
242: * @throws SystemException if we cannot obtain an instance of the pico
243: * container factory.
244: */
245: protected Action createAction(final String classNameParam,
246: final HttpServletRequest request,
247: final HttpServletResponse response,
248: final ActionMapping mapping, final ActionServlet servlet,
249: final Map actionsParam) throws IOException, SystemException {
250: if (logger.isDebugEnabled()) {
251: logger.debug("createAction(String classNameParam = "
252: + classNameParam
253: + ", HttpServletRequest request = " + request
254: + ", HttpServletResponse response = " + response
255: + ", ActionMapping mapping = " + mapping
256: + ", Map actions = " + actionsParam
257: + ", ActionServlet servlet = " + servlet
258: + ") - start");
259: }
260:
261: String className = classNameParam;
262: // Acquire the Action instance we will be using (if there is one)
263: Action instance = null;
264:
265: // Return any existing Action instance of this class
266: instance = (Action) actionsParam.get(className);
267:
268: if (instance != null) {
269: Action returnAction = (instance);
270: if (logger.isDebugEnabled()) {
271: logger.debug("createAction - end - return value = "
272: + returnAction);
273: }
274: return returnAction;
275: }
276:
277: // initialize the mask factory, if necessary
278: MaskFactory maskFactory = PicoContainerFactory.getInstance()
279: .getMaskFactory();
280: synchronized (maskFactory) {
281: // if the mask factory is not configured, create the field writer
282: // and initialize the mask factory...
283: if (!maskFactory.isConfigured()) {
284: ServletContext context = servlet.getServletContext();
285: FieldWriterFactory fieldWriterFactory = new DefaultFieldWriterFactory(
286: persistenceManager, "/mask/find.action");
287: context.setAttribute(
288: FieldWriterFactory.APPLICATION_ATTRIBUTE,
289: fieldWriterFactory);
290: maskFactory.readConfiguration(context
291: .getResourceAsStream(MASKS_FILE_NAME));
292: }
293: }
294:
295: HttpSession session = request.getSession();
296: SecuritySession securitySession = (SecuritySession) session
297: .getAttribute("securitySession");
298: PicoContainer container;
299: // if there is a session available, use the container from that
300: if (securitySession != null) {
301: container = securitySession.getContainer();
302: } else {
303: // we timed out? login as guest
304: securitySession = security.loginGuest();
305: session.setAttribute("securitySession", securitySession);
306: container = securitySession.getContainer();
307: // for now, create a browser with no javascript support
308: Browser browser = new Browser(request
309: .getHeader("User-Agent"), null);
310: session.setAttribute("browser", browser);
311: }
312: instance = (Action) PicoContainerFactory.getInstance()
313: .instantiateOrOverride(container, className);
314: if (instance == null) {
315: throw new SystemException(
316: "Could not instantiate this class");
317: }
318: actionsParam.put(className, instance);
319:
320: if (logger.isDebugEnabled()) {
321: logger.debug("createAction - end - return value = "
322: + instance);
323: }
324: return instance;
325: }
326:
327: /**
328: * <p>
329: * Get the appropriate action form for the parameters.
330: * </p>
331: *
332: * @param config Represents the configuration of the form bean, from the
333: * <em>Struts</em> configuration.
334: * @param request The servlet request being processed.
335: * @param response response we are sending.
336: * @param mapping the action mapping for the current request.
337: * @return ActionForm valid action form instance, or <code>null</code> if
338: * none is appropriate.
339: * @throws SystemException If the <code>PicoContainer</code> cannot
340: * instantiate the value object for any reason.
341: */
342: protected ActionForm createActionForm(final FormBeanConfig config,
343: final HttpServletRequest request,
344: final HttpServletResponse response,
345: final ActionMapping mapping) throws SystemException {
346: if (logger.isDebugEnabled()) {
347: logger.debug("createActionForm(FormBeanConfig config = "
348: + config + ", HttpServletRequest request = "
349: + request + ", HttpServletResponse response = "
350: + response + ", ActionMapping mapping = " + mapping
351: + ") - start");
352: }
353:
354: ActionForm instance = null;
355: HttpSession session = request.getSession();
356: String attribute = mapping.getAttribute();
357: if (attribute == null) {
358: if (logger.isDebugEnabled()) {
359: logger.debug("createActionForm - end - return value = "
360: + null);
361: }
362: return null;
363: }
364: if (config == null) {
365: if (logger.isDebugEnabled()) {
366: logger.debug("createActionForm - end - return value = "
367: + null);
368: }
369: return null;
370: }
371:
372: // if it gets down here, we need to create a new instance
373: SecuritySession securitySession = (SecuritySession) session
374: .getAttribute("securitySession");
375: if (securitySession == null) {
376: if (logger.isDebugEnabled()) {
377: logger
378: .debug("createActionForm - no security session found "
379: + "- end - return value = " + null);
380: }
381: return null;
382: }
383: PicoContainer container = securitySession.getContainer();
384: Class type;
385: try {
386: type = Class.forName(config.getType());
387: } catch (ClassNotFoundException e1) {
388: logger.error(
389: "createActionForm() - error creating a form class for"
390: + " type '" + config.getType() + "'.", e1);
391: throw new SystemException(e1);
392: }
393: // input & list masks require extra parameters in the constructor
394: String baseClassName = request.getParameter("baseClass.name");
395: if (baseClassName == null) {
396: baseClassName = request.getParameter("baseClass");
397: }
398: if ((baseClassName != null)
399: && (InputMaskForm.class.isAssignableFrom(type) || ListForm.class
400: .isAssignableFrom(type))) {
401: ActionForm returnActionForm2 = createMaskForm(request,
402: container, baseClassName, type);
403: if (logger.isDebugEnabled()) {
404: logger
405: .debug("createActionForm() - end - return value = "
406: + returnActionForm2);
407: }
408: return returnActionForm2;
409: } else {
410: // this is for non-ivata-masks forms. they are constructed via
411: // pico directly
412: try {
413: instance = (ActionForm) PicoContainerFactory
414: .getInstance().instantiateOrOverride(container,
415: config.getType());
416: } catch (SystemException e) {
417: logger
418: .error(
419: "createActionForm - exception creating action form.",
420: e);
421:
422: if (logger.isDebugEnabled()) {
423: logger
424: .debug("createActionForm - end - return value = "
425: + null);
426: }
427: return null;
428: }
429: }
430: ActionForm returnActionForm = instance;
431: if (logger.isDebugEnabled()) {
432: logger.debug("createActionForm - end - return value = "
433: + returnActionForm);
434: }
435: return returnActionForm;
436: }
437:
438: /**
439: * <p>
440: * Create a form of type <code>InputMaskForm</code>, or one of its
441: * subclasses, or a form of type <code>ListForm</code>, or one of its
442: * subclasses.
443: * </p>
444: * <p>
445: * This method uses <code>PicoContainer</code> to instantiate
446: * the class. The class must have a constructor with 3 parameters:
447: * <ul>
448: * <li>
449: * for <strong>input mask forms</strong> - the <code>valueObject</code>
450: * for the mask<br/>
451: * for <strong>list forms</strong> - a <code>List</code> of value
452: * objects to show - will be created as an empty <code>Vector</code>
453: * </li>
454: * <li>a <code>Mask</code> instance</li>
455: * <li><code>Class</code> instance for the base class to show</li>
456: * </ul>
457: * </p>
458: *
459: * @param request Current servlet request we are processing.
460: * @param container PicoContainer to use to instantiate the form.
461: * @param baseClassName The full module and class name of the value object
462: * class this mask will show.
463: * @param maskType Class of the form. Must be either
464: * <ul>
465: * <li><code>InputMaskForm</code>, or a subclass.</li>
466: * or
467: * <li><code>ListForm</code>, or a subclass.</li>
468: * </ul>
469: * @return Freshly minted input mask or list form.
470: * @throws SystemException If the form cannot be created for any reason.
471: */
472: protected MaskForm createMaskForm(final HttpServletRequest request,
473: final PicoContainer container, final String baseClassName,
474: final Class maskType) throws SystemException {
475: if (logger.isDebugEnabled()) {
476: logger.debug("createMaskForm(HttpServletRequest request = "
477: + request + ", PicoContainer container = "
478: + container + ", Class inputMaskType = " + maskType
479: + ") - start");
480: }
481:
482: SecuritySession securitySession = (SecuritySession) request
483: .getSession().getAttribute("securitySession");
484: assert (securitySession != null);
485:
486: // use the value object class/idstring, mask and base class to make an
487: // input mask, if we have them - note you need either the id or the
488: // class of the value object - you don't need both
489: String valueObjectClassName = request
490: .getParameter("valueObject.class.name");
491: String valueObjectIdString = request
492: .getParameter("valueObject.idString");
493: assert (!StringHandling.isNullOrEmpty(baseClassName));
494: if (valueObjectClassName == null) {
495: valueObjectClassName = baseClassName;
496: }
497: String maskName = request.getParameter("mask.name");
498:
499: Class valueObjectClass;
500: try {
501: valueObjectClass = Class.forName(valueObjectClassName);
502: } catch (ClassNotFoundException e) {
503: logger.error("createMaskForm - error instantiating '"
504: + valueObjectClassName + "'", e);
505: throw new SystemException(e);
506: }
507: Class baseClass;
508: try {
509: baseClass = Class.forName(baseClassName);
510: } catch (ClassNotFoundException e) {
511: logger.error("createMaskForm - error instantiating '"
512: + baseClassName + "'", e);
513: throw new SystemException(e);
514: }
515: MaskFactory maskFactory = PicoContainerFactory.getInstance()
516: .getMaskFactory();
517: Mask mask = null;
518: Parameter firstParameter;
519:
520: // here's where list forms and input mask forms differ - the first
521: // parameter
522: if (InputMaskForm.class.isAssignableFrom(maskType)) {
523: assert (!(StringHandling
524: .isNullOrEmpty(valueObjectClassName) && StringHandling
525: .isNullOrEmpty(valueObjectIdString)));
526: ValueObject valueObject;
527: if (maskName == null) {
528: maskName = maskFactory.getDefaultInputMask();
529: }
530: // if there is no id, make a new value object
531: if (StringHandling.isNullOrEmpty(valueObjectIdString)) {
532: valueObject = (ValueObject) PicoContainerFactory
533: .getInstance().instantiateOrOverride(container,
534: valueObjectClassName);
535:
536: // otherwise use persistence manager to find an existing instance
537: } else {
538: PersistenceSession persistenceSession = persistenceManager
539: .openSession(securitySession);
540: try {
541: valueObject = persistenceManager.findByPrimaryKey(
542: persistenceSession, valueObjectClass,
543: valueObjectIdString);
544: } finally {
545: persistenceSession.close();
546: }
547: }
548: firstParameter = new ConstantParameter(valueObject);
549: } else {
550: // list forms are easier - we just need an empty list.
551: assert (ListForm.class.isAssignableFrom(maskType));
552: firstParameter = new ConstantParameter(new Vector());
553: if (maskName == null) {
554: maskName = maskFactory.getDefaultListMask();
555: }
556: }
557: // now get the mask - the name may have been defaulted based on the type
558: // above
559: mask = maskFactory.getMask(valueObjectClass, maskName);
560:
561: // we expect mask forms to take 3 arguments - the first is different
562: // for list/input mask forms
563: Parameter[] constructorParameters = new Parameter[] {
564: firstParameter, new ConstantParameter(mask),
565: new ConstantParameter(baseClass) };
566: MutablePicoContainer tempContainer = new DefaultPicoContainer(
567: container);
568: tempContainer.registerComponentImplementation(maskType,
569: maskType, constructorParameters);
570: MaskForm returnMaskForm = (MaskForm) tempContainer
571: .getComponentInstance(maskType);
572: if (logger.isDebugEnabled()) {
573: logger.debug("createMaskForm() - end - return value = "
574: + returnMaskForm);
575: }
576: return returnMaskForm;
577:
578: }
579: }
|