001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.framework.common.utils;
042:
043: import java.io.BufferedReader;
044: import java.io.BufferedWriter;
045: import java.io.File;
046: import java.io.FileInputStream;
047: import java.io.FileWriter;
048: import java.io.IOException;
049: import java.io.InputStream;
050: import java.io.InputStreamReader;
051: import java.io.Reader;
052: import java.io.StringReader;
053: import java.net.URL;
054: import java.util.HashMap;
055: import java.util.Map;
056:
057: import javax.xml.parsers.DocumentBuilder;
058: import javax.xml.parsers.DocumentBuilderFactory;
059: import javax.xml.transform.Transformer;
060: import javax.xml.transform.TransformerFactory;
061: import javax.xml.transform.dom.DOMResult;
062: import javax.xml.transform.dom.DOMSource;
063:
064: import org.w3c.dom.Attr;
065: import org.w3c.dom.CharacterData;
066: import org.w3c.dom.Document;
067: import org.w3c.dom.Element;
068: import org.w3c.dom.NamedNodeMap;
069: import org.w3c.dom.Node;
070: import org.w3c.dom.NodeList;
071: import org.w3c.dom.Text;
072: import org.xml.sax.InputSource;
073:
074: import com.sun.sql.framework.exception.BaseException;
075: import com.sun.sql.framework.utils.Logger;
076: import com.sun.sql.framework.utils.StringUtil;
077:
078: /**
079: * Static class that contains utility methods for XML
080: *
081: * @author Ahimanikya Satapathy
082: * @version $Revision$
083: */
084: public class XmlUtil {
085:
086: /** XML_SUBSTITUTES is a list of character substitutes for XML_ILLEGALS. */
087: public static final String[] XML_ALLOWABLES = { "&", """,
088: "'", "<", ">" };
089:
090: /** XML_ILLEGALS is a list of character strings not parseable by XML. */
091: public static final String[] XML_ILLEGALS = { "&", "\"", "'", "<",
092: ">" };
093:
094: /** HTML_SUBSTITUTES is a list of character substitutes for XML_ILLEGALS. */
095: public static final String[] HTML_ALLOWABLES = { "&", """,
096: "<", ">" };
097:
098: /** HTML_ILLEGALS is a list of character strings not parseable by XML. */
099: public static final String[] HTML_ILLEGALS = { "&", "\"", "<", ">" };
100:
101: /** Runtime context for this class. */
102: private static final String LOG_CATEGORY = XmlUtil.class.getName();
103:
104: private static Map xslDocumentMap = new HashMap();
105:
106: private static String ETL_COLLAB_FOLDER = getEtlCollabFolder();
107:
108: private static final synchronized String getEtlCollabFolder() {
109: String nbUsrDir = System.getProperty("netbeans.user");
110: if ((nbUsrDir == null) || ("".equals(nbUsrDir))) {
111: nbUsrDir = ".." + File.separator + "usrdir";
112: }
113: return nbUsrDir + File.separator + "eTL" + File.separator
114: + "collab" + File.separator;
115: }
116:
117: /**
118: * Writes given XML string to file with given filename.
119: *
120: * @param fileName name of file to receive XML output.
121: * @param xmlString XML content to write out.
122: */
123: public static void dumpXMLString(String fileName, String xmlString) {
124: if (!Logger.isDebugEnabled(LOG_CATEGORY)) {
125: return;
126: }
127:
128: try {
129: File file = new File(ETL_COLLAB_FOLDER + fileName);
130: file.getParentFile().mkdirs();
131: BufferedWriter out = new BufferedWriter(
132: new FileWriter(file));
133: out.write(xmlString);
134: out.close();
135: } catch (IOException ioe) {
136: // ignore
137: }
138: }
139:
140: /**
141: * The escapeXML method is used to replace illegal xml characters with their
142: * acceptable equivalents.
143: *
144: * @param string String requiring replacement of characters.
145: * @return String with illegal characters translated.
146: */
147: public static String escapeXML(String string) {
148: return StringUtil.replaceInString(string, XML_ILLEGALS,
149: XML_ALLOWABLES);
150: }
151:
152: /**
153: * The escapeXML method is used to replace illegal xml characters with their
154: * acceptable equivalents.
155: *
156: * @param string String requiring replacement of characters.
157: * @return String with illegal characters translated.
158: */
159: public static String escapeHTML(String string) {
160: return StringUtil.replaceInString(string, HTML_ILLEGALS,
161: HTML_ALLOWABLES);
162: }
163:
164: /**
165: * Extracts attribute, if any, with given name from given DOM element.
166: *
167: * @param element DOM element in which to locate attribute
168: * @param attrName name of attribute to extract
169: * @param nullIfEmptyString indicates whether to return null if attribute is not found
170: * or returns as empty string
171: * @return attribute value as String. If parsing the element for attrName results in
172: * an empty String (or if either element or attrName are null), then return
173: * null if nullIfEmptyString is true, else return an empty String.
174: */
175: public static String getAttributeFrom(Element element,
176: String attrName, boolean nullIfEmptyString) {
177: if (element == null || attrName == null) {
178: return (nullIfEmptyString) ? null : "";
179: }
180:
181: String val = element.getAttribute(attrName);
182: if ("".equals(val) && nullIfEmptyString) {
183: val = null;
184: }
185:
186: return val;
187: }
188:
189: /**
190: * Reads in String XML content from given BufferedReader and converts it to a DOM
191: * Element for parsing.
192: *
193: * @param reader BufferedReader supplying String XML content
194: * @return XML content as a DOM element
195: */
196: public static Element loadXMLFile(BufferedReader reader) {
197: DocumentBuilderFactory dbf;
198: DocumentBuilder db;
199: Document doc;
200: Element modelElement = null;
201: if (reader == null) {
202: Logger.print(Logger.ERROR, LOG_CATEGORY,
203: "Invalid stream, nothing to load...");
204: }
205:
206: try {
207: dbf = DocumentBuilderFactory.newInstance();
208: db = dbf.newDocumentBuilder();
209: doc = db.parse(new InputSource(reader));
210:
211: modelElement = doc.getDocumentElement();
212: } catch (Exception e) {
213: Logger.printThrowable(Logger.ERROR, LOG_CATEGORY, null,
214: "Could not load XML: " + reader, e);
215: }
216: return modelElement;
217: }
218:
219: /**
220: * Reads in String XML content from given reader and converts it to a DOM Element for
221: * parsing.
222: *
223: * @param String supplying XML content
224: * @return XML content as a DOM element
225: */
226: public static Element loadXMLString(String xmlString) {
227: return loadXMLFile(new BufferedReader(new StringReader(
228: xmlString)));
229: }
230:
231: /**
232: * Reads in String XML content from given reader and converts it to a DOM Element for
233: * parsing.
234: *
235: * @param aReader Reader supplying String XML content
236: * @return XML content as a DOM element
237: */
238: public static Element loadXMLFile(Reader aReader) {
239: return loadXMLFile(new BufferedReader(aReader));
240: }
241:
242: /**
243: * Reads in String XML content from a file with the given name and converts it to a
244: * DOM Element for parsing.
245: *
246: * @param fileName name of file containing XML content
247: * @return XML content as a DOM element
248: */
249: public static Element loadXMLFile(String fileName) {
250: return loadXMLFile(fileName, null);
251: }
252:
253: /**
254: * Reads in String XML content from a file with the given name and converts it to a
255: * DOM Element for parsing.
256: *
257: * @param fileName name of file containing XML content
258: * @param classLoader ClassLoader to use in resolving <code>fileName</code>
259: * @return XML content as a DOM element
260: */
261: public static Element loadXMLFile(String fileName,
262: ClassLoader classLoader) {
263: InputStream istream = null;
264: Element element = null;
265:
266: if (classLoader == null) {
267: classLoader = XmlUtil.class.getClassLoader();
268: }
269:
270: if (StringUtil.isNullString(fileName)) {
271: Logger.print(Logger.ERROR, LOG_CATEGORY,
272: "Invalid file name, nothing to load...");
273: }
274:
275: try {
276: istream = classLoader.getResourceAsStream(fileName);
277: if (istream == null) {
278: File configFile = new File(fileName);
279:
280: if (configFile.exists()) {
281: fileName = configFile.getAbsolutePath();
282: istream = new FileInputStream(fileName);
283: }
284:
285: if (istream == null) {
286: Logger.print(Logger.ERROR, LOG_CATEGORY,
287: "configure",
288: "configure ERROR: Can't find file in classpath: "
289: + fileName);
290: return null;
291: }
292: }
293:
294: element = loadXMLFile(new BufferedReader(
295: new InputStreamReader(istream)));
296: if (element == null) {
297: throw new BaseException(LOG_CATEGORY, fileName
298: + " is empty");
299: }
300: } catch (Exception e) {
301: Logger.printThrowable(Logger.ERROR, LOG_CATEGORY, null,
302: "Could not load " + fileName, e);
303: } finally {
304: if (istream != null) {
305: try {
306: istream.close();
307: } catch (IOException e) {
308: // ignore this exception
309: }
310: }
311: }
312: return element;
313: }
314:
315: public static Element transform(URL xslFileUrl, Element sourceElem)
316: throws BaseException {
317: try {
318: TransformerFactory tFactory = TransformerFactory
319: .newInstance();
320:
321: if (tFactory.getFeature(DOMSource.FEATURE)
322: && tFactory.getFeature(DOMResult.FEATURE)) {
323: //Instantiate a DocumentBuilderFactory.
324: DocumentBuilderFactory dFactory = DocumentBuilderFactory
325: .newInstance();
326:
327: // And setNamespaceAware, which is required when parsing xsl files
328: dFactory.setNamespaceAware(true);
329:
330: //Use the DocumentBuilderFactory to create a DocumentBuilder.
331: DocumentBuilder dBuilder = dFactory
332: .newDocumentBuilder();
333:
334: //Use the DocumentBuilder to parse the XSL style sheet.
335: Document xslDoc = (Document) xslDocumentMap
336: .get(xslFileUrl);
337: if (xslDoc == null) {
338: xslDoc = dBuilder.parse(xslFileUrl.toString());
339: }
340:
341: // Use the DOM Document to define a DOMSource object.
342: DOMSource xslDomSource = new DOMSource(xslDoc);
343:
344: // Set the systemId: note this is actually a URL, not a local filename
345: xslDomSource.setSystemId(xslFileUrl.toString());
346:
347: // Process the style sheet DOMSource and generate a Transformer.
348: Transformer transformer = tFactory
349: .newTransformer(xslDomSource);
350:
351: // Use the DOM Document to define a DOMSource object.
352: DOMSource xmlDomSource = new DOMSource(sourceElem);
353:
354: // Create an empty DOMResult for the Result.
355: DOMResult domResult = new DOMResult();
356:
357: // Perform the transformation, placing the output in the DOMResult.
358: transformer.transform(xmlDomSource, domResult);
359: Node node = domResult.getNode();
360: if (node.getNodeType() == Node.DOCUMENT_NODE) {
361: return ((Document) node).getDocumentElement();
362: }
363: }
364:
365: } catch (Exception th) {
366: throw new BaseException(
367: "can not transform source document", th);
368: }
369:
370: return null;
371: }
372:
373: public static String toXmlString(Element element) {
374: StringBuilder buffer = new StringBuilder(200);
375: buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
376: write(element, buffer, 0);
377: return buffer.toString();
378: }
379:
380: private static void write(Element elem, StringBuilder buf,
381: int indentLevel) {
382: final String elementName = elem.getNodeName();
383:
384: buf.append("<");
385: buf.append(elementName);
386:
387: NamedNodeMap attrMap = elem.getAttributes();
388: for (int i = 0; i < attrMap.getLength(); i++) {
389: write((Attr) attrMap.item(i), buf);
390: }
391:
392: if (elem.hasChildNodes()) {
393: buf.append(">");
394:
395: NodeList childNodes = elem.getChildNodes();
396: write(childNodes, buf, indentLevel + 1);
397:
398: buf.append("</").append(elementName).append(">");
399: } else {
400: buf.append(" />");
401: }
402: }
403:
404: private static void write(NodeList nodes, StringBuilder buf,
405: int indentLevel) {
406: for (int i = 0; i < nodes.getLength(); i++) {
407: Node aNode = nodes.item(i);
408: if (aNode != null) {
409: short nodeType = aNode.getNodeType();
410: switch (nodeType) {
411: case Node.CDATA_SECTION_NODE:
412: CharacterData cdata = (CharacterData) aNode;
413: buf.append("<![CDATA[").append(cdata.getData())
414: .append("]]>");
415: break;
416:
417: case Node.TEXT_NODE:
418: Text myText = (Text) aNode;
419: buf.append(XmlUtil.escapeXML(myText.getData()));
420: break;
421:
422: case Node.ELEMENT_NODE:
423: write((Element) aNode, buf, indentLevel);
424: break;
425: }
426: }
427: }
428: }
429:
430: /**
431: * @param attr
432: * @param buf
433: */
434: private static void write(Attr attr, StringBuilder buf) {
435: buf.append(" ").append(attr.getName()).append("=\"");
436: String value = attr.getValue();
437: buf.append(
438: (value != null) ? XmlUtil.escapeXML(attr.getValue())
439: : "").append("\"");
440: }
441: }
|