Java tutorial
/* * $Header: /CVS/TBB/src/com/softech/tbb/actionform/BaseForm.java,v 1.1 2006/09/15 10:59:04 Louis Exp $ * $Revision: 1.1 $ * $Date: 2006/09/15 10:59:04 $ * * Copyright 2001-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 com.softech.tbb.actionform; import java.util.Iterator; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.scaffold.lang.ChainedException; import org.apache.commons.scaffold.lang.Log; import org.apache.commons.scaffold.lang.Tokens; import org.apache.commons.scaffold.text.ConvertUtils; import org.apache.struts.Globals; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.validator.ValidatorForm; /** * O * * @version $Revision: 1.1 */ public class BaseForm extends ValidatorForm { // ---------------------------------------------------------- Remote Host /** * The network address making this request. * <p> * This is the value returned by reqest.getremoteHost. It is provided so * that this can be logged by components on the business tier if needed. * This property is maintained automatically through the <code>reset</code> * method. */ private String remoteHost = null; /** * Return our remoteHost property. */ public String getRemoteHost() { return (this.remoteHost); } /** * Set our remoteHost property. */ public void setRemoteHost(String remoteHost) { this.remoteHost = remoteHost; } /** * Sets RemoteHost attribute to request.getRemoteHost(). */ protected void resetRemoteHost(HttpServletRequest request) { setRemoteHost(request.getRemoteHost()); } // ------------------------------------------------------- Session Locale /** * The session attribute key for our session locale [Action.LOCALE_KEY]. * (Suggestion only, may be overridden by presentation framework */ public static String STRUTS_LOCALE_KEY = Globals.LOCALE_KEY; /** * Our locale property. * <p> * If the formBean instance is mutable, this is set to the Struts session * locale whenever <code>reset()</code> is called. to update the session * locale, use <code>putSessionLocale()</code>. * <p> * The properties refer to this as the "SessionLocale" so as to avoid * naming/signature conflicts with business beans which may also maintain a * Locale property. */ private Locale locale = null; /** * Set our locale property. * */ public void setSessionLocale(Locale locale) { this.locale = locale; } /** * Retrieve our locale property. */ public Locale getSessionLocale() { return this.locale; } /** * Return the session key attribute for our locale object. */ public String getSessionLocaleName() { return STRUTS_LOCALE_KEY; } /** * Reset our locale property to the locale object found in the session * associated with this request. */ protected void resetSessionLocale(HttpServletRequest request) { HttpSession session = request.getSession(); if (session != null) { setSessionLocale((Locale) session.getAttribute(getSessionLocaleName())); } else { setSessionLocale(Locale.getDefault()); } } // end resetSessionLocale /** * Change the locale property in the session to our locale object, or the * default Locale if ours is null. */ protected void putSessionLocale(HttpServletRequest request) { Locale locale = getSessionLocale(); if (null == locale) locale = Locale.getDefault(); request.getSession(true).setAttribute(Globals.LOCALE_KEY, locale); } // end putSessionLocale /** * Display the user's locale setting or the default locale. */ public String getLocaleDisplay() { Locale locale = getSessionLocale(); if (null == locale) locale = Locale.getDefault(); return locale.getDisplayName(); } // end getLocaleDisplay /** * Set our locale to given ISO Language Code. An empty String is used for * the country. * <p> * Mainly provided for completeness. */ public void setLocaleDisplay(String language) { setSessionLocale(new Locale(language, EMPTY)); } // -------------------------------------------------------------- Mutable /** * The mutable state. * <p> * To avoid autopopulation when forwarding beans between actions, set * mutable to be true and be sure all setters observe the mutable state. * <p> (<code>if (isMutable()) this.field = field;</code>). subject to * autopopulation. */ private boolean mutable = true; /** * Set the mutable state. */ public void setMutable(boolean mutable) { this.mutable = mutable; } /** * Retrieve the mutable state. */ public boolean isMutable() { return this.mutable; } // ------------------------------------------------------------- Dispatch /** * The dispatch property. * <p> * This can be set by a JavaScript buttonto indicate which task should be * performed (or dispatched) by an action. Observes the bean's mutable * state. */ public String dispatch = null; /** * Set dispatch. */ public void setDispatch(String dispatch) { if (isMutable()) this.dispatch = dispatch; } /** * Get the dispatch. */ public String getDispatch() { return this.dispatch; } // --------------------------------------------------------- Public Methods /** * A static, empty String used by isBlank. */ private static String EMPTY = ""; /** * Convenience method to check for a null or empty String. * * @param s * The sting to check */ protected boolean blank(String s) { return ConvertUtils.isBlank(s); } /** * Convenience method to check for a null, empty, or "0" String. * * @param s * The sting to check */ protected boolean blankValue(String s) { return ConvertUtils.isBlankValue(s); } /** * @deprecated Use blank instead. */ protected boolean isBlank(String s) { return blank(s); } /** * Convenience method to test for a required field and setup the error * message. */ protected void required(ActionErrors errors, String field, String name, String arg) { if ((null == field) || (0 == field.length())) { errors.add(name, new ActionError(Tokens.ERRORS_REQUIRED, arg)); } } /** * Convenience method to test for a required array and setup the error * message. */ protected void required(ActionErrors errors, String[] field, String name, String arg) { if ((null == field) || (0 == field.length)) { errors.add(name, new ActionError(Tokens.ERRORS_REQUIRED, arg)); } } /** * Create an object of the specified class, throwing a runtime exception if * any error occurs. If an exception is not thrown, then helper is * guaranteed to exist. * * @param objectClass * The name of the class * @throws IllegalArgumentException * if object cannot be instantiated */ public Object createObject(String objectClass) { // Try the create Object object = null; try { object = Class.forName(objectClass).newInstance(); } catch (Throwable t) { object = null; // assemble message: {class}: {exception} StringBuffer sb = new StringBuffer(); sb.append(Log.CREATE_OBJECT_ERROR); sb.append(Log.CLASS); sb.append(objectClass); sb.append(Log.SPACE); sb.append(Log.ACTION_EXCEPTION); sb.append(t.toString()); // throw runtime exception throw new IllegalArgumentException(sb.toString()); } return object; } // createHelperObject() /** * Return map of properties for this bean. Base method uses * <code>PropertyUtils.describe</code>. Override if some properties * should not be transfered this way, or a property name should be altered. * This will return the actual public properties. * * @exception Exception * on any error. */ public Map describe() throws Exception { try { return PropertyUtils.describe(this); } catch (Throwable t) { throw new ChainedException(t); } } // end describe /** * Set properties from given object. Base method uses * <code>BeanUtils.copyProperties</code> and * <code>PropertyUtils.describe</code>. * * @param o * The object to use to populate this object. * @exception Exception * on any error. */ public void set(Object o) throws Exception { try { BeanUtils.copyProperties(this, o); } catch (Throwable t) { throw new ChainedException(t); } } // end set /** * Populate matching properties on given object. Base method uses * <code>BeanUtils.copyProperties</code> and <code>describe()</code>. * * @param o * The object to populate from this object. * @exception Exception * on any error. */ public void populate(Object o) throws Exception { try { BeanUtils.copyProperties(o, describe()); } catch (Throwable t) { throw new ChainedException(t); } } // end populate /** * // :FIXME: Needs testing. Works OK without a profile bean =:o) Merge a * profile bean with this bean to provide a unified map of the combined * parameters. Will on add properties to the map from the profile bean if * matching property on this bean is blank or null (which includes absent). * The result is a union of the properties, with the this bean's non-blank * properties having precedence over the profile's properties. The profile * is a base that this bean can override on the fly -- If this bean does not * supply a property, then the profile property is used. But any property * named on the userProfile is included (even if it has no match on this * bean). * <p> * If profile is null, a map of this bean's properties is returned. * <p> * The profile can be any JavaBean. * <p> * This method is forwardly-compatible with BaseMapForm. For an instance of * BaseMapForm, getMap() is used; otherwise describe() or * PropertyUtils.describe() is used. * * :FIXME: Needs testing. Works OK without a profile bean =:o) * * @param profile * The profile bean, if any * @throws Exception * if error transfering data to map */ protected Map merge(Object profile) throws Exception { Map formMap = null; if (this instanceof BaseMapForm) { BaseMapForm form = (BaseMapForm) this; formMap = form.getMap(); } else { formMap = describe(); } if (profile != null) { Map userMap = null; if (profile instanceof BaseMapForm) { BaseMapForm form = (BaseMapForm) profile; userMap = form.getMap(); } else if (profile instanceof BaseForm) { BaseForm form = (BaseForm) profile; userMap = form.describe(); } else { userMap = PropertyUtils.describe(this); } // Add user element to formMap if form element is null or blank // Starting with the formMap, for every element in the userMap, // see if the formMap element is non-existant, null, or an empty // String. // If it is (our formMap doesn't override), add the userMap value // to the formMap. Iterator i = userMap.keySet().iterator(); while (i.hasNext()) { String key = (String) i.next(); String formValue = (String) formMap.get(key); if (isBlank(formValue)) { formMap.put(key, userMap.get(key)); } } } return formMap; } // end merge /** * If bean is set to mutable, calls <code>resetSessionLocale</code> and * <code>resetRemoteHost</code>. * * Subclasses resetting their own fields should observe the mutable state (<code>if (isMutable()) ...</code>). * * @param mapping * The mapping used to select this instance * @param request * The servlet request we are processing */ public void reset(ActionMapping mapping, HttpServletRequest request) { if (isMutable()) { super.reset(mapping, request); // :TODO: Might be useful to have a collection of reset listeners resetRemoteHost(request); resetSessionLocale(request); } } // end reset /** * Return an empty ActionErrors or the result of calling the superclass * validate. Will not return null. */ public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = super.validate(mapping, request); if (null == errors) errors = new ActionErrors(); return errors; } } // end BaseForm