tim@335: /**
tim@335:  *
tim@335:  */
tim@335: package de.intevation.gnv.state;
tim@335: 
tim@335: import java.io.OutputStream;
tim@335: import java.util.ArrayList;
tim@335: import java.util.Collection;
ingo@610: import java.util.HashMap;
ingo@610: import java.util.Iterator;
ingo@626: import java.util.List;
tim@335: import java.util.Locale;
tim@335: 
ingo@626: import javax.xml.xpath.XPathConstants;
ingo@626: 
ingo@631: import net.sf.ehcache.Cache;
ingo@631: 
sascha@480: import org.apache.log4j.Logger;
tim@335: import org.w3c.dom.Document;
tim@335: import org.w3c.dom.Element;
tim@335: import org.w3c.dom.Node;
tim@335: import org.w3c.dom.NodeList;
tim@335: 
tim@616: import de.intevation.artifactdatabase.Config;
ingo@626: import de.intevation.artifactdatabase.XMLUtils; 
tim@616: import de.intevation.artifacts.CallContext;
tim@616: import de.intevation.artifacts.CallMeta;
tim@616: import de.intevation.gnv.artifacts.cache.CacheFactory;
tim@616: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
tim@616: import de.intevation.gnv.geobackend.base.Result;
tim@616: import de.intevation.gnv.geobackend.base.query.QueryExecutor;
tim@616: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
tim@616: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
tim@616: import de.intevation.gnv.state.describedata.MinMaxDescribeData;
tim@616: import de.intevation.gnv.state.exception.StateException;
tim@616: import de.intevation.gnv.utils.InputValidator;
tim@616: 
tim@335: /**
tim@335:  * @author Tim Englich <tim.englich@intevation.de>
tim@335:  * 
tim@335:  */
sascha@480: public abstract class OutputStateBase 
sascha@480: extends               StateBase 
sascha@480: implements            OutputState
sascha@480: {
sascha@480:     public static final String XPATH_OUTPUT_MODE =
sascha@480:         "/art:action/art:out/@name";
sascha@480: 
ingo@639:     public static final String XPATH_EXPORT_MODE =
ingo@639:         "/art:action/art:out/art:export/@name";
ingo@639: 
sascha@480:     public static final String XPATH_MIME_TYPE   =
sascha@480:         "/art:action/art:out/art:mime-type/@value";
tim@335: 
ingo@626:     public static final String XPATH_EXPORTS =
ingo@626:         "exportModes/export";
ingo@626: 
tim@335:     /**
tim@335:      * The UID of this Class
tim@335:      */
tim@335:     private static final long serialVersionUID = -1718732895737303823L;
tim@335: 
tim@335:     /**
tim@335:      * the logger, used to log exceptions and additonaly information
tim@335:      */
tim@335:     private static Logger log = Logger.getLogger(OutputStateBase.class);
tim@335: 
tim@335:     /**
tim@335:      * The different Outputmodes which are provided by an OutputState
tim@335:      */
tim@335:     protected Collection<OutputMode> outputModes = null;
tim@335:     
tim@335:     protected String queryODVID = null;
tim@335: 
tim@335:     /**
tim@335:      * Constructor
tim@335:      */
tim@335:     public OutputStateBase() {
tim@335:         super();
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.state.OutputState#getOutputModes()
tim@335:      */
tim@335:     public Collection<OutputMode> getOutputModes() {
tim@335:         log.debug("OutputStateBase.getOutputModes");
tim@335:         return this.outputModes;
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.state.StateBase#setup(org.w3c.dom.Node)
tim@335:      */
tim@335:     @Override
tim@335:     public void setup(Node configuration) {
tim@335:         log.debug("OutputStateBase.setup");
tim@335:         super.setup(configuration);
tim@335:         
tim@335:         this.queryODVID = Config.getStringXPath(configuration,"queryID-odv");
tim@335:         
tim@335:         NodeList outputModeList = Config.getNodeSetXPath(configuration,
tim@335:                 "outputsModes/outputsMode");
tim@335:         if (outputModeList != null) {
tim@335:             log.debug(outputModeList.getLength() + " were found.");
tim@335:             this.outputModes = new ArrayList<OutputMode>(outputModeList
tim@335:                     .getLength());
tim@335:             for (int i = 0; i < outputModeList.getLength(); i++) {
tim@335:                 Element currentNode = (Element)outputModeList.item(i);
tim@335:                 String name = currentNode.getAttribute("name");
tim@335:                 String description =currentNode.getAttribute("description");
tim@335:                 String mimeType = currentNode.getAttribute("mime-type");
tim@335:                 NodeList inputValuesList = Config.getNodeSetXPath(currentNode,
tim@335:                         "parameters/inputvalue");
tim@335:                 Collection<InputValue> inputParameters = null;
tim@335:                 if (inputValuesList != null) {
tim@335:                     inputParameters = new ArrayList<InputValue>(inputValuesList
tim@335:                             .getLength());
tim@335:                     for (int j = 0; j < inputValuesList.getLength(); j++) {
tim@335:                         Element currentInputValuesNode = (Element)inputValuesList.item(j);
tim@335:                         String inputValueName = currentInputValuesNode.getAttribute("name");
tim@335:                         String inputValueType = currentInputValuesNode.getAttribute("type");
tim@335:                         String defaultValue =currentInputValuesNode.getAttribute("value");
tim@335:                         boolean isMultiselect = false;
tim@335:                         InputValue inputValue = new DefaultInputValue(
tim@335:                                 inputValueName, inputValueType, defaultValue,
tim@335:                                 isMultiselect);
tim@335:                         inputParameters.add(inputValue);
tim@335:                     }
tim@335:                 }
tim@335: 
ingo@626:                 // parse export modes
ingo@626:                 List<ExportMode> exportList = null;
ingo@626:                 NodeList exports = (NodeList) XMLUtils.xpath(
ingo@626:                     currentNode, XPATH_EXPORTS, XPathConstants.NODESET);
ingo@626: 
ingo@626:                 if (exports != null) {
ingo@626:                     int exportSize   = exports.getLength();
ingo@626: 
ingo@626:                     exportList = new ArrayList<ExportMode>(exportSize);
ingo@626:                     for (int k = 0; k < exportSize; k++) {
ingo@626:                         Element exp    = (Element) exports.item(k);
ingo@626:                         String expName = exp.getAttribute("name");
ingo@626:                         String expDesc = exp.getAttribute("description");
ingo@626:                         String expMime = exp.getAttribute("mime-type");
ingo@626: 
ingo@626:                         exportList.add(
ingo@626:                             new DefaultExportMode(expName, expDesc, expMime));
ingo@626:                     }
ingo@626:                 }
ingo@626: 
tim@335:                 OutputMode outputMode = new DefaultOutputMode(name,
ingo@626:                         description, mimeType, inputParameters, exportList);
tim@335:                 log.debug(outputMode.toString());
tim@335:                 this.outputModes.add(outputMode);
tim@335: 
tim@335:             }
tim@335:         }
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.state.StateBase#advance()
tim@335:      */
tim@335:     @Override
ingo@493:     public void advance(String uuid, CallContext context)
ingo@493:     throws StateException
ingo@493:     {
tim@335:     }
tim@335: 
tim@335:     @Override
ingo@493:     public void initialize(String uuid, CallContext context)
ingo@493:     throws StateException
ingo@493:     {
tim@335:     }
tim@335: 
sascha@480:     public void out(
sascha@480:         Document              format, 
sascha@480:         Collection<InputData> inputData,
sascha@480:         OutputStream          outputStream, 
sascha@480:         String                uuid, 
sascha@480:         CallMeta              callMeta
sascha@480:     )
sascha@480:     throws StateException 
sascha@480:     {
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.state.OutputState#out(java.lang.String,
tim@335:      *      java.util.Collection, java.io.OutputStream)
tim@335:      */
tim@335:     public void out(String outputMode, Collection<InputData> inputData,
tim@335:                     OutputStream outputStream) throws StateException {
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @return
tim@335:      */
sascha@439:     protected Object getChartResult(String uuid, CallContext callContext) {
tim@335:         log.debug("OutputStateBase.getChartResult");
ingo@631:         CacheFactory factory = CacheFactory.getInstance();
ingo@631: 
ingo@631:         if (factory.isInitialized()) {
ingo@631:             // we use a cache
ingo@631:             log.info("Using cache.");
ingo@631:             Cache cache = factory.getCache();
ingo@631:             String key  = "chart_" + getHash();
ingo@631: 
ingo@631:             net.sf.ehcache.Element value = cache.get(key);
tim@335:             if (value != null) {
ingo@631:                 log.debug("Found element in cache.");
ingo@631:                 return value.getObjectValue();
ingo@631:             }
ingo@631:             else {
ingo@631:                 log.debug("Element not in cache, we need to ask the database");
ingo@631:                 Object result = getData(queryID);
ingo@631:                 cache.put(new net.sf.ehcache.Element(key, result));
ingo@631: 
ingo@631:                 return result;
tim@335:             }
tim@335:         }
ingo@631:         else {
ingo@631:             // we don't use a cache, so we have to query the database every
ingo@631:             // single time
ingo@631:             log.info("Not using a cache.");
ingo@631:             return getData(queryID);
ingo@631:         }
tim@335:     }
tim@335: 
sascha@439:     protected Object getChartFromCache(String uuid, CallContext callContext) {
tim@335:         log.debug("Fetch chart [" + uuid + "] from cache");
tim@335:         CacheFactory cacheFactory = CacheFactory.getInstance();
tim@335:         if (cacheFactory.isInitialized()) {
ingo@610:             String key = "chart_" + getHash();
tim@335:             net.sf.ehcache.Element object = cacheFactory.getCache().get(key);
tim@335: 
tim@335:             if (object != null) {
tim@335:                 return object.getObjectValue();
tim@335:             }
tim@335:         }
tim@335:         return null;
tim@335:     }
tim@335:     
tim@335:     protected Collection<Result> getODVResult(String uuid) {
tim@335:         log.debug("OutputStateBase.getODVResult");
tim@335:         // TODO add Caching? I think it's not nessessary
tim@335:         Collection<Result> returnValue = null;
tim@335:         if (this.queryODVID != null){
tim@335:             returnValue = this.getData(this.queryODVID);
tim@335:         }else{
tim@335:             log.warn("No Query for ODV Data is defined.");
tim@335:         }
tim@335:         return returnValue;
tim@335:     }
tim@335: 
tim@335:     /**
tim@335:      * @param returnValue
tim@335:      * @return
tim@335:      */
tim@616:     protected Collection<Result> getData(String queryID) {
tim@335:         log.debug("OutputStateBase.getData");
tim@335:         Collection<Result> returnValue = null;
tim@335:         try {
tim@335:             String[] filterValues = this.generateFilterValuesFromInputData();
tim@335:             try {
tim@335:                 QueryExecutor queryExecutor = QueryExecutorFactory
tim@335:                                               .getInstance()
tim@335:                                               .getQueryExecutor();
tim@335:                 returnValue  = queryExecutor.executeQuery(queryID,filterValues);
tim@335:             } catch (RuntimeException e) {
tim@335:                 log.error(e, e);
tim@335:             }
tim@335:         } catch (QueryException e) {
tim@335:             log.error(e, e);
tim@335:         }
tim@335:         return returnValue;
tim@335:     }
tim@335:     
tim@335:     protected void removeChartResult(String uuid) {
tim@335:         log.debug("OutputStateBase.getChartResult");
tim@335:         if (CacheFactory.getInstance().isInitialized()) {
ingo@610:             String key = "chart_" + getHash();
tim@335:             log.debug("Hash for Queryelements: " + key);
tim@335:             net.sf.ehcache.Element value = CacheFactory.getInstance().getCache().get(key);
tim@335:             if (value != null) {
tim@335:                 CacheFactory.getInstance().getCache().remove(key);
tim@335:             }
tim@335:         }
tim@335:     }
tim@335: 
tim@335:     protected void removeChart(String uuid) {
tim@335:         log.debug("OutputStateBase.removeChart from cache");
tim@335: 
tim@335:         CacheFactory cacheFactory = CacheFactory.getInstance();
tim@335:         if (cacheFactory.isInitialized()) {
ingo@610:             String key = "chart_" + getHash();
tim@335:             net.sf.ehcache.Element object = cacheFactory.getCache().get(key);
tim@335:             if (object != null)
tim@335:                 cacheFactory.getCache().remove(key);
tim@335:         }
tim@335:     }
tim@335: 
tim@335:     protected void purifyChart(Object chart, String uuid) {
tim@335:         log.debug("Prufify chart [" + uuid + "]");
tim@335:         CacheFactory cacheFactory = CacheFactory.getInstance();
tim@335:         if (cacheFactory.isInitialized()) {
ingo@610:             String key = "chart_" + getHash();
tim@335:             cacheFactory.getCache().put(new net.sf.ehcache.Element(key, chart));
tim@335:         }
tim@335:     }
tim@335: 
ingo@610: 
ingo@610:     @Override
ingo@610:     public void feed(Collection<InputData> inputData, String uuid)
ingo@610:     throws StateException
ingo@610:     {
ingo@610:         putInputData(inputData, uuid);
ingo@610:     }
ingo@610: 
tim@335:     /**
tim@335:      * @see de.intevation.gnv.state.StateBase#putInputData(java.util.Collection, java.lang.String)
tim@335:      */
tim@335:     @Override
tim@335:     public void putInputData(Collection<InputData> inputData, 
tim@335:                              String uuid)
tim@335:                                          throws StateException {
tim@335:         log.debug("OutputStateBase.putInputData");
tim@335:         this.removeChartResult(uuid);
tim@335:         this.removeChart(uuid);
ingo@610: 
ingo@610:         if (inputData != null) {
ingo@610:             Iterator<InputData> it = inputData.iterator();
ingo@610:             InputValidator iv = new InputValidator();
ingo@610:             while (it.hasNext()) {
ingo@610:                 InputData tmpItem     = it.next();
ingo@610:                 Object    tmpObj      = tmpItem.getObject();
ingo@610:                 InputValue inputValue = this.inputValues.get(tmpItem.getName());
ingo@610:                 if (inputValue != null) {
ingo@610:                     if (this.inputData == null) {
ingo@610:                         this.inputData = new HashMap<String, InputData>(
ingo@610:                                 inputData.size());
ingo@610:                     }
ingo@610: 
ingo@610:                     boolean valid = iv.isInputValid(tmpItem.getValue(),
ingo@610:                             inputValue.getType());
ingo@610:                     if (valid) {
ingo@610:                         if (tmpItem.getName().equals(MINVALUEFIELDNAME)){
ingo@610:                             String minValue = tmpItem.getValue();
ingo@610:                             String maxValue = getInputValue4ID(inputData, MAXVALUEFIELDNAME);
ingo@610:                             valid = iv.isInputValid(maxValue,inputValue.getType());
ingo@610:                             if (!valid){
ingo@610:                                 String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@610:                                                 + " is not an " + inputValue.getType()
ingo@610:                                                 + " Value.";
ingo@610:                                 log.warn(errMsg);
ingo@610:                                 throw new StateException(errMsg);
ingo@610:                             }
ingo@610: 
ingo@610:                             valid = iv.isInputValid(minValue,
ingo@610:                                     maxValue,
ingo@610:                                     inputValue.getType());
ingo@610:                             if (!valid){
ingo@610:                                 String errMsg = "MaxValue-Input is less than MinValue-Input ";
ingo@610:                                 log.warn(errMsg);
ingo@610:                                 throw new StateException(errMsg);
ingo@610:                             }
ingo@610:                         }else if (tmpItem.getName().equals(MAXVALUEFIELDNAME)){
ingo@610:                             String minValue = getInputValue4ID(inputData, MINVALUEFIELDNAME);
ingo@610:                             String maxValue = tmpItem.getValue();
ingo@610:                             valid = iv.isInputValid(minValue,inputValue.getType());
ingo@610:                             if (!valid){
ingo@610:                                 String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@610:                                                 + " is not an " + inputValue.getType()
ingo@610:                                                 + " Value.";
ingo@610:                                 log.warn(errMsg);
ingo@610:                                 throw new StateException(errMsg);
ingo@610:                             }
ingo@610: 
ingo@610:                             valid = iv.isInputValid(minValue,
ingo@610:                                                     maxValue,
ingo@610:                                                     inputValue.getType());
ingo@610:                             if (!valid){
ingo@610:                                 String errMsg = "MaxValue-Input is less than MinValue-Input ";
ingo@610:                                 log.warn(errMsg);
ingo@610:                                 throw new StateException(errMsg);
ingo@610:                             }
ingo@610:                         }
ingo@610:                         this.inputData.put(tmpItem.getName(), tmpItem);
ingo@610:                     } else {
ingo@610:                         String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@610:                                         + " is not an " + inputValue.getType()
ingo@610:                                         + " Value.";
ingo@610:                         log.warn(errMsg);
ingo@610:                         throw new StateException(errMsg);
ingo@610:                     }
ingo@610: 
ingo@610:                 } 
ingo@610:                 else if (tmpObj != null && tmpObj instanceof MinMaxDescribeData) {
ingo@610:                     MinMaxDescribeData data = (MinMaxDescribeData) tmpObj;
ingo@610:                     if (this.inputData == null) {
ingo@610:                         this.inputData = new HashMap<String, InputData>(inputData.size());
ingo@610:                     }
ingo@610:                     this.inputData.put(tmpItem.getName(), tmpItem);
ingo@610:                     this.inputData.put("minvalue", new DefaultInputData("minvalue", (String) data.getMinValue()));
ingo@610:                     this.inputData.put("maxvalue", new DefaultInputData("maxvalue", (String) data.getMaxValue()));
ingo@610:                 }
ingo@610:                 else {
ingo@610:                 
ingo@610:                     String errMsg = "No Inputvalue given for Inputdata "
ingo@610:                                     + tmpItem.getName();
ingo@610:                     log.warn(errMsg + "Value will be ignored");
ingo@610: 
ingo@610:                 }
ingo@610:             }
ingo@610:         } else {
ingo@610:             log.warn("No Inputdata given");
ingo@610:         }
tim@335:     }
tim@335: 
tim@335:     public void out(String outputMode, Collection<InputData> inputData,
tim@335:                     OutputStream outputStream, String uuid, CallMeta callMeta)
tim@335:                                                                               throws StateException {
tim@335:     }
tim@335: 
tim@335: 
tim@335:     protected String getMessage(Locale locale, String key, String value) {
tim@335:         return RessourceFactory.getInstance().getRessource(
tim@335:             locale,
tim@335:             key,
tim@335:             value
tim@335:         );
tim@335:     }
tim@335: }
ingo@626: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: