Package de.iritgo.aktera.model

Source Code of de.iritgo.aktera.model.DefaultModelValidator

/**
* This file is part of the Iritgo/Aktera Framework.
*
* Copyright (C) 2005-2011 Iritgo Technologies.
* Copyright (C) 2003-2005 BueroByte GbR.
*
* Iritgo licenses this file to You 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 de.iritgo.aktera.model;


import de.iritgo.aktera.model.Command;
import de.iritgo.aktera.model.Model;
import de.iritgo.aktera.model.ModelException;
import de.iritgo.aktera.model.ModelRequest;
import de.iritgo.aktera.model.ModelValidator;
import de.iritgo.aktera.util.string.SuperString;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.FloatConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import java.util.Iterator;


/**
* The DefaultModelValidator is used if no other "validator" hint
* is supplied in the model's configuration. It reads the model's
* configuration, and understands the following configuration (Xdoclet
* tags for these are also recognized):
* <br>
* <ul>
* <li>parameter: The parameter element with the usual "name" attribute
* (and the optional "value" attribute)
* will now also accept the following attributes:</li>
*     <ul>
* <li>required: True or false. Value for this parameter must be supplied.
* False is assumed if the attribute is absent.</li>
* <li>type: A valid Java type (e.g. "java.lang.Double"). The parameter's
* value must be capable of being converted to this type without error
* in order for the validation to pass. Any type accepted if this
* attribute is absent.</li>
* <li>default: A default value to be supplied for this parameter if
* there is no parameter of this name already in the request (or if
* the current value is null). No default if this attribute is absent.</li>
* <li>pattern: A regular expression that this field's value must match,
* see String.match() in the J2SE JavaDoc for details of the types
* of regular expressions accepted here. No match attempted if
* this attribute is absent.</li>
*     </ul>
* <li>validation-error: This element indicates a model that should be
* executed *instead* of the specified model in the event of a
* validation error. Allows a "Save" model to "jump" back to the "prompt"
* model, for instance. It accepts the following two attributes</li>
* <ul>
* <li>model: The id of the model or sequence to jump to in the event
* of a validation error. Required.</li>
* <li>params: Include the parameters to the current request as parameters
* to the validation-error model - e.g. "pass on" parameters. True or false,
* false assumed if attribute is absent.</li>
* </ul>
* </ul>
*
* @avalon.component
* @avalon.service type=de.iritgo.aktera.model.ModelValidator
* @x-avalon.info name=default-validator
* @x-avalon.lifestyle type=singleton
*
* @author Michael Nash
*/
public class DefaultModelValidator implements ModelValidator, LogEnabled
{
  private static Logger log = null;

  private static boolean convertersRegistered = false;

  /**
   * Examine the Model's configuration and see if there are any "parameter"
   * elements, which may provide certain validation information about each
   * parameter. If there are any such elements, validate the named
   * parameters, adding to a store of errors that are later passed on to the
   * model.
   *
   * @param req The ModelRequest containing the parameters to be validated
   * @param newModel The model to be executed.
   * @throws ConfigurationException
   *             If parameter configuration exists, but it incorrectly
   *             specified.
   * @throws ModelException If there is an exception accessing the parameters to be validated
   * @return A command, ready to be executed to return to the appropriate
   *         model for the user to try again, or null of no such
   *         validation-error model is specified. If null is returned, then
   *         any validation errors are stored as a Map in a request
   *         attribute, where they may be accessed by the Model as needed.
   */
  public Command validate(ModelRequest req, Model newModel) throws ConfigurationException, ModelException
  {
    Configuration conf = newModel.getConfiguration();

    /* If there's no config, we can't possibly have any parameter config */
    if (conf == null)
    {
      return null;
    }

    if (! convertersRegistered)
    {
      registerConverters();
    }

    String name = null;
    Object value = null;
    String defaultValue = null;
    String pattern = null;
    String type = null;
    boolean required = false;

    Configuration[] paramConfigs = conf.getChildren("parameter");

    for (int i = 0; i < paramConfigs.length; i++)
    {
      Configuration oneParamConfig = paramConfigs[i];

      name = oneParamConfig.getAttribute("name");
      required = oneParamConfig.getAttributeAsBoolean("required", false);
      value = req.getParameter(name);

      if (required && (value == null))
      {
        req.addError(name, "'" + name + "' is required");
      }

      defaultValue = oneParamConfig.getAttribute("default", null);
      type = oneParamConfig.getAttribute("type", null);

      if ((value == null) && (defaultValue != null))
      {
        req.setParameter(name, defaultValue);
      }

      if ((value != null) && (type != null))
      {
        /* verify the value can be converted to the specified type */
        if (! type.equals("java.lang.String"))
        {
          Class clazz = null;

          try
          {
            clazz = Class.forName(type);
          }
          catch (ClassNotFoundException ce)
          {
            throw new ConfigurationException("No class found for '" + type
                    + "', specified as type for parameter '" + name + "'");
          }

          if (type.equalsIgnoreCase("java.util.Date"))
          {
            try
            {
              new SuperString(value.toString()).toDate();
            }
            catch (Exception e)
            {
              log.error("Value '" + value + " cannot be converted to a date", e);
              req.addError(name, "Value '" + value + "' cannot be converted to a date");
            }
          }
          else
          {
            Converter c = ConvertUtils.lookup(clazz);

            if (c == null)
            {
              log.error("No converter found for class '" + type + "'");
              throw new IllegalArgumentException("No converter found for class '" + type + "'");
            }

            try
            {
              c.convert(clazz, value);
            }
            catch (ConversionException ce)
            {
              req.addError(name, "Value '" + value + "' cannot be converted to a '" + type + "'");
            }
          }
        }
      }

      pattern = oneParamConfig.getAttribute("pattern", null);

      if ((value != null) && (pattern != null))
      {
        if (! value.toString().matches(pattern))
        {
          req.addError(name, "Value '" + value + "' does not match validation pattern '" + pattern + "'");
        }
      }
    }

    if (conf.getChild("validation-error", false) != null)
    {
      Configuration validationErrorConfig = conf.getChild("validation-error");
      Command redirect = req.createResponse().createCommand(validationErrorConfig.getAttribute("model"));

      if (validationErrorConfig.getAttributeAsBoolean("params", true))
      {
        String oneParamName = null;

        for (Iterator i = req.getParameters().keySet().iterator(); i.hasNext();)
        {
          oneParamName = (String) i.next();
          redirect.setParameter(oneParamName, req.getParameter(oneParamName));

          return redirect;
        }
      }
    }

    return null;
  }

  /**
   * Receive our logger from the container
   * @param newLog The logger passed to this component by the container on initialization
   */
  public void enableLogging(Logger newLog)
  {
    log = newLog;
  }

  /**
   * The reason we re-register converters (as a number of defaults are
   * already registered) is that the default registrations set things up
   * such that a conversion error returns a "default" value, (e.g. zero).
   * We want to actually throw a ConversionException if there's a problem
   * instead of just returning a default value.
   * Support for additional types might require additional converters be
   * registered here.
   */
  private void registerConverters()
  {
    ConvertUtils.deregister();
    ConvertUtils.register(new LongConverter(), java.lang.Long.class);
    ConvertUtils.register(new IntegerConverter(), java.lang.Integer.class);
    ConvertUtils.register(new FloatConverter(), java.lang.Float.class);
    ConvertUtils.register(new DoubleConverter(), java.lang.Double.class);

    convertersRegistered = true;
  }
}
TOP

Related Classes of de.iritgo.aktera.model.DefaultModelValidator

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.