001 package org.apache.commons.digester3;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import static java.lang.String.format;
023 import static org.apache.commons.beanutils.BeanUtils.setProperty;
024 import static org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptor;
025
026 import java.beans.PropertyDescriptor;
027
028 import org.apache.commons.beanutils.DynaBean;
029 import org.apache.commons.beanutils.DynaProperty;
030 import org.xml.sax.Attributes;
031
032 /**
033 * Rule implementation that sets an individual property on the object at the top of the stack, based on attributes with
034 * specified names.
035 */
036 public class SetPropertyRule
037 extends Rule
038 {
039
040 // ----------------------------------------------------------- Constructors
041
042 /**
043 * Construct a "set property" rule with the specified name and value attributes.
044 *
045 * @param name Name of the attribute that will contain the name of the property to be set
046 * @param value Name of the attribute that will contain the value to which the property should be set
047 */
048 public SetPropertyRule( String name, String value )
049 {
050 this.name = name;
051 this.value = value;
052 }
053
054 // ----------------------------------------------------- Instance Variables
055
056 /**
057 * The attribute that will contain the property name.
058 */
059 protected String name = null;
060
061 /**
062 * The attribute that will contain the property value.
063 */
064 protected String value = null;
065
066 // --------------------------------------------------------- Public Methods
067
068 /**
069 * {@inheritDoc}
070 */
071 @Override
072 public void begin( String namespace, String name, Attributes attributes )
073 throws Exception
074 {
075 if ( attributes.getLength() == 0 )
076 {
077 return;
078 }
079
080 // Identify the actual property name and value to be used
081 String actualName = null;
082 String actualValue = null;
083 for ( int i = 0; i < attributes.getLength(); i++ )
084 {
085 String attributeName = attributes.getLocalName( i );
086 if ( "".equals( attributeName ) )
087 {
088 attributeName = attributes.getQName( i );
089 }
090 String value = attributes.getValue( i );
091 if ( attributeName.equals( this.name ) )
092 {
093 actualName = value;
094 }
095 else if ( attributeName.equals( this.value ) )
096 {
097 actualValue = value;
098 }
099 }
100
101 // Get a reference to the top object
102 Object top = getDigester().peek();
103
104 // Log some debugging information
105 if ( getDigester().getLogger().isDebugEnabled() )
106 {
107 getDigester().getLogger().debug( format( "[SetPropertiesRule]{%s} Set %s property %s to %s",
108 getDigester().getMatch(),
109 top.getClass().getName(),
110 actualName,
111 actualValue ) );
112 }
113
114 // Force an exception if the property does not exist
115 // (BeanUtils.setProperty() silently returns in this case)
116 //
117 // This code should probably use PropertyUtils.isWriteable(),
118 // like SetPropertiesRule does.
119 if ( top instanceof DynaBean )
120 {
121 DynaProperty desc = ( (DynaBean) top ).getDynaClass().getDynaProperty( actualName );
122 if ( desc == null )
123 {
124 throw new NoSuchMethodException( "Bean has no property named " + actualName );
125 }
126 }
127 else
128 /* this is a standard JavaBean */
129 {
130 PropertyDescriptor desc = getPropertyDescriptor( top, actualName );
131 if ( desc == null )
132 {
133 throw new NoSuchMethodException( "Bean has no property named " + actualName );
134 }
135 }
136
137 // Set the property (with conversion as necessary)
138 setProperty( top, actualName, actualValue );
139 }
140
141 /**
142 * {@inheritDoc}
143 */
144 @Override
145 public String toString()
146 {
147 return format( "SetPropertyRule[name=%s, value=%s]", name, value );
148 }
149
150 }