package com.eucalyptus.configurable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import javax.persistence.Entity; import javax.persistence.PersistenceContext; import javax.persistence.Transient; import org.apache.log4j.Logger; import com.eucalyptus.entities.EntityWrapper; public class MultiDatabasePropertyEntry extends AbstractConfigurableProperty implements ConfigurableProperty { private static Logger LOG = Logger.getLogger( MultiDatabasePropertyEntry.class ); protected String baseMethodName; protected Method get; protected Method set; protected Method setIdentifier; protected Field field; protected Field identifierField; protected String identifierValue; protected String persistenceContext; protected Class[] setArgs; public MultiDatabasePropertyEntry( Class definingClass, String entrySetName, Field field, Field identifierField, String description, String defaultValue, PropertyTypeParser typeParser, Boolean readOnly, String displayName, ConfigurableFieldType widgetType, String alias, String identifierValue ) { super( definingClass, entrySetName, field.getName( ), defaultValue, description, typeParser, readOnly, displayName, widgetType, alias ); this.identifierField = identifierField; this.field = field; this.baseMethodName = field.getName( ).substring( 0, 1 ).toUpperCase( ) + field.getName( ).substring( 1 ); String identifiedMethodName = identifierField.getName( ).substring( 0, 1 ).toUpperCase( ) + identifierField.getName( ).substring( 1 ); this.identifierValue = identifierValue; this.persistenceContext = ( ( PersistenceContext ) definingClass.getAnnotation( PersistenceContext.class ) ).name( ); this.setArgs = new Class[] { field.getType( ) }; try { get = definingClass.getDeclaredMethod( "get" + this.baseMethodName ); set = definingClass.getDeclaredMethod( "set" + this.baseMethodName, this.setArgs ); setIdentifier = definingClass.getDeclaredMethod( "set" + identifiedMethodName, new Class[] { identifierField.getType()} ); } catch ( Exception e ) { LOG.debug( e, e ); } } private Method getSetter( ) { if( this.set != null ) { return this.set; } else { synchronized(this) { if( this.set == null ) { try { this.set = this.getDefiningClass( ).getDeclaredMethod( "set" + this.baseMethodName, this.setArgs ); } catch ( Exception e ) { LOG.debug( "Known methods: " + this.getDefiningClass( ).getDeclaredMethods( ) ); LOG.debug( "Known methods: " + this.getDefiningClass( ).getMethods( ) ); LOG.debug( e, e ); } } } return this.set; } } private Method getGetter( ) { if ( this.get != null ) { return this.get; } else { synchronized ( this ) { if ( this.get == null ) { try { this.get = this.getDefiningClass( ).getDeclaredMethod( "get" + this.baseMethodName ); } catch ( Exception e ) { LOG.debug( "Known methods: " + this.getDefiningClass( ).getDeclaredMethods( ) ); LOG.debug( "Known methods: " + this.getDefiningClass( ).getMethods( ) ); LOG.debug( e, e ); } } } return this.get; } } private Object getQueryObject( ) throws Exception { Object queryObject = super.getDefiningClass( ).newInstance( ); setIdentifier.invoke(queryObject, identifierValue); return queryObject; } @Override public String getValue( ) { EntityWrapper db = new EntityWrapper( this.persistenceContext ); try { Object o = db.getUnique( this.getQueryObject( ) ); Method getter = this.getGetter( ); Object prop = null; if ( getter != null ) { prop = getter.invoke( o ); } String result = prop != null ? prop.toString( ) : "null"; db.commit( ); return result; } catch ( Exception e ) { db.rollback( ); return "Unknown"; } } @Override public String setValue( String s ) { EntityWrapper db = new EntityWrapper( this.persistenceContext ); try { Object o = db.getUnique( this.getQueryObject( ) ); Object prop = this.getTypeParser( ).parse( s ); Method setter = this.getSetter( ); if ( setter != null ) { setter.invoke( o, prop ); } db.commit( ); return s; } catch ( Exception e ) { db.rollback( ); return "Error: " + e.getMessage( ); } } @Override public void resetValue( ) {} public static class DatabasePropertyBuilder implements ConfigurablePropertyBuilder { private static Logger LOG = Logger.getLogger( MultiDatabasePropertyEntry.DatabasePropertyBuilder.class ); @Override public ConfigurableProperty buildProperty( Class c, Field f ) throws ConfigurablePropertyException { if ( c.isAnnotationPresent( Entity.class ) && !((ConfigurableClass)c.getAnnotation(ConfigurableClass.class)).singleton()) { ConfigurableClass classAnnote = ( ConfigurableClass ) c.getAnnotation( ConfigurableClass.class ); Field identifierField = null; for( Field field : c.getDeclaredFields( ) ) { if(field.isAnnotationPresent(ConfigurableIdentifier.class)) { identifierField = field; break; } } if(identifierField == null) { return null; } if(f.isAnnotationPresent( ConfigurableField.class ) ) { LOG.debug( "Checking field: " + c.getName( ) + "." + f.getName( ) ); ConfigurableField annote = f.getAnnotation( ConfigurableField.class ); String fqPrefix = classAnnote.root( ); String alias = classAnnote.alias(); String description = annote.description( ); String defaultValue = annote.initial( ); PropertyTypeParser p = PropertyTypeParser.get( f.getType( ) ); try { if ( !Modifier.isStatic( f.getModifiers( ) ) && !f.isAnnotationPresent( Transient.class ) ) { ConfigurableProperty prop = new MultiDatabasePropertyEntry( c, fqPrefix, f, identifierField, description, defaultValue, p, annote.readonly( ), annote.displayName(), annote.type(), alias, null ); return prop; } } catch ( Throwable e ) { LOG.debug( e, e ); return null; } } } else { return null; } return null; } } public void setIdentifierValue(String value) { identifierValue = value; } @Override public String getEntrySetName( ) { if(identifierValue != null) return identifierValue + "." + this.entrySetName; else return this.entrySetName; } @Override public String getQualifiedName( ) { if(identifierValue != null) return identifierValue + "." + this.qualifiedName; else return this.qualifiedName; } public MultiDatabasePropertyEntry getClone(String identifierValue) { return new MultiDatabasePropertyEntry(definingClass, entrySetName, field, identifierField, description, defaultValue, typeParser, readOnly, displayName, widgetType, alias, identifierValue); } }