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 java.util.Collection;
023: import java.util.Iterator;
024: import java.util.TreeMap;
025: import java.util.TreeSet;
026:
027: import org.apache.log4j.Logger;
028: import org.w3c.dom.Element;
029:
030: import de.schlund.pfixcore.generator.IHandler;
031: import de.schlund.pfixcore.generator.IWrapper;
032: import de.schlund.pfixcore.generator.IWrapperParam;
033: import de.schlund.pfixcore.generator.RequestData;
034: import de.schlund.pfixcore.generator.StatusCodeInfo;
035: import de.schlund.pfixcore.workflow.Context;
036: import de.schlund.pfixxml.PfixServletRequest;
037: import de.schlund.pfixxml.ResultDocument;
038: import de.schlund.pfixxml.XMLException;
039: import de.schlund.pfixxml.config.IWrapperConfig;
040: import de.schlund.pfixxml.config.PageRequestConfig;
041: import de.schlund.pfixxml.perflogging.PerfEvent;
042: import de.schlund.pfixxml.perflogging.PerfEventType;
043: import de.schlund.pfixxml.resources.FileResource;
044: import de.schlund.pfixxml.resources.ResourceUtil;
045:
046: /**
047: * Default implementation of the <code>IWrapperContainer</code> interface.
048: * <br/>
049: *
050: * @author <a href="mailto:jtl@schlund.de">Jens Lautenbacher</a>
051: *
052: */
053:
054: public class IWrapperContainerImpl implements IWrapperContainer {
055: private TreeMap<String, IWrapper> wrappers = new TreeMap<String, IWrapper>();
056: private TreeSet<IWrapper> allwrappers = new TreeSet<IWrapper>();
057: private TreeSet<IWrapper> selectedwrappers = new TreeSet<IWrapper>();
058: private TreeSet<IWrapper> always_retrieve = new TreeSet<IWrapper>();
059:
060: private Context context = null;
061: private ResultDocument resdoc = null;
062: private PfixServletRequest preq = null;
063: private RequestData reqdata = null;
064: private boolean is_loaded = false;
065:
066: protected Logger LOG = Logger.getLogger(this .getClass());
067:
068: private static final String SELECT_WRAPPER = "SELWRP";
069: private static final String WRAPPER_LOGDIR = "interfacelogging";
070:
071: /**
072: * This method must be called right after an instance of this class is created.
073: *
074: * @param context a <code>Context</code> value. Not null.
075: * @param preq a <code>PfixServletRequest</code> value. Not null.
076: * @param resdoc a <code>ResultDocument</code> value. Not null.
077: * @exception Exception if an error occurs
078: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#initIWrappers(Context, PfixServletRequest, ResultDocument)
079: */
080: public synchronized void initIWrappers(Context context,
081: PfixServletRequest preq, ResultDocument resdoc)
082: throws Exception {
083: if (context == null)
084: throw new IllegalArgumentException(
085: "A 'null' value for the Context argument is not acceptable here.");
086: if (preq == null)
087: throw new IllegalArgumentException(
088: "A 'null' value for the PfixServletRequest argument is not acceptable here.");
089: if (resdoc == null)
090: throw new IllegalArgumentException(
091: "A 'null' value for the ResultDocument argument is not acceptable here.");
092:
093: this .context = context;
094: this .preq = preq;
095: this .resdoc = resdoc;
096: this .reqdata = new RequestDataImpl(context, preq);
097:
098: createIWrapperGroups();
099: }
100:
101: /**
102: * Use this method at any time to check if any error has happened in
103: * any of the "currently active" IWrappers of this Container.
104: * Depending on the use of grouping, or restricting to certain
105: * IWrappers the term "currently active" means something between
106: * the two extremes of "all handled IWrappers" to
107: * "just the one I explicitely talk to".
108: *
109: * @return a <code>boolean</code> value
110: * @exception Exception if an error occurs
111: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#errorHappened()
112: */
113: public boolean errorHappened() throws Exception {
114: if (allwrappers.isEmpty())
115: return false; // border case
116: if (!is_loaded)
117: throw new XMLException(
118: "You must first call handleSubmittedData() here!");
119:
120: for (Iterator<IWrapper> iter = selectedwrappers.iterator(); iter
121: .hasNext();) {
122: IWrapper wrapper = iter.next();
123: if (wrapper.errorHappened()) {
124: return true;
125: }
126: }
127: return false;
128: }
129:
130: /**
131: * This method takes care of putting all error messages into the ResultDocument.
132: * This method needs the instance to be initialized with a non-null resdoc param (see
133: * {@link initIWrappers initIWrappers}).
134: * @exception Exception if an error occurs
135: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#addErrorCodes()
136: */
137: public void addErrorCodes() throws Exception {
138: for (Iterator<IWrapper> iter = selectedwrappers.iterator(); iter
139: .hasNext();) {
140: IWrapper wrapper = iter.next();
141: String prefix = wrapper.gimmePrefix();
142: IWrapperParam[] errors = wrapper.gimmeAllParamsWithErrors();
143: if (errors != null) {
144: wrapper.tryErrorLogging();
145: for (int j = 0; j < errors.length; j++) {
146: IWrapperParam param = errors[j];
147: StatusCodeInfo[] scodeinfos = param
148: .getStatusCodeInfos();
149: String name = prefix + "." + param.getName();
150: if (scodeinfos != null) {
151: for (int k = 0; k < scodeinfos.length; k++) {
152: StatusCodeInfo sci = scodeinfos[k];
153: resdoc.addStatusCode(context
154: .getProperties(), sci
155: .getStatusCode(), sci.getArgs(),
156: sci.getLevel(), name);
157: }
158: }
159: }
160: }
161: }
162: }
163:
164: /**
165: * This method puts all the string representation of all submitted
166: * form values back into the result tree.
167: * This method needs the instance to be initialized with a non-null resdoc param (see
168: * {@link initIWrappers initIWrappers}).
169: *
170: * @exception Exception if an error occurs
171: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#addStringValues()
172: */
173: public void addStringValues() throws Exception {
174: for (Iterator<IWrapper> iter = allwrappers.iterator(); iter
175: .hasNext();) {
176: IWrapper wrapper = iter.next();
177: String prfx = wrapper.gimmePrefix();
178: IWrapperParam[] pinfoall = wrapper.gimmeAllParams();
179: for (int j = 0; j < pinfoall.length; j++) {
180: IWrapperParam pinfo = pinfoall[j];
181: String name = pinfo.getName();
182: String[] strval = pinfo.getStringValue();
183: if (strval != null) {
184: for (int k = 0; k < strval.length; k++) {
185: resdoc.addValue(prfx + "." + name, strval[k]);
186: }
187: }
188: }
189: }
190: }
191:
192: /**
193: * Returns the {@link ResultDocument ResultDocument} that's associated with this IWrapperContainer.
194: * @return a <code>ResultDocument</code> value
195: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#getAssociatedResultDocument()
196: */
197: public ResultDocument getAssociatedResultDocument() {
198: return resdoc;
199: }
200:
201: /**
202: * Returns the {@link PfixServletRequest} that's associated with this IWrapperContainer.
203: *
204: * @return a <code>HttpServletRequest</code> value
205: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#getAssociatedPfixServletRequest()
206: */
207: public PfixServletRequest getAssociatedPfixServletRequest() {
208: return preq;
209: }
210:
211: /**
212: * Returns the {@link Context} that's associated with this IWrapperContainer.
213: *
214: * @return a <code>Context</code> value
215: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#getAssociatedContext()
216: */
217: public Context getAssociatedContext() {
218: return context;
219: }
220:
221: /**
222: * <code>addIWrapperStatus</code> inserts the status of all IWrappers into the result tree.
223: * @exception Exception if an error occurs
224: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#addIWrapperStatus()
225: */
226: public void addIWrapperStatus() throws Exception {
227: Element status = resdoc.createNode("iwrapperstatus");
228: for (Iterator<IWrapper> iter = allwrappers.iterator(); iter
229: .hasNext();) {
230: IWrapper wrapper = iter.next();
231: IHandler handler = wrapper.gimmeIHandler();
232: Element wrap = resdoc.createSubNode(status, "interface");
233: wrap.setAttribute("active", "" + handler.isActive(context));
234: wrap.setAttribute("name", wrapper.getClass().getName());
235: wrap.setAttribute("prefix", wrapper.gimmePrefix());
236: }
237: }
238:
239: /**
240: * <code>handleSubmittedData</code> will call all or a part of the defined IWrappers
241: * (depending on restricting the IWrappers) to get
242: * the IHandler that these IWrappers are bound to. The IHandler are called in turn to handle the submitted data.
243: * This works by calling ihandler.handleSubmittedData(Context context, IWrapper wrapper).
244: * See {@link IHandler}.
245: *
246: * @exception Exception if an error occurs
247: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#handleSubmittedData()
248: */
249: public void handleSubmittedData() throws Exception {
250: for (Iterator<IWrapper> iter = allwrappers.iterator(); iter
251: .hasNext();) {
252: IWrapper wrapper = iter.next();
253: IHandler handler = wrapper.gimmeIHandler();
254: if (handler.isActive(context)) {
255: wrapper.load(reqdata);
256: if (selectedwrappers.contains(wrapper)) {
257: wrapper.tryParamLogging();
258: if (!wrapper.errorHappened()) {
259: PerfEvent pe = new PerfEvent(
260: PerfEventType.IHANDLER_HANDLESUBMITTEDDATA,
261: handler.getClass().getName());
262: pe.start();
263: handler.handleSubmittedData(context, wrapper);
264: pe.save();
265: }
266: }
267: }
268: }
269: is_loaded = true;
270: }
271:
272: /**
273: * <code>retrieveCurrentStatus</code> will call all or a part of the defined IWrappers
274: * (depending on restricting the IWrappers and the always_retrieve flag) to get the "active" IHandlers, which
275: * are called in turn via ihandler.retrieveCurrentStatus(Context context, IWrapper wrapper).
276: *
277: * @exception Exception if an error occurs
278: * @see de.schlund.pfixcore.workflow.app.IWrapperContainer#retrieveCurrentStatus()
279: */
280: public void retrieveCurrentStatus() throws Exception {
281: TreeSet<IWrapper> retrieve = new TreeSet<IWrapper>();
282: retrieve.addAll(selectedwrappers);
283: if (always_retrieve != null && !always_retrieve.isEmpty()) {
284: retrieve.addAll(always_retrieve);
285: }
286: for (Iterator<IWrapper> iter = retrieve.iterator(); iter
287: .hasNext();) {
288: IWrapper wrapper = iter.next();
289: IHandler handler = wrapper.gimmeIHandler();
290: if (handler.isActive(context)) {
291: handler.retrieveCurrentStatus(context, wrapper);
292: }
293: }
294: }
295:
296: //
297: // PRIVATE
298: //
299:
300: private void createIWrapperGroups() throws Exception {
301: PageRequestConfig config = context
302: .getConfigForCurrentPageRequest();
303: Collection<? extends IWrapperConfig> interfaces = config
304: .getIWrappers().values();
305:
306: if (interfaces.size() == 0) {
307: LOG.debug("*** Found no interfaces for this page (page="
308: + context.getCurrentPageRequest().getName() + ")");
309: } else {
310: // Initialize all wrappers
311: int order = 0;
312: for (IWrapperConfig iConfig : interfaces) {
313: String prefix = iConfig.getPrefix();
314: if (wrappers.get(prefix) != null) {
315: throw new XMLException(
316: "FATAL: you have already defined a wrapper with prefix "
317: + prefix
318: + " on page "
319: + context.getCurrentPageRequest()
320: .getName());
321: }
322:
323: String iface = iConfig.getWrapperClass().getName();
324:
325: Class<?> thewrapper = null;
326: IWrapper wrapper = null;
327: try {
328: thewrapper = Class.forName(iface);
329: wrapper = (IWrapper) thewrapper.newInstance();
330: } catch (ClassNotFoundException e) {
331: throw new XMLException("unable to find class ["
332: + iface + "] :" + e.getMessage());
333: } catch (InstantiationException e) {
334: throw new XMLException(
335: "unable to instantiate class [" + iface
336: + "] :" + e.getMessage());
337: } catch (IllegalAccessException e) {
338: throw new XMLException("unable to acces class ["
339: + iface + "] :" + e.getMessage());
340: } catch (ClassCastException e) {
341: throw new XMLException(
342: "class ["
343: + iface
344: + "] does not implement the interface IWrapper :"
345: + e.getMessage());
346: }
347:
348: wrapper.defineOrder(order++);
349:
350: wrappers.put(prefix, wrapper);
351: wrapper.init(prefix);
352:
353: allwrappers.add(wrapper);
354:
355: if (iConfig.isAlwaysRetrieve()) {
356: LOG.debug("*** Adding interface '"
357: + iConfig.getPrefix()
358: + "' to the always_retrieve group...");
359: always_retrieve.add(wrapper);
360: }
361:
362: String logdir = context.getProperties().getProperty(
363: WRAPPER_LOGDIR);
364: boolean dolog = iConfig.getLogging();
365: if (dolog && logdir != null && !logdir.equals("")) {
366: FileResource dir = ResourceUtil
367: .getFileResourceFromDocroot(logdir);
368: if (dir.isDirectory() && dir.canWrite()) {
369: wrapper.initLogging(dir, context
370: .getCurrentPageRequest().getName(),
371: context.getVisitId());
372: }
373: }
374: }
375:
376: // TODO: This mechanism MUST be at least augmented with a "action based" selection mechanism.
377: // In the future we will only allow to select from a predefined set auf wrapper sets.
378: // The configuration will group wrappers to actions, and the request is only allowed to give one of
379: // the defined action names, but it will be no longer possible to create any desired grouping from the
380: // outside.
381: String[] selwrappers = reqdata.getCommands(SELECT_WRAPPER);
382: if (selwrappers != null) {
383: for (int i = 0; i < selwrappers.length; i++) {
384: String prefix = selwrappers[i];
385: LOG.debug(" >> Restricted to Wrapper: " + prefix);
386: IWrapper selwrap = (IWrapper) wrappers.get(prefix);
387: if (selwrap == null) {
388: LOG.warn(" *** No wrapper found for prefix "
389: + prefix + "! ignoring");
390: continue;
391: }
392: selectedwrappers.add(selwrap);
393: }
394: }
395: // If we don't have any directly selected wrappers, use all of them
396: if (selectedwrappers.isEmpty()) {
397: selectedwrappers.addAll(allwrappers);
398: }
399:
400: }
401: }
402:
403: }// IWrapperSimpleContainer
|