/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Blacksmith, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.web; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSDictionary; import net.wotonomy.foundation.NSMutableDictionary; /** * The base class for dynamic WOElements. Dynamic elements are expected to do * something useful with user-entered data in the request and with any binding * associations with the context's current WOComponent. * * @author michael@mpowers.net * @author $Author: cgruber $ * @version $Revision: 905 $ */ public abstract class WODynamicElement extends WOElement { private static final long serialVersionUID = -5383805382837136590L; protected String name; protected WOElement rootElement; protected NSDictionary associations; /** * The default constructor. */ protected WODynamicElement() { name = null; associations = new NSMutableDictionary(); rootElement = null; } /** * Required constructor specifying the class name of the component, a map of * associations, and the root element of the tree that contains this element * (which may be null). The map keys correspond to properties of this element, * and the values are associations to be applied to the context's current * component. */ public WODynamicElement(String aName, NSDictionary anAssociationMap, WOElement aRootElement) { this(); name = aName; associations = anAssociationMap; rootElement = aRootElement; } /** * Package access only. Called to initialize the component with the proper * context before the start of the request-response cycle. If the context has a * current component, that component becomes this component's parent. */ @Override void ensureAwakeInContext(WOContext aContext) { if (rootElement != null) { rootElement.ensureAwakeInContext(aContext); } } /** * Use this method to get a map with the properties that start with a question * mark. These are supposed to go at the end of a URL, and it is very useful for * components that generate URLs, specially with direct actions. * * @param c The component where the values of the properties have to be * retrieved from. */ Map urlFields(WOComponent c) { HashMap map = new HashMap(associations.count()); Enumeration enumeration = associations.keyEnumerator(); while (enumeration.hasMoreElements()) { String key = (String) enumeration.nextElement(); if (key.charAt(0) == '?') { map.put(key.substring(1), valueForProperty(key, c)); } } return map; } /** Convenience method for getting the value of an association. */ Object valueForProperty(String key, WOComponent c) { WOAssociation a = (WOAssociation) associations.objectForKey(key); if (a != null) return a.valueInComponent(c); return null; } /** Convenience method for getting the string value of an association. */ String stringForProperty(String key, WOComponent c) { WOAssociation a = (WOAssociation) associations.objectForKey(key); Object result = null; if (a != null) result = a.valueInComponent(c); if (result == null) return null; return result.toString(); } /** Convenience method for getting the string value of an association. */ boolean booleanForProperty(String key, WOComponent c) { WOAssociation a = (WOAssociation) associations.objectForKey(key); Object result = null; if (a != null) result = a.valueInComponent(c); if (result == null) return false; if (result.toString().toLowerCase().equals("true")) return true; return Boolean.TRUE.equals(result); } /** Convenience method for setting the value of an association. */ void setValueForProperty(String key, Object value, WOComponent c) { WOAssociation a = (WOAssociation) associations.objectForKey(key); if (a != null && a.isValueSettable()) a.setValue(value, c); } /** * this method composes a String suitable for inclusion inside a HTML tag. It * includes the key-value pairs of all the associations not mentioned in the * standardProperties parameter. This is very useful for including extra * properties in tags without having to worry if the HTML specification has * changed or if non-standard tags are being used. * * @param c The component where the associations' values should * be retrieved from. * @param standardProperties An array of Strings with all the associations that * should be excluded from the resulting string. */ String additionalHTMLProperties(WOComponent c, NSArray standardProperties) { Enumeration enumeration = associations.keyEnumerator(); StringBuffer buf = new StringBuffer(); while (enumeration.hasMoreElements()) { String key = (String) enumeration.nextElement(); if (!(standardProperties.containsObject(key) || key.charAt(0) == '?')) { buf.append(' '); buf.append(key); buf.append("=\""); buf.append(valueForProperty(key, c)); buf.append('\"'); } } return buf.toString(); } /** * This method is called to retrieve user-entered data from the request. * WOElements should retrieve data from the request based on their elementID and * set values in the context's current WOComponent, typically those values that * are associated with the element in the binding. This implementation does * nothing. */ @Override public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) { } /** * This method is called on all objects and elements of the application until a * non-null value is returned. WOElements should first check to see if they are * the target of an action by checking the WOContext's senderID to see if it * matches this element's elementID. If this element is the target, it should * perform an appropriate action on the context's current WOComponent, usually * the action specified in the binding, and return the result of that action. * This implementation returns null. */ @Override public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) { return null; } /** * This method is called on all elements of the content tree to build a response * to a user request. The message should be forwarded to any child elements so * that the entire tree is traversed. This implementation does nothing. */ @Override public void appendToResponse(WOResponse aResponse, WOContext aContext) { // does nothing } @Override public WOResponse generateResponse() { return null; } }