Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] Using advice to wrap a call into a thread

I just started expliring AOP and i started rewriting an application of mine and along the way checking to see if there was anything i could make cleaner by using aspects. When i finally got it to work I realized all I need was a new SWT Display object, but the problem i ran into is still intriguiging. In the first lines of my existing code a splash screen is drawn. This splash screen has a progress bar which is updated by a simple timer. However getting it to run in the background, without a new display object for it requires the drawing code be in the main thread, the timer to be in a seperate and the update of the progress bar to be in a new thread syncing to display thread. I know that AOP is rather useless in GUI programming but it was more of an exercise than anything. I thought it would be neet to just write the splash screen code as if it was the only program running, causing all other execution to stop until it was done, and then add
an aspect which would put it in the background. Code - bs as follows:

main program:
    Display = new Display();
       new SplashScreen();
       while(true){
           if(!Display.readAndDispatch())
               Display.sleep();
       }

splash screen:
       Shell shell = new Shell(xtellirad2AOP.Display, SWT.NO_TRIM);
       shell.pack();
      shell.open();
      //draw image
       while(true){
           try{
           Thread.sleep(10);
            //update progress bar
           }catch(Exception e){}
       }

then came my aspect, my solution was to create a new thread and run it when new splashscreen was called, and when any SWT constructor or method is called in splashscreen, a new thread is created and Display.syncExex()'d this is a mess, there has got to be a better way to do this. I know some of my reflect code should be changed to use argument types from the signature, but i realized a new Display() would work much better before I got that
far and it would not help to illustrate my point, here is the aspect:

public aspect BackgroundThread {
   class ConstructorRunner implements Runnable{
       public Object output;
       private Object[] arguments;
       private Constructor constructor;
       public ConstructorRunner(String signature, Object[] arguments){
           this.arguments = arguments;
           signature = signature.substring(0,signature.indexOf('('));
           Class argumentTypes[] = new Class[arguments.length];
           for(int i=0; i < arguments.length; i++){
                   argumentTypes[i] = arguments[i].getClass();
               if(argumentTypes[i] == Integer.class)
                   argumentTypes[i] = int.class;
           }
           try{
           Class shellDefinition = Class.forName(signature);
           constructor = shellDefinition.getConstructor(argumentTypes);
           }catch(Exception e){e.printStackTrace();}
       }
       public void run(){
           try{
           output = constructor.newInstance(arguments);
           }catch(Exception e){e.printStackTrace();}
       }
   }
class MethodRunner implements Runnable{
       private Object object;
       private Method method;
       private Object arguments[];
       public Object output;
public MethodRunner(Object object, String signature, Object arguments[]){
           this.arguments = arguments;
           this.object = object;
           Class argumentTypes[] = new Class[arguments.length];
           for(int i=0; i < arguments.length; i++){
               argumentTypes[i] = arguments[i].getClass();
               if(argumentTypes[i] == Integer.class)
                   argumentTypes[i] = int.class;
           }
signature = signature.substring(signature.lastIndexOf('.') + 1, signature.indexOf('('));
           try{
           method = object.getClass().getMethod(signature, argumentTypes);
           }catch(Exception e){e.printStackTrace();}
       }
       public void run(){
           try{
           output = method.invoke(object, arguments);
           }catch(Exception e){e.printStackTrace();}
       }
   }
   pointcut init() : call(SplashScreen.new());
   pointcut widgetConstructor() : call(org.eclipse.swt.*.*.new(..));
   pointcut widgetMethod() : call(public * org.eclipse.swt.*.*.*(..));
SplashScreen around(): init() && !within(BackgroundThread){ new Thread(new ConstructorRunner(thisJoinPoint.getSignature().toString(), thisJoinPoint.getArgs())).start();
       return null;
   }
Object around (): widgetConstructor() && within(SplashScreen){ ConstructorRunner cr = new ConstructorRunner(thisJoinPoint.getSignature().toString(), thisJoinPoint.getArgs());
       xtellirad2AOP.Display.syncExec(cr);
       return cr.output;
   }
Object around (): widgetMethod() && within(SplashScreen){ MethodRunner or = new MethodRunner(thisJoinPoint.getTarget(), thisJoinPoint.getSignature().toString(), thisJoinPoint.getArgs());
       xtellirad2AOP.Display.syncExec(or);
       return or.output;
   }
}

I'm sure there are other more useful applications for this kind of aspect, is there another way to save/transfer/execute what proceed()
is going to do?

Cheers,
jonpry
jon at nospam xtelli dot net





Back to the top