001package 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 022import static java.lang.String.format; 023import static org.apache.commons.beanutils.BeanUtils.setProperty; 024import static org.apache.commons.beanutils.PropertyUtils.getPropertyDescriptor; 025 026import java.beans.PropertyDescriptor; 027 028import org.apache.commons.beanutils.DynaBean; 029import org.apache.commons.beanutils.DynaProperty; 030import 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 */ 036public 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}