001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.controller;
066:
067: import com.jcorporate.expresso.core.misc.StringUtil;
068: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
069: import org.w3c.dom.NamedNodeMap;
070: import org.w3c.dom.Node;
071: import org.w3c.dom.NodeList;
072:
073: import java.io.Serializable;
074: import java.util.Enumeration;
075: import java.util.HashMap;
076: import java.util.Map;
077: import java.util.Vector;
078:
079: /**
080: * A Block is a logical grouping of Expresso Controller Elements used for nesting.
081: * <p/>
082: * <h4>Recognized Types:</h4>
083: * <p>The following types are recognized by the expresso framework and
084: * automatically rendered: You may add your own types or ignore them
085: * if you are doing your own page rendering.</p>
086: * <p/>
087: * <p>header-row: Renders each subobject in it's own cell with the appropriate
088: * jc-header class Make the cells pipe-delimited strings </p>
089: * <p/>
090: * <p>row: Renders all subobjects in one row</p>
091: * <p>borderWidth: Renders the table width a paricular border.</p>
092: * <p><i>default behavior:</i> Render as a table/nested table.</p>
093: *
094: * @author Shash Chatterjee
095: */
096: public class Block extends ControllerElement implements Cloneable,
097: Serializable {
098: private static final String this Class = Block.class.getName() + ".";
099: private Transition formTransition = null;
100:
101: private Map mNestedBlocks = null;
102: private Map mNestedTransitions = null;
103: private Map mNestedInputs = null;
104: private Map mNestedOutputs = null;
105:
106: /**
107: * Instantiation Constructor. Normally not called
108: */
109: public Block() {
110: }
111:
112: /**
113: * Convenience constructor - to make a new Block object
114: * with a specific name.
115: *
116: * @param newName The new name of the block
117: */
118: public Block(String newName) {
119: setName(newName);
120: } /* Block(String) */
121:
122: /**
123: * Add an element to this Block
124: *
125: * @param element an element to be added
126: */
127: public void add(ControllerElement element) {
128: addNested(element);
129: // iterate through the 4 possibilites in order to
130: // fill the right map
131: if (element instanceof Output) {
132: if (mNestedOutputs == null) {
133: mNestedOutputs = new HashMap();
134: }
135: mNestedOutputs.put(element.getName(), element);
136: } else if (element instanceof Input) {
137: if (mNestedInputs == null) {
138: mNestedInputs = new HashMap();
139: }
140: mNestedInputs.put(element.getName(), element);
141: } else if (element instanceof Transition) {
142: if (mNestedTransitions == null) {
143: mNestedTransitions = new HashMap();
144: }
145: mNestedTransitions.put(element.getName(), element);
146: } else if (element instanceof Block) {
147: if (mNestedBlocks == null) {
148: mNestedBlocks = new HashMap();
149: }
150: mNestedBlocks.put(element.getName(), element);
151: }
152: }
153:
154: /**
155: * Retrieve the transitions as a map so that JSTL can cope with navigating the
156: * ControllerResponse through a named fashion
157: *
158: * @return java.util.Map map of transitions which have been added
159: */
160: public Map getNamedTransitions() {
161: return mNestedTransitions;
162: }
163:
164: /**
165: * Retrieve the outputs as a map so that JSTL can cope with navigating the
166: * ControllerResponse through a named fashion
167: *
168: * @return java.util.Map map of outputs which have been added
169: */
170: public Map getNamedOutputs() {
171: return mNestedOutputs;
172: }
173:
174: /**
175: * Retrieve the inputs as a map so that JSTL can cope with navigating the
176: * ControllerResponse through a named fashion
177: *
178: * @return java.util.Map map of inputs which have been added
179: */
180: public Map getNamedInputs() {
181: return mNestedInputs;
182: }
183:
184: /**
185: * Retrieve the Blocks as a map so that JSTL can cope with navigating the
186: * ControllerResponse through a named fashion
187: *
188: * @return java.util.Map map of blocks which have been added
189: */
190: public Map getNamedBlocks() {
191: return mNestedBlocks;
192: }
193:
194: /**
195: * Remove an element from the nested elements for this item
196: *
197: * @param elementToRemove The element to be removed from the list of
198: * nested items.
199: * @throws ControllerException if there is no such item nested in this item
200: */
201: public void removeNested(ControllerElement elementToRemove)
202: throws ControllerException {
203: super .removeNested(elementToRemove);
204:
205: if (elementToRemove instanceof Input) {
206: mNestedInputs.remove(elementToRemove.getName());
207: } else if (elementToRemove instanceof Output) {
208: mNestedOutputs.remove(elementToRemove.getName());
209: } else if (elementToRemove instanceof Transition) {
210: mNestedTransitions.remove(elementToRemove.getName());
211: } else if (elementToRemove instanceof Block) {
212: mNestedBlocks.remove(elementToRemove.getName());
213: }
214: } /* removeNested(ControllerElement) */
215:
216: /**
217: * Generate a copy of this current Block
218: *
219: * @return an instantiated Block onbject
220: */
221: public Object clone() throws CloneNotSupportedException {
222: Block b;
223:
224: synchronized (this ) {
225: b = (Block) super .clone();
226: b.formTransition = this .formTransition;
227: b.mNestedBlocks = this .mNestedBlocks;
228: b.mNestedTransitions = this .mNestedTransitions;
229: b.mNestedInputs = this .mNestedInputs;
230: b.mNestedOutputs = this .mNestedOutputs;
231: }
232:
233: return b;
234: }
235:
236: /**
237: * Return a controller element based upon the xml fragment
238: *
239: * @param n a DOM Node that we extract the internal elements
240: * @return an instantiated ControllerElement [specifically a block]
241: * @throws ControllerException if unable to build itself from the DOM node
242: */
243: public static ControllerElement fromXML(Node n)
244: throws ControllerException {
245:
246: //If we're at the root node, then it'll be doc instead of input.
247: if (n.getNodeName().equals("#document")) {
248: return fromXML(n.getChildNodes().item(0));
249: }
250: if (!n.getNodeName().equals("block")) {
251: return null;
252: }
253:
254: Block b = new Block();
255:
256: //Get node attributes
257: NamedNodeMap transitionAttributes = n.getAttributes();
258: Node attributeNode = transitionAttributes.getNamedItem("name");
259:
260: if (attributeNode != null) {
261: String value = attributeNode.getNodeValue();
262:
263: if (value != null) {
264: b.setName(value);
265: }
266: }
267:
268: NodeList nl = n.getChildNodes();
269:
270: for (int i = 0; i < nl.getLength(); i++) {
271: Node oneChild = nl.item(i);
272: String nodeName = oneChild.getNodeName();
273:
274: if (nodeName.equals("controller-element")) {
275: b = (Block) ControllerElement.fromXML(oneChild, b);
276: break;
277: }
278: }
279:
280: return b;
281: }
282:
283: /**
284: * Retrieve a list of blocks contained within this Block
285: *
286: * @return java.util.Vector
287: */
288: public Vector getBlocks() {
289: Vector elements = new Vector(16);
290: ControllerElement t = null;
291:
292: for (Enumeration e = getNested().elements(); e
293: .hasMoreElements();) {
294: t = (ControllerElement) e.nextElement();
295:
296: if (t instanceof Block) {
297: elements.add(t);
298: }
299: }
300:
301: return elements;
302: }
303:
304: /**
305: * Retrieve a newsted Block by name. Note that for this to work correctly,
306: * all added items in the block MUST have unique names. otherwise, you may
307: * get ClassCastExceptions
308: *
309: * @param blockName the name of the block to retrieve
310: * @return Block or null if the subBlock doesn't exit
311: */
312: public Block getBlock(String blockName) {
313: return (Block) this .getNestedMap().get(blockName);
314: }
315:
316: /**
317: * Retrieve a nested input by name. Note that for this to work correctly,
318: * all added items in the block MUST have unique names. otherwise, you may
319: * get ClassCastExceptions
320: *
321: * @param inputName the name of the block to retrieve
322: * @return Input or null if the sub input doesn't exit
323: */
324: public Input getInput(String inputName) {
325: return (Input) this .getNestedMap().get(inputName);
326: }
327:
328: /**
329: * Retrieve a nested output by name. Note that for this to work correctly,
330: * all added items in the block MUST have unique names. otherwise, you may
331: * get ClassCastExceptions
332: *
333: * @param outputName the name of the block to retrieve
334: * @return Output or null if the sub output doesn't exit
335: */
336: public Output getOutput(String outputName) {
337: return (Output) this .getNestedMap().get(outputName);
338: }
339:
340: /**
341: * Retrieve a nested transition by name. Note that for this to work correctly,
342: * all added items in the block MUST have unique names. otherwise, you may
343: * get ClassCastExceptions
344: *
345: * @param transitionName the name of the block to retrieve
346: * @return Transition or null if the sub Transition doesn't exit
347: */
348: public Transition getTransition(String transitionName) {
349: return (Transition) this .getNestedMap().get(transitionName);
350: }
351:
352: /**
353: * Retrieve the form encoding attribute of this block
354: *
355: * @return java.lang.String or null
356: */
357: public String getFormEncoding() {
358: return getAttribute("formEncoding");
359: } /* getFormEncoding() */
360:
361: /**
362: * Get the form method whether GET or POST
363: *
364: * @return java.lang.String either GET or POST
365: */
366: public String getFormMethod() {
367: String formMethod = StringUtil
368: .notNull(getAttribute("formMethod"));
369:
370: if (!formMethod.equalsIgnoreCase("get")) {
371: formMethod = "post";
372: }
373:
374: return formMethod;
375: } /* getFormMethod() */
376:
377: /**
378: * Get the Form Transition
379: *
380: * @return com.jcorporate.expresso.core.controller.Transition
381: */
382: public Transition getFormTransition() {
383: return formTransition;
384: } /* getFormTransition() */
385:
386: /**
387: * Get the nested Inputs
388: *
389: * @return java.util.Vector of Inputs
390: */
391: public Vector getInputs() {
392: Vector elements = new Vector(16);
393: ControllerElement t = null;
394:
395: for (Enumeration e = getNested().elements(); e
396: .hasMoreElements();) {
397: t = (ControllerElement) e.nextElement();
398:
399: if (t instanceof Input) {
400: elements.add(t);
401: }
402: }
403:
404: return elements;
405: }
406:
407: /**
408: * Get the number of elements contained within the nested block
409: *
410: * @return integer describing the size of the nested contents
411: */
412: public int getNumContents() {
413: return getNested().size();
414: } /* getNumContents() */
415:
416: /**
417: * Retrieve a list of Outputs nested wtihin this block
418: *
419: * @return java.util.Vector of nested Outputs
420: */
421: public Vector getOutputs() {
422: Vector elements = new Vector(16);
423: ControllerElement t = null;
424:
425: for (Enumeration e = getNested().elements(); e
426: .hasMoreElements();) {
427: t = (ControllerElement) e.nextElement();
428:
429: if (t instanceof Output) {
430: elements.add(t);
431: }
432: }
433:
434: return elements;
435: }
436:
437: /**
438: * Retrieve a list of Transitions nested wtihin this block
439: *
440: * @return java.util.Vector of nested Transitions
441: */
442: public Vector getTransitions() {
443: Vector elements = new Vector(16);
444: ControllerElement t = null;
445:
446: for (Enumeration e = getNested().elements(); e
447: .hasMoreElements();) {
448: t = (ControllerElement) e.nextElement();
449:
450: if (t instanceof Transition) {
451: elements.add(t);
452: }
453: }
454:
455: return elements;
456: }
457:
458: /**
459: * Return true if the form attribute for this block has been set
460: *
461: * @return boolean true if the attribute form has been set to true for this block
462: */
463: public boolean isForm() {
464: if (StringUtil.notNull(getAttribute("form")).equals("true")) {
465: return true;
466: } else {
467: return false;
468: }
469: } /* isForm() */
470:
471: /**
472: * Set whether this form is true or not.
473: *
474: * @param isForm either 'true' or 'false' (lower case)
475: * @throws ControllerException if the methods are invalid
476: */
477: public void setForm(String isForm) throws ControllerException {
478: String this Method = this Class + "setForm";
479:
480: if (!(isForm.equals("true") || isForm.equals("false"))) {
481: throw new ControllerException(
482: this Method
483: + ":parameter passed in must be \"true\" or \"false\"");
484: }
485:
486: setAttribute("form", isForm);
487: } /* setForm(String) */
488:
489: /**
490: * Set the encoding attribute for the block form
491: *
492: * @param encoding java.lang.String
493: * @throws ControllerException if the attribute is unable to be thrown
494: */
495: public void setFormEncoding(String encoding)
496: throws ControllerException {
497: setAttribute("formEncoding", encoding);
498: } /* setFormEncoding(String) */
499:
500: /**
501: * Set the form method.
502: *
503: * @param method The string get or post (lower case)
504: * @throws ControllerException upon invalid argument
505: */
506: public void setFormMethod(String method) throws ControllerException {
507: String this Method = this Class + "setFormMethod";
508:
509: if (!(method.equals("get") || method.equals("post"))) {
510: throw new ControllerException(
511: this Method
512: + ": parameter passed in must be \"get\" or \"post\"");
513: }
514:
515: setAttribute("formMethod", method);
516: } /* setFormMethod(String) */
517:
518: /**
519: * Sets the form transition
520: *
521: * @param a a Transition that is the equiv of the 'submit' button on the
522: * form.
523: * @throws ControllerException if the transition is null
524: */
525: public void setFormTransition(Transition a)
526: throws ControllerException {
527: String this Method = this Class + "setFormTransition";
528:
529: if (a == null) {
530: throw new ControllerException(this Method
531: + ":Transition cannot be null");
532: }
533:
534: formTransition = a;
535: } /* setFormTransition(Transition) */
536:
537: /**
538: * Concert the object to an xml fragment.
539: *
540: * @param stream an instantiated FastStringBuffer to which we are supposed
541: * to append to.
542: * @return a fleshed out FastStringBuffer (usually the stream parameter)
543: */
544: public FastStringBuffer toXML(FastStringBuffer stream) {
545: stream.append("<block name=\""
546: + StringUtil.xmlEscape(this .getName()) + "\">\n");
547: stream = super .toXML(stream);
548:
549: // stream = toNestedXML(stream,"nested-outputs", getOutputs());
550: // stream = toNestedXML(stream,"nested-inputs", getInputs());
551: // stream = toNestedXML(stream,"nested-transitions", getTransitions());
552: // stream = toNestedXML(stream,"nested-blocks", getBlocks());
553: stream.append("</block>");
554:
555: return stream;
556: }
557:
558: protected FastStringBuffer toNestedXML(FastStringBuffer stream,
559: String blockLabel, Vector elements) {
560: stream.append("<");
561: stream.append(blockLabel);
562: stream.append(">");
563:
564: for (Enumeration eb = elements.elements(); eb.hasMoreElements();) {
565: ControllerElement oneControllerElement = (ControllerElement) eb
566: .nextElement();
567: stream = oneControllerElement.toXML(stream);
568: } /* each element in this block */
569:
570: stream.append("</");
571: stream.append(blockLabel);
572: stream.append(">");
573:
574: return stream;
575: }
576: }
577:
578: /* Block */
|