001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.transformation;
018:
019: import org.apache.avalon.framework.parameters.Parameters;
020: import org.apache.cocoon.ProcessingException;
021: import org.apache.excalibur.source.Source;
022: import org.apache.excalibur.source.SourceException;
023: import org.apache.cocoon.components.source.SourceUtil;
024: import org.apache.cocoon.environment.SourceResolver;
025: import org.xml.sax.Attributes;
026: import org.xml.sax.Locator;
027: import org.xml.sax.SAXException;
028:
029: import java.io.FileWriter;
030: import java.io.IOException;
031: import java.util.Date;
032: import java.util.Map;
033:
034: /**
035: * @cocoon.sitemap.component.documentation
036: * The <code>LogTransformer</code> is a class that can be plugged into a pipeline
037: * to print the SAX events which passes thru this transformer in a readable form
038: * to a file.
039: *
040: * @cocoon.sitemap.component.name log
041: * @cocoon.sitemap.component.logger sitemap.transformer.log
042: *
043: * @cocoon.sitemap.component.pooling.max 16
044: *
045: *
046: * The <code>LogTransformer</code> is a class that can be plugged into a pipeline
047: * to print the SAX events which passes thru this transformer in a readable form
048: * to a file.
049: * <br>
050: * The file will be specified in a parameter tag in the sitemap pipeline to the
051: * transformer as follows:
052: * <p>
053: * <pre>
054: * <map:transform type="log">
055: * <map:parameter name="logfile" value="logfile.log"/>
056: * <map:parameter name="append" value="no"/>
057: * </map:transform>
058: * </pre>
059: * </p>
060: *
061: * Because the log file will be hardcoded into the sitemap this LOGTransformer will
062: * not be thread save!!
063: * <br>
064: * This transformations main purpose is debugging.
065: *
066: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
067: * @author <a href="mailto:giacomo.pati@pwr.ch">Giacomo Pati</a>
068: * (PWR Organisation & Entwicklung)
069: * @version CVS $Id: LogTransformer.java 433543 2006-08-22 06:22:54Z crossley $
070: *
071: */
072: public class LogTransformer extends AbstractTransformer {
073:
074: private static String lf = System.getProperty("line.separator",
075: "\n");
076:
077: /** log file */
078: private FileWriter logfile;
079:
080: /**
081: * Setup
082: */
083: public void setup(SourceResolver resolver, Map objectModel,
084: String src, Parameters parameters)
085: throws ProcessingException, SAXException, IOException {
086: final boolean append = parameters.getParameterAsBoolean(
087: "append", false);
088: final String logfilename = parameters.getParameter("logfile",
089: null);
090:
091: // Check for null, use System.out if logfile is not specified.
092: this .logfile = null;
093: if (null != logfilename) {
094: Source source = null;
095: try {
096: source = resolver.resolveURI(logfilename);
097: final String systemId = source.getURI();
098: if (systemId.startsWith("file:")) {
099: this .logfile = new FileWriter(
100: systemId.substring(5), append);
101: } else {
102: throw new ProcessingException(
103: "The logfile parameter must point to a file: "
104: + logfilename);
105: }
106: } catch (SourceException se) {
107: throw SourceUtil.handle(se);
108: } finally {
109: resolver.release(source);
110: }
111: }
112:
113: Date date = new Date();
114: StringBuffer logEntry = new StringBuffer();
115: logEntry.append("---------------------------- [");
116: logEntry.append(date.toString());
117: logEntry.append("] ----------------------------");
118: this .log("setup", logEntry.toString());
119: }
120:
121: /**
122: * Recycle
123: */
124: public void recycle() {
125: super .recycle();
126: try {
127: if (this .logfile != null)
128: logfile.close();
129: } catch (Exception e) {
130: this .getLogger().warn("LogTransformer.recycle()", e);
131: }
132: this .logfile = null;
133: }
134:
135: /**
136: * Receive an object for locating the origin of SAX document events.
137: */
138: public void setDocumentLocator(Locator locator) {
139: this .log("setDocumentLocator", locator != null ? "systemid="
140: + locator.getSystemId() + ",publicid="
141: + locator.getPublicId() : "(locator is null)");
142: if (super .contentHandler != null) {
143: super .contentHandler.setDocumentLocator(locator);
144: }
145: }
146:
147: /**
148: * Receive notification of the beginning of a document.
149: */
150: public void startDocument() throws SAXException {
151: this .log("startDocument", "");
152: if (super .contentHandler != null) {
153: super .contentHandler.startDocument();
154: }
155: }
156:
157: /**
158: * Receive notification of the end of a document.
159: */
160: public void endDocument() throws SAXException {
161: this .log("endDocument", "");
162: if (super .contentHandler != null) {
163: super .contentHandler.endDocument();
164: }
165: }
166:
167: /**
168: * Begin the scope of a prefix-URI Namespace mapping.
169: */
170: public void startPrefixMapping(String prefix, String uri)
171: throws SAXException {
172: this .log("startPrefixMapping", "prefix=" + prefix + ",uri="
173: + uri);
174: if (super .contentHandler != null) {
175: super .contentHandler.startPrefixMapping(prefix, uri);
176: }
177: }
178:
179: /**
180: * End the scope of a prefix-URI mapping.
181: */
182: public void endPrefixMapping(String prefix) throws SAXException {
183: this .log("endPrefixMapping", "prefix=" + prefix);
184: if (super .contentHandler != null) {
185: super .contentHandler.endPrefixMapping(prefix);
186: }
187: }
188:
189: /**
190: * Receive notification of the beginning of an element.
191: */
192: public void startElement(String uri, String loc, String raw,
193: Attributes a) throws SAXException {
194: this .log("startElement", "uri=" + uri + ",local=" + loc
195: + ",raw=" + raw);
196: for (int i = 0; i < a.getLength(); i++) {
197: this .log(" ", Integer.toString(i + 1) + ". uri="
198: + a.getURI(i) + ",local=" + a.getLocalName(i)
199: + ",qname=" + a.getQName(i) + ",type="
200: + a.getType(i) + ",value=" + a.getValue(i));
201: }
202: if (super .contentHandler != null) {
203: super .contentHandler.startElement(uri, loc, raw, a);
204: }
205: }
206:
207: /**
208: * Receive notification of the end of an element.
209: */
210: public void endElement(String uri, String loc, String raw)
211: throws SAXException {
212: this .log("endElement", "uri=" + uri + ",local=" + loc + ",raw="
213: + raw);
214: if (super .contentHandler != null) {
215: super .contentHandler.endElement(uri, loc, raw);
216: }
217: }
218:
219: /**
220: * Receive notification of character data.
221: */
222: public void characters(char ch[], int start, int len)
223: throws SAXException {
224: this .log("characters", new String(ch, start, len));
225: if (super .contentHandler != null) {
226: super .contentHandler.characters(ch, start, len);
227: }
228: }
229:
230: /**
231: * Receive notification of ignorable whitespace in element content.
232: */
233: public void ignorableWhitespace(char ch[], int start, int len)
234: throws SAXException {
235: this .log("ignorableWhitespace", new String(ch, start, len));
236: if (super .contentHandler != null) {
237: super .contentHandler.ignorableWhitespace(ch, start, len);
238: }
239: }
240:
241: /**
242: * Receive notification of a processing instruction.
243: */
244: public void processingInstruction(String target, String data)
245: throws SAXException {
246: log("processingInstruction", "target=" + target + ",data="
247: + data);
248: if (super .contentHandler != null) {
249: super .contentHandler.processingInstruction(target, data);
250: }
251: }
252:
253: /**
254: * Receive notification of a skipped entity.
255: */
256: public void skippedEntity(String name) throws SAXException {
257: this .log("skippedEntity", "name=" + name);
258: if (super .contentHandler != null) {
259: super .contentHandler.skippedEntity(name);
260: }
261: }
262:
263: /**
264: * Report the start of DTD declarations, if any.
265: */
266: public void startDTD(String name, String publicId, String systemId)
267: throws SAXException {
268: this .log("startDTD", "name=" + name + ",publicId=" + publicId
269: + ",systemId=" + systemId);
270: if (super .lexicalHandler != null) {
271: super .lexicalHandler.startDTD(name, publicId, systemId);
272: }
273: }
274:
275: /**
276: * Report the end of DTD declarations.
277: */
278: public void endDTD() throws SAXException {
279: this .log("endDTD", "");
280: if (super .lexicalHandler != null) {
281: super .lexicalHandler.endDTD();
282: }
283: }
284:
285: /**
286: * Report the beginning of an entity.
287: */
288: public void startEntity(String name) throws SAXException {
289: this .log("startEntity", "name=" + name);
290: if (super .lexicalHandler != null) {
291: super .lexicalHandler.startEntity(name);
292: }
293: }
294:
295: /**
296: * Report the end of an entity.
297: */
298: public void endEntity(String name) throws SAXException {
299: this .log("endEntity", "name=" + name);
300: if (super .lexicalHandler != null) {
301: super .lexicalHandler.endEntity(name);
302: }
303: }
304:
305: /**
306: * Report the start of a CDATA section.
307: */
308: public void startCDATA() throws SAXException {
309: this .log("startCDATA", "");
310: if (super .lexicalHandler != null) {
311: super .lexicalHandler.startCDATA();
312: }
313: }
314:
315: /**
316: * Report the end of a CDATA section.
317: */
318: public void endCDATA() throws SAXException {
319: this .log("endCDATA", "");
320: if (super .lexicalHandler != null) {
321: super .lexicalHandler.endCDATA();
322: }
323: }
324:
325: /**
326: * Report an XML comment anywhere in the document.
327: */
328: public void comment(char ch[], int start, int len)
329: throws SAXException {
330: this .log("comment", new String(ch, start, len));
331: if (super .lexicalHandler != null) {
332: super .lexicalHandler.comment(ch, start, len);
333: }
334: }
335:
336: /**
337: * Report to logfile.
338: */
339: private void log(String location, String description) {
340: final StringBuffer logEntry = new StringBuffer();
341: logEntry.append("[");
342: logEntry.append(location);
343: logEntry.append("] ");
344: logEntry.append(description);
345: logEntry.append(lf);
346: final String text = logEntry.toString();
347: if (this .getLogger().isInfoEnabled()) {
348: this .getLogger().info(text);
349: }
350: try {
351: if (null != this .logfile) {
352: this .logfile.write(text, 0, text.length());
353: this .logfile.flush();
354: } else {
355: System.out.println(text);
356: }
357: } catch (IOException ioe) {
358: this .getLogger().debug("LogTransformer.log", ioe);
359: }
360: }
361:
362: /**
363: * Attempt to close the log file when the class is GC'd
364: */
365: public void destroy() {
366: try {
367: if (this .logfile != null)
368: logfile.close();
369: } catch (Exception e) {
370: getLogger().debug("LogTransformer.destroy()", e);
371: }
372: }
373: }
|