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 }