1 package net.sourceforge.basher.internal.impl;
2
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Constructor;
5 import java.lang.reflect.Modifier;
6
7 import net.sourceforge.basher.Task;
8 import net.sourceforge.basher.BasherException;
9 import net.sourceforge.basher.Phase;
10 import net.sourceforge.basher.annotations.*;
11 import net.sourceforge.basher.internal.TaskDecorator;
12 import net.sourceforge.basher.tasks.AbstractTask;
13 import org.ops4j.gaderian.service.*;
14 import org.apache.commons.logging.Log;
15
16
17
18
19
20 public class TaskDecoratorImpl implements TaskDecorator
21 {
22 private ClassFactory _classFactory;
23 private Log _log;
24
25 public void setLog( final Log log )
26 {
27 _log = log;
28 }
29
30 public void setClassFactory( final ClassFactory classFactory )
31 {
32 _classFactory = classFactory;
33 }
34
35 public Task decorateInstance( final Object taskInstance )
36 {
37 try
38 {
39 if (_log.isDebugEnabled())
40 {
41 _log.debug("Decorating instance: " + taskInstance.getClass().getName());
42 }
43
44 final String taskInstanceClassName = taskInstance.getClass().getName();
45 final String className = taskInstanceClassName.substring( taskInstanceClassName.lastIndexOf( '.' ) + 1 );
46
47 final String taskClassName = className + "BasherDecoratedTask";
48
49
50 final String executionMethodName = determineExecutionMethodName( taskInstance );
51
52
53 return createDecoratedTask( taskClassName, executionMethodName, taskInstance );
54 }
55 catch ( Exception e )
56 {
57 throw new BasherException( e.getMessage(), e );
58 }
59 }
60
61 private void processMethods( final Class<? extends Object> taskInstanceClass, final ClassFab decoratedTask )
62 {
63 if ( taskInstanceClass.isAssignableFrom( Task.class ) )
64 {
65
66 return;
67 }
68
69
70 final Class superClass = taskInstanceClass.getSuperclass();
71 if ( !superClass.equals( Object.class ) )
72 {
73 processMethods( superClass, decoratedTask );
74 }
75
76
77 final Method[] taskMethods = Task.class.getDeclaredMethods();
78 for ( int i = 0; i < taskMethods.length; i++ )
79 {
80 Method taskMethod = taskMethods[ i ];
81
82 try
83 {
84 final Method declaredMethod = taskInstanceClass.getDeclaredMethod( taskMethod.getName(), taskMethod.getParameterTypes() );
85
86 final MethodSignature methodSignature = new MethodSignature( declaredMethod );
87
88 final MethodFab methodFab = decoratedTask.getMethodFab( methodSignature );
89
90
91 if ( methodFab == null )
92 {
93
94
95 decoratedTask.addMethod( Modifier.PUBLIC, methodSignature, "return _taskInstance." + declaredMethod.getName() + "();" );
96 }
97
98 }
99 catch ( NoSuchMethodException e )
100 {
101
102 }
103
104 }
105
106 }
107
108 private Task createDecoratedTask( final String decoratedTaskClassName, final String executionMethodName, final Object taskInstance ) throws Exception
109 {
110 final ClassFab fab = _classFactory.newClass( decoratedTaskClassName, DecoratedTask.class );
111 fab.addField( "_taskInstance", taskInstance.getClass() );
112
113 final BodyBuilder bodyBuilder = new BodyBuilder();
114 bodyBuilder.begin();
115 bodyBuilder.addln( "_taskInstance." + executionMethodName + "();" );
116 bodyBuilder.end();
117
118 fab.addMethod( java.lang.reflect.Modifier.PUBLIC, new MethodSignature( void.class, "doExecuteTask", new Class[0], new Class[]{ Throwable.class } ), bodyBuilder.toString() );
119
120 bodyBuilder.clear();
121
122
123 processMethods( taskInstance.getClass(), fab );
124
125 bodyBuilder.begin();
126 bodyBuilder.addln( "super();" );
127 bodyBuilder.addln( "_taskInstance = $1;" );
128 bodyBuilder.end();
129
130 fab.addConstructor( new Class[]{ taskInstance.getClass() }, new Class[0], bodyBuilder.toString() );
131
132 final Class<Task> decoratedTask = fab.createClass();
133
134 final Constructor<Task> constructor = decoratedTask.getConstructor( taskInstance.getClass() );
135
136 return constructor.newInstance( taskInstance );
137
138 }
139
140 String determineExecutionMethodName( final Object taskInstance )
141 {
142 final Method[] methods = taskInstance.getClass().getMethods();
143
144 Method selectedMethod = null;
145
146 for ( final Method method : methods )
147 {
148 if ( method.getAnnotation( BasherExecuteMethod.class ) != null )
149 {
150 if ( selectedMethod == null )
151 {
152
153 selectedMethod = method;
154 }
155 else
156 {
157 throw new BasherException( "Found more than 1 execute method", null );
158 }
159 }
160 }
161
162 if ( selectedMethod != null )
163 {
164 validateExecutionMethod( selectedMethod );
165 return selectedMethod.getName();
166 }
167
168
169 try
170 {
171 taskInstance.getClass().getMethod( "executeTask" );
172 return "executeTask";
173 }
174 catch ( NoSuchMethodException e )
175 {
176 throw new BasherException( "Could not find executeTask", e );
177 }
178
179 }
180
181 private void validateExecutionMethod( Method method )
182 {
183 if ( method.getParameterTypes().length != 0 )
184 {
185 throw new BasherException( "Execution method '" + method.getName() + "' must not take any parameters", null );
186 }
187
188 }
189 }