ingo@4213: package de.intevation.flys.artifacts.services; ingo@4213: ingo@4213: import java.awt.Dimension; ingo@4213: import java.awt.Transparency; ingo@4213: import java.awt.image.BufferedImage; ingo@4213: import java.io.ByteArrayOutputStream; ingo@4213: import java.io.IOException; ingo@4213: ingo@4213: import javax.imageio.ImageIO; ingo@4213: ingo@4213: import org.apache.log4j.Logger; ingo@4213: import org.jfree.chart.JFreeChart; ingo@4213: import org.w3c.dom.Document; ingo@4213: import org.w3c.dom.Element; ingo@4213: import org.w3c.dom.NodeList; ingo@4213: ingo@4213: import de.intevation.artifactdatabase.DefaultService; ingo@4213: import de.intevation.artifacts.CallMeta; ingo@4213: import de.intevation.artifacts.GlobalContext; ingo@4213: import de.intevation.artifacts.Service; ingo@4213: felix@5343: /** Serve chart. */ ingo@4213: public abstract class AbstractChartService extends DefaultService { ingo@4213: ingo@4213: public static final int DEFAULT_WIDTH = 240; ingo@4213: public static final int DEFAULT_HEIGHT = 180; ingo@4213: ingo@4213: public static final String DEFAULT_FORMAT = "png"; ingo@4213: ingo@4213: private static final Logger log = Logger ingo@4213: .getLogger(AbstractChartService.class); ingo@4213: ingo@4213: // TODO: Load fancy image from resources. ingo@4213: public static final byte[] EMPTY = { (byte) 0x89, (byte) 0x50, (byte) 0x4e, ingo@4213: (byte) 0x47, (byte) 0x0d, (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, ingo@4213: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49, ingo@4213: (byte) 0x48, (byte) 0x44, (byte) 0x52, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x01, (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x3a, (byte) 0x7e, (byte) 0x9b, (byte) 0x55, ingo@4213: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x73, ingo@4213: (byte) 0x52, (byte) 0x47, (byte) 0x42, (byte) 0x00, (byte) 0xae, ingo@4213: (byte) 0xce, (byte) 0x1c, (byte) 0xe9, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x09, (byte) 0x70, (byte) 0x48, (byte) 0x59, ingo@4213: (byte) 0x73, (byte) 0x00, (byte) 0x00, (byte) 0x0b, (byte) 0x13, ingo@4213: (byte) 0x00, (byte) 0x00, (byte) 0x0b, (byte) 0x13, (byte) 0x01, ingo@4213: (byte) 0x00, (byte) 0x9a, (byte) 0x9c, (byte) 0x18, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x74, (byte) 0x49, ingo@4213: (byte) 0x4d, (byte) 0x45, (byte) 0x07, (byte) 0xdc, (byte) 0x04, ingo@4213: (byte) 0x04, (byte) 0x10, (byte) 0x30, (byte) 0x15, (byte) 0x7d, ingo@4213: (byte) 0x77, (byte) 0x36, (byte) 0x0b, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x08, (byte) 0x74, (byte) 0x45, (byte) 0x58, ingo@4213: (byte) 0x74, (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x6d, ingo@4213: (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x00, (byte) 0xf6, ingo@4213: (byte) 0xcc, (byte) 0x96, (byte) 0xbf, (byte) 0x00, (byte) 0x00, ingo@4213: (byte) 0x00, (byte) 0x0a, (byte) 0x49, (byte) 0x44, (byte) 0x41, ingo@4213: (byte) 0x54, (byte) 0x08, (byte) 0xd7, (byte) 0x63, (byte) 0xf8, ingo@4213: (byte) 0x0f, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x01, ingo@4213: (byte) 0x00, (byte) 0x1b, (byte) 0xb6, (byte) 0xee, (byte) 0x56, ingo@4213: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, ingo@4213: (byte) 0x45, (byte) 0x4e, (byte) 0x44, (byte) 0xae, (byte) 0x42, ingo@4213: (byte) 0x60, (byte) 0x82 }; ingo@4213: ingo@4213: private static final Output empty() { ingo@4213: return new Output(EMPTY, "image/png"); ingo@4213: } ingo@4213: ingo@4213: protected abstract JFreeChart createChart(Document data, ingo@4213: GlobalContext globalContext, CallMeta callMeta); ingo@4213: ingo@4213: protected void init() { ingo@4213: }; ingo@4213: ingo@4213: protected void finish() { ingo@4213: }; ingo@4213: ingo@4213: @Override ingo@4213: public Service.Output process(Document data, GlobalContext globalContext, ingo@4213: CallMeta callMeta) { ingo@4213: log.debug("process"); ingo@4213: ingo@4213: init(); ingo@4213: try { ingo@4213: JFreeChart chart = createChart(data, globalContext, callMeta); ingo@4213: ingo@4213: if (chart == null) { ingo@4213: return empty(); ingo@4213: } ingo@4213: ingo@4213: Dimension extent = getExtent(data); ingo@4213: String format = getFormat(data); ingo@4213: ingo@4213: return encode(chart, extent, format); ingo@4213: } ingo@4213: finally { ingo@4213: finish(); ingo@4213: } ingo@4213: } ingo@4213: ingo@4213: protected static Output encode(JFreeChart chart, Dimension extent, ingo@4213: String format) { ingo@4213: BufferedImage image = chart.createBufferedImage(extent.width, ingo@4213: extent.height, Transparency.BITMASK, null); ingo@4213: ingo@4213: ByteArrayOutputStream out = new ByteArrayOutputStream(); ingo@4213: ingo@4213: try { ingo@4213: ImageIO.write(image, format, out); ingo@4213: } ingo@4213: catch (IOException ioe) { ingo@4213: log.warn("writing image failed", ioe); ingo@4213: return empty(); ingo@4213: } ingo@4213: ingo@4213: return new Output(out.toByteArray(), "image/" + format); ingo@4213: } ingo@4213: ingo@4213: protected static Dimension getExtent(Document input) { ingo@4213: ingo@4213: int width = DEFAULT_WIDTH; ingo@4213: int height = DEFAULT_HEIGHT; ingo@4213: ingo@4213: NodeList extents = input.getElementsByTagName("extent"); ingo@4213: ingo@4213: if (extents.getLength() > 0) { ingo@4213: Element element = (Element) extents.item(0); ingo@4213: String w = element.getAttribute("width"); ingo@4213: String h = element.getAttribute("height"); ingo@4213: ingo@4213: try { ingo@4213: width = Math.max(1, Integer.parseInt(w)); ingo@4213: } ingo@4213: catch (NumberFormatException nfe) { ingo@4213: log.warn("width '" + w + "' is not a valid."); ingo@4213: } ingo@4213: ingo@4213: try { ingo@4213: height = Math.max(1, Integer.parseInt(h)); ingo@4213: } ingo@4213: catch (NumberFormatException nfe) { ingo@4213: log.warn("height '" + h + "' is not a valid"); ingo@4213: } ingo@4213: } ingo@4213: ingo@4213: return new Dimension(width, height); ingo@4213: } ingo@4213: ingo@4213: protected static String getFormat(Document input) { ingo@4213: String format = DEFAULT_FORMAT; ingo@4213: ingo@4213: NodeList formats = input.getElementsByTagName("format"); ingo@4213: ingo@4213: if (formats.getLength() > 0) { ingo@4213: String type = ((Element) formats.item(0)).getAttribute("type"); ingo@4213: if (type.length() > 0) { ingo@4213: format = type; ingo@4213: } ingo@4213: } ingo@4213: ingo@4213: return format; ingo@4213: } ingo@4213: }