001: /*
002: * AbstractWingElement.java
003: *
004: * Version: $Revision: 1.6 $
005: *
006: * Date: $Date: 2006/03/13 17:19:39 $
007: *
008: * Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
009: * Institute of Technology. All rights reserved.
010: *
011: * Redistribution and use in source and binary forms, with or without
012: * modification, are permitted provided that the following conditions are
013: * met:
014: *
015: * - Redistributions of source code must retain the above copyright
016: * notice, this list of conditions and the following disclaimer.
017: *
018: * - Redistributions in binary form must reproduce the above copyright
019: * notice, this list of conditions and the following disclaimer in the
020: * documentation and/or other materials provided with the distribution.
021: *
022: * - Neither the name of the Hewlett-Packard Company nor the name of the
023: * Massachusetts Institute of Technology nor the names of their
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038: * DAMAGE.
039: */
040:
041: package org.dspace.app.xmlui.wing.element;
042:
043: import org.dspace.app.xmlui.wing.AttributeMap;
044: import org.dspace.app.xmlui.wing.Namespace;
045: import org.dspace.app.xmlui.wing.Message;
046: import org.dspace.app.xmlui.wing.WingConstants;
047: import org.dspace.app.xmlui.wing.WingContext;
048: import org.dspace.app.xmlui.wing.WingException;
049: import org.dspace.app.xmlui.wing.WingInvalidArgument;
050: import org.xml.sax.Attributes;
051: import org.xml.sax.ContentHandler;
052: import org.xml.sax.SAXException;
053: import org.xml.sax.helpers.AttributesImpl;
054: import org.xml.sax.helpers.NamespaceSupport;
055:
056: /**
057: * This class represents a generic element inside the Wing framework.
058: *
059: * The primary purpose of this abstract class is to create a generic datatype
060: * for storage of any WingElement. Second, this class also provides a set of
061: * utilities for easy maintenance of each wing element. There are a set of
062: * methods for sending SAX events that handle namespaces and attributes so that
063: * each individual wing element does not.
064: *
065: * There are also a set of utility methods for checking method parameters.
066: *
067: * @author Scott Phillips
068: */
069: public abstract class AbstractWingElement implements WingElement {
070:
071: /**
072: * The current context this element is operating under. From the context
073: * contentHandler, namespace support, and unique id generation can be found.
074: * This context is shared between many elements.
075: */
076: protected WingContext context;
077:
078: /**
079: * Construct a new WingElement. All wing elements must have access to a
080: * current WingContext.
081: *
082: * @param context
083: * (Required) The context this element is contained in.
084: * @throws WingException
085: */
086: protected AbstractWingElement(WingContext context) {
087: if (context == null)
088: throw new NullPointerException("Context may not be null.");
089: this .context = context;
090: }
091:
092: /**
093: * Construct a new WingElement without access to the current wing Context.
094: * This means that the wing element will not be able to know the component
095: * name because the context is not available.
096: *
097: * This invocation method is intended for wing element implementations that
098: * are outside the wing pacakage.
099: */
100: protected AbstractWingElement() {
101:
102: }
103:
104: /**
105: * Return the currently registered wing context.
106: *
107: */
108: protected WingContext getWingContext() {
109: return this .context;
110: }
111:
112: /**
113: * Set the WingContext, note there are potential side effects of changing
114: * the WingContext once it has been used. This context should not be changed
115: * after elements have been added to a wingElement.
116: *
117: * @param context
118: * The new WingContext.
119: */
120: protected void setWingContext(WingContext context) {
121: this .context = context;
122: }
123:
124: /**
125: * These methods: require, restrict, greater, lesser, greater, requireFalse,
126: * requireTrue are simple methods to describe the restrictions and
127: * requirements of attribute values.
128: */
129:
130: /**
131: * Check to make sure the parameter is not null or an empty string.
132: *
133: * @param parameter
134: * A non null and none empty string
135: * @param message
136: * The exception message thrown if parameter is invalid.
137: */
138: protected void require(String parameter, String message)
139: throws WingInvalidArgument {
140: if (parameter == null || parameter.equals(""))
141: throw new WingInvalidArgument(message);
142: }
143:
144: /**
145: * Check to make sure the parameter is not null or an empty string.
146: *
147: * @param parameter
148: * A non null and none empty string
149: * @param message
150: * The exception message thrown if parameter is invalid.
151: */
152: protected void require(Message parameter, String message)
153: throws WingInvalidArgument {
154: if (parameter == null)
155: throw new WingInvalidArgument(message);
156: }
157:
158: /**
159: * Check to make sure that the parameter is a member of one of the options.
160: * This method will accept null values, if you need to restrict and not
161: * allow null values then use the require() method in conjunction with this
162: * method.
163: *
164: * @param parameter
165: * A null string, or a member of the options array.
166: * @param options
167: * A list of possible values for the parameter.
168: * @param message
169: * The exception message thrown if the parameter is invalid.
170: */
171: protected void restrict(String parameter, String[] options,
172: String message) throws WingInvalidArgument {
173: if (parameter == null)
174: return;
175:
176: for (String test : options)
177: if (parameter.equals(test))
178: return; // short circuit the method call.
179:
180: throw new WingInvalidArgument(message);
181: }
182:
183: /**
184: * Check to make sure that the parameter is GREATER THAN (note: not equal
185: * to) the given greater variable.
186: *
187: * @param parameter
188: * An int who's value is greater than greater.
189: * @param greater
190: * An int who's value is lesser that greater.
191: * @param message
192: * The exception message thrown if the parameter is invalid.
193: */
194: protected void greater(int parameter, int greater, String message)
195: throws WingInvalidArgument {
196: if (parameter <= greater)
197: throw new WingInvalidArgument(message);
198: }
199:
200: /**
201: * Check to make sure that the parameter is LESS THAN (note: not equal to)
202: * the given lesser variable.
203: *
204: * @param parameter
205: * An int who's value is less than lesser.
206: * @param greater
207: * An int who's value is greater that lesser.
208: * @param message
209: * The exception message thrown if the parameter is invalid.
210: */
211: protected void lesser(int parameter, int lesser, String message)
212: throws WingInvalidArgument {
213: if (parameter >= lesser)
214: throw new WingInvalidArgument(message);
215: }
216:
217: /**
218: * Check to make sure that the boolean test value is false.
219: *
220: * @param test
221: * A false value.
222: * @param message
223: * The exception message thrown if "test" is invalid.
224: */
225: protected void requireFalse(boolean test, String message)
226: throws WingInvalidArgument {
227: if (test)
228: throw new WingInvalidArgument(message);
229: }
230:
231: /**
232: * Check to make sure that the boolean test value is true.
233: *
234: * @param test
235: * A true value.
236: * @param message
237: * The exception message thrown if "test" is invalid.
238: */
239: protected void requireTrue(boolean test, String message)
240: throws WingInvalidArgument {
241: if (!test)
242: throw new WingInvalidArgument(message);
243: }
244:
245: /**
246: * Send the SAX event to start this element.
247: *
248: * Assume the DRI namespace.
249: *
250: * @param contentHandler
251: * (Required) The registered contentHandler where SAX events
252: * should be routed too.
253: * @param namespaces
254: * (Required) SAX Helper class to keep track of namespaces able
255: * to determine the correct prefix for a given namespace URI.
256: * @param name
257: * (Required) The element's localName
258: * @param attributes
259: * (May be null) Attributes for this element.
260: */
261: protected void startElement(ContentHandler contentHandler,
262: NamespaceSupport namespaces, String name,
263: AttributeMap attributes) throws SAXException {
264: startElement(contentHandler, namespaces, WingConstants.DRI,
265: name, attributes);
266: }
267:
268: /**
269: * Send the SAX events to start this element.
270: *
271: * @param contentHandler
272: * (Required) The registered contentHandler where SAX events
273: * should be routed too.
274: * @param namespaces
275: * (Required) SAX Helper class to keep track of namespaces able
276: * to determine the correct prefix for a given namespace URI.
277: * @param namespace
278: * (Required) The namespace of this element.
279: * @param name
280: * (Required) The local name of this element.
281: * @param attributes
282: * (May be null) Attributes for this element
283: */
284: protected void startElement(ContentHandler contentHandler,
285: NamespaceSupport namespaces, Namespace namespace,
286: String name, AttributeMap attributes) throws SAXException {
287: String prefix = namespaces.getPrefix(namespace.URI);
288: contentHandler.startElement(namespace.URI, name, qName(prefix,
289: name), map2sax(namespace, namespaces, attributes));
290: }
291:
292: /**
293: * Send the SAX event for these plain characters, not wrapped in any
294: * elements.
295: *
296: * @param contentHandler
297: * (Required) The registered contentHandler where SAX events
298: * should be routed too.
299: * @param characters
300: * (May be null) Characters to send.
301: */
302: protected void sendCharacters(ContentHandler contentHandler,
303: String characters) throws SAXException {
304: if (characters != null) {
305: char[] contentArray = characters.toCharArray();
306: contentHandler.characters(contentArray, 0,
307: contentArray.length);
308: }
309: }
310:
311: /**
312: * Send the SAX events to end this element.
313: *
314: * Assume the DRI namespace.
315: *
316: * @param contentHandler
317: * (Required) The registered contentHandler where SAX events
318: * should be routed too.
319: * @param namespaces
320: * (Required) SAX Helper class to keep track of namespaces able
321: * to determine the correct prefix for a given namespace URI.
322: * @param name
323: * (Required) The localName of this element.
324: */
325: protected void endElement(ContentHandler contentHandler,
326: NamespaceSupport namespaces, String name)
327: throws SAXException {
328: endElement(contentHandler, namespaces, WingConstants.DRI, name);
329: }
330:
331: /**
332: * Send the SAX events to end this element.
333: *
334: * @param contentHandler
335: * (Required) The registered contentHandler where SAX events
336: * should be routed too.
337: * @param namespaces
338: * (Required) SAX Helper class to keep track of namespaces able
339: * to determine the correct prefix for a given namespace URI.
340: * @param namespace
341: * (Required) The namespace of this element.
342: * @param name
343: * (Required) The local name of this element.
344: */
345: protected void endElement(ContentHandler contentHandler,
346: NamespaceSupport namespaces, Namespace namespace,
347: String name) throws SAXException {
348: String prefix = namespaces.getPrefix(namespace.URI);
349: contentHandler.endElement(namespace.URI, name, qName(prefix,
350: name));
351: }
352:
353: /**
354: * Build the SAX attributes object based upon Java's String Map.
355: *
356: * @param namespaces
357: * SAX Helper class to keep track of namespaces able to determine
358: * the correct prefix for a given namespace URI.
359: * @param attributeMap
360: * Map of attributes and values.
361: * @return SAX Attributes object of the given map.
362: */
363: private Attributes map2sax(Namespace elementNamespace,
364: NamespaceSupport namespaces, AttributeMap attributeMap) {
365: return map2sax(elementNamespace, namespaces, null, attributeMap);
366: }
367:
368: /**
369: * Build the SAX attributes object based upon Java's String map. This
370: * convenience method will build, or add to an existing attributes object,
371: * the attributes detailed in the AttributeMap.
372: *
373: * @param namespaces
374: * SAX Helper class to keep track of namespaces able to determine
375: * the correct prefix for a given namespace URI.
376: * @param attributes
377: * An existing SAX AttributesImpl object to add attributes too.
378: * If the value is null then a new attributes object will be
379: * created to house the attributes.
380: * @param attributeMap
381: * A map of attributes and values.
382: * @return
383: */
384: private AttributesImpl map2sax(Namespace elementNamespace,
385: NamespaceSupport namespaces, AttributesImpl attributes,
386: AttributeMap attributeMap) {
387:
388: if (attributes == null)
389: attributes = new AttributesImpl();
390: if (attributeMap != null) {
391: // Figure out the namespace issue
392: Namespace namespace = attributeMap.getNamespace();
393: String URI;
394: if (namespace != null)
395: URI = namespace.URI;
396: else
397: URI = WingConstants.DRI.URI;
398:
399: String prefix = namespaces.getPrefix(URI);
400:
401: // copy each one over.
402: for (String name : attributeMap.keySet()) {
403: String value = attributeMap.get(name);
404: if (value == null)
405: continue;
406:
407: // If the indended namespace is the element's namespace then we
408: // leave
409: // off the namespace declaration because w3c say's its redundent
410: // and breaks lots of xsl stuff.
411: if (elementNamespace.URI.equals(URI))
412: attributes.addAttribute("", name, name, "CDATA",
413: value);
414: else
415: attributes.addAttribute(URI, name, qName(prefix,
416: name), "CDATA", value);
417: }
418: }
419: return attributes;
420: }
421:
422: /**
423: * Create the qName for the element with the given localName and namespace
424: * prefix.
425: *
426: * @param prefix
427: * (May be null) The namespace prefix.
428: * @param localName
429: * (Required) The element's local name.
430: * @return
431: */
432: private String qName(String prefix, String localName) {
433: if (prefix == null || prefix.equals(""))
434: return localName;
435: else
436: return prefix + ":" + localName;
437: }
438:
439: /**
440: * Dispose
441: */
442: public void dispose() {
443: this.context = null;
444: }
445: }
|