001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.datatypes.util.xml;
011:
012: import org.mmbase.datatypes.processors.*;
013: import java.util.*;
014: import org.w3c.dom.*;
015:
016: import org.mmbase.util.*;
017: import org.mmbase.util.functions.Parameters;
018: import org.mmbase.util.functions.BeanFunction;
019: import org.mmbase.util.xml.DocumentReader;
020: import org.mmbase.util.logging.*;
021: import org.mmbase.util.transformers.*;
022:
023: /**
024: * Static methods used for parsing of datatypes.xml
025: *
026: * @author Michiel Meeuwissen
027: * @version $Id: DataTypeXml.java,v 1.12 2007/11/01 09:44:37 michiel Exp $
028: * @since MMBase-1.8
029: **/
030: public abstract class DataTypeXml {
031:
032: private static final Logger log = Logging
033: .getLoggerInstance(DataTypeXml.class);
034:
035: /**
036: * Returns whether an element has a certain attribute, either an unqualified attribute or an attribute that fits in the
037: * default namespace
038: */
039: public static boolean hasAttribute(Element element, String localName) {
040: return DocumentReader.hasAttribute(element,
041: DataTypeReader.NAMESPACE_DATATYPES, localName);
042: }
043:
044: /**
045: * Returns the value of a certain attribute, either an unqualified attribute or an attribute that fits in the
046: * default namespace
047: */
048: protected static String getAttribute(Element element,
049: String localName) {
050: return DocumentReader.getAttribute(element,
051: DataTypeReader.NAMESPACE_DATATYPES, localName);
052: }
053:
054: /**
055: * Reads a number of tags with 'xml:lang' attributes.
056: *
057: * @param tagName Wich tags to read. The bodies are the values.
058: * @param element From which element this tags must be childs.
059: * @param descriptions Existing LocalizedString instance or <code>null</code> if a new one must be created.
060: * @param defaultKey If the localized string was created with some silly automatic key, it can be provided here, in
061: * which case it will be changed if a tag withouth xml:lang is found, or with xml:lang equals the current default.
062: * It can also be <code>null</code>
063: * @return A new LocalizedString or the updated 'descriptions' parameter if that was not <code>null</code>
064: */
065:
066: public static LocalizedString getLocalizedDescription(
067: final String tagName, final Element element,
068: LocalizedString descriptions, final String defaultKey) {
069: if (descriptions == null)
070: descriptions = new LocalizedString(null);
071: descriptions.fillFromXml(tagName, element);
072: if (defaultKey != null
073: && descriptions.getKey().equals(defaultKey)) {
074: descriptions.setKey(descriptions.get(LocalizedString
075: .getDefault()));
076: }
077: return descriptions;
078: }
079:
080: public static boolean getBooleanValue(Element element,
081: boolean defaultValue) {
082: if (hasAttribute(element, "value")) {
083: return Boolean.valueOf(getAttribute(element, "value"))
084: .booleanValue();
085: } else {
086: return defaultValue;
087: }
088: }
089:
090: public static Processor chainProcessors(Processor processor1,
091: Processor processor2) {
092: Processor processor = processor1;
093: if (processor == null || processor instanceof CopyProcessor) {
094: processor = processor2;
095: } else if (processor2 instanceof CopyProcessor) {
096: processor = processor1;
097: } else if (processor instanceof ChainedProcessor) {
098: ((ChainedProcessor) processor).add(processor2);
099: } else {
100: ChainedProcessor chain = new ChainedProcessor();
101: chain.add(processor1);
102: chain.add(processor2);
103: processor = chain;
104: }
105: return processor;
106: }
107:
108: public static CommitProcessor chainProcessors(
109: CommitProcessor processor1, CommitProcessor processor2) {
110: CommitProcessor processor = processor1;
111: if (processor == null
112: || processor instanceof EmptyCommitProcessor) {
113: processor = processor2;
114: } else if (processor2 instanceof EmptyCommitProcessor) {
115: processor = processor1;
116: } else if (processor instanceof ChainedCommitProcessor) {
117: ((ChainedCommitProcessor) processor).add(processor2);
118: } else {
119: ChainedCommitProcessor chain = new ChainedCommitProcessor();
120: chain.add(processor1);
121: chain.add(processor2);
122: processor = chain;
123: }
124: return processor;
125: }
126:
127: private static Object getParameterValue(Element param) {
128: String stringValue = param.getAttribute("value");
129: if (stringValue == null || "".equals(stringValue)) {
130: stringValue = DocumentReader.getNodeTextValue(param, false);
131: NodeList childNodes = param.getChildNodes();
132: Collection<Entry<String, Object>> subParams = null;
133: for (int i = 0; i < childNodes.getLength(); i++) {
134: Node child = childNodes.item(i);
135: if (!(child instanceof Element))
136: continue;
137: if (child.getLocalName().equals("param")) {
138: Element subParam = (Element) child;
139: if (subParams == null)
140: subParams = new ArrayList<Entry<String, Object>>();
141: String name = subParam.getAttribute("name");
142: subParams.add(new Entry<String, Object>(name,
143: getParameterValue(subParam)));
144: }
145: }
146: if (subParams != null) {
147: if (stringValue != null
148: && !stringValue.trim().equals("")) {
149: log
150: .warn(""
151: + param
152: + " has both a text value and sub parameters, ignoring the text value '"
153: + stringValue + "'");
154: }
155: return subParams;
156: } else {
157: return stringValue;
158: }
159: } else {
160: NodeList childNodes = param.getChildNodes();
161: if (childNodes.getLength() > 0) {
162: log
163: .warn("Using value attribute together with child nodes on "
164: + param);
165: }
166: return stringValue;
167: }
168: }
169:
170: private static void fillParameters(Element paramContainer,
171: Parameters params) {
172: NodeList childNodes = paramContainer.getChildNodes();
173: for (int i = 0; i < childNodes.getLength(); i++) {
174: if (childNodes.item(i) instanceof Element) {
175: Element paramElement = (Element) childNodes.item(i);
176: if ("param".equals(paramElement.getLocalName())) {
177: String name = paramElement.getAttribute("name");
178: Object value = getParameterValue(paramElement);
179: params.set(name, value);
180: }
181: }
182: }
183: }
184:
185: /**
186: * @since MMBase-1.8.5
187: */
188: private static String fillBeanParameters(Element paramContainer,
189: Object bean) {
190: try {
191: Parameters params = null;
192: BeanFunction function = null;
193: NodeList childNodes = paramContainer.getChildNodes();
194: for (int i = 0; i < childNodes.getLength(); i++) {
195: if (childNodes.item(i) instanceof Element) {
196: Element paramElement = (Element) childNodes.item(i);
197: if ("param".equals(paramElement.getLocalName())) {
198: String name = paramElement.getAttribute("name");
199: Object value = getParameterValue(paramElement);
200: if (params == null) {
201: function = new BeanFunction(bean,
202: "toString"); // any object has 'toString'.
203: params = function.createParameters();
204: params.setAutoCasting(true);
205: }
206: params.set(name, value);
207: }
208: }
209: }
210: if (params != null) {
211: Object res = function.getFunctionValue(params); // calling the function actually calls setters
212: return "" + res;
213: }
214: } catch (Exception e) {
215: log.error(e.getMessage(), e);
216: }
217: return null;
218: }
219:
220: public static Processor createProcessor(Element processorElement) {
221: Processor processor = null;
222: NodeList childNodes = processorElement.getChildNodes();
223: for (int k = 0; k < childNodes.getLength(); k++) {
224: if (childNodes.item(k) instanceof Element) {
225: Element classElement = (Element) childNodes.item(k);
226: if ("class".equals(classElement.getLocalName())) {
227: String clazString = classElement
228: .getAttribute("name");
229: if (clazString.equals("")) {
230: log.warn("No 'name' attribute on "
231: + org.mmbase.util.xml.XMLWriter.write(
232: classElement, true)
233: + ", trying body");
234: clazString = DocumentReader
235: .getNodeTextValue(classElement);
236: }
237: try {
238: Class claz = Class.forName(clazString);
239: Processor newProcessor;
240: if (CharTransformer.class
241: .isAssignableFrom(claz)) {
242: CharTransformer charTransformer = Transformers
243: .getCharTransformer(clazString,
244: null, " valueintercepter ",
245: false);
246: if (charTransformer != null) {
247: newProcessor = new CharTransformerProcessor(
248: charTransformer);
249: fillBeanParameters(classElement,
250: newProcessor);
251: } else {
252: continue;
253: }
254: } else if (Processor.class
255: .isAssignableFrom(claz)) {
256: newProcessor = (Processor) claz
257: .newInstance();
258: fillBeanParameters(classElement,
259: newProcessor);
260: } else if (ParameterizedTransformerFactory.class
261: .isAssignableFrom(claz)) {
262: ParameterizedTransformerFactory factory = (ParameterizedTransformerFactory) claz
263: .newInstance();
264: Parameters params = factory
265: .createParameters();
266: fillParameters(classElement, params);
267: Transformer transformer = factory
268: .createTransformer(params);
269: newProcessor = new CharTransformerProcessor(
270: (CharTransformer) transformer);
271: } else if (ParameterizedProcessorFactory.class
272: .isAssignableFrom(claz)) {
273: ParameterizedProcessorFactory factory = (ParameterizedProcessorFactory) claz
274: .newInstance();
275: Parameters params = factory
276: .createParameters();
277: fillParameters(classElement, params);
278: newProcessor = factory
279: .createProcessor(params);
280: } else {
281: log
282: .error("Found class "
283: + clazString
284: + " is not a Processor or a CharTransformer, nor a factory for those.");
285: continue;
286: }
287: processor = chainProcessors(processor,
288: newProcessor);
289: } catch (ClassNotFoundException cnfe) {
290: log.error("Class '" + clazString
291: + "' could not be found");
292: } catch (IllegalAccessException iae) {
293: log.error("Class " + clazString
294: + " may not be instantiated. " + iae);
295: } catch (InstantiationException ie) {
296: log
297: .error("Class " + clazString
298: + " can not be instantiated. "
299: + ie, ie);
300: }
301:
302: }
303: }
304: }
305: return processor == null ? CopyProcessor.getInstance()
306: : processor;
307: }
308:
309: public static CommitProcessor createCommitProcessor(
310: Element processorElement) {
311: CommitProcessor processor = null;
312: NodeList childNodes = processorElement.getChildNodes();
313: for (int k = 0; k < childNodes.getLength(); k++) {
314: if (childNodes.item(k) instanceof Element) {
315: Element classElement = (Element) childNodes.item(k);
316: if ("class".equals(classElement.getLocalName())) {
317: String clazString = classElement
318: .getAttribute("name");
319: if (clazString.equals("")) {
320: log.warn("No 'name' attribute on "
321: + org.mmbase.util.xml.XMLWriter.write(
322: classElement, true)
323: + ", trying body");
324: clazString = DocumentReader
325: .getNodeTextValue(classElement);
326: }
327: try {
328: Class claz = Class.forName(clazString);
329: CommitProcessor newProcessor;
330: if (CommitProcessor.class
331: .isAssignableFrom(claz)) {
332: newProcessor = (CommitProcessor) claz
333: .newInstance();
334: fillBeanParameters(classElement,
335: newProcessor);
336: } else if (ParameterizedCommitProcessorFactory.class
337: .isAssignableFrom(claz)) {
338: ParameterizedCommitProcessorFactory factory = (ParameterizedCommitProcessorFactory) claz
339: .newInstance();
340: Parameters params = factory
341: .createParameters();
342: fillParameters(classElement, params);
343: newProcessor = factory
344: .createProcessor(params);
345: } else {
346: log
347: .error("Found class "
348: + clazString
349: + " is not a CommitProcessor or a factory for that.");
350: continue;
351: }
352: processor = chainProcessors(processor,
353: newProcessor);
354: } catch (ClassNotFoundException cnfe) {
355: log.error("Class '" + clazString
356: + "' could not be found");
357: } catch (IllegalAccessException iae) {
358: log.error("Class " + clazString
359: + " may not be instantiated");
360: } catch (InstantiationException ie) {
361: log.error("Class " + clazString
362: + " can not be instantiated");
363: }
364:
365: }
366: }
367: }
368: return processor == null ? EmptyCommitProcessor.getInstance()
369: : processor;
370: }
371:
372: public static String getValue(Element element) {
373: if (hasAttribute(element, "value")) {
374: return getAttribute(element, "value");
375: } else {
376: throw new IllegalArgumentException("no 'value' argument");
377: }
378: }
379:
380: public static long getLongValue(Element element) {
381: if (hasAttribute(element, "value")) {
382: return Long.parseLong(getAttribute(element, "value"));
383: } else {
384: throw new IllegalArgumentException("no 'value' argument");
385: }
386: }
387: }
|