| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.generation.asciiart; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.text.DecimalFormat; |
| import java.text.DecimalFormatSymbols; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import org.apache.avalon.framework.parameters.Parameters; |
| import org.apache.cocoon.CascadingIOException; |
| import org.apache.cocoon.ProcessingException; |
| import org.apache.cocoon.caching.CacheableProcessingComponent; |
| import org.apache.cocoon.components.source.SourceUtil; |
| import org.apache.cocoon.environment.SourceResolver; |
| import org.apache.cocoon.generation.AbstractGenerator; |
| import org.apache.excalibur.source.Source; |
| import org.apache.excalibur.source.SourceException; |
| import org.apache.excalibur.source.SourceValidity; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| /** |
| * A simple AsciiArt text SVG XML generator. |
| * |
| * @author <a href="mailto:huber@apache.org">Bernhard Huber</a> |
| * @version CVS $Id$ |
| * @since Cocoon 2.1, 22 December 2002 |
| */ |
| public class AsciiArtSVGGenerator |
| extends AbstractGenerator |
| implements CacheableProcessingComponent { |
| |
| /** |
| * The input source |
| */ |
| protected Source inputSource; |
| |
| private AttributesImpl attributes = null; |
| private AsciiArtPad asciiArtPad; |
| |
| //private String static PREFIX = "svg"; |
| private String PREFIX = ""; |
| private String URI = "http://www.w3.org/2000/svg"; |
| |
| /** default SVG line attributes |
| */ |
| private final static String DEFAULT_LINE_ATTRIBUTE = "stroke:black; stroke-width:1.5"; |
| |
| /** default SVG text attribute |
| */ |
| private final static String DEFAULT_TEXT_ATTRIBUTE = "font-size: 12; font-family:Times Roman; fill:blue;"; |
| |
| private String lineAttribute = DEFAULT_LINE_ATTRIBUTE; |
| private String textAttribute = DEFAULT_TEXT_ATTRIBUTE; |
| |
| |
| final static int DEFAULT_X_GRID = 10; |
| final static int DEFAULT_Y_GRID = 12; |
| private int xGrid = DEFAULT_X_GRID; |
| private int yGrid = DEFAULT_Y_GRID; |
| |
| /** |
| * Setup the AsciiArtSVG generator. |
| * Try to get the last modification date of the source for caching. |
| * |
| *@param resolver Cocoon's resolver |
| *@param objectModel Cocoon's objectModel |
| *@param src generator's src attribute |
| *@param par sitemap parameters |
| *@exception ProcessingException setup fails |
| *@exception SAXException sax generation fails |
| *@exception IOException general io fails |
| */ |
| public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) |
| throws ProcessingException, SAXException, IOException { |
| super.setup(resolver, objectModel, src, par); |
| |
| try { |
| this.inputSource = resolver.resolveURI(src); |
| } catch (SourceException se) { |
| throw SourceUtil.handle("Error during resolving of '" + src + "'.", se); |
| } |
| |
| // Setup lineAttribute |
| lineAttribute = par.getParameter("line-attribute", DEFAULT_LINE_ATTRIBUTE); |
| // Setup textAttribute |
| textAttribute = par.getParameter("text-attribute", DEFAULT_TEXT_ATTRIBUTE); |
| |
| xGrid = par.getParameterAsInteger("x-grid", DEFAULT_X_GRID); |
| yGrid = par.getParameterAsInteger("y-grid", DEFAULT_Y_GRID); |
| } |
| |
| |
| /** |
| * Recycle this component. |
| * All instance variables are set to <code>null</code>. |
| */ |
| public void recycle() { |
| if (null != this.inputSource) { |
| super.resolver.release(this.inputSource); |
| this.inputSource = null; |
| } |
| super.recycle(); |
| } |
| |
| |
| /** |
| * Generate the unique key. |
| * This key must be unique inside the space of this component. |
| * |
| * @return The generated key hashes the src |
| */ |
| public java.io.Serializable getKey() { |
| return this.inputSource.getURI(); |
| } |
| |
| |
| /** |
| * Generate the validity object. |
| * |
| * @return The generated validity object or <code>null</code> if the |
| * component is currently not cacheable. |
| */ |
| public SourceValidity getValidity() { |
| return this.inputSource.getValidity(); |
| } |
| |
| |
| /** |
| * Generate XML data. |
| */ |
| public void generate() |
| throws IOException, SAXException, ProcessingException { |
| try { |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Source " + super.source + |
| " resolved to " + this.inputSource.getURI()); |
| } |
| |
| // read the ascii art |
| String[] asciiArt = readAsciiArt(); |
| // setup ascii art pad |
| asciiArtPad = new AsciiArtPad(); |
| asciiArtPad.setXGrid(this.xGrid); |
| asciiArtPad.setYGrid(this.yGrid); |
| |
| // build the ascii art |
| AsciiArtPad.AsciiArtPadBuilder builder = new AsciiArtPad.AsciiArtPadBuilder(asciiArtPad); |
| builder.build(asciiArt); |
| attributes = new AttributesImpl(); |
| |
| // start the document |
| this.contentHandler.startDocument(); |
| this.contentHandler.startPrefixMapping(PREFIX, URI); |
| |
| // generate root element |
| attributes.clear(); |
| // set svg attributes |
| addAttribute("width", String.valueOf(asciiArtPad.getXGrid() * asciiArtPad.getWidth())); |
| addAttribute("height", String.valueOf(asciiArtPad.getYGrid() * asciiArtPad.getHeight())); |
| startElement("svg", attributes); |
| |
| // generate svg g, and path elements |
| attributes.clear(); |
| // set line attributes |
| addAttribute("style", this.lineAttribute); |
| startElement("g", attributes); |
| generateSVGLineElements(); |
| endElement("g"); |
| |
| // generate svg g, and text elements |
| attributes.clear(); |
| // set text attributes |
| addAttribute("style", this.textAttribute); |
| startElement("g", attributes); |
| generateSVGTextElements(); |
| endElement("g"); |
| |
| // end root element, document |
| endElement("svg"); |
| this.contentHandler.endPrefixMapping(PREFIX); |
| this.contentHandler.endDocument(); |
| } catch (SAXException e) { |
| SourceUtil.handleSAXException(this.inputSource.getURI(), e); |
| } |
| } |
| |
| |
| /** |
| * Read the ascii art from the input source. |
| * |
| *@return String[] describing the ascii art |
| *@exception IOException reading the ascii art fails |
| */ |
| protected String[] readAsciiArt() throws IOException { |
| InputStream is = null; |
| BufferedReader br = null; |
| try { |
| is = this.inputSource.getInputStream(); |
| br = new BufferedReader(new InputStreamReader(is)); |
| String line; |
| List lines = new ArrayList(); |
| while ((line = br.readLine()) != null) { |
| lines.add(line); |
| } |
| String[] asciiArt = (String[]) lines.toArray(new String[0]); |
| return asciiArt; |
| } catch (SourceException se) { |
| throw new CascadingIOException("Cannot get input stream", se); |
| } finally { |
| if (is != null) { |
| is.close(); |
| } |
| if (br != null) { |
| br.close(); |
| } |
| } |
| } |
| |
| |
| /** |
| * Generate SVG path elements. |
| * The SVG path elements are generated from ascii art lines. |
| * |
| *@throws SAXException iff SAX generation fails. |
| */ |
| protected void generateSVGLineElements() throws SAXException { |
| //NumberFormat nf = NumberFormat.getInstance(Locale.US); |
| //nf.setGroupingIsUsed( false ); |
| DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US); |
| DecimalFormat df = new DecimalFormat("##0.0##", dfs); |
| Iterator i = asciiArtPad.iterator(); |
| while (i.hasNext()) { |
| Object o = i.next(); |
| if (o instanceof AsciiArtPad.AsciiArtLine) { |
| AsciiArtPad.AsciiArtLine aal = (AsciiArtPad.AsciiArtLine) o; |
| double mx = aal.getXStart(); |
| double my = aal.getYStart(); |
| double lx = aal.getXEnd(); |
| double ly = aal.getYEnd(); |
| |
| attributes.clear(); |
| addAttribute("d", |
| "M " + df.format(mx) + " " + df.format(my) + " " + |
| "L " + df.format(lx) + " " + df.format(ly)); |
| startElement("path", attributes); |
| endElement("path"); |
| } |
| } |
| } |
| |
| |
| /** |
| * Generate SVG text elements. |
| * The SVG text elements are generated from ascii art string. |
| * |
| *@throws SAXException iff SAX generation fails. |
| */ |
| protected void generateSVGTextElements() throws SAXException { |
| //NumberFormat nf = NumberFormat.getInstance(Locale.US); |
| DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US); |
| DecimalFormat df = new DecimalFormat("##0.0##", dfs); |
| Iterator i = asciiArtPad.iterator(); |
| while (i.hasNext()) { |
| Object o = i.next(); |
| if (o instanceof AsciiArtPad.AsciiArtString) { |
| AsciiArtPad.AsciiArtString aas = (AsciiArtPad.AsciiArtString) o; |
| double x = aas.getX(); |
| double y = aas.getY(); |
| attributes.clear(); |
| addAttribute("x", df.format(x)); |
| addAttribute("y", df.format(y)); |
| startElement("text", attributes); |
| characters(aas.getS()); |
| endElement("text"); |
| } |
| } |
| } |
| |
| |
| /** |
| * SAX startElement helper |
| * |
| *@param nodeName name of the element's name |
| *@param attributes of the node |
| *@throws SAXException iff SAX generation fails |
| */ |
| protected void startElement(String nodeName, Attributes attributes) throws SAXException { |
| if (PREFIX.length() > 0) { |
| this.contentHandler.startElement(URI, nodeName, PREFIX + ":" + nodeName, attributes); |
| } else { |
| this.contentHandler.startElement(URI, nodeName, nodeName, attributes); |
| } |
| } |
| |
| |
| /** |
| * SAX character helper |
| * |
| *@param s Description of the Parameter |
| *@throws SAXException iff SAX generation fails |
| */ |
| protected void characters(String s) throws SAXException { |
| if (s != null) { |
| char[] stringCharacters = s.toCharArray(); |
| this.contentHandler.characters(stringCharacters, 0, stringCharacters.length); |
| } |
| } |
| |
| |
| /** |
| * SAX endElement helper |
| * |
| *@param nodeName name of the element's name |
| *@throws SAXException iff SAX generation fails |
| */ |
| protected void endElement(String nodeName) throws SAXException { |
| if (PREFIX.length() > 0) { |
| this.contentHandler.endElement(URI, nodeName, PREFIX + ":" + nodeName); |
| } else { |
| this.contentHandler.endElement(URI, nodeName, nodeName); |
| } |
| } |
| |
| |
| /** |
| * Adds a feature to the Attribute attribute of the MailXMLSerializer |
| * object |
| * |
| *@param nodeName name of the attriute's name |
| *@param nodeValue value of the attribute |
| */ |
| protected void addAttribute(String nodeName, String nodeValue) { |
| attributes.addAttribute("", nodeName, nodeName, "CDATA", nodeValue); |
| } |
| } |
| |