tim@335: package de.intevation.gnv.state;
tim@335: 
ingo@839: import java.text.DateFormat;
ingo@839: import java.text.SimpleDateFormat;
ingo@839: 
tim@335: import java.util.ArrayList;
tim@598: import java.util.Arrays;
tim@335: import java.util.Collection;
tim@335: import java.util.Date;
tim@335: import java.util.GregorianCalendar;
tim@335: import java.util.HashMap;
tim@335: import java.util.Iterator;
tim@335: import java.util.List;
ingo@725: import java.util.Locale;
tim@335: import java.util.Map;
tim@335: 
ingo@488: import javax.xml.xpath.XPathConstants;
ingo@488: 
ingo@607: import net.sf.ehcache.Cache;
ingo@607: 
tim@335: 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@823: import de.intevation.artifactdatabase.Config;
tim@823: import de.intevation.artifactdatabase.XMLUtils;
tim@823: import de.intevation.artifacts.ArtifactNamespaceContext;
tim@823: import de.intevation.artifacts.CallContext;
tim@823: import de.intevation.artifacts.CallMeta;
tim@823: import de.intevation.gnv.artifacts.cache.CacheFactory;
tim@823: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
tim@823: import de.intevation.gnv.geobackend.base.Result;
tim@823: import de.intevation.gnv.geobackend.base.query.QueryExecutor;
tim@823: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
tim@823: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
tim@823: import de.intevation.gnv.geobackend.util.DateUtils;
tim@823: import de.intevation.gnv.state.describedata.DefaultKeyValueDescribeData;
tim@823: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
tim@823: import de.intevation.gnv.state.describedata.MinMaxDescribeData;
tim@823: import de.intevation.gnv.state.describedata.NamedArrayList;
tim@823: import de.intevation.gnv.state.describedata.NamedCollection;
tim@823: import de.intevation.gnv.state.describedata.SingleValueDescribeData;
tim@823: import de.intevation.gnv.state.exception.StateException;
tim@823: import de.intevation.gnv.utils.ArtifactXMLUtilities;
tim@823: import de.intevation.gnv.utils.InputValidator;
tim@823: 
tim@335: /**
ingo@796:  * This is the major implementation of <code>State</code>. Nearly every other
ingo@796:  * state is derived by this class.
ingo@796:  *
sascha@780:  * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
sascha@780:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
sascha@780:  * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
tim@335:  */
tim@335: public abstract class StateBase implements State {
tim@335: 
tim@335:     /**
tim@335:      * The UID of this Class
tim@335:      */
tim@335:     private static final long serialVersionUID = 2411169179001645426L;
tim@335: 
tim@335:     /**
tim@335:      * the logger, used to log exceptions and additonaly information
tim@335:      */
ingo@630:     private static Logger log = Logger.getLogger(StateBase.class);
ingo@605: 
ingo@607:     protected final static String MINVALUEFIELDNAME = "minvalue";
ingo@815: 
ingo@607:     protected final static String MAXVALUEFIELDNAME = "maxvalue";
ingo@605: 
tim@335:     private final static String NODATASELECTIONKEY = "n/n";
ingo@605: 
ingo@473:     public final static String DESCRIBEDATAKEY = "_DESCRIBEDATA";
tim@335: 
ingo@488:     public final static String XPATH_STATIC_UI  = "art:static";
ingo@815: 
ingo@488:     public final static String XPATH_DYNAMIC_UI = "art:dynamic";
ingo@488: 
ingo@725:     public static final String EXCEPTION_NO_INPUT      = "no.input.data";
ingo@815: 
ingo@725:     public static final String EXCEPTION_INVALID_INPUT =
ingo@725:         "input.is.not.valid";
ingo@870: 
tim@845:     public final static String HASH_ID_SEPARATOR = "#";
ingo@725: 
ingo@605:     /** input value names which should not be rendered from State itself */
ingo@605:     public final static String[] BLACKLIST = {"sourceid", "fisname"};
ingo@605: 
tim@335:     private String id = null;
tim@335: 
ingo@609:     protected String hash;
ingo@609: 
tim@335:     private String description = null;
tim@335: 
tim@335:     protected String dataName = null;
ingo@605: 
tim@598:     protected String preSettingsName = null;
tim@335: 
tim@335:     protected boolean dataMultiSelect = false;
ingo@605: 
tim@335:     protected boolean dataNoSelect = false;
tim@335: 
tim@335:     protected String queryID = null;
tim@335: 
tim@335:     protected Collection<String> inputValueNames = null;
tim@335: 
ingo@607:     protected Map<String, InputValue> inputValues = null;
tim@335: 
ingo@607:     protected State parent = null;
tim@335: 
tim@335:     protected Map<String, InputData> inputData = null;
ingo@605: 
ingo@607:     protected Map<String, InputData> preSettings = null;
tim@335: 
ingo@839: 
ingo@839:     /**
ingo@839:      * The source date format as string.
ingo@839:      */
ingo@839:     public static String srcDateFormat = "yyyy.MM.dd hh:mm:ss";
ingo@839: 
ingo@839: 
ingo@839:     /**
ingo@839:      * The source date format used to read string represented strings.
ingo@839:      */
ingo@839:     public static DateFormat srcFormat;
ingo@839: 
ingo@839: 
ingo@839:     static {
ingo@839:         srcFormat = new SimpleDateFormat(srcDateFormat);
ingo@839:     }
ingo@839: 
ingo@839: 
tim@335:     /**
tim@335:      * Constructor
tim@335:      */
tim@335:     public StateBase() {
tim@335:         super();
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     public String getID() {
tim@335:         return this.id;
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     public String getDescription() {
tim@335:         return this.description;
tim@335:     }
tim@335: 
tim@335: 
tim@335:     public Collection<InputValue> getRequiredInputValues() {
tim@335:         return this.inputValues.values();
tim@335:     }
tim@335: 
ingo@470: 
ingo@470:     public void reset(String uuid) {
ingo@614:         inputData.remove(dataName);
ingo@470:     }
ingo@470: 
ingo@473: 
tim@335:     public void setup(Node configuration) {
tim@335:         this.id = ((Element)configuration).getAttribute("id");
tim@335:         this.description = ((Element)configuration).getAttribute("description");
tim@335: 
tim@335:         log.info("State-ID = " + this.id);
sascha@778: 
tim@335:         NodeList inputValuesNodes = Config.getNodeSetXPath(configuration,
tim@335:                 "inputvalues/inputvalue");
tim@335:         this.inputValues = new HashMap<String, InputValue>(inputValuesNodes
tim@335:                 .getLength());
tim@335:         this.inputValueNames = new ArrayList<String>(inputValuesNodes
tim@335:                 .getLength());
tim@335:         for (int i = 0; i < inputValuesNodes.getLength(); i++) {
tim@335:             Element inputValueNode = (Element)inputValuesNodes.item(i);
tim@335:             String usedinQueryValue = inputValueNode.getAttribute("usedinquery");
tim@335:             int usedinQuery = 1;
tim@335:             if (usedinQueryValue != null) {
tim@335:                 try {
tim@335:                     usedinQuery = Integer.parseInt(usedinQueryValue);
tim@335:                 } catch (NumberFormatException e) {
tim@335:                     log
tim@335:                             .warn("Used in Query Value cannot be transformed into a Number");
tim@335:                 }
tim@335:             }
sascha@778:             InputValue inputValue = new DefaultInputValue(inputValueNode.getAttribute("name"),
sascha@778:                                                           inputValueNode.getAttribute("type"),
tim@335:                                                           Boolean.parseBoolean(inputValueNode.
tim@335:                                                           getAttribute("multiselect")), usedinQuery);
tim@335:             this.inputValues.put(inputValue.getName(), inputValue);
tim@335:             this.inputValueNames.add(inputValue.getName());
tim@335:         }
tim@335: 
tim@335:         this.queryID = Config.getStringXPath(configuration, "queryID");
tim@335:         log.info("QueryID ==> " + this.queryID);
tim@335: 
tim@335:         this.dataName = Config.getStringXPath(configuration, "dataname");
tim@335: 
tim@335:         String dataMultiSelectValue = Config.getStringXPath(configuration,
tim@335:                                                            "data-multiselect");
tim@335:         if (dataMultiSelectValue != null) {
tim@335:             this.dataMultiSelect = Boolean.parseBoolean(dataMultiSelectValue);
tim@335:         }
sascha@778: 
tim@335:         String dataNoSelectValue =Config.getStringXPath(configuration,
tim@335:                                                         "data-noselect");
tim@335:         if (dataNoSelectValue != null) {
tim@335:             this. dataNoSelect = Boolean.parseBoolean(dataNoSelectValue);
tim@335:         }
sascha@778: 
sascha@778:         this.preSettingsName = Config.getStringXPath(configuration, "presettings-name");
sascha@778: 
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     public State getParent() {
tim@335:         return this.parent;
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     public void setParent(State state) {
tim@335:         this.parent = state;
tim@335:     }
tim@335: 
ingo@607: 
ingo@725:     public Document feed(
ingo@725:         CallContext           context,
ingo@725:         Collection<InputData> inputData,
ingo@725:         String                uuid)
ingo@607:     throws StateException
ingo@607:     {
ingo@725:         RessourceFactory resFactory = RessourceFactory.getInstance();
ingo@725:         Locale[] serverLocales      = resFactory.getLocales();
ingo@725:         Locale locale               = context.getMeta().getPreferredLocale(
ingo@725:             serverLocales);
ingo@725: 
tim@335:         if (inputData != null) {
tim@335:             Iterator<InputData> it = inputData.iterator();
tim@335:             InputValidator iv = new InputValidator();
tim@335:             while (it.hasNext()) {
tim@335:                 InputData tmpItem = it.next();
tim@335:                 InputValue inputValue = this.inputValues.get(tmpItem.getName());
tim@335:                 if (inputValue != null) {
tim@335:                     if (this.inputData == null) {
tim@335:                         this.inputData = new HashMap<String, InputData>(
tim@335:                                 inputData.size());
tim@335:                     }
ingo@607: 
ingo@796:                     boolean valid = InputValidator.isInputValid(tmpItem.getValue(),
tim@335:                             inputValue.getType());
tim@335:                     if (valid) {
sascha@778: 
tim@763:                         if (tmpItem.getName().equals(this.dataName)){
tim@763:                             String[] desc = getDescriptionForInputData(tmpItem, uuid);
tim@763:                             tmpItem.setDescription(desc);
tim@763:                         }
tim@335:                         this.inputData.put(tmpItem.getName(), tmpItem);
tim@335:                     } else {
ingo@725:                         String msg = resFactory.getRessource(
ingo@725:                             locale,
ingo@725:                             EXCEPTION_INVALID_INPUT,
ingo@725:                             EXCEPTION_INVALID_INPUT);
ingo@725:                         log.warn(msg);
ingo@725:                         return feedFailure(msg);
tim@335:                     }
tim@335: 
tim@335:                 } else {
ingo@725:                     String msg = resFactory.getRessource(
ingo@725:                         locale,
ingo@725:                         EXCEPTION_INVALID_INPUT,
ingo@725:                         EXCEPTION_INVALID_INPUT);
ingo@725:                     log.warn(msg);
ingo@725:                     return feedFailure(msg);
tim@335: 
tim@335:                 }
tim@335:             }
ingo@725: 
ingo@725:             return feedSuccess();
tim@335:         } else {
ingo@725:             String msg = resFactory.getRessource(
ingo@725:                 locale,
ingo@725:                 EXCEPTION_NO_INPUT,
ingo@725:                 EXCEPTION_NO_INPUT);
ingo@725:             log.warn(msg);
ingo@725:             return feedFailure(msg);
tim@335:         }
tim@335:     }
tim@598: 
ingo@608: 
ingo@725:     protected Document feedSuccess() {
ingo@725:         return ArtifactXMLUtilities.createSuccessReport(
ingo@725:             "Initialize success", XMLUtils.newDocument());
ingo@725:     }
ingo@725: 
ingo@725: 
ingo@725:     protected Document feedFailure(String msg) {
ingo@725:         return ArtifactXMLUtilities.createInputExceptionReport(
ingo@725:             msg, XMLUtils.newDocument());
ingo@725:     }
ingo@725: 
ingo@725: 
tim@736:     protected String[] getDescriptionForInputData(InputData data, String uuid) {
ingo@608:         // there is only one element in the list, so take the first
ingo@608:         Object obj = getDescibeData(uuid).get(0);
ingo@615:         List descs = new ArrayList();
ingo@608: 
ingo@608:         if (obj instanceof NamedArrayList) {
ingo@608:             NamedArrayList list = (NamedArrayList) obj;
ingo@634:             List       selected = Arrays.asList(data.splitValue());
ingo@608:             int            size = list.size();
ingo@608: 
ingo@608:             for (int i = 0; i < size; i++) {
ingo@608:                 KeyValueDescibeData kv = (KeyValueDescibeData) list.get(i);
ingo@608: 
ingo@615:                 // values are concatinated in InputData, so one InputData object can
ingo@615:                 // contain many input
ingo@634:                 String key = kv.getKey();
ingo@634:                 int idx = selected.indexOf(key);
ingo@634:                 if (idx >= 0) {
ingo@634:                     descs.add(kv.getValue());
ingo@634: 
ingo@634:                     // XXX Workarround: I just wanted to remove the element at
ingo@634:                     // 'idx' from selected, but for any reason this is not
ingo@634:                     // possible (throws an exception) (iw)
ingo@634:                     List tmp = new ArrayList();
ingo@634:                     for (int j = 0; j < selected.size(); j++) {
ingo@634:                         if (j != idx)
ingo@634:                             tmp.add(selected.get(j));
ingo@615:                     }
ingo@634: 
ingo@634:                     selected = tmp;
ingo@608:                 }
ingo@608:             }
ingo@608:         }
ingo@608: 
ingo@615:         return (String[]) descs.toArray(new String[descs.size()]);
ingo@608:     }
ingo@608: 
ingo@608: 
ingo@607:     public void putInputData(Collection<InputData> inputData, String uuid)
ingo@607:     throws StateException {
ingo@607:         if (inputData != null) {
ingo@607:             Iterator<InputData> it = inputData.iterator();
ingo@607:             InputValidator iv = new InputValidator();
ingo@607:             while (it.hasNext()) {
ingo@607:                 InputData tmpItem = it.next();
ingo@607:                 InputValue inputValue = this.inputValues.get(tmpItem.getName());
ingo@607:                 if (inputValue != null) {
ingo@607:                     if (this.inputData == null) {
ingo@607:                         this.inputData = new HashMap<String, InputData>(
ingo@607:                                 inputData.size());
ingo@607:                     }
ingo@607: 
ingo@796:                     boolean valid = InputValidator.isInputValid(tmpItem.getValue(),
ingo@607:                             inputValue.getType());
ingo@607:                     if (valid) {
ingo@607:                         if (tmpItem.getName().equals(MINVALUEFIELDNAME)){
ingo@607:                             String minValue = tmpItem.getValue();
ingo@607:                             String maxValue = this.getInputValue4ID(inputData, MAXVALUEFIELDNAME);
ingo@796:                             valid = InputValidator.isInputValid(maxValue,inputValue.getType());
ingo@607:                             if (!valid){
ingo@607:                                 String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@607:                                                 + " is not an " + inputValue.getType()
ingo@607:                                                 + " Value.";
ingo@607:                                 log.warn(errMsg);
ingo@607:                                 throw new StateException(errMsg);
ingo@607:                             }
ingo@607: 
ingo@796:                             valid = InputValidator.isInputValid(minValue,
ingo@607:                                     maxValue,
ingo@607:                                     inputValue.getType());
ingo@607:                             if (!valid){
ingo@607:                                 String errMsg = "MaxValue-Input is less than MinValue-Input ";
ingo@607:                                 log.warn(errMsg);
ingo@607:                                 throw new StateException(errMsg);
ingo@607:                             }
ingo@607:                         }else if (tmpItem.getName().equals(MAXVALUEFIELDNAME)){
ingo@607:                             String minValue = this.getInputValue4ID(inputData, MINVALUEFIELDNAME);
ingo@607:                             String maxValue = tmpItem.getValue();
ingo@796:                             valid = InputValidator.isInputValid(minValue,inputValue.getType());
ingo@607:                             if (!valid){
ingo@607:                                 String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@607:                                                 + " is not an " + inputValue.getType()
ingo@607:                                                 + " Value.";
ingo@607:                                 log.warn(errMsg);
ingo@607:                                 throw new StateException(errMsg);
ingo@607:                             }
ingo@607: 
ingo@796:                             valid = InputValidator.isInputValid(minValue,
ingo@607:                                                     maxValue,
ingo@607:                                                     inputValue.getType());
ingo@607:                             if (!valid){
ingo@607:                                 String errMsg = "MaxValue-Input is less than MinValue-Input ";
ingo@607:                                 log.warn(errMsg);
ingo@607:                                 throw new StateException(errMsg);
ingo@607:                             }
ingo@607:                         }
ingo@607:                         this.inputData.put(tmpItem.getName(), tmpItem);
ingo@607:                     } else {
ingo@607:                         String errMsg = "Wrong input for " + tmpItem.getValue()
ingo@607:                                         + " is not an " + inputValue.getType()
ingo@607:                                         + " Value.";
ingo@607:                         log.warn(errMsg);
ingo@607:                         throw new StateException(errMsg);
ingo@607:                     }
ingo@607: 
ingo@607:                 } else {
ingo@607:                     String errMsg = "No Inputvalue given for Inputdata "
ingo@607:                                     + tmpItem.getName();
ingo@607:                     log.warn(errMsg + "Value will be ignored");
ingo@607: 
ingo@607:                 }
ingo@607:             }
ingo@607:         } else {
ingo@607:             log.warn("No Inputdata given");
ingo@607:         }
ingo@607: 
ingo@609:         setHash(uuid);
ingo@607:     }
ingo@607: 
ingo@607: 
tim@598:     public void setPreSettings(Map<String, InputData> preSettings) {
tim@598:         this.preSettings = preSettings;
tim@598:     }
sascha@778: 
sascha@778: 
tim@612:     public Map<String, InputData> getPreSettings() {
tim@612:         return this.preSettings;
tim@612:     }
tim@598: 
ingo@815: 
ingo@610:     protected String getInputValue4ID(Collection<InputData> inputData, String inputName){
tim@335:         Iterator<InputData> it = inputData.iterator();
tim@335:         while (it.hasNext()) {
tim@335:             InputData tmpItem = it.next();
tim@335:             if (tmpItem.getName().equals(inputName)){
tim@335:                 return tmpItem.getValue();
tim@335:             }
tim@335:         }
tim@335:         return null;
tim@335:     }
tim@335: 
tim@335: 
ingo@493:     public void advance(String uuid, CallContext context)
ingo@493:     throws StateException
ingo@493:     {
tim@335:     }
ingo@607: 
ingo@815: 
ingo@493:     public void initialize(String uuid, CallContext context)
ingo@493:     throws StateException
ingo@493:     {
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     protected String[] generateFilterValuesFromInputData() {
tim@335:         List<String> list = new ArrayList<String>();
tim@335:         Iterator<String> it = this.inputValueNames.iterator();
tim@335:         while (it.hasNext()) {
tim@335:             String value = it.next();
tim@335:             InputData data = this.inputData.get(value);
tim@335:             if (data != null
tim@335:                 && this.inputValues.containsKey(data.getName())) {
tim@335:                 int size = this.inputValues.get(data.getName())
tim@335:                         .usedInQueries();
tim@335:                 String type = this.inputValues.get(data.getName())
tim@335:                         .getType();
tim@335:                 String requestValue = data.getValue();
tim@335:                 if (type.equalsIgnoreCase("string")) {
tim@335:                     requestValue = this
tim@335:                             .prepareInputData4DBQuery(requestValue);
tim@335:                 } else if (type.equalsIgnoreCase("date")) {
tim@335:                     requestValue = this
tim@335:                             .prepareInputData4DateDBQuery(requestValue);
tim@745:                 } else if (type.equalsIgnoreCase("coordinate") || (type.equalsIgnoreCase("geometry") && requestValue.toLowerCase().startsWith("point"))){
tim@335:                     requestValue = this
tim@335:                     .prepareInputData4RegionDBQuery(requestValue);
tim@335:                 }
tim@335:                 for (int j = 0; j < size; j++) {
tim@335:                     list.add(requestValue);
tim@335:                 }
tim@335:             }
tim@335:         }
ingo@428:         String[] filterValues = list.toArray(new String[list.size()]);
tim@335:         return filterValues;
tim@335:     }
sascha@778: 
ingo@815: 
tim@335:     protected String prepareInputData4RegionDBQuery(String value){
tim@335:         return value;
tim@335:     }
tim@335: 
tim@335:     private String prepareInputData4DateDBQuery(String value) {
tim@335:         if (value != null) {
tim@335:             String[] values = value.split(",");
tim@335:             String newValue = "";
tim@335:             for (int i = 0; i < values.length; i++) {
tim@335:                 if (newValue.length() > 0) {
tim@335:                     newValue = newValue + " , ";
tim@335:                 }
tim@335:                 // TODO JUST HACK FIND A BETTER RESOLUTION
tim@335:                 newValue = newValue + "to_date('" + values[i].trim()
tim@335:                            + "', 'YYYY.MM.DD HH24:MI:SS')";
tim@335:             }
tim@335:             return newValue;
tim@335:         }
tim@335: 
tim@335:         return value;
tim@335:     }
tim@335: 
tim@335:     private String prepareInputData4DBQuery(String value) {
tim@335:         if (value != null) {
tim@335:             String[] values = value.split(",");
tim@335:             String newValue = "";
tim@335:             for (int i = 0; i < values.length; i++) {
tim@335:                 if (newValue.length() > 0) {
tim@335:                     newValue = newValue + " , ";
tim@335:                 }
tim@335:                 newValue = newValue + "'" + values[i].trim() + "'";
tim@335:             }
tim@335:             return newValue;
tim@335:         }
tim@335: 
tim@335:         return value;
tim@335: 
tim@335:     }
tim@335: 
ingo@815: 
ingo@607:     protected List<Object> purifyResult(Collection<Result> result, String uuid) {
ingo@607:         List<Object> describeData = new ArrayList<Object>();
ingo@607: 
ingo@607:         NamedCollection<KeyValueDescibeData> keyValueDescibeData =
ingo@607:             extractKVP(result, "KEY", "VALUE");
ingo@607: 
ingo@607:         describeData.add(keyValueDescibeData);
ingo@607: 
ingo@607:         return describeData;
tim@335:     }
tim@335: 
ingo@815: 
tim@335:     protected NamedCollection<KeyValueDescibeData> extractKVP(Collection<Result> result,
tim@335:                                                               String keyid,
tim@335:                                                               String valueid) {
tim@335:         Iterator<Result> rit = result.iterator();
tim@335:         int dataSize = (this.dataNoSelect ? result.size()+1 : result.size());
ingo@607: 
tim@335:         NamedCollection<KeyValueDescibeData> keyValueDescibeData = new NamedArrayList<KeyValueDescibeData>(
tim@335:                 this.dataName, dataSize);
tim@335:         keyValueDescibeData.setMultiSelect(this.dataMultiSelect);
ingo@607: 
tim@335:         if (this.dataNoSelect){
ingo@473:             keyValueDescibeData.add(new DefaultKeyValueDescribeData(
ingo@473:                 NODATASELECTIONKEY,
ingo@473:                 "No Selection",
ingo@473:                 getID()
ingo@473:             ));
tim@335:         }
ingo@473: 
tim@335:         boolean initialized = false;
ingo@473:         int     keyPos      = 0;
ingo@473:         int     valuePos    = 1;
ingo@473:         String  previousKey = null;
ingo@607:         InputData preSettingsData =
ingo@607:             (this.preSettings != null && this.preSettingsName != null)
ingo@607:                 ? this.preSettings.get(this.preSettingsName)
ingo@607:                 : null;
tim@598:         boolean filterWithPresettings = preSettingsData != null;
ingo@607: 
tim@598:         List<String> preSettingValues = null;
tim@598:         if(filterWithPresettings){
tim@598:             preSettingValues = Arrays.asList(preSettingsData.splitValue());
tim@598:         }
tim@335:         while (rit.hasNext()) {
tim@335:             Result resultValue = rit.next();
tim@335:             if (!initialized){
tim@335:                 keyPos = resultValue.getResultDescriptor().getColumnIndex(keyid);
tim@335:                 valuePos = resultValue.getResultDescriptor().getColumnIndex(valueid);
tim@335:                 if (valuePos < 0){
tim@335:                     valuePos = 1;
tim@335:                 }
tim@335:                 initialized = true;
tim@335:             }
tim@335:             String tmpKey = resultValue.getString(keyPos);
ingo@607: 
sascha@778:             // TODO: FIXME: We have to do that because the arcsde does not
tim@598:             //       support a distinct Query on Layers.
tim@335:             if (previousKey == null || !tmpKey.equals(previousKey)){
tim@335:                 previousKey = tmpKey;
tim@598:                 if (!filterWithPresettings || preSettingValues.contains(tmpKey)){
tim@598:                     keyValueDescibeData.add(
tim@598:                             new DefaultKeyValueDescribeData(
sascha@778:                                                 tmpKey,
tim@598:                                                 resultValue.getString(valuePos),
tim@598:                                                 getID())
tim@598:                                 );
tim@598:                 }
tim@335:             }
tim@335:         }
tim@335:         return keyValueDescibeData;
tim@335:     }
tim@335: 
ingo@605: 
ingo@605:     public static boolean inBlackList(String key) {
ingo@605:         int length = BLACKLIST.length;
ingo@605:         for (int i = 0; i < length; i++) {
ingo@605:             if (BLACKLIST[i].equals(key)) {
ingo@605:                 return true;
ingo@605:             }
ingo@605:         }
ingo@605: 
ingo@605:         return false;
ingo@605:     }
ingo@605: 
ingo@815: 
ingo@605:     public void describe(
ingo@605:         Document    document,
ingo@605:         Node        rootNode,
ingo@605:         CallContext context,
ingo@605:         String      uuid)
ingo@605:     {
ingo@605:         XMLUtils.ElementCreator xCreator = new XMLUtils.ElementCreator(
ingo@605:             document,
ingo@605:             XMLUtils.XFORM_URL,
ingo@605:             XMLUtils.XFORM_PREFIX
ingo@605:         );
ingo@605: 
ingo@605:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@605:             document,
ingo@605:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@605:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@605:         );
ingo@605: 
ingo@605:         // append dynamic node
ingo@605:         Node dynamic = (Node) XMLUtils.xpath(
ingo@605:             rootNode,
ingo@605:             XPATH_DYNAMIC_UI,
ingo@605:             XPathConstants.NODE,
ingo@605:             ArtifactNamespaceContext.INSTANCE
ingo@605:         );
ingo@605: 
ingo@605:         describeDynamic(
ingo@605:             creator, xCreator, document, dynamic, context, uuid);
ingo@605: 
ingo@605:         // append static nodes
ingo@605:         Node staticNode = (Node) XMLUtils.xpath(
ingo@605:             rootNode,
ingo@605:             XPATH_STATIC_UI,
ingo@605:             XPathConstants.NODE,
ingo@605:             ArtifactNamespaceContext.INSTANCE
ingo@605:         );
ingo@605: 
ingo@636:         State parent = getParent();
ingo@636:         if (parent != null && parent instanceof StateBase) {
ingo@636:             ((StateBase) parent).describeStatic(
ingo@636:                 creator,xCreator, document, staticNode, context,uuid);
ingo@636:         }
ingo@605:     }
ingo@605: 
ingo@605: 
ingo@605:     protected void describeDynamic(
ingo@605:         XMLUtils.ElementCreator artCreator,
ingo@605:         XMLUtils.ElementCreator creator,
ingo@605:         Document                document,
ingo@605:         Node                    dynamic,
ingo@605:         CallContext             context,
ingo@605:         String                  uuid)
ingo@605:     {
ingo@605:         CallMeta callMeta = context.getMeta();
ingo@605: 
ingo@608:         if (dataName == null)
ingo@607:             return;
ingo@607: 
ingo@605:         List<Object> descibeData = getDescibeData(uuid);
ingo@605:         if (descibeData != null) {
ingo@605:             Iterator<Object> it = descibeData.iterator();
ingo@605: 
ingo@605:             while (it.hasNext()) {
ingo@605:                 Object o = it.next();
ingo@605:                 if ((!it.hasNext() && dataName != null)) {
ingo@605:                     appendToDynamicNode(
ingo@605:                         artCreator, creator, document, dynamic, callMeta, o);
ingo@605:                 }
ingo@605:             }
ingo@605:         }
ingo@605:     }
ingo@605: 
ingo@605: 
ingo@605:     protected void describeStatic(
ingo@605:         XMLUtils.ElementCreator artCreator,
ingo@605:         XMLUtils.ElementCreator creator,
ingo@605:         Document                document,
ingo@605:         Node                    staticNode,
ingo@605:         CallContext             context,
ingo@605:         String                  uuid)
ingo@605:     {
ingo@605:         State parent = getParent();
ingo@605:         if (parent != null && parent instanceof StateBase) {
ingo@605:             ((StateBase) parent).describeStatic(
ingo@605:                 artCreator, creator, document, staticNode, context, uuid);
ingo@605:         }
ingo@605: 
ingo@605:         CallMeta callMeta = context.getMeta();
ingo@608:         appendToStaticNode(artCreator, creator, document, staticNode, callMeta);
ingo@605:     }
tim@335: 
tim@335: 
ingo@456:     protected void appendToStaticNode(
ingo@473:         XMLUtils.ElementCreator artCreator,
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Document                document,
ingo@464:         Node                    staticNode,
ingo@608:         CallMeta                callMeta
ingo@456:     ) {
ingo@608:         InputData  data = inputData.get(dataName);
ingo@456: 
ingo@608:         if (data == null) {
ingo@605:             return;
ingo@456:         }
ingo@605: 
ingo@608:         Element selectNode = creator.create("select1");
ingo@608:         creator.addAttr(selectNode, "ref", dataName);
ingo@605: 
ingo@605:         Element lableNode = creator.create("label");
ingo@605:         lableNode.setTextContent(RessourceFactory.getInstance()
ingo@608:                 .getRessource(callMeta.getLanguages(), dataName, dataName));
ingo@605:         Element choiceNode = creator.create("choices");
ingo@605: 
ingo@605:         artCreator.addAttr(
ingo@605:             selectNode, "state", getID(), true
ingo@605:         );
ingo@605: 
ingo@615:         String[] descriptions = data.getDescription();
ingo@615:         int              size = descriptions.length;
ingo@605: 
ingo@615:         for (int i = 0; i < size; i++) {
ingo@615:             Element itemNode = creator.create("item");
ingo@637:             String value = data.getValue();
ingo@637:             String desc  = descriptions[i];
ingo@637:             desc = desc == null ? value : desc;
ingo@605: 
ingo@615:             creator.addAttr(itemNode, "selected", "true");
ingo@615: 
ingo@615:             Element choiceLableNode = creator.create("label");
ingo@637:             choiceLableNode.setTextContent(desc);
ingo@615:             itemNode.appendChild(choiceLableNode);
ingo@615: 
ingo@615:             Element choiceValueNode = creator.create("value");
ingo@637:             choiceValueNode.setTextContent(value);
ingo@615:             itemNode.appendChild(choiceValueNode);
ingo@615:             choiceNode.appendChild(itemNode);
ingo@456:         }
ingo@615: 
ingo@605:         selectNode.appendChild(lableNode);
ingo@605:         selectNode.appendChild(choiceNode);
ingo@605: 
ingo@605:         staticNode.appendChild(selectNode);
ingo@456:     }
ingo@456: 
ingo@456: 
ingo@456:     protected void appendToDynamicNode(
ingo@473:         XMLUtils.ElementCreator artCreator,
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Document                document,
ingo@464:         Node                    dynamicNode,
ingo@464:         CallMeta                callMeta,
ingo@464:         Object                  o
ingo@456:     ) {
ingo@456:         if (o instanceof Collection<?>) {
ingo@456:             String name = null;
ingo@456:             boolean multiselect = false;
ingo@456:             if (o instanceof NamedCollection<?>) {
ingo@456:                 NamedCollection<?> nc = ((NamedCollection<?>) o);
ingo@456:                 name = nc.getName();
ingo@456:                 multiselect = nc.isMultiSelect();
ingo@456:             } else {
ingo@456:                 Object[] names = this.inputValueNames.toArray();
ingo@456:                 name = names[names.length - 1].toString();
ingo@607:             }
ingo@456: 
ingo@464:             Element selectNode = creator.create(multiselect?"select":"select1");
ingo@464:             creator.addAttr(selectNode, "ref", name);
ingo@456: 
ingo@464:             Element lableNode = creator.create("label");
ingo@456:             lableNode.setTextContent(RessourceFactory.getInstance()
ingo@456:                     .getRessource(callMeta.getLanguages(), name, name));
ingo@464:             Element choiceNode = creator.create("choices");
ingo@456: 
ingo@456:             Collection<KeyValueDescibeData> values = (Collection<KeyValueDescibeData>) o;
ingo@456:             Iterator<KeyValueDescibeData> resultIt = values.iterator();
ingo@456:             while (resultIt.hasNext()) {
ingo@456:                 KeyValueDescibeData result = resultIt.next();
ingo@464:                 Element itemNode = creator.create("item");
ingo@456: 
ingo@456:                 if (result.isSelected()) {
ingo@456:                     itemNode.setAttribute("selected", "true");
tim@335:                 }
tim@335: 
ingo@464:                 Element choiceLableNode = creator.create("label");
ingo@456:                 choiceLableNode.setTextContent(result.getValue());
ingo@456:                 itemNode.appendChild(choiceLableNode);
ingo@456: 
ingo@464:                 Element choicValueNode = creator.create("value");
ingo@456:                 choicValueNode.setTextContent("" + result.getKey());
ingo@456:                 itemNode.appendChild(choicValueNode);
ingo@456:                 choiceNode.appendChild(itemNode);
tim@335:             }
ingo@456:             selectNode.appendChild(lableNode);
ingo@456:             selectNode.appendChild(choiceNode);
ingo@456: 
ingo@456:             dynamicNode.appendChild(selectNode);
tim@335:         }
ingo@456:         else if (o instanceof MinMaxDescribeData) {
ingo@456:             appendMinMaxDescribeData(
ingo@473:                 artCreator,
ingo@464:                 creator,
ingo@456:                 document,
ingo@456:                 dynamicNode,
ingo@456:                 callMeta,
ingo@456:                 o);
ingo@456:         }
ingo@456:         else if (o instanceof SingleValueDescribeData) {
ingo@456:             appendSingleValueDescribeData(
ingo@473:                 artCreator,
ingo@464:                 creator,
ingo@456:                 document,
ingo@456:                 dynamicNode,
ingo@456:                 callMeta,
ingo@456:                 o);
ingo@456:         }
ingo@456:     }
ingo@456: 
ingo@456: 
ingo@456:     protected void appendMinMaxDescribeData(
ingo@473:         XMLUtils.ElementCreator artCreator,
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Document                document,
ingo@464:         Node                    node,
ingo@464:         CallMeta                callMeta,
ingo@464:         Object                  o
ingo@456:     ) {
ingo@456:         MinMaxDescribeData minMaxDescibeData = (MinMaxDescribeData) o;
ingo@456:         Object min = minMaxDescibeData.getMinValue();
ingo@456:         Object max = minMaxDescibeData.getMaxValue();
ingo@456:         if (min instanceof GregorianCalendar) {
ingo@456:             Date d = ((GregorianCalendar) min).getTime();
ingo@456:             min = DateUtils.getPatternedDateAmer(d);
ingo@456:         }
ingo@456: 
ingo@456:         if (max instanceof GregorianCalendar) {
ingo@456:             Date d = ((GregorianCalendar) max).getTime();
ingo@456:             max = DateUtils.getPatternedDateAmer(d);
ingo@456:         }
ingo@456: 
ingo@464:         Element groupNode = creator.create("group");
ingo@473:         artCreator.addAttr(groupNode, "state", minMaxDescibeData.getState(), true);
ingo@473: 
ingo@464:         creator.addAttr(groupNode, "ref", minMaxDescibeData.getName());
ingo@464:         Element groupNodeLableNode = creator.create("label");
ingo@456:         groupNodeLableNode.setTextContent(RessourceFactory
ingo@456:                 .getInstance().getRessource(
ingo@456:                         callMeta.getLanguages(),
ingo@456:                         minMaxDescibeData.getName(),
ingo@456:                         minMaxDescibeData.getName()));
ingo@456:         groupNode.appendChild(groupNodeLableNode);
ingo@456: 
ingo@464:         Element inputMinNode = creator.create("input");
ingo@464:         creator.addAttr(inputMinNode, "ref", MINVALUEFIELDNAME);
ingo@464:         Element inputMinLableNode = creator.create("label");
ingo@456:         inputMinLableNode.setTextContent(RessourceFactory
ingo@456:                 .getInstance().getRessource(
ingo@456:                         callMeta.getLanguages(), MINVALUEFIELDNAME,
ingo@456:                         MINVALUEFIELDNAME));
ingo@456:         inputMinNode.appendChild(inputMinLableNode);
ingo@456: 
ingo@464:         Element inputMinValueNode = creator.create("value");
ingo@456:         inputMinValueNode.setTextContent(min.toString());
ingo@456:         inputMinNode.appendChild(inputMinValueNode);
ingo@456: 
ingo@464:         Element inputMaxNode = creator.create("input");
ingo@464:         creator.addAttr(inputMaxNode, "ref", MAXVALUEFIELDNAME);
ingo@464:         Element inputMaxLableNode = creator.create("label");
ingo@456:         inputMaxLableNode.setTextContent(RessourceFactory
ingo@456:                 .getInstance().getRessource(
ingo@456:                         callMeta.getLanguages(), MAXVALUEFIELDNAME,
ingo@456:                         MAXVALUEFIELDNAME));
ingo@456:         inputMaxNode.appendChild(inputMaxLableNode);
ingo@456: 
ingo@464:         Element inputMaxValueNode = creator.create("value");
ingo@456:         inputMaxValueNode.setTextContent(max.toString());
ingo@456:         inputMaxNode.appendChild(inputMaxValueNode);
ingo@456: 
ingo@456:         groupNode.appendChild(inputMinNode);
ingo@456:         groupNode.appendChild(inputMaxNode);
ingo@456: 
ingo@456:         node.appendChild(groupNode);
ingo@456:     }
ingo@456: 
ingo@456: 
ingo@456:     protected void appendSingleValueDescribeData(
ingo@473:         XMLUtils.ElementCreator artCreator,
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Document                document,
ingo@464:         Node                    node,
ingo@464:         CallMeta                callMeta,
ingo@464:         Object                  o
ingo@456:     ) {
ingo@456:         SingleValueDescribeData svdb = (SingleValueDescribeData) o;
ingo@456: 
ingo@464:         Element groupNode = creator.create("group");
ingo@473:         artCreator.addAttr(groupNode, "state", svdb.getState(), true);
ingo@464:         creator.addAttr(groupNode, "ref",  svdb.getName());
ingo@464: 
ingo@464:         Element groupNodeLableNode = creator.create("label");
ingo@456:         groupNodeLableNode.setTextContent(RessourceFactory
ingo@456:                 .getInstance().getRessource(
ingo@456:                         callMeta.getLanguages(),
ingo@456:                         svdb.getName(),
ingo@456:                         svdb.getName()));
ingo@456:         groupNode.appendChild(groupNodeLableNode);
ingo@456: 
ingo@464:         Element inputNode = creator.create("input");
ingo@464:         creator.addAttr(inputNode, "ref", svdb.getName());
ingo@456: 
ingo@464:         Element inputLableNode = creator.create("label");
ingo@456:         inputLableNode.setTextContent("");
ingo@456:         inputNode.appendChild(inputLableNode);
ingo@456: 
ingo@464:         Element inputValueNode = creator.create("value");
ingo@456:         inputValueNode.setTextContent(svdb.getValue());
ingo@456:         inputNode.appendChild(inputValueNode);
ingo@456: 
ingo@456:         groupNode.appendChild(inputNode);
ingo@456: 
ingo@456:         node.appendChild(groupNode);
tim@335:     }
tim@335: 
ingo@607: 
ingo@609:     protected void setHash(String uuid) {
tim@845:         this.hash = uuid +
tim@845:                     HASH_ID_SEPARATOR +
tim@845:                     id +
tim@845:                     HASH_ID_SEPARATOR +
tim@845:                     inputData.hashCode();
ingo@609:     }
ingo@609: 
ingo@609: 
ingo@609:     protected String getHash() {
ingo@609:         return this.hash;
tim@335:     }
ingo@605: 
ingo@607: 
ingo@607:     public List<Object> getDescibeData(String uuid) {
ingo@607:         CacheFactory factory = CacheFactory.getInstance();
ingo@607:         if (factory.isInitialized()) {
ingo@607:             // we use a cache
ingo@609:             log.debug("Using cache.");
ingo@607:             Cache cache = factory.getCache();
ingo@609:             String key  = getHash();
ingo@607: 
ingo@607:             net.sf.ehcache.Element value = cache.get(key);
ingo@607:             if (value != null) {
ingo@607:                 // element already in cache, so return it.
ingo@609:                 log.debug("Found element in cache.");
ingo@607:                 return (List<Object>) (value.getObjectValue());
ingo@607:             }
ingo@607:             else {
ingo@607:                 // element is not in cache yet, so we need to fetch data from
ingo@607:                 // database and put it into cache right now
ingo@609:                 log.debug("Element not in cache, we need to ask the database");
ingo@607:                 try {
ingo@607:                     String[] filterValues = generateFilterValuesFromInputData();
ingo@607:                     List<Object> data     = queryDatabase(filterValues, uuid);
ingo@607: 
ingo@607:                     cache.put(new net.sf.ehcache.Element(key, data));
ingo@607:                     return data;
ingo@607:                 }
ingo@607:                 catch (QueryException qe) {
ingo@607:                     log.error(qe, qe);
ingo@607:                 }
ingo@607:             }
tim@335:         }
ingo@607:         else {
ingo@607:             // we don't use a cache, so we have to query the database every
ingo@607:             // single time
ingo@609:             log.debug("Not using cache.");
ingo@607:             String[] filterValues     = generateFilterValuesFromInputData();
ingo@607:             Collection<Result> result = null;
ingo@607:             try {
ingo@607:                 return queryDatabase(filterValues, uuid);
ingo@607:             }
ingo@607:             catch (RuntimeException e) {
ingo@607:                 log.error(e, e);
ingo@607:             }
ingo@607:             catch (QueryException e) {
ingo@607:                 log.error(e, e);
ingo@607:             }
ingo@607:         }
ingo@607: 
ingo@607:         return null;
tim@335:     }
tim@335: 
ingo@815: 
ingo@607:     protected List<Object> queryDatabase(String[] filterValues, String uuid)
ingo@607:     throws QueryException {
ingo@607:         Collection<Result> result = null;
ingo@607: 
ingo@607:         if (queryID != null) {
ingo@607:             QueryExecutor queryExecutor =
ingo@607:                 QueryExecutorFactory.getInstance().getQueryExecutor();
ingo@607: 
ingo@607:             result = queryExecutor.executeQuery(queryID, filterValues);
ingo@607:         }
ingo@607:         return purifyResult(result, uuid);
ingo@607:     }
ingo@607: 
ingo@607: 
ingo@815: 
ingo@473:     public Map<String, InputData> inputData() {
ingo@473:         return inputData;
ingo@473:     }
ingo@473: 
ingo@815: 
tim@335:     public Collection<InputData> getInputData() throws StateException {
tim@335:         return this.inputData != null ? this.inputData.values() : null;
tim@335:     }
sascha@481: 
ingo@815: 
ingo@740:     public InputData getInputDataByName(String name) {
ingo@740:         State state = this;
ingo@740: 
ingo@740:         while (state != null) {
ingo@740:             InputData data = state.inputData().get(name);
ingo@740:             if (data != null) {
ingo@740:                 return data;
ingo@740:             }
ingo@740: 
ingo@740:             state = state.getParent();
ingo@740:         }
ingo@740: 
ingo@740:         return null;
ingo@740:     }
ingo@740: 
ingo@815: 
sascha@481:     public void endOfLife(Object globalContext) {
sascha@481:     }
ingo@759: 
ingo@759: 
ingo@759:     public void cleanup(Object context) {
ingo@759:     }
tim@335: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :