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:
ingo@634: package de.intevation.gnv.state;
ingo@634:
sascha@1117: import de.intevation.artifacts.common.utils.XMLUtils;
sascha@652:
ingo@785: import de.intevation.artifacts.CallContext;
ingo@634: import de.intevation.artifacts.CallMeta;
ingo@634:
ingo@634: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
sascha@652:
ingo@634: import de.intevation.gnv.geobackend.base.Result;
ingo@634: import de.intevation.gnv.geobackend.base.ResultDescriptor;
sascha@652:
ingo@634: import de.intevation.gnv.state.describedata.ExtendedKeyValueData;
ingo@634: import de.intevation.gnv.state.describedata.KeyValueDescibeData;
ingo@634: import de.intevation.gnv.state.describedata.NamedArrayList;
ingo@634: import de.intevation.gnv.state.describedata.NamedCollection;
ingo@634:
ingo@785: import de.intevation.gnv.state.exception.StateException;
ingo@785:
ingo@785: import de.intevation.gnv.utils.InputValidator;
ingo@785:
ingo@634: import java.util.ArrayList;
ingo@634: import java.util.Arrays;
ingo@634: import java.util.Collection;
ingo@634: import java.util.Iterator;
ingo@634: import java.util.List;
ingo@785: import java.util.Locale;
ingo@1030: import java.util.TreeMap;
ingo@634:
ingo@634: import org.apache.log4j.Logger;
ingo@634:
ingo@634: import org.w3c.dom.Document;
ingo@634: import org.w3c.dom.Element;
ingo@634: import org.w3c.dom.Node;
ingo@634:
ingo@634: /**
ingo@796: * This state handles input of measurements relating to a parameter. The user
ingo@796: * interface description created by this class represents a matrix - each
ingo@796: * parameter in a single row, each measurement in a column. An invalid
ingo@796: * measurement column for a specific parameter is marked as disabled and should
ingo@796: * not be selected.
sascha@803: *
sascha@780: * @author Ingo Weinzierl
ingo@634: */
ingo@634: public class MeasurementState
ingo@634: extends DefaultState
ingo@634: {
ingo@634: private static Logger logger = Logger.getLogger(MeasurementState.class);
ingo@634:
ingo@634: public static final String SQL_KEY_PARAMETERID = "PARAMETERID";
ingo@634:
ingo@785: public static final String SEPARATOR = ";";
ingo@785:
ingo@634:
ingo@796: /**
ingo@796: * This class is used to generate the Matrix in MinMaxDateState
.
ingo@796: * Parameter and Measurements are stored in separate lists and can be
ingo@796: * requested via different methods.
ingo@796: *
ingo@796: * @author Ingo Weinzierl
ingo@796: */
ingo@634: private class ParameterMatrix {
ingo@634: private final Logger logger =
ingo@634: Logger.getLogger(ParameterMatrix.class);
ingo@634:
ingo@634: private List measurements;
ingo@634: private List mDescriptions;
ingo@634: private List parameters;
ingo@634: private boolean[][] values;
ingo@634:
ingo@796: /**
ingo@796: * Constructs a new matrix.
ingo@796: *
ingo@796: * @param data A collection containing the measurements.
ingo@796: * @param parameter An array of parameters.
ingo@796: */
ingo@634: public ParameterMatrix(Collection data, String[] parameter) {
ingo@634: measurements = new ArrayList(data.size());
ingo@634: mDescriptions = new ArrayList(data.size());
ingo@634: parameters = new ArrayList(parameter.length);
ingo@634:
ingo@634: values = new boolean[data.size()][parameter.length];
ingo@634: for (int i = 0; i < data.size(); i++) {
ingo@634: Arrays.fill(values[i], false);
ingo@634: }
ingo@634:
ingo@634: initParameters(parameter);
ingo@634: initMeasurements(data);
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Initialize the measurements used in this matrix.
sascha@803: *
ingo@796: * @param data The measurements.
ingo@796: */
ingo@634: private void initMeasurements(Collection data) {
ingo@634: Iterator iter = data.iterator();
ingo@634: while (iter.hasNext()) {
ingo@634: ExtendedKeyValueData value = (ExtendedKeyValueData) iter.next();
ingo@634: String key = value.getKey();
ingo@634: String val = value.getValue();
ingo@634: String parameter = value.getParameter();
ingo@634:
ingo@634: int i = measurements.indexOf(key);
ingo@634: int j = parameters.indexOf(parameter);
ingo@634: int tmp = mDescriptions.indexOf(val);
ingo@634:
ingo@634: if (i < 0) {
ingo@634: measurements.add(key);
ingo@634: i = measurements.indexOf(key);
ingo@1102:
ingo@1102: mDescriptions.add(val);
ingo@1102: tmp = mDescriptions.indexOf(val);
ingo@634: }
ingo@634:
ingo@634: if (j < 0) {
ingo@634: logger.warn("Not a valid parameter: " + parameter);
ingo@634: }
ingo@634:
ingo@634: if (i >= 0 && i < measurements.size() && j >= 0
ingo@634: && j < parameters.size())
ingo@634: {
ingo@634: values[i][j] = true;
ingo@634: }
ingo@634: }
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Initialize the parameters used in this matrix.
sascha@803: *
ingo@796: * @param parameter Parameters.
ingo@796: */
ingo@634: private void initParameters(String[] parameter) {
ingo@785: for (String param: parameter) {
ingo@785: parameters.add(param);
ingo@634: }
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Returns the number of measurements.
sascha@803: *
ingo@796: * @return the number of measurements.
ingo@796: */
ingo@634: public int measurementSize() {
ingo@634: if (measurements != null)
ingo@634: return measurements.size();
ingo@634:
ingo@634: return 0;
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Returns the number of parameters.
sascha@803: *
ingo@796: * @return number of parameters.
ingo@796: */
ingo@634: public int parameterSize() {
ingo@634: if (parameters != null)
ingo@634: return parameters.size();
ingo@634:
ingo@634: return 0;
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Returns the measurement at idx.
sascha@803: *
ingo@796: * @param idx Index.
ingo@796: * @return the measurement.
ingo@796: */
ingo@634: public String getMeasurement(int idx) {
ingo@634: if (idx >= 0 && idx < measurements.size())
ingo@634: return (String) measurements.get(idx);
ingo@634:
ingo@634: logger.warn("Index is out of bounds: " + idx);
ingo@634: return "";
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Returns the parameter at idx.
sascha@803: *
ingo@796: * @param idx Index
ingo@796: * @return the parameter.
ingo@796: */
ingo@634: public String getParameter(int idx) {
ingo@634: if (idx >= 0 && idx < parameters.size()) {
ingo@634: return (String) parameters.get(idx);
ingo@634: }
ingo@634:
ingo@634: logger.warn("Index is out of bounds: " + idx);
ingo@634: return "";
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * Returns a description text for a specific measurement.
ingo@796: *
ingo@796: * @param idx Index of a measurement.
ingo@796: * @return measurement's description.
ingo@796: */
ingo@634: public String getMDescription(int idx) {
ingo@634: if (mDescriptions != null) {
ingo@634: return (String) mDescriptions.get(idx);
ingo@634: }
ingo@634:
ingo@634: return null;
ingo@634: }
ingo@634:
ingo@796: /**
ingo@796: * This method returns true, if a measurement is valid for a specific
ingo@796: * parameter - otherwise false.
sascha@803: *
ingo@796: * @param i Index of a measurement column.
ingo@796: * @param j Index of a parameter row.
ingo@796: * @return true, if valid, else false.
ingo@796: */
ingo@634: public boolean isValid(int i, int j) {
ingo@634: if (i < 0 || i > measurements.size()
ingo@634: || j < 0 || j > parameters.size())
ingo@634: {
ingo@634: logger.warn("Index out of bounds: " + i + "|" + j);
ingo@634: return false;
ingo@634: }
ingo@634:
ingo@634: return values[i][j];
ingo@634: }
ingo@634: } // End of ParameterMatrix
ingo@634:
ingo@634:
ingo@634: public MeasurementState() {
ingo@634: super();
ingo@634: }
ingo@634:
ingo@634: @Override
ingo@634: protected NamedCollection extractKVP(
ingo@634: Collection result,
ingo@634: String keyid,
ingo@634: String valueid
ingo@634: ) {
ingo@634: NamedCollection kvdd =
ingo@634: new NamedArrayList(dataName, result.size());
ingo@634:
ingo@634: kvdd.setMultiSelect(true);
ingo@634:
ingo@634: int keyPos = -1;
ingo@634: int valPos = -1;
ingo@634: int parPos = -1;
ingo@634:
ingo@634: for (Result res: result) {
ingo@634: if (keyPos < 0 || valPos < 0 || parPos < 0) {
ingo@634: ResultDescriptor rd = res.getResultDescriptor();
ingo@634:
ingo@634: keyPos = rd.getColumnIndex(keyid);
ingo@634: valPos = rd.getColumnIndex(valueid);
ingo@634: parPos = rd.getColumnIndex(SQL_KEY_PARAMETERID);
ingo@634: }
ingo@634:
ingo@634: kvdd.add(new ExtendedKeyValueData(
ingo@634: res.getString(keyPos),
ingo@634: res.getString(valPos),
ingo@634: getID(),
ingo@634: res.getString(parPos)));
ingo@634: }
ingo@634:
ingo@634: return kvdd;
ingo@634: }
ingo@634:
ingo@634:
ingo@796: /**
ingo@796: * This method create the user interface description for measurement and
ingo@796: * parameters as matrix. A row for each parameter, a column for each
ingo@796: * measurement.
ingo@796: */
ingo@634: @Override
ingo@634: protected void appendToDynamicNode(
ingo@634: XMLUtils.ElementCreator artCreator,
ingo@634: XMLUtils.ElementCreator creator,
ingo@634: Document document,
ingo@634: Node dynamicNode,
ingo@634: CallMeta callMeta,
ingo@634: Object o
ingo@634: ) {
ingo@634: NamedArrayList all = (NamedArrayList) o;
ingo@634: String name = all.getName();
ingo@634: RessourceFactory factory = RessourceFactory.getInstance();
ingo@634:
ingo@634: Element matrixNode = creator.create("group");
ingo@634: Element matrixLabel = creator.create("label");
ingo@634: matrixLabel.setTextContent(factory.getRessource(
ingo@634: callMeta.getLanguages(), all.getName(), all.getName()));
ingo@634: creator.addAttr(matrixNode, "mode", "matrix");
ingo@634: matrixNode.appendChild(matrixLabel);
ingo@634:
ingo@634: InputData inputParam = inputData.get("parameterid");
ingo@634: ParameterMatrix matrix = new ParameterMatrix(all, inputParam.splitValue());
ingo@634:
ingo@634: int measurements = matrix.measurementSize();
ingo@634: int parameters = matrix.parameterSize();
ingo@634:
ingo@744: for (int i = 0; i < parameters; i++) {
ingo@634: Element select = creator.create("select");
ingo@785: String param = matrix.getParameter(i);
ingo@785: creator.addAttr(select, "label", inputParam.getDescription(param));
ingo@650: creator.addAttr(select, "ref", name);
ingo@634:
ingo@744: for (int j = 0; j < measurements; j++) {
ingo@634: Element item = creator.create("item");
ingo@634: Element label = creator.create("label");
ingo@634: Element value = creator.create("value");
ingo@634:
ingo@634: creator.addAttr(item, "ref", name);
ingo@634: creator.addAttr(
ingo@634: item,
ingo@634: "parameter",
ingo@744: matrix.getMDescription(j));
ingo@634:
ingo@744: if (!matrix.isValid(j, i)) {
ingo@634: creator.addAttr(item, "disabled", "true");
ingo@634: }
ingo@634: else {
ingo@634: creator.addAttr(item, "disabled", "false");
ingo@634: }
ingo@634:
ingo@785: String tmpValue = matrix.getMeasurement(j) + ";" + param;
ingo@744: label.setTextContent(matrix.getMDescription(j));
ingo@785: value.setTextContent(tmpValue);
ingo@634:
ingo@634: item.appendChild(label);
ingo@634: item.appendChild(value);
ingo@634: select.appendChild(item);
ingo@634: }
ingo@634:
ingo@634: matrixNode.appendChild(select);
ingo@634: }
ingo@634:
ingo@634: dynamicNode.appendChild(matrixNode);
ingo@634: }
ingo@785:
ingo@785:
ingo@796: /**
ingo@796: * This feed takes some input data storing measurement ids and parameter ids
ingo@796: * and put them into ExtendedInputData objects to save the relation between
ingo@796: * a measurement and the parameter it belongs to.
ingo@796: */
ingo@785: @Override
ingo@785: public Document feed(
ingo@785: CallContext context,
ingo@785: Collection input,
ingo@785: String uuid)
ingo@785: throws StateException
ingo@785: {
ingo@785: RessourceFactory resFactory = RessourceFactory.getInstance();
ingo@785: Locale[] serverLocales = resFactory.getLocales();
ingo@785: Locale locale = context.getMeta().getPreferredLocale(
ingo@785: serverLocales);
ingo@785:
ingo@785: if (input == null) {
ingo@785: String msg = resFactory.getRessource(
ingo@785: locale,
ingo@785: EXCEPTION_NO_INPUT,
ingo@785: EXCEPTION_NO_INPUT);
ingo@785: logger.warn(msg);
ingo@785: return feedFailure(msg);
ingo@785: }
ingo@785:
ingo@785: for(InputData item: input) {
ingo@785: String name = item.getName();
ingo@785: InputValue inputValue = inputValues.get(name);
ingo@785:
ingo@785: String[] tupel = extractValuesAndParams(item.getValue());
ingo@785: String type = inputValue.getType();
ingo@785:
ingo@785: if (inputValue == null) {
ingo@785: String msg = resFactory.getRessource(
ingo@785: locale,
ingo@785: EXCEPTION_INVALID_INPUT,
ingo@785: EXCEPTION_INVALID_INPUT);
ingo@785: logger.warn(msg);
ingo@785: return feedFailure(msg);
ingo@785: }
ingo@785:
ingo@785: if (!InputValidator.isInputValid(tupel[0], type)) {
ingo@785: String msg = resFactory.getRessource(
ingo@785: locale,
ingo@785: EXCEPTION_INVALID_INPUT,
ingo@785: EXCEPTION_INVALID_INPUT);
ingo@785: logger.warn(msg);
ingo@785: return feedFailure(msg);
ingo@785: }
ingo@785:
ingo@785: if (inputData == null) {
ingo@1030: inputData = new TreeMap();
ingo@785: }
ingo@785:
ingo@785: ExtendedInputData extended = new ExtendedInputData(
ingo@785: name,
ingo@785: tupel[0],
ingo@785: item.getObject(),
ingo@785: tupel[1]);
ingo@785:
ingo@785: if (name.equals(dataName)) {
ingo@1038: String[] desc = getDescriptionForInputData(
ingo@1038: extended, context, uuid);
ingo@785: extended.setDescription(desc);
ingo@785: }
ingo@785:
ingo@785: inputData.put(name, extended);
ingo@785: }
ingo@785:
ingo@785: return feedSuccess();
ingo@785: }
ingo@785:
ingo@785:
ingo@796: /**
ingo@796: * Extract parameter ids and measurement ids from DefaultInputData objects
ingo@796: * and return an array. In the first position of this array, the measurement
ingo@796: * ids are placed, in the second position the parameter ids - all separated
ingo@796: * by a character.
ingo@796: *
ingo@796: * @param tmp String containing measurement ids and parameter ids.
ingo@796: * @return An array with separated measurements and parameters.
ingo@796: */
ingo@785: protected String[] extractValuesAndParams(String tmp) {
ingo@785: String[] array = tmp.split(DefaultInputData.VALUE_SEPARATOR);
ingo@785:
ingo@785: String[] extracted = new String[2];
ingo@785: for (String item: array) {
ingo@785: String[] tupel = item.split(ExtendedInputData.SEPARATOR);
ingo@785:
ingo@785: if (extracted[0] == null) {
ingo@785: extracted[0] = tupel[0];
ingo@785: }
ingo@785: else {
ingo@785: extracted[0] +=
ingo@785: DefaultInputData.VALUE_SEPARATOR + tupel[0];
ingo@785: }
ingo@785:
ingo@785: if (extracted[1] == null) {
ingo@785: extracted[1] = tupel[1];
ingo@785: }
ingo@785: else {
ingo@785: extracted[1] += DefaultInputData.VALUE_SEPARATOR + tupel[1];
ingo@785: }
ingo@785: }
ingo@785:
ingo@785: logger.debug("VALUES RESULT: " + extracted[0]);
ingo@785: logger.debug("PARAMS RESULT: " + extracted[1]);
ingo@785:
ingo@785: return extracted;
ingo@785: }
ingo@634: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :