Package org.apache.cocoon.woody.formmodel

Source Code of org.apache.cocoon.woody.formmodel.AggregateField

/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.woody.formmodel;

import org.apache.cocoon.woody.Constants;
import org.apache.cocoon.woody.FormContext;
import org.apache.cocoon.woody.formmodel.AggregateFieldDefinition.SplitMapping;
import org.apache.cocoon.woody.util.I18nMessage;
import org.apache.cocoon.woody.validation.ValidationError;
import org.apache.cocoon.xml.AttributesImpl;
import org.apache.excalibur.xml.sax.XMLizable;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Matcher;

import org.outerj.expression.ExpressionException;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
* An aggregated field allows to represent one value as multiple input fields, or several values
* as one field. Hence this widget is a field and a container widget simultaneously.
*
* <p>Upon submit, it first attempts to read own value from the request, and splits over nested
* field widgets using a regular expression. If split fails, this will simply give a validation error.
* If own value was not submitted, it attempts to read values for nested field widgets, and combines
* theirs values using combine expression.
*
* <p>To validate this widget, both the validation rules of the nested widgets are
* checked, and those of the aggregated field themselves. The validation rules of the aggregated
* field can perform checks on the string as entered by the user (e.g. check its total length).
*
* <p>This field and nested fields can be of any supported type, as long as combine expression
* gives result of the correct type, and split regular expression can split string representation
* into parts which can be converted to the values of nested fields.
*
* @version CVS $Id: AggregateField.java,v 1.18 2004/03/09 13:53:55 reinhard Exp $
*/
public class AggregateField extends Field {

    /**
     * List of nested fields
     */
    private List fields = new ArrayList();

    /**
     * Map of nested fields
     */
    private Map fieldsById = new HashMap();


    public AggregateField(AggregateFieldDefinition definition) {
        super(definition);
    }

    public final AggregateFieldDefinition getAggregateFieldDefinition() {
        return (AggregateFieldDefinition)super.definition;
    }

    protected void addField(Field field) {
        field.setParent(this);
        fields.add(field);
        fieldsById.put(field.getId(), field);
    }

    public Iterator getChildren() {
        return fields.iterator();
    }

    public void readFromRequest(FormContext formContext) {
        String newEnteredValue = formContext.getRequest().getParameter(getFullyQualifiedId());
        if (newEnteredValue != null) {
            // There is one aggregated entered value. Read it and split it.
            super.readFromRequest(formContext);
            if (needsParse) {
                setFieldsValues(enteredValue);
            }
        } else {
            // Check if there are multiple splitted values. Read them and aggregate them.
            boolean needsParse = false;
            for (Iterator i = fields.iterator(); i.hasNext();) {
                Field field = (Field)i.next();
                field.readFromRequest(formContext);
                needsParse |= field.needsParse;
            }
            if (needsParse) {
                combineFields();
            }
        }
    }

    public void setValue(Object newValue) {
        super.setValue(newValue);
        if (needsValidate) {
            setFieldsValues(enteredValue);
        }
    }

    /**
     * Returns false if all fields have no value.
     */
    private boolean fieldsHaveValues() {
        for (Iterator i = fields.iterator(); i.hasNext();) {
            Field field = (Field)i.next();
            if (field.getValue() != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Splits passed value and sets values of all nested fields.
     * If split fails, resets all fields.
     */
    private void setFieldsValues(String value) {
        if (value == null) {
            resetFieldsValues();
        } else {
            PatternMatcher matcher = new Perl5Matcher();
            if (matcher.matches(value, getAggregateFieldDefinition().getSplitPattern())) {
                MatchResult matchResult = matcher.getMatch();
                Iterator iterator = getAggregateFieldDefinition().getSplitMappingsIterator();
                while (iterator.hasNext()) {
                    SplitMapping splitMapping = (SplitMapping)iterator.next();
                    String result = matchResult.group(splitMapping.getGroup());

                    // Fields can have a non-string datatype, going to the readFromRequest
                    Field field = (Field)fieldsById.get(splitMapping.getFieldId());
                    field.readFromRequest(result);
                }
            } else {
                resetFieldsValues();
            }
        }
    }

    public void combineFields() {
        try {
            Object value = getAggregateFieldDefinition().getCombineExpression().evaluate(new ExpressionContextImpl(this, true));
            super.setValue(value);
        } catch (CannotYetResolveWarning e) {
            super.setValue(null);
        } catch (ExpressionException e) {
            super.setValue(null);
        } catch (ClassCastException e) {
            super.setValue(null);
        }
    }

    /**
     * Sets values of all nested fields to null
     */
    private void resetFieldsValues() {
        for (Iterator i = fields.iterator(); i.hasNext();) {
            Field field = (Field)i.next();
            field.setValue(null);
        }
    }

    public boolean validate(FormContext formContext) {
        if ((enteredValue != null) != fieldsHaveValues()) {
            XMLizable failMessage = getAggregateFieldDefinition().getSplitFailMessage();
            if (failMessage != null) {
                validationError = new ValidationError(failMessage);
            } else {
                validationError = new ValidationError(new I18nMessage("aggregatedfield.split-failed",
                                                                      new String[] { getAggregateFieldDefinition().getSplitRegexp() },
                                                                      Constants.I18N_CATALOGUE));
            }
            return false;
        }

        // validate my child fields
        for (Iterator i = fields.iterator(); i.hasNext();) {
            Field field = (Field)i.next();
            if (!field.validate(formContext)) {
                validationError = field.getValidationError();
                return false;
            }
        }

        return super.validate(formContext);
    }


    private static final String AGGREGATEFIELD_EL = "aggregatefield";
    private static final String VALUE_EL = "value";
    private static final String VALIDATION_MSG_EL = "validation-message";

    public void generateSaxFragment(ContentHandler contentHandler, Locale locale) throws SAXException {
        AttributesImpl aggregatedFieldAttrs = new AttributesImpl();
        aggregatedFieldAttrs.addCDATAAttribute("id", getFullyQualifiedId());
        aggregatedFieldAttrs.addCDATAAttribute("required", String.valueOf(getAggregateFieldDefinition().isRequired()));
        contentHandler.startElement(Constants.WI_NS, AGGREGATEFIELD_EL, Constants.WI_PREFIX_COLON + AGGREGATEFIELD_EL, aggregatedFieldAttrs);

        if (enteredValue != null || value != null) {
            contentHandler.startElement(Constants.WI_NS, VALUE_EL, Constants.WI_PREFIX_COLON + VALUE_EL, Constants.EMPTY_ATTRS);
            String stringValue;
            if (value != null) {
                stringValue = getDatatype().convertToString(value, locale);
            } else {
                stringValue = enteredValue;
            }
            contentHandler.characters(stringValue.toCharArray(), 0, stringValue.length());
            contentHandler.endElement(Constants.WI_NS, VALUE_EL, Constants.WI_PREFIX_COLON + VALUE_EL);
        }

        // validation message element: only present if the value is not valid
        if (validationError != null) {
            contentHandler.startElement(Constants.WI_NS, VALIDATION_MSG_EL, Constants.WI_PREFIX_COLON + VALIDATION_MSG_EL, Constants.EMPTY_ATTRS);
            validationError.generateSaxFragment(contentHandler);
            contentHandler.endElement(Constants.WI_NS, VALIDATION_MSG_EL, Constants.WI_PREFIX_COLON + VALIDATION_MSG_EL);
        }

        // generate label, help, hint, etc.
        definition.generateDisplayData(contentHandler);

        // generate selection list, if any
        if (selectionList != null) {
            selectionList.generateSaxFragment(contentHandler, locale);
        } else if (getFieldDefinition().getSelectionList() != null) {
            getFieldDefinition().getSelectionList().generateSaxFragment(contentHandler, locale);
        }
        contentHandler.endElement(Constants.WI_NS, AGGREGATEFIELD_EL, Constants.WI_PREFIX_COLON + AGGREGATEFIELD_EL);
    }

    public void generateLabel(ContentHandler contentHandler) throws SAXException {
        definition.generateLabel(contentHandler);
    }

    public Widget getWidget(String id) {
        return (Widget)fieldsById.get(id);
    }
}
TOP

Related Classes of org.apache.cocoon.woody.formmodel.AggregateField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.