package net.xoetrope.optional.annotation;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Hashtable;
import java.util.StringTokenizer;
import net.xoetrope.builder.XuiBuilder;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.nanoxml.NanoXmlElement;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.annotation.*;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.data.XDataBinding;
/**
* A processsor for XPage annotations
* <p>Copyright (c) Xoetrope Ltd., 2002-2006</p>
* <p>License: see license.txt</p>
* $Revision: 1.9 $
*/
public class XPageAnnotationProcessor implements PageAnnotationProcessor
{
/**
* Get the page file name declaration.
* This is designed for pages loaded outside of the normal XUI application and
* xui page lifecycle.
* @return the name of the page file to load
*/
public String getPage( PageSupport page )
{
Page pageAnnotation = page.getClass().getAnnotation( Page.class );
if ( pageAnnotation != null ) {
// Check that the page is not being loaded by a secondary loader
StackTraceElement e[] = Thread.currentThread().getStackTrace();
for ( StackTraceElement ste : e ) {
if ( ste.getClassName().equals( "XuiBuilder" ) && ste.getMethodName().equals("loadPage"))
return null;
}
return pageAnnotation.value();
}
return null;
}
/**
* <p>Setup the annotated component references. Component references can
* be annotated as follows:
* <br>
* <code>
*
* @Bind( "a/b/c" )
* protected XButton myBtn;
* </code>
* </p>
* @Find protected XButton myBtn;
* </code>
* <br>
* and prior to the pageCreated method being called, this method is invoked to
* fixup those references.</p>
* <p>
* Data can also be bound to the components by specifying a Bind annotation
* <br>
* <code>
* @param page the owner page, and the class containing the annotated component references
*/
public void setupComponents( PageSupport page )
{
setupComponents( page, page );
}
/**
* <p>Setup the annotated component references. Component references can
* be annotated as follows:
* <br>
* <code>
*
* @Bind( "a/b/c" )
* protected XButton myBtn;
* </code>
* </p>
* @Find protected XButton myBtn;
* </code>
* <br>
* and prior to the pageCreated method being called, this method is invoked to
* fixup those references.</p>
* <p>
* Data can also be bound to the components by specifying a Bind annotation
* <br>
* <code>
* @param page the owner page
* @param source the class instance containing the annotated component references
*/
public void setupComponents( PageSupport page, Object source )
{
Class pageClass = source.getClass();
setupComponents( page, source, pageClass );
}
private void setupComponents( PageSupport page, Object source, Class pageClass )
{
XProject currentProject = page.getProject();
XuiBuilder builder = (XuiBuilder)currentProject.getObject( "Builder" );
Field[] fields = pageClass.getDeclaredFields();
for ( Field field : fields ) {
boolean isAccessible = field.isAccessible();
if ( !isAccessible ) {
try {
field.setAccessible( true );
}
catch ( SecurityException ex ) {
// There may be a security policy in place preventing this
ex.printStackTrace();
}
}
String fieldName = field.getName();
Object targetComp = null;
// Setup the annotated component references
Annotation annotation = field.getAnnotation( Find.class );
if ( annotation != null ) {
try {
targetComp = page.findComponent( fieldName );
if ( BuildProperties.DEBUG ) {
if ( targetComp == null ) {
DebugLogger.logError( "The annotated component \"" + fieldName + "\" was not found in the page." );
continue;
}
}
field.set( source, targetComp );
}
catch ( IllegalArgumentException iae )
{
if ( BuildProperties.DEBUG )
DebugLogger.logError( "The annotated component \"" + fieldName + "\" does not match the type of component declared in the page." );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
// Setup the annotated data bindings
annotation = field.getAnnotation( Bind.class );
if ( annotation != null ) {
try {
// String srcStr = ((Bind)annotation).value();
// XModel srcModel = (XModel)page.getProject().getModel().get( page.evaluatePath( srcStr ));
Hashtable instanceConfig = new Hashtable();
String extraStr = ((Bind)annotation).extra();
StringTokenizer tokenizer = new StringTokenizer( extraStr, "," );
while( tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
int pos = token.indexOf( '=' );
instanceConfig.put( token.substring( 0, pos ), token.substring( pos + 1 ));
}
if ( targetComp == null )
targetComp = page.findComponent( fieldName );
XDataBinding binding = builder.getFactoryBinding( page, targetComp, instanceConfig );
page.addBinding( binding );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
// Setup the annotated validations
annotation = field.getAnnotation( Validate.class );
if ( annotation != null ) {
try {
Validate validateAnnotation = (Validate)annotation;
String ruleStr = validateAnnotation.value();
XmlElement validateElement = new NanoXmlElement();
String extraStr = validateAnnotation.extra();
StringTokenizer tokenizer = new StringTokenizer( extraStr, "," );
while( tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
int pos = token.indexOf( '=' );
validateElement.setAttribute( token.substring( 0, pos ), token.substring( pos + 1 ));
}
int whenAttribValue = FocusEvent.FOCUS_LOST;
String whenAttrib = validateAnnotation.when();
validateElement.setAttribute( "when", whenAttrib );
if (( whenAttrib != null ) && ( whenAttrib.length() > 0 )) {
if ( whenAttrib.toLowerCase().compareTo( "mouseclicked" ) == 0 )
whenAttribValue = MouseEvent.MOUSE_CLICKED;
}
if ( targetComp == null )
targetComp = page.findComponent( fieldName );
page.addValidation( targetComp, ruleStr, validateAnnotation.method(), whenAttribValue, validateElement );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
// Setup the annotated events
annotation = field.getAnnotation( Event.class );
if ( annotation != null ) {
try {
Event eventAnnotation = (Event)annotation;
String methodStr = eventAnnotation.method();
String typeStr = eventAnnotation.type();
if ( targetComp == null )
targetComp = page.findComponent( fieldName );
page.getEventHandler().addHandler( page, targetComp, typeStr, methodStr );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
field.setAccessible( isAccessible );
}
Class superClass = pageClass.getSuperclass();
if ( superClass != null ) {
Class[] interfaces = superClass.getInterfaces();
for ( Class cls : interfaces ) {
if ( cls == XAnnotatedPage.class ) {
setupComponents( page, source, superClass );
break;
}
}
}
}
}