ingo@391: package de.intevation.flys.exports; ingo@391: ingo@391: import java.io.IOException; ingo@391: import java.io.OutputStream; ingo@391: import java.io.OutputStreamWriter; ingo@391: felix@2284: import java.text.NumberFormat; felix@2284: ingo@391: import org.w3c.dom.Document; ingo@391: ingo@391: import org.apache.log4j.Logger; ingo@391: ingo@391: import au.com.bytecode.opencsv.CSVWriter; ingo@391: ingo@391: import de.intevation.artifacts.Artifact; ingo@391: import de.intevation.artifacts.CallContext; ingo@391: felix@1944: import de.intevation.artifactdatabase.state.ArtifactAndFacet; ingo@1979: import de.intevation.artifactdatabase.state.Settings; ingo@695: ingo@445: import de.intevation.artifacts.common.ArtifactNamespaceContext; ingo@445: import de.intevation.artifacts.common.utils.XMLUtils; ingo@445: ingo@416: import de.intevation.flys.artifacts.resources.Resources; ingo@3422: import de.intevation.flys.collections.FLYSArtifactCollection; ingo@416: felix@2284: import de.intevation.flys.utils.Formatter; felix@2284: ingo@391: ingo@391: /** ingo@391: * An abstract exporter that implements some basic methods for exporting data of ingo@391: * artifacts. ingo@391: * ingo@391: * @author Ingo Weinzierl ingo@391: */ ingo@391: public abstract class AbstractExporter implements OutGenerator { ingo@391: ingo@391: /** The logger used in this exporter.*/ ingo@391: private static Logger logger = Logger.getLogger(AbstractExporter.class); ingo@391: sascha@3223: /* XXX: Why does AbstractExporter do not implement FacetTypes? */ sascha@3223: public static String FIX_PARAMETERS = "fix_parameters"; ingo@391: felix@1160: /** The name of the CSV facet which triggers the CSV creation. */ ingo@391: public static final String FACET_CSV = "csv"; ingo@391: raimund@2176: /** The name of the PDF facet which triggers the PDF creation. */ raimund@2176: public static final String FACET_PDF = "pdf"; raimund@2176: felix@1160: /** The default charset for the CSV export. */ ingo@391: public static final String DEFAULT_CSV_CHARSET = "UTF-8"; ingo@391: felix@1160: /** The default separator for the CSV export. */ ingo@391: public static final char DEFAULT_CSV_SEPARATOR = ','; ingo@391: felix@1160: /** XPath that points to the desired export facet. */ ingo@445: public static final String XPATH_FACET = "/art:action/@art:type"; ingo@445: felix@1160: /** The document of the incoming out() request. */ ingo@391: protected Document request; ingo@391: felix@1160: /** The output stream where the data should be written to. */ ingo@391: protected OutputStream out; ingo@391: felix@1160: /** The CallContext object. */ ingo@391: protected CallContext context; ingo@391: felix@1160: /** The selected facet. */ ingo@391: protected String facet; ingo@391: ingo@3422: /** The collection.*/ ingo@3422: protected FLYSArtifactCollection collection; ingo@3422: felix@1160: /** The master artifact. */ ingo@412: protected Artifact master; ingo@412: ingo@391: ingo@391: /** ingo@391: * Concrete subclasses need to use this method to write their special data ingo@391: * objects into the CSV document. ingo@391: * ingo@391: * @param writer The CSVWriter. ingo@391: */ ingo@2792: protected abstract void writeCSVData(CSVWriter writer) throws IOException; ingo@391: ingo@391: ingo@391: /** raimund@2176: * Concrete subclasses need to use this method to write their special data raimund@2176: * objects into the PDF document. raimund@2176: */ raimund@2176: protected abstract void writePDF(OutputStream out); raimund@2176: raimund@2176: raimund@2176: /** ingo@391: * This method enables concrete subclasses to collected its own special ingo@391: * data. ingo@391: * felix@3270: * @param data The artifact that stores the data that has to be ingo@391: * exported. ingo@391: */ sascha@701: protected abstract void addData(Object data); ingo@391: felix@3270: sascha@710: @Override ingo@391: public void init(Document request, OutputStream out, CallContext context) { ingo@391: logger.debug("AbstractExporter.init"); ingo@391: ingo@391: this.request = request; ingo@391: this.out = out; ingo@391: this.context = context; ingo@391: } ingo@391: ingo@391: sascha@710: @Override ingo@412: public void setMasterArtifact(Artifact master) { ingo@412: this.master = master; ingo@412: } ingo@412: ingo@412: ingo@3422: @Override ingo@3422: public void setCollection(FLYSArtifactCollection collection) { ingo@3422: this.collection = collection; ingo@3422: } ingo@3422: ingo@3422: ingo@391: /** ingo@391: * This doOut() just collects the data of multiple artifacts. Therefore, it ingo@391: * makes use of the addData() method which enables concrete subclasses to ingo@391: * store its data on its own. The real output creation takes place in the ingo@391: * concrete generate() methods. ingo@391: * felix@3270: * @param artifactFacet The artifact and facet. felix@3270: * The facet to add - NOTE: the facet needs to fit to the first ingo@391: * facet inserted into this exporter. Otherwise this artifact/facet is ingo@391: * skipped. ingo@391: * @param attr The attr document. ingo@391: */ sascha@710: @Override ingo@1684: public void doOut( felix@1944: ArtifactAndFacet artifactFacet, felix@1944: Document attr, felix@1944: boolean visible ingo@1684: ) { felix@1944: String name = artifactFacet.getFacetName(); ingo@391: ingo@695: logger.debug("AbstractExporter.doOut: " + name); ingo@695: ingo@695: if (!isFacetValid(name)) { ingo@695: logger.warn("Facet '" + name + "' not valid. No output created!"); ingo@391: return; ingo@391: } ingo@391: ingo@2038: addData(artifactFacet.getData(context)); ingo@391: } ingo@391: ingo@391: ingo@391: /** ingo@391: * Generates an export based on a specified facet. ingo@391: */ sascha@710: @Override ingo@391: public void generate() ingo@391: throws IOException ingo@391: { ingo@391: logger.debug("AbstractExporter.generate"); ingo@391: sascha@3217: if (facet == null) { sascha@3217: throw new IOException("invalid (null) facet for exporter"); sascha@3217: } sascha@3217: sascha@3217: if (facet.equals(FACET_CSV)) { ingo@391: generateCSV(); ingo@391: } sascha@3217: else if (facet.equals(FACET_PDF)) { raimund@2176: generatePDF(); raimund@2176: } ingo@391: else { sascha@3223: throw new IOException( sascha@3223: "invalid facet for exporter: '" + facet + "'"); ingo@391: } ingo@391: } ingo@391: ingo@391: ingo@391: /** ingo@391: * Determines if the desired facet is valid for this exporter. If no facet ingo@391: * is currently set, facet is set. ingo@391: * ingo@391: * @param facet The desired facet. ingo@391: * ingo@391: * @return true, if facet is valid, otherwise false. ingo@391: */ ingo@391: protected boolean isFacetValid(String facet) { felix@2284: logger.debug("AbstractExporter.isFacetValid : " + facet + " (" + getFacet() + ")" ); ingo@391: ingo@445: String thisFacet = getFacet(); ingo@445: ingo@445: if (thisFacet == null || thisFacet.length() == 0) { ingo@391: return false; ingo@391: } ingo@445: else if (facet == null || facet.length() == 0) { ingo@445: return false; ingo@391: } ingo@391: else { ingo@445: return thisFacet.equals(facet); ingo@391: } ingo@391: } ingo@391: ingo@391: ingo@445: /** ingo@445: * Returns the name of the desired facet. ingo@445: * ingo@445: * @return the name of the desired facet. ingo@445: */ ingo@445: protected String getFacet() { ingo@445: if (facet == null) { ingo@445: facet = getFacetFromRequest(); ingo@445: } ingo@445: ingo@445: return facet; ingo@445: } ingo@445: ingo@445: ingo@445: /** ingo@445: * Extracts the name of the requested facet from request document. ingo@445: * ingo@445: * @return the name of the requested facet. ingo@445: */ ingo@445: protected String getFacetFromRequest() { ingo@445: return XMLUtils.xpathString( ingo@445: request, XPATH_FACET, ArtifactNamespaceContext.INSTANCE); ingo@445: } ingo@445: ingo@416: ingo@416: protected String msg(String key, String def) { ingo@416: return Resources.getMsg(context.getMeta(), key, def); ingo@416: } ingo@416: ingo@416: ingo@391: /** ingo@391: * This method starts CSV creation. It makes use of writeCSVData() which has ingo@391: * to be implemented by concrete subclasses. ingo@391: */ ingo@391: protected void generateCSV() ingo@391: throws IOException ingo@391: { ingo@391: logger.info("AbstractExporter.generateCSV"); ingo@391: rrenkert@4910: char quote = '"'; rrenkert@4910: char escape = '\\'; rrenkert@4910: ingo@391: CSVWriter writer = new CSVWriter( ingo@391: new OutputStreamWriter( ingo@391: out, ingo@391: DEFAULT_CSV_CHARSET), rrenkert@4910: DEFAULT_CSV_SEPARATOR, quote, escape, "\r\n"); ingo@391: ingo@391: writeCSVData(writer); ingo@391: ingo@391: writer.close(); ingo@391: } ingo@1979: ingo@1979: ingo@1979: /** raimund@2176: * This method starts PDF creation. raimund@2176: */ raimund@2176: protected void generatePDF() raimund@2176: throws IOException raimund@2176: { raimund@2176: logger.info("AbstractExporter.generatePDF"); raimund@2176: writePDF(this.out); raimund@2176: } raimund@2176: raimund@2176: raimund@2176: /** ingo@1979: * Returns an instance of EmptySettings currently! ingo@1979: * ingo@1979: * @return an instance of EmptySettings. ingo@1979: */ ingo@1979: public Settings getSettings() { ingo@1979: return new EmptySettings(); ingo@1979: } ingo@2047: ingo@2047: ingo@2047: /** ingo@2047: * This method is not implemented. Override it in subclasses if those need a ingo@2047: * Settings object. ingo@2047: */ ingo@2047: public void setSettings(Settings settings) { ingo@2047: // do nothing ingo@2047: } felix@2284: felix@2284: felix@2284: /** felix@2284: * Returns the number formatter for kilometer values. felix@2284: * felix@2284: * @return the number formatter for kilometer values. felix@2284: */ felix@2284: protected NumberFormat getKmFormatter() { felix@2284: return Formatter.getWaterlevelKM(context); felix@2284: } felix@2284: felix@2284: felix@2284: /** felix@2284: * Returns the number formatter for W values. felix@2284: * felix@2284: * @return the number formatter for W values. felix@2284: */ felix@2284: protected NumberFormat getWFormatter() { felix@2284: return Formatter.getWaterlevelW(context); felix@2284: } felix@2284: felix@2284: felix@2284: /** felix@2284: * Returns the number formatter for Q values. felix@2284: * felix@2284: * @return the number formatter for Q values. felix@2284: */ felix@2284: protected NumberFormat getQFormatter() { felix@2284: return Formatter.getWaterlevelQ(context); felix@2284: } ingo@391: } ingo@391: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :