001: /* ====================================================================
002: The Jicarilla Software License
003:
004: Copyright (c) 2003 Leo Simons.
005: All rights reserved.
006:
007: Permission is hereby granted, free of charge, to any person obtaining
008: a copy of this software and associated documentation files (the
009: "Software"), to deal in the Software without restriction, including
010: without limitation the rights to use, copy, modify, merge, publish,
011: distribute, sublicense, and/or sell copies of the Software, and to
012: permit persons to whom the Software is furnished to do so, subject to
013: the following conditions:
014:
015: The above copyright notice and this permission notice shall be
016: included in all copies or substantial portions of the Software.
017:
018: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
019: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
020: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
021: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
022: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
023: TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
024: SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
025: ==================================================================== */
026: package org.jicarilla.collections;
027:
028: import org.apache.avalon.framework.configuration.Configuration;
029: import org.apache.avalon.framework.configuration.ConfigurationException;
030: import org.apache.avalon.framework.configuration.ConfigurationUtil;
031: import org.apache.avalon.framework.configuration.DefaultConfiguration;
032: import org.apache.avalon.framework.context.Context;
033: import org.apache.avalon.framework.context.DefaultContext;
034: import org.apache.avalon.framework.parameters.Parameters;
035: import org.w3c.dom.CharacterData;
036: import org.w3c.dom.Element;
037: import org.w3c.dom.NamedNodeMap;
038: import org.w3c.dom.NodeList;
039:
040: import java.util.Iterator;
041: import java.util.Map;
042: import java.util.Properties;
043:
044: /**
045: * Provides conversion to and from various other objects.
046: *
047: * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
048: * @version $Id: NodeUtil.java,v 1.3 2004/02/26 16:51:54 lsimons Exp $
049: */
050: public class NodeUtil {
051: public final static Node EMPTY_NODE = new DefaultNode("empty");
052:
053: /**
054: * Turns a Tree of Nodes into a tree of Context objects.
055: *
056: * @param node
057: * @return
058: */
059: public static Context toAvalonContext(final Node node) {
060: final DefaultContext c = new DefaultContext();
061:
062: // copy values
063: Iterator it = node.entrySet().iterator();
064: while (it.hasNext()) {
065: final Map.Entry entry = (Map.Entry) it.next();
066: final Object key = entry.getKey();
067: final Object value = entry.getValue();
068:
069: c.put(key, value);
070: }
071:
072: // copy children
073: it = node.iterator();
074: while (it.hasNext()) {
075: final Node child = (Node) it.next();
076:
077: // recurse
078: final String key = child.getName();
079: c.put(key, NodeUtil.toAvalonContext(child));
080: }
081: return c;
082: }
083:
084: public static Node fromAvalonConfiguration(final Configuration c) {
085: return fromAvalonConfiguration(c, "value");
086: }
087:
088: public static Node fromAvalonConfiguration(final Configuration c,
089: final Object valueKey) {
090: final DefaultNode node = new DefaultNode(c.getName());
091:
092: // copy value as "value"
093: try {
094: final String value = c.getValue();
095: node.put(valueKey, value);
096: } catch (ConfigurationException ce) {
097: }
098:
099: // copy attributes as values
100: final String[] names = c.getAttributeNames();
101: for (int i = 0; i < names.length; i++) {
102: try {
103: node.put(names[i], c.getAttribute(names[i]));
104: } catch (ConfigurationException ce) { /* won't happen */
105: }
106: }
107:
108: // copy children as children
109: final Configuration[] children = c.getChildren();
110: for (int i = 0; i < children.length; i++) {
111: // recurse
112: node.addChild(NodeUtil.fromAvalonConfiguration(children[i],
113: valueKey));
114: }
115:
116: return node;
117: }
118:
119: public static Configuration toAvalonConfiguration(final Node node) {
120: final DefaultConfiguration c = new DefaultConfiguration(node
121: .getName());
122:
123: // copy attributes
124: Iterator it = node.entrySet().iterator();
125: while (it.hasNext()) {
126: final Map.Entry entry = (Map.Entry) it.next();
127: final Object key = entry.getKey();
128: final Object value = entry.getValue();
129:
130: c.setAttribute(key.toString(), value.toString());
131: }
132:
133: // copy children
134: it = node.iterator();
135: while (it.hasNext()) {
136: final Node child = (Node) it.next();
137:
138: // recurse
139: c.addChild(NodeUtil.toAvalonConfiguration(child));
140: }
141: return c;
142: }
143:
144: public static Parameters toParameters(final Node node) {
145: return Parameters.fromProperties(NodeUtil.toProperties(node));
146: }
147:
148: public static Node fromParameters(final Parameters parameters) {
149: return NodeUtil.fromProperties(Parameters
150: .toProperties(parameters));
151: }
152:
153: public static Element toElement(final Node node) {
154: // defer to the implementation of this stuff in avalon-framework
155: return ConfigurationUtil.toElement(NodeUtil
156: .toAvalonConfiguration(node));
157: }
158:
159: public static Node fromElement(final Element element) {
160: // defer to the implementation of this stuff in avalon-framework
161: return NodeUtil
162: .fromAvalonConfiguration(elementToAvalonConfiguration(element));
163: }
164:
165: /**
166: * Also flattens, and converts keys and values to strings.
167: *
168: * node.getChild( "bla" ).getChild( "bla2" ).get( "blah" )
169: *
170: * becomes
171: *
172: * properties.getProperty( "bla.bla2.blah" );
173: *
174: * @param node
175: * @return
176: */
177: public static Properties toProperties(final Node node) {
178: final Properties p = new Properties();
179:
180: // copy values
181: Iterator it = node.entrySet().iterator();
182: while (it.hasNext()) {
183: final Map.Entry entry = (Map.Entry) it.next();
184: final Object key = entry.getKey();
185: final Object value = entry.getValue();
186:
187: // store as strings even though the class doesn't
188: // require it -- it is what the world expects from
189: // a Properties object
190: p.put(key.toString(), value.toString());
191: }
192:
193: // copy children
194: it = node.iterator();
195: while (it.hasNext()) {
196: final Node child = (Node) it.next();
197:
198: // recurse
199: toProperties(p, node.getName(), ".", child);
200: }
201: return p;
202: }
203:
204: /**
205: * Converts properties to nested node tree using '.' as the
206: * seperator. So
207: *
208: * properties.getProperty( "bla.bla2.blah" );
209: *
210: * becomes
211: *
212: * node.getChild( "bla" ).getChild( "bla2" ).get( "blah" )
213: *
214: * @param p
215: * @return
216: */
217: public static Node fromProperties(final Properties p) {
218: return fromProperties(p, null, ".");
219: }
220:
221: public static Node fromProperties(final Properties p,
222: final String prefix, final String separator) {
223: final DefaultNode root = new DefaultNode("");
224:
225: final Iterator it = p.keySet().iterator();
226: while (it.hasNext()) {
227: String key = it.next().toString();
228: key = key.trim();
229:
230: if (key == null)
231: continue;
232:
233: if (key.startsWith(prefix))
234: key = key.substring(prefix.length());
235:
236: final String[] path = key.split(separator);
237: final Object value = p.get(key);
238: addNodeAtLocation(path, value, root);
239: }
240: return root;
241: }
242:
243: private static void addNodeAtLocation(final String[] path,
244: final Object value, final DefaultNode root) {
245: final DefaultNode node = new DefaultNode(path[0]);
246:
247: if (path.length == 0) {
248: root.setContents(value);
249: return;
250: }
251:
252: if (!root.containsChild(node)) {
253: root.addChild(node);
254: }
255:
256: final String[] subpath = new String[path.length - 1];
257: System.arraycopy(path, 1, subpath, 0, subpath.length);
258:
259: addNodeAtLocation(subpath, value, node);
260: }
261:
262: /**
263: * Helper method for the toProperties() method.
264: *
265: * @param p
266: * @param prefix
267: * @param separator
268: * @param node
269: */
270: public static void toProperties(final Properties p,
271: final String prefix, final String separator, final Node node) {
272: // copy values
273: Iterator it = node.entrySet().iterator();
274: while (it.hasNext()) {
275: final Map.Entry entry = (Map.Entry) it.next();
276: final Object key = entry.getKey();
277: final Object value = entry.getValue();
278:
279: // store as strings even though the class doesn't
280: // require it -- it is what the world expects from
281: // a Properties object
282: p
283: .put(prefix + separator + key.toString(), value
284: .toString());
285: }
286:
287: it = node.iterator();
288: while (it.hasNext()) {
289: final Node child = (Node) it.next();
290:
291: // recurse
292: toProperties(p, prefix + separator + node.getName(),
293: separator, child);
294: }
295: }
296:
297: /*
298: * This method is governed by the Apache Software License. It came from
299: * the ConfigurationUtil class in avalon-framework; it is included here
300: * until the next release of the avalon-framework library.
301: *
302: * ====================================================================
303: * The Apache Software License, Version 1.1
304: *
305: * Copyright (c) 1997-2003 The Apache Software Foundation. All rights
306: * reserved.
307: *
308: * Redistribution and use in source and binary forms, with or without
309: * modification, are permitted provided that the following conditions
310: * are met:
311: *
312: * 1. Redistributions of source code must retain the above copyright
313: * notice, this list of conditions and the following disclaimer.
314: *
315: * 2. Redistributions in binary form must reproduce the above copyright
316: * notice, this list of conditions and the following disclaimer in
317: * the documentation and/or other materials provided with the
318: * distribution.
319: *
320: * 3. The end-user documentation included with the redistribution,
321: * if any, must include the following acknowledgment:
322: * "This product includes software developed by the
323: * Apache Software Foundation (http://www.apache.org/)."
324: * Alternately, this acknowledgment may appear in the software
325: * itself, if and wherever such third-party acknowledgments
326: * normally appear.
327: *
328: * 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
329: * must not be used to endorse or promote products derived from this
330: * software without prior written permission. For written
331: * permission, please contact apache@apache.org.
332: *
333: * 5. Products derived from this software may not be called "Apache",
334: * nor may "Apache" appear in their name, without prior written
335: * permission of the Apache Software Foundation.
336: *
337: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
338: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
339: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
340: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
341: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
342: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
344: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
345: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
346: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
347: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
348: * SUCH DAMAGE.
349: * ====================================================================
350: *
351: * This software consists of voluntary contributions made by many
352: * individuals on behalf of the Apache Software Foundation. For more
353: * information on the Apache Software Foundation, please see
354: * <http://www.apache.org/>.
355: */
356: private static Configuration elementToAvalonConfiguration(
357: final Element element) {
358: final DefaultConfiguration configuration = new DefaultConfiguration(
359: element.getNodeName(), "dom-created");
360: final NamedNodeMap attributes = element.getAttributes();
361: final int length = attributes.getLength();
362: for (int i = 0; i < length; i++) {
363: final org.w3c.dom.Node node = attributes.item(i);
364: final String name = node.getNodeName();
365: final String value = node.getNodeValue();
366: configuration.setAttribute(name, value);
367: }
368:
369: String content = null;
370: final NodeList nodes = element.getChildNodes();
371: final int count = nodes.getLength();
372: for (int i = 0; i < count; i++) {
373: final org.w3c.dom.Node node = nodes.item(i);
374: if (node instanceof Element) {
375: final Configuration child = elementToAvalonConfiguration((Element) node);
376: configuration.addChild(child);
377: } else if (node instanceof CharacterData) {
378: final CharacterData data = (CharacterData) node;
379: content += data.getData();
380: }
381: }
382:
383: if (content != null) {
384: configuration.setValue(content);
385: }
386:
387: return configuration;
388: }
389: }
|