ingo@1115: /* ingo@1115: * Copyright (c) 2010 by Intevation GmbH ingo@1115: * ingo@1115: * This program is free software under the LGPL (>=v2.1) ingo@1115: * Read the file LGPL.txt coming with the software for details ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1115: */ ingo@1115: 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; ingo@1030: import java.util.Set; ingo@1030: import java.util.TreeMap; 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: sascha@1117: import de.intevation.artifacts.common.utils.Config; sascha@1117: import de.intevation.artifacts.common.utils.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 State. Nearly every other ingo@796: * state is derived by this class. ingo@796: * sascha@780: * @author Tim Englich sascha@780: * @author Ingo Weinzierl sascha@780: * @author Sascha L. Teichmann 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 inputValueNames = null; tim@335: ingo@607: protected Map inputValues = null; tim@335: ingo@607: protected State parent = null; tim@335: tim@335: protected Map inputData = null; ingo@605: ingo@607: protected Map 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 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(inputValuesNodes tim@335: .getLength()); tim@335: this.inputValueNames = new ArrayList(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, 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 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) { ingo@1030: this.inputData = new TreeMap(); 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)){ ingo@1038: String[] desc = getDescriptionForInputData( ingo@1038: tmpItem, context, 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: ingo@1038: protected String[] getDescriptionForInputData( ingo@1038: InputData data, CallContext context, String uuid) ingo@1038: { 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, String uuid) ingo@607: throws StateException { ingo@607: if (inputData != null) { ingo@607: Iterator 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@1030: this.inputData = new TreeMap(); 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 preSettings) { tim@598: this.preSettings = preSettings; tim@598: } sascha@778: sascha@778: tim@612: public Map getPreSettings() { tim@612: return this.preSettings; tim@612: } tim@598: ingo@815: ingo@610: protected String getInputValue4ID(Collection inputData, String inputName){ tim@335: Iterator 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 list = new ArrayList(); tim@335: Iterator 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())) { ingo@1030: 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 purifyResult(Collection result, String uuid) { ingo@607: List describeData = new ArrayList(); ingo@607: ingo@607: NamedCollection 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 extractKVP(Collection result, tim@335: String keyid, tim@335: String valueid) { tim@335: Iterator rit = result.iterator(); tim@335: int dataSize = (this.dataNoSelect ? result.size()+1 : result.size()); ingo@607: tim@335: NamedCollection keyValueDescibeData = new NamedArrayList( 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 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 descibeData = getDescibeData(uuid); ingo@605: if (descibeData != null) { ingo@605: Iterator 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@1030: if (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@1030: InputData data = dataName!= null ? inputData.get(dataName) : null; 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 values = (Collection) o; ingo@456: Iterator 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) { ingo@1030: String newHash = uuid + HASH_ID_SEPARATOR + id + HASH_ID_SEPARATOR; ingo@1030: Set keys = inputData.keySet(); ingo@1030: ingo@1030: int nhash = 0; ingo@1030: int shift = 0; ingo@1030: ingo@1030: for (Object o: keys) { ingo@1030: nhash ^= inputData.get(o).hashCode() << shift; ingo@1030: shift += 2; ingo@1030: } ingo@1030: ingo@1030: log.info("### OLD HASH: " + hash); ingo@1030: log.info("### NEW HASH: " + (newHash + nhash)); ingo@1030: ingo@1030: this.hash = newHash + nhash; ingo@609: } ingo@609: ingo@609: ingo@1060: protected String getHash() { ingo@609: return this.hash; tim@335: } ingo@605: ingo@607: ingo@607: public List getDescibeData(String uuid) { ingo@607: CacheFactory factory = CacheFactory.getInstance(); ingo@607: if (factory.isInitialized()) { ingo@607: // we use a cache ingo@607: Cache cache = factory.getCache(); ingo@1060: String key = getHash(); ingo@1030: ingo@1030: log.debug("Using cache - key: " + key); 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) (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 data = queryDatabase(filterValues, uuid); ingo@607: ingo@607: cache.put(new net.sf.ehcache.Element(key, data)); ingo@1030: 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 = 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 queryDatabase(String[] filterValues, String uuid) ingo@607: throws QueryException { ingo@607: Collection 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 inputData() { ingo@473: return inputData; ingo@473: } ingo@473: ingo@815: tim@335: public Collection 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) { ingo@1060: log.debug("end of life of the current state."); ingo@1060: ingo@1060: CacheFactory factory = CacheFactory.getInstance(); ingo@1060: if (factory.isInitialized()) { ingo@1060: Cache cache = factory.getCache(); ingo@1060: String key = getHash(); ingo@1060: ingo@1060: if (key != null && cache.remove(key)) { ingo@1060: log.info("Removed element from cache - key: " + key); ingo@1060: } ingo@1060: } 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 :