teichmann@5831: package org.dive4elements.river.artifacts.states; ingo@126: ingo@669: import java.text.NumberFormat; ingo@669: import java.util.Locale; ingo@126: import java.util.Map; sascha@697: import java.util.List; ingo@126: ingo@126: import org.apache.log4j.Logger; ingo@126: ingo@126: import org.w3c.dom.Document; ingo@126: import org.w3c.dom.Element; ingo@126: import org.w3c.dom.Node; ingo@126: teichmann@5831: import org.dive4elements.artifacts.Artifact; teichmann@5831: import org.dive4elements.artifacts.ArtifactNamespaceContext; teichmann@5831: import org.dive4elements.artifacts.CallContext; teichmann@5831: import org.dive4elements.artifacts.CallMeta; ingo@126: teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; sascha@697: teichmann@5831: import org.dive4elements.artifactdatabase.ProtocolUtils; ingo@126: teichmann@5831: import org.dive4elements.artifactdatabase.data.StateData; sascha@697: teichmann@5831: import org.dive4elements.artifactdatabase.state.AbstractState; teichmann@5831: import org.dive4elements.artifactdatabase.state.Facet; teichmann@5831: teichmann@5831: import org.dive4elements.river.artifacts.FLYSArtifact; teichmann@5831: teichmann@5831: import org.dive4elements.river.artifacts.resources.Resources; ingo@126: ingo@126: ingo@126: /** ingo@126: * @author Ingo Weinzierl ingo@126: */ ingo@126: public abstract class DefaultState extends AbstractState { ingo@126: felix@1029: /** The logger that is used in this class. */ ingo@126: private static Logger logger = Logger.getLogger(DefaultState.class); ingo@126: ingo@2015: ingo@2015: /** Determines, if the DESCRIBE document should contain default values or ingo@2015: * not. */ ingo@2015: public static final boolean USE_DEFAULTS = ingo@2015: Boolean.getBoolean("flys.use.default.values"); ingo@2015: felix@1768: /** The three possible compute types. */ sascha@697: public static enum ComputeType { ingo@942: FEED, ADVANCE, INIT sascha@697: } ingo@126: felix@1768: ingo@624: protected StateData getData(FLYSArtifact artifact, String name) { ingo@624: return artifact.getData(name); ingo@624: } ingo@624: ingo@624: felix@1136: /** felix@1136: * Append to a node and return xml description relevant for gui. felix@1136: */ ingo@134: public Element describeStatic( ingo@624: Artifact artifact, ingo@134: Document document, ingo@134: Node root, ingo@134: CallContext context, ingo@134: String uuid) ingo@134: { ingo@1159: ElementCreator creator = new ElementCreator( ingo@134: document, ingo@134: ArtifactNamespaceContext.NAMESPACE_URI, ingo@134: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@134: ingo@142: CallMeta meta = context.getMeta(); ingo@142: bjoern@4155: String helpText = getHelpText() != null ? bjoern@4155: Resources.getMsg(meta, getHelpText(), getHelpText()) bjoern@4155: : null; ingo@2661: ingo@142: String label = Resources.getMsg(meta, getID(), getID()); ingo@136: Element ui = ProtocolUtils.createArtNode( ingo@134: creator, "state", ingo@2661: new String[] { "name", "uiprovider", "label", "helpText"}, ingo@2661: new String[] { getID(), getUIProvider(), label, helpText }); ingo@134: ingo@134: Map theData = getData(); ingo@134: if (theData == null) { ingo@134: return ui; ingo@134: } ingo@134: sascha@3732: FLYSArtifact flys = (FLYSArtifact)artifact; ingo@134: sascha@3732: for (String name: theData.keySet()) { ingo@1180: appendStaticData(flys, context, creator, ui, name); ingo@134: } ingo@134: ingo@134: return ui; ingo@134: } ingo@134: ingo@134: ingo@1159: protected void appendStaticData( ingo@1159: FLYSArtifact flys, ingo@1180: CallContext context, ingo@1180: ElementCreator cr, ingo@1159: Element ui, ingo@1159: String name ingo@1159: ) { ingo@1159: StateData data = getData(flys, name); ingo@1159: String value = (data != null) ? (String) data.getValue() : null; ingo@1159: ingo@1159: if (value == null) { ingo@1159: return; ingo@1159: } ingo@1159: ingo@2205: String type = data.getType(); ingo@1159: sascha@3732: if (logger.isDebugEnabled()) { sascha@3732: logger.debug( sascha@3732: "Append element " + type + "'" + sascha@3732: name + "' (" + value + ")"); sascha@3732: } ingo@2205: ingo@2205: Element e = createStaticData(flys, cr, context, name, value, type); ingo@1180: ingo@1180: ui.appendChild(e); ingo@1180: ingo@1180: } ingo@1180: ingo@1180: ingo@1180: /** ingo@1180: * Creates a data element used in the static part of the DESCRIBE ingo@1180: * document. ingo@1180: * ingo@1180: * @param creator The ElementCreator that is used to build new Elements. felix@3284: * @param cc The CallContext object used for nested i18n retrieval. ingo@1180: * @param name The name of the data item. ingo@1180: * @param value The value as string. ingo@1180: * ingo@1180: * @return an Element. ingo@1180: */ ingo@1180: protected Element createStaticData( ingo@1743: FLYSArtifact flys, ingo@1180: ElementCreator creator, ingo@1180: CallContext cc, ingo@1180: String name, ingo@1180: String value, ingo@1180: String type ingo@1180: ) { ingo@1159: Element dataElement = creator.create("data"); ingo@1159: creator.addAttr(dataElement, "name", name, true); ingo@1180: creator.addAttr(dataElement, "type", type, true); ingo@1159: ingo@1159: Element itemElement = creator.create("item"); ingo@1159: creator.addAttr(itemElement, "value", value, true); ingo@1159: ingo@2205: creator.addAttr( ingo@2205: itemElement, ingo@2205: "label", ingo@2205: getLabelFor(cc, name, value, type), ingo@2205: true); ingo@2205: ingo@2205: dataElement.appendChild(itemElement); ingo@2205: ingo@2205: return dataElement; ingo@2205: } ingo@2205: ingo@2205: ingo@2205: /** ingo@2205: * @param cc ingo@2205: * @param name ingo@2205: * @param value ingo@2205: * @param type ingo@2205: * ingo@2205: * @return ingo@2205: */ ingo@2205: protected String getLabelFor( ingo@2205: CallContext cc, ingo@2205: String name, ingo@2205: String value, ingo@2205: String type ingo@2205: ) { ingo@2205: CallMeta meta = cc.getMeta(); ingo@2205: ingo@1159: try { ingo@1159: // XXX A better way to format the output would be to use the ingo@1159: // 'type' value of the data objects. sascha@3732: double doubleVal = Double.parseDouble(value); ingo@1159: Locale l = Resources.getLocale(meta); ingo@1159: NumberFormat nf = NumberFormat.getInstance(l); ingo@1159: ingo@2205: return nf.format(doubleVal); ingo@1159: } ingo@1159: catch (NumberFormatException nfe) { ingo@2205: return Resources.getMsg(meta, value, value); ingo@1159: } ingo@1159: } ingo@1159: ingo@1159: ingo@3407: /** ingo@3407: * This method returns the default value and description for data. ingo@3407: * Note, that this method returns the defaults only if USE_DEFAULTS sascha@3414: * is set; otherwise, null is returned. ingo@3407: * @param context The CallContext used for i18n. ingo@3407: * @param data The data objects that the defaults are for. ingo@3407: * @return a String[] with [default value, default label]. ingo@3407: */ ingo@3407: protected String[] getDefaultsFor(CallContext context, StateData data) { ingo@3407: if (USE_DEFAULTS) { ingo@3407: String defValue = (String) data.getValue(); ingo@3407: String defDesc = null; ingo@3407: ingo@3407: if (defValue != null && defValue.length() > 0) { ingo@3407: defDesc = Resources.getMsg( ingo@3407: context.getMeta(), ingo@3407: defValue, ingo@3407: defValue); ingo@3407: } ingo@3407: ingo@3407: if (defValue != null && defDesc != null) { ingo@3407: return new String[] { defValue, defDesc }; ingo@3407: } ingo@3407: } ingo@3407: ingo@3407: return null; ingo@3407: } ingo@3407: ingo@3407: ingo@126: public Element describe( ingo@306: Artifact artifact, ingo@126: Document document, ingo@126: Node root, ingo@126: CallContext context, ingo@126: String uuid) ingo@126: { ingo@1159: ElementCreator creator = new ElementCreator( ingo@126: document, ingo@126: ArtifactNamespaceContext.NAMESPACE_URI, ingo@126: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@126: ingo@2661: String helpText = Resources.getMsg( ingo@2661: context.getMeta(), getHelpText(), getHelpText()); ingo@2661: ingo@135: Element ui = null; ingo@135: String uiprovider = getUIProvider(); ingo@135: if (uiprovider != null) { felix@1136: ui = ProtocolUtils.createArtNode( ingo@135: creator, "dynamic", ingo@2661: new String[] { "uiprovider", "helpText" }, ingo@2661: new String[] { uiprovider, helpText }); ingo@135: } ingo@135: else { ingo@2661: ui = ProtocolUtils.createArtNode( ingo@2661: creator, "dynamic", ingo@2661: new String[] { "helpText" }, ingo@2661: new String[] { helpText }); ingo@135: } ingo@126: ingo@126: Map theData = getData(); ingo@126: if (theData == null) { ingo@126: return ui; ingo@126: } ingo@126: sascha@3732: FLYSArtifact flys = (FLYSArtifact)artifact; ingo@126: sascha@3732: for (String name: theData.keySet()) { ingo@624: StateData data = getData(flys, name); ingo@624: sascha@3732: if (data == null) { sascha@3732: data = getData(name); sascha@3732: } ingo@624: ingo@313: Element select = createData(creator, artifact, data, context); ingo@126: ingo@3407: String[] defaults = getDefaultsFor(context, data); ingo@3407: if (defaults != null && defaults.length > 1) { ingo@3407: creator.addAttr(select, "defaultValue", defaults[0], true); ingo@3407: creator.addAttr(select, "defaultLabel", defaults[1], true); ingo@630: } ingo@630: ingo@2189: appendItems(artifact, creator, name, context, select); ingo@126: ui.appendChild(select); ingo@126: } ingo@126: ingo@126: return ui; ingo@126: } ingo@126: ingo@126: ingo@126: /** ingo@2189: * @param artifact ingo@2189: * @param creator ingo@2189: * @param name ingo@2189: * @param context ingo@2189: * @param select ingo@2189: */ ingo@2189: protected void appendItems( ingo@2189: Artifact artifact, ingo@2189: ElementCreator creator, ingo@2189: String name, ingo@2189: CallContext context, ingo@2189: Element select ingo@2189: ) { ingo@2189: Element choices = ProtocolUtils.createArtNode( ingo@2189: creator, "choices", null, null); ingo@2189: ingo@2189: select.appendChild(choices); ingo@2189: ingo@2189: Element[] items = createItems(creator, artifact, name, context); ingo@2189: if (items != null) { ingo@2189: for (Element item: items) { ingo@2189: choices.appendChild(item); ingo@2189: } ingo@2189: } ingo@2189: } ingo@2189: ingo@2189: ingo@2189: /** ingo@126: * This method creates the root node that contains the list of selectable ingo@126: * items. ingo@126: * ingo@126: * @param cr The ElementCreator. ingo@126: * ingo@126: * @return the root node of the item list. ingo@126: */ ingo@126: protected Element createData( ingo@1159: ElementCreator cr, ingo@313: Artifact artifact, ingo@126: StateData data, ingo@126: CallContext context) ingo@126: { ingo@126: Element select = ProtocolUtils.createArtNode( ingo@126: cr, "select", null, null); ingo@129: cr.addAttr(select, "name", data.getName(), true); ingo@126: ingo@126: Element label = ProtocolUtils.createArtNode( ingo@126: cr, "label", null, null); ingo@126: ingo@129: select.appendChild(label); ingo@129: ingo@126: label.setTextContent(Resources.getMsg( ingo@126: context.getMeta(), ingo@126: getID(), ingo@126: getID())); ingo@126: ingo@126: return select; ingo@126: } ingo@126: ingo@126: ingo@126: /** ingo@126: * This method creates a list of items. These items represent the amount of ingo@126: * input data that is possible for this state. ingo@126: * ingo@126: * @param cr The ElementCreator. ingo@126: * @param name The name of the amount of data. ingo@126: * ingo@126: * @return a list of items. ingo@126: */ sascha@660: protected Element[] createItems( ingo@1159: ElementCreator cr, ingo@313: Artifact artifact, ingo@126: String name, sascha@660: CallContext context sascha@660: ) { sascha@660: return null; sascha@660: } ingo@135: ingo@135: ingo@322: /** ingo@1180: * This method is used to create an item Element that contains two ingo@1180: * further elements label and value. The label and value ingo@1180: * elements both have text nodes. ingo@1180: * ingo@1180: * @param cr The ElementCreator used to build new Elements. ingo@1180: * @param obj This implementation awaits a String array with [0] = label and ingo@1180: * [1] = value. ingo@1180: * ingo@1180: * @return an Element. ingo@1180: */ ingo@1180: protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { ingo@1180: Element item = ProtocolUtils.createArtNode(cr, "item", null, null); ingo@1180: Element label = ProtocolUtils.createArtNode(cr, "label", null, null); ingo@1180: Element value = ProtocolUtils.createArtNode(cr, "value", null, null); ingo@1180: ingo@1180: String[] arr = (String[]) obj; ingo@1180: ingo@1180: label.setTextContent(arr[0]); ingo@1180: value.setTextContent(arr[1]); ingo@1180: ingo@1180: item.appendChild(label); ingo@1180: item.appendChild(value); ingo@1180: ingo@1180: return item; ingo@1180: } ingo@1180: ingo@1180: ingo@1180: /** ingo@1176: * This method transform a given value into a StateData object. ingo@1176: * ingo@1176: * @param flys The FLYSArtifact. ingo@1176: * @param name The name of the data object. ingo@1176: * @param val The value of the data object. ingo@1176: * ingo@1176: * @return a StateData object with name and value. ingo@1176: */ ingo@1176: public StateData transform( ingo@1176: FLYSArtifact flys, ingo@1176: CallContext cc, ingo@2205: StateData stateData, ingo@1176: String name, ingo@1176: String val ingo@1176: ) { sascha@3732: if (logger.isDebugEnabled()) { sascha@3732: logger.debug("Transform data ('" + name + "','" + val + "')"); sascha@3732: } ingo@2205: ingo@2205: stateData.setValue(val); ingo@2205: ingo@2205: return stateData; ingo@1176: } ingo@1176: ingo@1176: ingo@1176: /** ingo@322: * This method validates the inserted data and returns true, if everything ingo@322: * was correct, otherwise an exception is thrown. ingo@322: * ingo@322: * @param artifact A reference to the owner artifact. ingo@322: * ingo@322: * @return true, if everything was fine. ingo@322: */ sascha@1050: public boolean validate(Artifact artifact) ingo@322: throws IllegalArgumentException ingo@322: { ingo@322: return true; ingo@322: } ingo@322: ingo@322: felix@1691: /** felix@1691: * Returns which UIProvider shall be used to aid user input. felix@1691: */ ingo@135: protected String getUIProvider() { ingo@135: return null; ingo@135: } ingo@687: felix@1136: sascha@697: public Object computeAdvance( sascha@697: FLYSArtifact artifact, sascha@697: String hash, sascha@742: CallContext context, sascha@742: List facets, sascha@697: Object old sascha@697: ) { sascha@697: return null; sascha@697: } ingo@687: felix@1136: sascha@697: public Object computeFeed( sascha@697: FLYSArtifact artifact, sascha@697: String hash, sascha@697: CallContext context, sascha@742: List facets, sascha@697: Object old sascha@697: ) { ingo@687: return null; ingo@687: } ingo@941: felix@1136: ingo@941: public Object computeInit( ingo@941: FLYSArtifact artifact, ingo@941: String hash, ingo@958: Object context, ingo@941: CallMeta meta, ingo@941: List facets) ingo@941: { ingo@941: return null; ingo@941: } ingo@126: } ingo@126: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :