001: /**
002: * Copyright 2006-2007 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.buildutil;
016:
017: import java.io.File;
018: import java.io.FileInputStream;
019: import java.io.FileOutputStream;
020: import java.io.InputStream;
021: import java.io.OutputStream;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.Iterator;
025: import java.util.List;
026: import javax.xml.parsers.DocumentBuilder;
027: import javax.xml.parsers.DocumentBuilderFactory;
028: import javax.xml.transform.OutputKeys;
029: import javax.xml.transform.Result;
030: import javax.xml.transform.Source;
031: import javax.xml.transform.Transformer;
032: import javax.xml.transform.TransformerFactory;
033: import javax.xml.transform.dom.DOMSource;
034: import javax.xml.transform.stream.StreamResult;
035: import org.apache.xerces.dom.DocumentImpl;
036: import org.apache.xerces.dom.NodeImpl;
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.w3c.dom.Node;
040: import org.w3c.dom.NodeList;
041:
042: /**
043: * Utility to merge tag attribute information found from 'tag-class-descriptor' (contained in
044: * aranea.jar) with TLD generated by xdoclet and containing tags that extend concrete or abstract
045: * tag classes of Aranea JSP. Its purpose is to avoid unnecessary duplication of methods and
046: * xdoclet annotations; or needing always to keep Aranea JSP source ready when compiling tags
047: * depending on Aranea JSP.
048: *
049: * @author Taimo Peelo (taimo@araneaframework.org)
050: */
051: public class TcdAndTldMerger {
052: public static void main(String[] args) throws Exception {
053: if (args.length != 3) {
054: System.err.println("USAGE: TCD TLD outputTLD");
055: System.err
056: .println("If TCD is not found from file system, it is searched from classpath.");
057: System.err
058: .println("TLD and outputTLD may be the same, though it is not recommended.");
059: System.err
060: .println("This utility depends on xerces XML parser.");
061: System.err
062: .println("Tag classes referenced by TCD and/or TLD must all be available on classpath.");
063: System.exit(1);
064: }
065:
066: //System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
067:
068: String tcdName = args[0], tldName = args[1], outputTLD = args[2];
069:
070: File firstFile = new File(tcdName);
071: InputStream first = firstFile.exists() ? new FileInputStream(
072: tcdName) : TcdAndTldMerger.class.getClassLoader()
073: .getResourceAsStream(tcdName);
074:
075: if (first == null) {
076: System.err.println(tcdName
077: + " was not found from filesystem or classpath.");
078: System.exit(1);
079: }
080:
081: File second = new File(tldName);
082:
083: if (!second.exists() || !second.canRead()) {
084: System.err.println(tldName + " unreadable.");
085: System.exit(1);
086: }
087:
088: File output = new File(outputTLD);
089:
090: process(first, second, output);
091: }
092:
093: public static void process(InputStream first, File second,
094: File output) throws Exception {
095: DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
096: .newInstance();
097: DocumentBuilder docBuilder = docBuilderFactory
098: .newDocumentBuilder();
099:
100: Document fDoc = docBuilder.parse(first);
101: Document sDoc = docBuilder.parse(second);
102:
103: NodeList sTags = sDoc.getElementsByTagName("tag");
104:
105: for (int i = 0; i < sTags.getLength(); i++) {
106: Node current = sTags.item(i);
107: NodeList children = current.getChildNodes();
108: for (int j = 0; j < children.getLength(); j++) {
109: Node node = children.item(j);
110: if (node.getNodeName().equals("tag-class")) {
111: String tagClassName = ((NodeImpl) node)
112: .getTextContent();
113: if (tagClassName == null)
114: continue;
115: Class tagClazz = Class.forName(tagClassName);
116: while (tagClazz.getSuperclass() != null) {
117: List additionalAttributes = getAttributesFromTCD(
118: fDoc, tagClazz.getSuperclass()
119: .getName());
120: for (Iterator it = additionalAttributes
121: .iterator(); it.hasNext();) {
122: Node additional = (Node) it.next();
123: String attrName = ((NodeImpl) ((Element) additional)
124: .getElementsByTagName("name").item(
125: 0)).getTextContent();
126:
127: // attribute from parentclass should only be added if it does not exist already
128: NodeList currentAttrs = ((Element) current)
129: .getElementsByTagName("attribute");
130:
131: boolean found = false;
132: for (int zz = 0; zz < currentAttrs
133: .getLength(); zz++) {
134: if (((NodeImpl) ((Element) currentAttrs
135: .item(zz))
136: .getElementsByTagName("name")
137: .item(0)).getTextContent()
138: .equals(attrName)) {
139: found = true;
140: break;
141: }
142: }
143:
144: if (found)
145: continue;
146:
147: current.appendChild(((DocumentImpl) sDoc)
148: .adoptNode((additional
149: .cloneNode(true))));
150: }
151:
152: // if any supertag has extra attributes, it should have them all
153: if (additionalAttributes.size() > 0) {
154: System.out.println(additionalAttributes
155: .size()
156: + " attributes for '"
157: + tagClassName
158: + "' found from '"
159: + tagClazz.getSuperclass()
160: .getName() + "'.");
161: break;
162: }
163:
164: tagClazz = tagClazz.getSuperclass();
165: }
166: }
167: }
168: }
169:
170: Source input = new DOMSource(sDoc);
171: OutputStream ostream = new FileOutputStream(output);
172: Result out = new StreamResult(ostream);
173:
174: TransformerFactory xformFactory = TransformerFactory
175: .newInstance();
176:
177: try {
178: Transformer idTransformer = xformFactory.newTransformer();
179:
180: if (sDoc.getDoctype() != null) {
181: String publicValue = (sDoc.getDoctype().getPublicId());
182: idTransformer.setOutputProperty(
183: OutputKeys.DOCTYPE_PUBLIC, publicValue);
184:
185: String systemValue = (sDoc.getDoctype().getSystemId());
186: idTransformer.setOutputProperty(
187: OutputKeys.DOCTYPE_SYSTEM, systemValue);
188:
189: idTransformer.setOutputProperty(OutputKeys.INDENT,
190: "yes");
191: }
192:
193: idTransformer.transform(input, out);
194:
195: } catch (Exception e) {
196: e.printStackTrace();
197: } finally {
198: ostream.flush();
199: ostream.close();
200: }
201: }
202:
203: public static List getAttributesFromTCD(Document tcd,
204: String tagClass) {
205: NodeList nodes = tcd.getElementsByTagName("tag-class");
206: Node tagClassNode = null;
207: for (int i = 0; i < nodes.getLength(); i++) {
208: Node current = nodes.item(i);
209: if (((NodeImpl) current).getTextContent() != null
210: && ((NodeImpl) current).getTextContent().equals(
211: tagClass)) {
212: tagClassNode = current;
213: break;
214: }
215: }
216:
217: if (tagClassNode == null)
218: return Collections.EMPTY_LIST;
219:
220: Node node = tagClassNode;
221: while (node.getPreviousSibling() != null) {
222: node = node.getPreviousSibling();
223: }
224:
225: List result = new ArrayList();
226:
227: while (node.getNextSibling() != null) {
228: if (node.getNextSibling().getNodeName().equals("attribute"))
229: result.add(node.getNextSibling());
230:
231: node = node.getNextSibling();
232: }
233:
234: return result;
235: }
236: }
|