001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixcore.workflow.app;
021:
022: import de.schlund.pfixcore.util.TokenManager;
023: import de.schlund.pfixcore.workflow.Context;
024: import de.schlund.pfixcore.workflow.StateImpl;
025: import de.schlund.pfixxml.PfixServletRequest;
026: import de.schlund.pfixxml.PropertyObjectManager;
027: import de.schlund.pfixxml.RequestParam;
028: import de.schlund.pfixxml.ResultDocument;
029: import de.schlund.pfixxml.XMLException;
030: import de.schlund.pfixxml.config.PageRequestConfig;
031: import de.schlund.pfixxml.perflogging.PerfEvent;
032: import de.schlund.pfixxml.perflogging.PerfEventType;
033: import de.schlund.util.statuscodes.StatusCodeLib;
034:
035: /**
036: * DefaultIWrapperState.java
037: *
038: *
039: * Created: Wed Oct 10 10:31:49 2001
040: *
041: * @author <a href="mailto:jtl@schlund.de">Jens Lautenbacher</a>
042: */
043:
044: public class DefaultIWrapperState extends StateImpl {
045:
046: public final static String DEF_WRP_CONTAINER = "de.schlund.pfixcore.workflow.app.IWrapperSimpleContainer";
047: private final static String DEF_FINALIZER = "de.schlund.pfixcore.workflow.app.ResdocSimpleFinalizer";
048: public final static String PROP_CONTAINER = "defaultiwrapperstate.iwrappercontainer";
049: private final static String IHDL_CONT_MANAGER = "de.schlund.pfixcore.workflow.app.IHandlerContainerManager";
050:
051: /**
052: * @see de.schlund.pfixcore.workflow.State#isAccessible(Context,
053: * PfixServletRequest)
054: */
055: @Override
056: public boolean isAccessible(Context context, PfixServletRequest preq)
057: throws Exception {
058: IHandlerContainer container = getIHandlerContainer(context);
059: return (container.isPageAccessible(context) && container
060: .areHandlerActive(context));
061: }
062:
063: /**
064: * @see de.schlund.pfixcore.workflow.State#needsData(Context,
065: * PfixServletRequest)
066: */
067: @Override
068: public boolean needsData(Context context, PfixServletRequest preq)
069: throws Exception {
070: CAT.debug(">>> [" + context.getCurrentPageRequest().getName()
071: + "] Checking needsData()...");
072: // IWrapperContainer container = getIWrapperContainer(context);
073: // container.initIWrappers(context, preq, new ResultDocument());
074: // boolean retval = container.needsData();
075: IHandlerContainer container = getIHandlerContainer(context);
076: boolean retval = container.needsData(context);
077:
078: if (retval) {
079: CAT
080: .debug(" TRUE! now going to retrieve the current status.");
081: } else {
082: CAT.debug(" FALSE! continue with pageflow check.");
083: }
084: return retval;
085: }
086:
087: /**
088: * @see de.schlund.pfixcore.workflow.State#getDocument(Context,
089: * PfixServletRequest)
090: */
091: @Override
092: @SuppressWarnings("deprecation")
093: public ResultDocument getDocument(Context context,
094: PfixServletRequest preq) throws Exception {
095: IWrapperContainer container = getIWrapperContainer(context);
096: ResdocFinalizer rfinal = getResdocFinalizer(context);
097: ResultDocument resdoc = new ResultDocument();
098:
099: CAT.debug("[[[[[ " + context.getCurrentPageRequest().getName()
100: + " ]]]]]");
101:
102: PerfEvent pe = new PerfEvent(PerfEventType.PAGE_INITIWRAPPERS,
103: context.getCurrentPageRequest().toString());
104:
105: pe.start();
106: container.initIWrappers(context, preq, resdoc);
107: pe.save();
108:
109: if (isSubmitTrigger(context, preq)) {
110: CAT.debug(">>> In SubmitHandling...");
111:
112: boolean valid = true;
113: RequestParam rp = preq.getRequestParam("__token");
114: if (rp != null) {
115: String token = rp.getValue();
116: String[] tokenParts = token.split(":");
117: if (tokenParts.length == 3) {
118: String tokenName = tokenParts[0];
119: String errorPage = tokenParts[1];
120: String tokenValue = tokenParts[2];
121: TokenManager tm = (TokenManager) context;
122: if (tm.isValidToken(tokenName, tokenValue)) {
123: tm.invalidateToken(tokenName);
124: } else {
125: context
126: .addPageMessage(StatusCodeLib.PFIXCORE_GENERATOR_FORM_TOKEN_INVALID);
127: if (errorPage.equals("")) {
128: pe = new PerfEvent(
129: PerfEventType.PAGE_RETRIEVECURRENTSTATUS,
130: context.getCurrentPageRequest()
131: .toString());
132: pe.start();
133: container.retrieveCurrentStatus();
134: pe.save();
135: rfinal.onRetrieveStatus(container);
136: context.prohibitContinue();
137: } else {
138: context.setJumpToPage(errorPage);
139: }
140: valid = false;
141: }
142: } else {
143: throw new IllegalArgumentException(
144: "Invalid token format: " + token);
145: }
146: } else {
147: PageRequestConfig pageConf = context
148: .getConfigForCurrentPageRequest();
149: if (pageConf != null && pageConf.requiresToken()) {
150: context
151: .addPageMessage(StatusCodeLib.PFIXCORE_GENERATOR_FORM_TOKEN_MISSING);
152: pe = new PerfEvent(
153: PerfEventType.PAGE_RETRIEVECURRENTSTATUS,
154: context.getCurrentPageRequest().toString());
155: pe.start();
156: container.retrieveCurrentStatus();
157: pe.save();
158: rfinal.onRetrieveStatus(container);
159: context.prohibitContinue();
160: valid = false;
161: }
162: }
163:
164: if (valid) {
165: pe = new PerfEvent(
166: PerfEventType.PAGE_HANDLESUBMITTEDDATA, context
167: .getCurrentPageRequest().toString());
168: pe.start();
169: container.handleSubmittedData();
170: pe.save();
171:
172: if (container.errorHappened()) {
173: CAT
174: .debug(" => Can't continue, as errors happened during load/work.");
175: rfinal.onWorkError(container);
176: context.prohibitContinue();
177: } else {
178: CAT
179: .debug(" => No error happened during work ...");
180: if (container.getClass().getName().equals(
181: DEF_WRP_CONTAINER)) {
182: // TODO: REMOVE THIS whole "if" branch we're in completely once we don't have to support the old behavior anymore
183: if (!context.isJumpToPageSet()
184: && ((IWrapperSimpleContainer) container)
185: .stayAfterSubmit()) {
186: CAT
187: .debug("... Container says he wants to stay on this page and no jumptopage is set: Setting prohibitcontinue=true");
188: context.prohibitContinue();
189: } else {
190: CAT
191: .debug("... Container says he is ready.");
192: }
193: }
194:
195: CAT
196: .debug(" => end of submit reached successfully.");
197: CAT.debug(" => retrieving current status.");
198: pe = new PerfEvent(
199: PerfEventType.PAGE_RETRIEVECURRENTSTATUS,
200: context.getCurrentPageRequest().toString());
201: pe.start();
202: container.retrieveCurrentStatus();
203: pe.save();
204:
205: rfinal.onSuccess(container);
206: }
207: }
208: } else if (isDirectTrigger(context, preq)
209: || context.finalPageIsRunning()
210: || context.flowIsRunning()) {
211: CAT.debug(">>> Retrieving current status...");
212:
213: pe = new PerfEvent(
214: PerfEventType.PAGE_RETRIEVECURRENTSTATUS, context
215: .getCurrentPageRequest().toString());
216: pe.start();
217: container.retrieveCurrentStatus();
218: pe.save();
219: if (CAT.isDebugEnabled()) {
220: if (isDirectTrigger(context, preq)) {
221: CAT.debug(" => REASON: DirectTrigger");
222: } else if (context.finalPageIsRunning()) {
223: CAT.debug(" => REASON: FinalPage");
224: } else {
225: CAT.debug(" => REASON: WorkFlow");
226: }
227: }
228: rfinal.onRetrieveStatus(container);
229: context.prohibitContinue();
230: } else {
231: throw new XMLException(
232: "This should not happen: No submit trigger, no direct trigger, no final page and no workflow???");
233: }
234:
235: // We want to optimize away the case where the context tells us that we
236: // don't need to supply a full document as the context will - because of
237: // the current state of
238: // the context itself - not use the returned document for displaying the
239: // page or any
240: // further processing anyway. The context is responsible to only return
241: // false when it can be 100% sure that the
242: // document is not needed. Most notably this is NOT the case whenever
243: // the current flow step has
244: // pageflow actions attached, because those can possibly call
245: // prohibitContinue() which in turn would force
246: // the context to display the current page.
247: // See the implementation of Context.stateMustSupplyFullDocument() for
248: // details.
249: if (context.stateMustSupplyFullDocument()) {
250: container.addStringValues();
251: container.addErrorCodes();
252:
253: container.addIWrapperStatus();
254: renderContextResources(context, resdoc);
255: addResponseHeadersAndType(context, resdoc);
256: }
257: return resdoc;
258: }
259:
260: // Eeek, unfortunately we can't use a flyweight here... (somewhere we need
261: // to store state after all)
262: protected IWrapperContainer getIWrapperContainer(Context context)
263: throws XMLException {
264: IWrapperContainer obj = null;
265:
266: String classname = context.getContextConfig().getProperties()
267: .getProperty(PROP_CONTAINER);
268:
269: if (classname == null) {
270: classname = DEF_WRP_CONTAINER;
271: }
272:
273: try {
274: obj = (IWrapperContainer) Class.forName(classname)
275: .newInstance();
276: } catch (InstantiationException e) {
277: throw new XMLException("unable to instantiate class ["
278: + classname + "] :" + e.getMessage());
279: } catch (IllegalAccessException e) {
280: throw new XMLException("unable access class [" + classname
281: + "] :" + e.getMessage());
282: } catch (ClassNotFoundException e) {
283: throw new XMLException("unable to find class [" + classname
284: + "] :" + e.getMessage());
285: } catch (ClassCastException e) {
286: throw new XMLException(
287: "class ["
288: + classname
289: + "] does not implement the interface IWrapperContainer :"
290: + e.getMessage());
291: }
292:
293: return obj;
294: }
295:
296: // Remember, a ResdocFinalizer is a flyweight!!!
297: protected ResdocFinalizer getResdocFinalizer(Context context)
298: throws XMLException {
299: PageRequestConfig config = context
300: .getConfigForCurrentPageRequest();
301: Class<? extends ResdocFinalizer> clazz = config.getFinalizer();
302: String classname = DEF_FINALIZER;
303: if (clazz != null) {
304: classname = clazz.getName();
305: }
306:
307: ResdocFinalizer fin = ResdocFinalizerFactory.getInstance()
308: .getResdocFinalizer(classname);
309:
310: if (fin == null) {
311: throw new RuntimeException(
312: "No finalizer found: classname = " + classname);
313: }
314:
315: return fin;
316: }
317:
318: // Remember, a IHandlerContainer is a flyweight!!!
319: protected IHandlerContainer getIHandlerContainer(Context context)
320: throws Exception {
321: // Use context config object as dummy configuration object to make sure
322: // each context (server) has its own IHandlerContainerManager
323: IHandlerContainerManager ihcm = (IHandlerContainerManager) PropertyObjectManager
324: .getInstance().getConfigurableObject(
325: context.getContextConfig(), IHDL_CONT_MANAGER);
326: return ihcm.getIHandlerContainer(context);
327: }
328:
329: }// DefaultIWrapperState
|