001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.hivemind.lib.groovy;
016
017 import java.util.HashMap;
018 import java.util.Map;
019
020 import groovy.xml.SAXBuilder;
021
022 import org.xml.sax.Attributes;
023 import org.xml.sax.ContentHandler;
024 import org.xml.sax.Locator;
025 import org.xml.sax.helpers.AttributesImpl;
026
027 /**
028 * The HiveMindBuilder is a <a href="http://groovy.codehaus.org/GroovyMarkup">groovy markup builder
029 * </a> which can be used to define HiveMind
030 * {@link org.apache.hivemind.parse.ModuleDescriptor module descriptors} using a Groovy script. A
031 * single Groovy script must only define one module descriptor.
032 * <p>
033 * The markup in the Groovy script is equivalent to the XML markup for module descriptors. The only
034 * difference being that any dashes in element names and attribute names (which would confuse the
035 * Groovy parser) are replaced by a camelCase notation. So for example
036 * <code>configuration-point</code> becomes <code>configurationPoint</code> in a Groovy script.
037 *
038 * @since 1.1
039 * @author Knut Wannheden
040 */
041 public class HiveMindBuilder extends SAXBuilder
042 {
043 public static final Locator GROOVY_LOCATOR = new GroovyLocator();
044
045 private static final Map CAMEL_TO_HYPHEN_MAP = new HashMap();
046
047 public HiveMindBuilder(ContentHandler parser)
048 {
049 super(parser);
050
051 parser.setDocumentLocator(GROOVY_LOCATOR);
052 }
053
054 protected void nodeCompleted(Object parent, Object node)
055 {
056 super.nodeCompleted(parent, getHyphenatedName(node.toString()));
057 }
058
059 protected void doStartElement(Object name, Attributes attributes)
060 {
061 super.doStartElement(
062 getHyphenatedName(name.toString()),
063 getHyphenatedAttributes(attributes));
064 }
065
066 private String getHyphenatedName(String name)
067 {
068 String hyphenatedName = (String) CAMEL_TO_HYPHEN_MAP.get(name);
069
070 if (hyphenatedName == null)
071 {
072 char[] chars = name.toCharArray();
073
074 StringBuffer hyphenated = new StringBuffer();
075
076 for (int i = 0; i < name.length(); i++)
077 {
078 if (Character.isUpperCase(chars[i]))
079 hyphenated.append('-').append(Character.toLowerCase(chars[i]));
080 else
081 hyphenated.append(chars[i]);
082 }
083
084 hyphenatedName = hyphenated.toString();
085
086 CAMEL_TO_HYPHEN_MAP.put(name, hyphenatedName);
087 }
088
089 return hyphenatedName;
090 }
091
092 private Attributes getHyphenatedAttributes(Attributes attributes)
093 {
094 AttributesImpl result = (AttributesImpl) attributes;
095
096 for (int i = 0; i < result.getLength(); i++)
097 {
098 result.setLocalName(i, getHyphenatedName(result.getLocalName(i)));
099 }
100
101 return result;
102 }
103
104 private static class GroovyLocator implements Locator
105 {
106 public String getPublicId()
107 {
108 return null;
109 }
110
111 public String getSystemId()
112 {
113 return null;
114 }
115
116 public int getLineNumber()
117 {
118 try
119 {
120 throw new Throwable();
121 }
122 catch (Throwable t)
123 {
124 StackTraceElement[] trace = t.getStackTrace();
125
126 for (int i = 0; i < trace.length; i++)
127 {
128 String fileName = trace[i].getFileName();
129 if (fileName != null && fileName.endsWith(".groovy"))
130 return trace[i].getLineNumber();
131 }
132 }
133
134 return -1;
135 }
136
137 public int getColumnNumber()
138 {
139 return -1;
140 }
141 }
142 }