1 package com.bradmcevoy.property;
2
3 import com.bradmcevoy.http.Resource;
4 import com.bradmcevoy.http.exceptions.NotAuthorizedException;
5 import java.beans.PropertyDescriptor;
6 import java.lang.reflect.InvocationTargetException;
7 import java.util.ArrayList;
8 import java.util.List;
9 import javax.xml.namespace.QName;
10 import org.apache.commons.beanutils.PropertyUtils;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13
14
15
16
17
18
19
20
21
22
23 public class BeanPropertySource implements PropertySource {
24
25 private static final Logger log = LoggerFactory.getLogger( BeanPropertySource.class );
26 private static final Object[] NOARGS = new Object[0];
27
28 public Object getProperty( QName name, Resource r ) throws NotAuthorizedException {
29 PropertyDescriptor pd = getPropertyDescriptor( r, name.getLocalPart() );
30 if( pd == null ) {
31 throw new IllegalArgumentException( "no prop: " + name.getLocalPart() + " on " + r.getClass() );
32 }
33 try {
34 return pd.getReadMethod().invoke( r, NOARGS );
35 } catch( Exception ex ) {
36 if( ex.getCause() instanceof NotAuthorizedException ) {
37 NotAuthorizedException na = (NotAuthorizedException) ex.getCause();
38 throw na;
39 } else {
40 throw new RuntimeException( name.toString(), ex );
41 }
42 }
43 }
44
45 public void setProperty( QName name, Object value, Resource r ) throws NotAuthorizedException, PropertySetException {
46 log.debug( "setProperty: " + name + " = " + value );
47 PropertyDescriptor pd = getPropertyDescriptor( r, name.getLocalPart() );
48 try {
49 pd.getWriteMethod().invoke( r, value );
50 } catch( PropertySetException e ) {
51 throw e;
52 } catch( Exception ex ) {
53 if( ex.getCause() instanceof NotAuthorizedException ) {
54 NotAuthorizedException na = (NotAuthorizedException) ex.getCause();
55 throw na;
56 } else if( ex.getCause() instanceof PropertySetException ) {
57 PropertySetException na = (PropertySetException) ex.getCause();
58 throw na;
59 } else {
60 if( value == null ) {
61 log.error( "Exception setting property: " + name.toString() + " to null" );
62 } else {
63 log.error( "Exception setting property: " + name.toString() + " to value: " + value + " class:" + value.getClass() );
64 }
65 throw new RuntimeException( name.toString(), ex );
66 }
67 }
68 }
69
70 public PropertyMetaData getPropertyMetaData( QName name, Resource r ) {
71 log.debug( "getPropertyMetaData" );
72 BeanPropertyResource anno = getAnnotation( r );
73 if( anno == null ) {
74 log.debug( " no annotation: ", r.getClass().getCanonicalName() );
75 return PropertyMetaData.UNKNOWN;
76 }
77 if( !name.getNamespaceURI().equals( anno.value() ) ) {
78 log.debug( "different namespace", anno.value(), name.getNamespaceURI() );
79 return PropertyMetaData.UNKNOWN;
80 }
81
82 PropertyDescriptor pd = getPropertyDescriptor( r, name.getLocalPart() );
83 if( pd == null || pd.getReadMethod() == null ) {
84 log.debug( "no read method" );
85 return PropertyMetaData.UNKNOWN;
86 } else {
87 BeanPropertyAccess propAnno = pd.getReadMethod().getAnnotation( BeanPropertyAccess.class );
88 if( propAnno != null ) {
89 if( !propAnno.value() ) {
90 log.trace( "property is annotated and value is false, so do not allow access" );
91 return PropertyMetaData.UNKNOWN;
92 } else {
93 log.trace( "property is annotated and value is true, so allow access" );
94 }
95 } else {
96 if( anno.enableByDefault() ) {
97 log.trace( "no property annotation, property annotation is enable by default so allow access" );
98 } else {
99 log.trace( "no property annotation, class annotation says disable by default, decline access" );
100 return PropertyMetaData.UNKNOWN;
101 }
102 }
103 if( log.isDebugEnabled() ) {
104 log.debug( "writable: " + anno.writable() + " - " + ( pd.getWriteMethod() != null ) );
105 }
106 boolean writable = anno.writable() && ( pd.getWriteMethod() != null );
107 if( writable ) {
108 return new PropertyMetaData( PropertyAccessibility.WRITABLE, pd.getPropertyType() );
109 } else {
110 return new PropertyMetaData( PropertyAccessibility.READ_ONLY, pd.getPropertyType() );
111 }
112 }
113 }
114
115 public void clearProperty( QName name, Resource r ) throws NotAuthorizedException {
116 setProperty( name, null, r );
117 }
118
119 public List<QName> getAllPropertyNames( Resource r ) {
120 BeanPropertyResource anno = getAnnotation( r );
121 if( anno == null ) return null;
122 PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors( r );
123 List<QName> list = new ArrayList<QName>();
124 for( PropertyDescriptor pd : pds ) {
125 if( pd.getReadMethod() != null ) {
126 list.add( new QName( anno.value(), pd.getName() ) );
127 }
128 }
129 return list;
130 }
131
132 private BeanPropertyResource getAnnotation( Resource r ) {
133 return r.getClass().getAnnotation( BeanPropertyResource.class );
134 }
135
136 private PropertyDescriptor getPropertyDescriptor( Resource r, String name ) {
137 try {
138 PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor( r, name );
139 return pd;
140 } catch( IllegalAccessException ex ) {
141 throw new RuntimeException( ex );
142 } catch( InvocationTargetException ex ) {
143 throw new RuntimeException( ex );
144 } catch( NoSuchMethodException ex ) {
145 return null;
146 }
147
148 }
149 }