Author: tchemit Date: 2010-03-12 18:21:11 +0100 (Fri, 12 Mar 2010) New Revision: 1777 Log: add AbstractActionthread.createRunnable to create easely a Runnable interface from a given method name to invoke in a proxy Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java 2010-03-12 16:09:15 UTC (rev 1776) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java 2010-03-12 17:21:11 UTC (rev 1777) @@ -2,10 +2,15 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; import javax.swing.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; /** * An abstract action thread to consume actions in a non Swing event thread. @@ -59,6 +64,10 @@ protected Exception error; + protected long startTime; + + protected long endTime; + public ActionWorker(String actionLabel, Runnable target) { this.target = target; this.actionLabel = actionLabel; @@ -66,13 +75,18 @@ @Override protected Void doInBackground() throws Exception { + startTime = System.nanoTime(); if (log.isDebugEnabled()) { - log.debug("Action is starting " + getActionLabel()); + log.debug("Action [" + getActionLabel() + "] is starting..."); } try { target.run(); } catch (Exception e) { error = e; + } finally { + if (log.isDebugEnabled()) { + log.debug("Action [" + getActionLabel() + "] is ending..."); + } } return null; } @@ -96,21 +110,30 @@ @Override protected void done() { super.done(); + endTime = System.nanoTime(); if (error != null) { status = ActionStatus.FAIL; - return; - } - - if (isCancelled()) { + } else if (isCancelled()) { status = ActionStatus.CANCEL; - return; + } else { + status = ActionStatus.OK; } - status = ActionStatus.OK; if (log.isDebugEnabled()) { - log.debug("Action is ending " + getActionLabel() + - " with status : " + status); + log.debug("Action [" + getActionLabel() + "] ends with status : " + status + " in " + getTime()); } } + + public String getTime() { + return StringUtil.convertTime(endTime - startTime); + } + + public long getStartTime() { + return startTime; + } + + public long getEndTime() { + return endTime; + } } protected AbstractActionThread(String name) { @@ -119,10 +142,11 @@ @Override public void propertyChange(PropertyChangeEvent evt) { - if (log.isInfoEnabled()) { - log.info("action " + evt.getSource() + " property " + - evt.getPropertyName() + " changed <" + - evt.getOldValue() + " - " + evt.getNewValue() + ">"); + if (log.isDebugEnabled()) { + log.debug("action " + evt.getSource() + " property " + + evt.getPropertyName() + " changed <" + + evt.getOldValue() + " - " + evt.getNewValue() + + '>'); } if ("state".equals(evt.getPropertyName())) { @@ -143,8 +167,9 @@ // prochaine operation ActionStatus status = source.getStatus(); - if (log.isInfoEnabled()) { - log.info("status = " + status); + if (log.isDebugEnabled()) { + log.debug("Action [" + source.getActionLabel() + + "] status = " + status); } try { switch (status) { @@ -171,6 +196,96 @@ } /** + * Creates a runnable instance (via a Proxy) to a method given by his name + * ({@code methodName}) to invoke on {@code methodcontainer} with given + * {@code arguments}. + * <p/> + * This is a great feature to create runnable code with a real context. + * + * @param methodContainer the container of the method to invoke + * @param methodName the name of the method to invoke + * @param arguments parameters to pass to method to invke. + * @return the proxy instance + */ + public Runnable createRunnable(final Object methodContainer, + String methodName, + final Object... arguments) { + + // find method + + Class<?> klass = methodContainer.getClass(); + Method mFound = null; + for (Method m : klass.getDeclaredMethods()) { + if (!methodName.equals(m.getName())) { + continue; + } + //same method name + + Class<?>[] types = m.getParameterTypes(); + if (arguments.length != types.length) { + continue; + } + + // same number arguments + mFound = m; + break; + } + if (mFound == null) { + throw new IllegalArgumentException( + "could not find method " + methodName + " on type " + + klass.getName()); + } + + //TODO Test arguments are on good type... + + final Method targetMethod = mFound; + targetMethod.setAccessible(true); + Runnable result; + + // create runnable proxy + + result = (Runnable) Proxy.newProxyInstance( + getClass().getClassLoader(), + new Class<?>[]{Runnable.class}, + new InvocationHandler() { + + @Override + public Object invoke(Object proxy, + Method method, + Object[] args) { + String methodName = method.getName(); + + if ("run".equals(methodName)) { + try { + if (log.isDebugEnabled()) { + log.debug("will invoke run method"); + } + return targetMethod.invoke(methodContainer, arguments); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "could not invoke on container " + + methodContainer, e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + if (methodName.equals("toString")) { + return toString(); + } + if (methodName.equals("equals")) { + return equals(args[0]); + } + if (methodName.equals("hashCode")) { + return hashCode(); + } + return null; + } + } + ); + return result; + } + + /** * Add an new action to perform. * * @param actionLabel the name of the action to perform @@ -272,12 +387,6 @@ // est terminée ou a été annulée, on passera alors // dans la méthode onPropertyChanged - if (canceled) { -// getModel().setOperationState(WizardOperationState.CANCELED); - } else { -// getModel().setOperationState(currentAction.getOperationState()); - } - } finally { if (worker != null) { // le thread n'écoute plus l'action car elle est terminée