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.generation.asciiart;
018:
019: import java.io.BufferedReader;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.InputStreamReader;
023: import java.text.DecimalFormat;
024: import java.text.DecimalFormatSymbols;
025: import java.util.ArrayList;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Locale;
029: import java.util.Map;
030: import org.apache.avalon.framework.parameters.Parameters;
031: import org.apache.cocoon.CascadingIOException;
032: import org.apache.cocoon.ProcessingException;
033: import org.apache.cocoon.caching.CacheableProcessingComponent;
034: import org.apache.cocoon.components.source.SourceUtil;
035: import org.apache.cocoon.environment.SourceResolver;
036: import org.apache.cocoon.generation.AbstractGenerator;
037: import org.apache.excalibur.source.Source;
038: import org.apache.excalibur.source.SourceException;
039: import org.apache.excalibur.source.SourceValidity;
040: import org.xml.sax.Attributes;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.helpers.AttributesImpl;
043:
044: /**
045: * A simple AsciiArt text SVG XML generator.
046: *
047: * @author <a href="mailto:huber@apache.org">Bernhard Huber</a>
048: * @version CVS $Id: AsciiArtSVGGenerator.java 433543 2006-08-22 06:22:54Z crossley $
049: * @since Cocoon 2.1, 22 December 2002
050: */
051: public class AsciiArtSVGGenerator extends AbstractGenerator implements
052: CacheableProcessingComponent {
053:
054: /**
055: * The input source
056: */
057: protected Source inputSource;
058:
059: private AttributesImpl attributes = null;
060: private AsciiArtPad asciiArtPad;
061:
062: //private String static PREFIX = "svg";
063: private String PREFIX = "";
064: private String URI = "http://www.w3.org/2000/svg";
065:
066: /** default SVG line attributes
067: */
068: private final static String DEFAULT_LINE_ATTRIBUTE = "stroke:black; stroke-width:1.5";
069:
070: /** default SVG text attribute
071: */
072: private final static String DEFAULT_TEXT_ATTRIBUTE = "font-size: 12; font-family:Times Roman; fill:blue;";
073:
074: private String lineAttribute = DEFAULT_LINE_ATTRIBUTE;
075: private String textAttribute = DEFAULT_TEXT_ATTRIBUTE;
076:
077: final static int DEFAULT_X_GRID = 10;
078: final static int DEFAULT_Y_GRID = 12;
079: private int xGrid = DEFAULT_X_GRID;
080: private int yGrid = DEFAULT_Y_GRID;
081:
082: /**
083: * Setup the AsciiArtSVG generator.
084: * Try to get the last modification date of the source for caching.
085: *
086: *@param resolver Cocoon's resolver
087: *@param objectModel Cocoon's objectModel
088: *@param src generator's src attribute
089: *@param par sitemap parameters
090: *@exception ProcessingException setup fails
091: *@exception SAXException sax generation fails
092: *@exception IOException general io fails
093: */
094: public void setup(SourceResolver resolver, Map objectModel,
095: String src, Parameters par) throws ProcessingException,
096: SAXException, IOException {
097: super .setup(resolver, objectModel, src, par);
098:
099: try {
100: this .inputSource = resolver.resolveURI(src);
101: } catch (SourceException se) {
102: throw SourceUtil.handle("Error during resolving of '" + src
103: + "'.", se);
104: }
105:
106: // Setup lineAttribute
107: lineAttribute = par.getParameter("line-attribute",
108: DEFAULT_LINE_ATTRIBUTE);
109: // Setup textAttribute
110: textAttribute = par.getParameter("text-attribute",
111: DEFAULT_TEXT_ATTRIBUTE);
112:
113: xGrid = par.getParameterAsInteger("x-grid", DEFAULT_X_GRID);
114: yGrid = par.getParameterAsInteger("y-grid", DEFAULT_Y_GRID);
115: }
116:
117: /**
118: * Recycle this component.
119: * All instance variables are set to <code>null</code>.
120: */
121: public void recycle() {
122: if (null != this .inputSource) {
123: super .resolver.release(this .inputSource);
124: this .inputSource = null;
125: }
126: super .recycle();
127: }
128:
129: /**
130: * Generate the unique key.
131: * This key must be unique inside the space of this component.
132: *
133: * @return The generated key hashes the src
134: */
135: public java.io.Serializable getKey() {
136: return this .inputSource.getURI();
137: }
138:
139: /**
140: * Generate the validity object.
141: *
142: * @return The generated validity object or <code>null</code> if the
143: * component is currently not cacheable.
144: */
145: public SourceValidity getValidity() {
146: return this .inputSource.getValidity();
147: }
148:
149: /**
150: * Generate XML data.
151: */
152: public void generate() throws IOException, SAXException,
153: ProcessingException {
154: try {
155: if (getLogger().isDebugEnabled()) {
156: getLogger().debug(
157: "Source " + super .source + " resolved to "
158: + this .inputSource.getURI());
159: }
160:
161: // read the ascii art
162: String[] asciiArt = readAsciiArt();
163: // setup ascii art pad
164: asciiArtPad = new AsciiArtPad();
165: asciiArtPad.setXGrid(this .xGrid);
166: asciiArtPad.setYGrid(this .yGrid);
167:
168: // build the ascii art
169: AsciiArtPad.AsciiArtPadBuilder builder = new AsciiArtPad.AsciiArtPadBuilder(
170: asciiArtPad);
171: builder.build(asciiArt);
172: attributes = new AttributesImpl();
173:
174: // start the document
175: this .contentHandler.startDocument();
176: this .contentHandler.startPrefixMapping(PREFIX, URI);
177:
178: // generate root element
179: attributes.clear();
180: // set svg attributes
181: addAttribute("width", String.valueOf(asciiArtPad.getXGrid()
182: * asciiArtPad.getWidth()));
183: addAttribute("height", String.valueOf(asciiArtPad
184: .getYGrid()
185: * asciiArtPad.getHeight()));
186: startElement("svg", attributes);
187:
188: // generate svg g, and path elements
189: attributes.clear();
190: // set line attributes
191: addAttribute("style", this .lineAttribute);
192: startElement("g", attributes);
193: generateSVGLineElements();
194: endElement("g");
195:
196: // generate svg g, and text elements
197: attributes.clear();
198: // set text attributes
199: addAttribute("style", this .textAttribute);
200: startElement("g", attributes);
201: generateSVGTextElements();
202: endElement("g");
203:
204: // end root element, document
205: endElement("svg");
206: this .contentHandler.endPrefixMapping(PREFIX);
207: this .contentHandler.endDocument();
208: } catch (SAXException e) {
209: SourceUtil.handleSAXException(this .inputSource.getURI(), e);
210: }
211: }
212:
213: /**
214: * Read the ascii art from the input source.
215: *
216: *@return String[] describing the ascii art
217: *@exception IOException reading the ascii art fails
218: */
219: protected String[] readAsciiArt() throws IOException {
220: InputStream is = null;
221: BufferedReader br = null;
222: try {
223: is = this .inputSource.getInputStream();
224: br = new BufferedReader(new InputStreamReader(is));
225: String line;
226: List lines = new ArrayList();
227: while ((line = br.readLine()) != null) {
228: lines.add(line);
229: }
230: String[] asciiArt = (String[]) lines.toArray(new String[0]);
231: return asciiArt;
232: } catch (SourceException se) {
233: throw new CascadingIOException("Cannot get input stream",
234: se);
235: } finally {
236: if (is != null) {
237: is.close();
238: }
239: if (br != null) {
240: br.close();
241: }
242: }
243: }
244:
245: /**
246: * Generate SVG path elements.
247: * The SVG path elements are generated from ascii art lines.
248: *
249: *@throws SAXException iff SAX generation fails.
250: */
251: protected void generateSVGLineElements() throws SAXException {
252: //NumberFormat nf = NumberFormat.getInstance(Locale.US);
253: //nf.setGroupingIsUsed( false );
254: DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
255: DecimalFormat df = new DecimalFormat("##0.0##", dfs);
256: Iterator i = asciiArtPad.iterator();
257: while (i.hasNext()) {
258: Object o = i.next();
259: if (o instanceof AsciiArtPad.AsciiArtLine) {
260: AsciiArtPad.AsciiArtLine aal = (AsciiArtPad.AsciiArtLine) o;
261: double mx = aal.getXStart();
262: double my = aal.getYStart();
263: double lx = aal.getXEnd();
264: double ly = aal.getYEnd();
265:
266: attributes.clear();
267: addAttribute("d", "M " + df.format(mx) + " "
268: + df.format(my) + " " + "L " + df.format(lx)
269: + " " + df.format(ly));
270: startElement("path", attributes);
271: endElement("path");
272: }
273: }
274: }
275:
276: /**
277: * Generate SVG text elements.
278: * The SVG text elements are generated from ascii art string.
279: *
280: *@throws SAXException iff SAX generation fails.
281: */
282: protected void generateSVGTextElements() throws SAXException {
283: //NumberFormat nf = NumberFormat.getInstance(Locale.US);
284: DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
285: DecimalFormat df = new DecimalFormat("##0.0##", dfs);
286: Iterator i = asciiArtPad.iterator();
287: while (i.hasNext()) {
288: Object o = i.next();
289: if (o instanceof AsciiArtPad.AsciiArtString) {
290: AsciiArtPad.AsciiArtString aas = (AsciiArtPad.AsciiArtString) o;
291: double x = aas.getX();
292: double y = aas.getY();
293: attributes.clear();
294: addAttribute("x", df.format(x));
295: addAttribute("y", df.format(y));
296: startElement("text", attributes);
297: characters(aas.getS());
298: endElement("text");
299: }
300: }
301: }
302:
303: /**
304: * SAX startElement helper
305: *
306: *@param nodeName name of the element's name
307: *@param attributes of the node
308: *@throws SAXException iff SAX generation fails
309: */
310: protected void startElement(String nodeName, Attributes attributes)
311: throws SAXException {
312: if (PREFIX.length() > 0) {
313: this .contentHandler.startElement(URI, nodeName, PREFIX
314: + ":" + nodeName, attributes);
315: } else {
316: this .contentHandler.startElement(URI, nodeName, nodeName,
317: attributes);
318: }
319: }
320:
321: /**
322: * SAX character helper
323: *
324: *@param s Description of the Parameter
325: *@throws SAXException iff SAX generation fails
326: */
327: protected void characters(String s) throws SAXException {
328: if (s != null) {
329: char[] stringCharacters = s.toCharArray();
330: this .contentHandler.characters(stringCharacters, 0,
331: stringCharacters.length);
332: }
333: }
334:
335: /**
336: * SAX endElement helper
337: *
338: *@param nodeName name of the element's name
339: *@throws SAXException iff SAX generation fails
340: */
341: protected void endElement(String nodeName) throws SAXException {
342: if (PREFIX.length() > 0) {
343: this .contentHandler.endElement(URI, nodeName, PREFIX + ":"
344: + nodeName);
345: } else {
346: this .contentHandler.endElement(URI, nodeName, nodeName);
347: }
348: }
349:
350: /**
351: * Adds a feature to the Attribute attribute of the MailXMLSerializer
352: * object
353: *
354: *@param nodeName name of the attriute's name
355: *@param nodeValue value of the attribute
356: */
357: protected void addAttribute(String nodeName, String nodeValue) {
358: attributes.addAttribute("", nodeName, nodeName, "CDATA",
359: nodeValue);
360: }
361: }
|