| /* $Id$ |
| * |
| * 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 org.apache.tomcat.util.digester; |
| |
| |
| import org.apache.tomcat.util.IntrospectionUtils; |
| import org.xml.sax.Attributes; |
| |
| |
| /** |
| * <p>Rule implementation that sets properties on the object at the top of the |
| * stack, based on attributes with corresponding names.</p> |
| * |
| * <p>This rule supports custom mapping of attribute names to property names. |
| * The default mapping for particular attributes can be overridden by using |
| * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}. |
| * This allows attributes to be mapped to properties with different names. |
| * Certain attributes can also be marked to be ignored.</p> |
| */ |
| |
| public class SetPropertiesRule extends Rule { |
| |
| |
| // ----------------------------------------------------------- Constructors |
| |
| |
| /** |
| * Default constructor sets only the the associated Digester. |
| * |
| * @param digester The digester with which this rule is associated |
| * |
| * @deprecated The digester instance is now set in the {@link Digester#addRule} method. |
| * Use {@link #SetPropertiesRule()} instead. |
| */ |
| public SetPropertiesRule(Digester digester) { |
| |
| this(); |
| |
| } |
| |
| |
| /** |
| * Base constructor. |
| */ |
| public SetPropertiesRule() { |
| |
| // nothing to set up |
| |
| } |
| |
| /** |
| * <p>Convenience constructor overrides the mapping for just one property.</p> |
| * |
| * <p>For details about how this works, see |
| * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.</p> |
| * |
| * @param attributeName map this attribute |
| * @param propertyName to a property with this name |
| */ |
| public SetPropertiesRule(String attributeName, String propertyName) { |
| |
| attributeNames = new String[1]; |
| attributeNames[0] = attributeName; |
| propertyNames = new String[1]; |
| propertyNames[0] = propertyName; |
| } |
| |
| /** |
| * <p>Constructor allows attribute->property mapping to be overriden.</p> |
| * |
| * <p>Two arrays are passed in. |
| * One contains the attribute names and the other the property names. |
| * The attribute name / property name pairs are match by position |
| * In order words, the first string in the attribute name list matches |
| * to the first string in the property name list and so on.</p> |
| * |
| * <p>If a property name is null or the attribute name has no matching |
| * property name, then this indicates that the attibute should be ignored.</p> |
| * |
| * <h5>Example One</h5> |
| * <p> The following constructs a rule that maps the <code>alt-city</code> |
| * attribute to the <code>city</code> property and the <code>alt-state</code> |
| * to the <code>state</code> property. |
| * All other attributes are mapped as usual using exact name matching. |
| * <code><pre> |
| * SetPropertiesRule( |
| * new String[] {"alt-city", "alt-state"}, |
| * new String[] {"city", "state"}); |
| * </pre></code> |
| * |
| * <h5>Example Two</h5> |
| * <p> The following constructs a rule that maps the <code>class</code> |
| * attribute to the <code>className</code> property. |
| * The attribute <code>ignore-me</code> is not mapped. |
| * All other attributes are mapped as usual using exact name matching. |
| * <code><pre> |
| * SetPropertiesRule( |
| * new String[] {"class", "ignore-me"}, |
| * new String[] {"className"}); |
| * </pre></code> |
| * |
| * @param attributeNames names of attributes to map |
| * @param propertyNames names of properties mapped to |
| */ |
| public SetPropertiesRule(String[] attributeNames, String[] propertyNames) { |
| // create local copies |
| this.attributeNames = new String[attributeNames.length]; |
| for (int i=0, size=attributeNames.length; i<size; i++) { |
| this.attributeNames[i] = attributeNames[i]; |
| } |
| |
| this.propertyNames = new String[propertyNames.length]; |
| for (int i=0, size=propertyNames.length; i<size; i++) { |
| this.propertyNames[i] = propertyNames[i]; |
| } |
| } |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| /** |
| * Attribute names used to override natural attribute->property mapping |
| */ |
| private String [] attributeNames; |
| /** |
| * Property names used to override natural attribute->property mapping |
| */ |
| private String [] propertyNames; |
| |
| |
| // --------------------------------------------------------- Public Methods |
| |
| |
| /** |
| * Process the beginning of this element. |
| * |
| * @param attributes The attribute list of this element |
| */ |
| public void begin(Attributes attributes) throws Exception { |
| |
| // Populate the corresponding properties of the top object |
| Object top = digester.peek(); |
| if (digester.log.isDebugEnabled()) { |
| if (top != null) { |
| digester.log.debug("[SetPropertiesRule]{" + digester.match + |
| "} Set " + top.getClass().getName() + |
| " properties"); |
| } else { |
| digester.log.debug("[SetPropertiesRule]{" + digester.match + |
| "} Set NULL properties"); |
| } |
| } |
| |
| // set up variables for custom names mappings |
| int attNamesLength = 0; |
| if (attributeNames != null) { |
| attNamesLength = attributeNames.length; |
| } |
| int propNamesLength = 0; |
| if (propertyNames != null) { |
| propNamesLength = propertyNames.length; |
| } |
| |
| for (int i = 0; i < attributes.getLength(); i++) { |
| String name = attributes.getLocalName(i); |
| if ("".equals(name)) { |
| name = attributes.getQName(i); |
| } |
| String value = attributes.getValue(i); |
| |
| // we'll now check for custom mappings |
| for (int n = 0; n<attNamesLength; n++) { |
| if (name.equals(attributeNames[n])) { |
| if (n < propNamesLength) { |
| // set this to value from list |
| name = propertyNames[n]; |
| |
| } else { |
| // set name to null |
| // we'll check for this later |
| name = null; |
| } |
| break; |
| } |
| } |
| |
| if (digester.log.isDebugEnabled()) { |
| digester.log.debug("[SetPropertiesRule]{" + digester.match + |
| "} Setting property '" + name + "' to '" + |
| value + "'"); |
| } |
| IntrospectionUtils.setProperty(top, name, value); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Add an additional attribute name to property name mapping. |
| * This is intended to be used from the xml rules. |
| */ |
| public void addAlias(String attributeName, String propertyName) { |
| |
| // this is a bit tricky. |
| // we'll need to resize the array. |
| // probably should be synchronized but digester's not thread safe anyway |
| if (attributeNames == null) { |
| |
| attributeNames = new String[1]; |
| attributeNames[0] = attributeName; |
| propertyNames = new String[1]; |
| propertyNames[0] = propertyName; |
| |
| } else { |
| int length = attributeNames.length; |
| String [] tempAttributes = new String[length + 1]; |
| for (int i=0; i<length; i++) { |
| tempAttributes[i] = attributeNames[i]; |
| } |
| tempAttributes[length] = attributeName; |
| |
| String [] tempProperties = new String[length + 1]; |
| for (int i=0; i<length && i< propertyNames.length; i++) { |
| tempProperties[i] = propertyNames[i]; |
| } |
| tempProperties[length] = propertyName; |
| |
| propertyNames = tempProperties; |
| attributeNames = tempAttributes; |
| } |
| } |
| |
| |
| /** |
| * Render a printable version of this Rule. |
| */ |
| public String toString() { |
| |
| StringBuffer sb = new StringBuffer("SetPropertiesRule["); |
| sb.append("]"); |
| return (sb.toString()); |
| |
| } |
| |
| |
| } |