1 package org.apache.commons.digester3;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import static java.lang.String.format;
23 import static org.apache.commons.beanutils.BeanUtils.setProperty;
24 import static org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptor;
25
26 import java.beans.PropertyDescriptor;
27
28 import org.apache.commons.beanutils.DynaBean;
29 import org.apache.commons.beanutils.DynaProperty;
30 import org.xml.sax.Attributes;
31
32 /**
33 * Rule implementation that sets an individual property on the object at the top of the stack, based on attributes with
34 * specified names.
35 */
36 public class SetPropertyRule
37 extends Rule
38 {
39
40 // ----------------------------------------------------------- Constructors
41
42 /**
43 * Construct a "set property" rule with the specified name and value attributes.
44 *
45 * @param name Name of the attribute that will contain the name of the property to be set
46 * @param value Name of the attribute that will contain the value to which the property should be set
47 */
48 public SetPropertyRule( String name, String value )
49 {
50 this.name = name;
51 this.value = value;
52 }
53
54 // ----------------------------------------------------- Instance Variables
55
56 /**
57 * The attribute that will contain the property name.
58 */
59 protected String name = null;
60
61 /**
62 * The attribute that will contain the property value.
63 */
64 protected String value = null;
65
66 // --------------------------------------------------------- Public Methods
67
68 /**
69 * {@inheritDoc}
70 */
71 @Override
72 public void begin( String namespace, String name, Attributes attributes )
73 throws Exception
74 {
75 if ( attributes.getLength() == 0 )
76 {
77 return;
78 }
79
80 // Identify the actual property name and value to be used
81 String actualName = null;
82 String actualValue = null;
83 for ( int i = 0; i < attributes.getLength(); i++ )
84 {
85 String attributeName = attributes.getLocalName( i );
86 if ( "".equals( attributeName ) )
87 {
88 attributeName = attributes.getQName( i );
89 }
90 String value = attributes.getValue( i );
91 if ( attributeName.equals( this.name ) )
92 {
93 actualName = value;
94 }
95 else if ( attributeName.equals( this.value ) )
96 {
97 actualValue = value;
98 }
99 }
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 }