r1946 - in trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing: . application wizard
Author: tchemit Date: 2010-06-04 05:53:17 +0200 (Fri, 04 Jun 2010) New Revision: 1946 Url: http://nuiton.org/repositories/revision/jaxx/1946 Log: - introduce application package - deprecated AbstractActionThread (prefer let SwingWorker deals with threads) - add headers Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionExecutor.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionWorker.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ApplicationRunner.java Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionModel.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-06-02 10:27:55 UTC (rev 1945) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/AbstractActionThread.java 2010-06-04 03:53:17 UTC (rev 1946) @@ -24,11 +24,12 @@ */ package jaxx.runtime.swing; +import jaxx.runtime.swing.application.ActionExecutor; +import jaxx.runtime.swing.application.ActionWorker; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.nuiton.util.StringUtil; -import javax.swing.*; +import javax.swing.SwingWorker; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationHandler; @@ -44,11 +45,12 @@ * <p/> * To consume an action, use the method {@link #addAction(String, Runnable)}. * <p/> - * TODO Make this multi-action enable * * @author tchemit <chemit@codelutin.com> * @since 2.0 + * @deprecated since 2.1, prefer the {@link ActionExecutor}. */ +@Deprecated public abstract class AbstractActionThread extends Thread { /** Logger */ @@ -70,96 +72,6 @@ /** the listener of running action */ protected final PropertyChangeListener workerListener; - /** State of a running action */ - enum ActionStatus { - OK, - CANCEL, - FAIL - } - - /** Action worker to execute a incoming action. */ - public static class ActionWorker extends SwingWorker<Void, Object> { - - protected final String actionLabel; - - protected final Runnable target; - - protected ActionStatus status; - - protected Exception error; - - protected long startTime; - - protected long endTime; - - public ActionWorker(String actionLabel, Runnable target) { - this.target = target; - this.actionLabel = actionLabel; - } - - @Override - protected Void doInBackground() throws Exception { - startTime = System.nanoTime(); - if (log.isDebugEnabled()) { - 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; - } - - public boolean isFailed() { - return (isDone() || isCancelled()) && error != null; - } - - public Exception getError() { - return error; - } - - public ActionStatus getStatus() { - return status; - } - - public String getActionLabel() { - return actionLabel; - } - - @Override - protected void done() { - super.done(); - endTime = System.nanoTime(); - if (error != null) { - status = ActionStatus.FAIL; - } else if (isCancelled()) { - status = ActionStatus.CANCEL; - } else { - status = ActionStatus.OK; - } - if (log.isDebugEnabled()) { - 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) { super(name); workerListener = new PropertyChangeListener() { @@ -190,7 +102,7 @@ // on rend la main au thread pour qu'il attende une // prochaine operation - ActionStatus status = source.getStatus(); + ActionWorker.ActionStatus status = source.getStatus(); if (log.isDebugEnabled()) { log.debug("Action [" + source.getActionLabel() + "] status = " + status); Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionExecutor.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionExecutor.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionExecutor.java 2010-06-04 03:53:17 UTC (rev 1946) @@ -0,0 +1,306 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.application; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.SwingWorker; +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; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +/** + * Executor of {@link ActionWorker}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public abstract class ActionExecutor { + + /** Logger */ + private static final Log log = + LogFactory.getLog(ActionExecutor.class); + + /** current tasks */ + protected final Set<ActionWorker> tasks = new HashSet<ActionWorker>(); + + /** the listener of running action */ + protected final PropertyChangeListener workerListener; + + /** + * Hook when a action is about to start. + * + * @param source the action worker containing the action to perform + */ + public abstract void onActionStart(ActionWorker source); + + /** + * Hook when a action has failed. + * + * @param source the action worker containing the action to perform + */ + public abstract void onActionFail(ActionWorker source); + + + /** + * Hook when a action has been canceled. + * + * @param source the action worker containing the action to perform + */ + public abstract void onActionCancel(ActionWorker source); + + /** + * Hook when a action has end with no failure or cancel. + * + * @param source the action worker containing the action to perform + */ + public abstract void onActionEnd(ActionWorker source); + + /** + * Hook atfer action is consumed. + * + * @param source the action worker containing the action to perform + */ + public abstract void onAfterAction(ActionWorker source); + + public ActionExecutor() { + workerListener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (log.isDebugEnabled()) { + log.debug("action " + evt.getSource() + " property " + + evt.getPropertyName() + " changed <" + + evt.getOldValue() + " - " + evt.getNewValue() + + '>'); + } + + if ("state".equals(evt.getPropertyName())) { + ActionWorker source = (ActionWorker) evt.getSource(); + SwingWorker.StateValue state = + (SwingWorker.StateValue) evt.getNewValue(); + + + if (state == SwingWorker.StateValue.STARTED) { + // starting new action + + onActionStart(source); + return; + } + + if (state == SwingWorker.StateValue.DONE) { + // on rend la main au thread pour qu'il attende une + // prochaine operation + + ActionWorker.ActionStatus status = source.getStatus(); + if (log.isDebugEnabled()) { + log.debug("Action [" + source.getActionLabel() + + "] status = " + status); + } + try { + switch (status) { + + case OK: + onActionEnd(source); + break; + case CANCEL: + onActionCancel(source); + break; + case FAIL: + onActionFail(source); + break; + } + } finally { + tasks.remove(source); + onAfterAction(source); + } + } + } + } + }; + } + + /** + * Add an new action to perform. + * + * @param actionLabel the name of the action to perform + * @param action the action to perform + * @return the worker that will launch the action + */ + public ActionWorker addAction(String actionLabel, Runnable action) { + + ActionWorker worker; + if (action instanceof ActionWorker) { + + worker = (ActionWorker) action; + } else { + worker = new ActionWorker(actionLabel, action); + } + worker.addPropertyChangeListener(workerListener); + tasks.add(worker); + worker.execute(); + return worker; + } + + /** + * Ask the thread to stop. + * <p/> + * It will finish all incoming files (but will not accept more tasks). + * <p/> + * <b>Note:</b> The method does not return until all tasks are not + * consumed. + * + * @throws InterruptedException if something wrong while waiting end of + * executor + */ + public void terminatesAndWaits() throws InterruptedException { + + if (log.isDebugEnabled()) { + log.debug("Executor " + this + " is terminating..."); + } + + // ask executor to terminate + for (ActionWorker task : tasks) { + task.cancel(true); + } + +// // wait until all submited jobs are terminated +// // i don't want timeout, i think 2 minutes is good :) +// ExecutorService service = ActionWorker.getWorkersExecutorService(); +// if (service != null) { +// log.info("Shutodown executor service"); +// service.shutdown(); +// } + + if (log.isDebugEnabled()) { + log.debug("Executor " + this + " is terminated at " + new Date()); + } + } + + public int getNbActions() { + return getTasks().size(); + } + + public Set<ActionWorker> getTasks() { + return tasks; + } + + /** + * 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; + } +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionExecutor.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionWorker.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionWorker.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionWorker.java 2010-06-04 03:53:17 UTC (rev 1946) @@ -0,0 +1,132 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.application; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; + +import javax.swing.SwingWorker; + +/** + * Action worker to execute a incoming action. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public class ActionWorker extends SwingWorker<Void, Object> { + + + /** Logger */ + private static final Log log = + LogFactory.getLog(ActionWorker.class); + + protected final String actionLabel; + + protected final Runnable target; + + protected ActionStatus status; + + protected Exception error; + + protected long startTime; + + protected long endTime; + + public ActionWorker(String actionLabel, Runnable target) { + this.target = target; + this.actionLabel = actionLabel; + } + + @Override + protected Void doInBackground() throws Exception { + startTime = System.nanoTime(); + if (log.isDebugEnabled()) { + 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; + } + + public boolean isFailed() { + return (isDone() || isCancelled()) && error != null; + } + + public Exception getError() { + return error; + } + + public ActionStatus getStatus() { + return status; + } + + public String getActionLabel() { + return actionLabel; + } + + @Override + protected void done() { + super.done(); + endTime = System.nanoTime(); + if (error != null) { + status = ActionStatus.FAIL; + } else if (isCancelled()) { + status = ActionStatus.CANCEL; + } else { + status = ActionStatus.OK; + } + if (log.isDebugEnabled()) { + 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; + } + + /** State of a running action */ + public enum ActionStatus { + OK, + CANCEL, + FAIL + } + +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ActionWorker.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ApplicationRunner.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ApplicationRunner.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ApplicationRunner.java 2010-06-04 03:53:17 UTC (rev 1946) @@ -0,0 +1,251 @@ +/* + * #%L + * JAXX :: Runtime + * * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.application; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Simple application runner which authorize to reload an application. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public abstract class ApplicationRunner { + + /** Logger */ + private static Log log = LogFactory.getLog(ApplicationRunner.class); + + private static final Object lock = new Object(); + + private static ApplicationRunner runner; + + public static ApplicationRunner getRunner() { + if (runner == null) { + throw new IllegalStateException("No runner initialized"); + } + return runner; + } + + public static void lock() throws InterruptedException { + synchronized (lock) { + // on arrete le thread principal + // pour rendre la main a la methode main + lock.wait(); + } + } + + public static void unlock() { + synchronized (lock) { + // on arrete le thread principal + // pour rendre la main a la methode main + lock.notifyAll(); + } + } + + /** arguments given to runner at launch time */ + protected final String[] args; + + /** flag to reload the runner when closing it */ + protected boolean reload; + + /** the runner to start application */ + protected final Runnable runnable; + + protected long startingTime; + + protected Exception error; + + /** + * To execute some code only once. + * <p/> + * This code will not be re-execute when reloading the runner. + */ + protected abstract void initOnce(); + + /** + * Hook to init runner. + * + * @throws Exception if any problem + */ + protected abstract void onInit() throws Exception; + + /** + * Hook to start runner. + * + * @throws Exception if any problem + */ + protected abstract void onStart() throws Exception; + + /** + * Hook to close runner. + * + * @param reload if reload was asked + * @throws Exception if any problme + */ + protected abstract void onClose(boolean reload) throws Exception; + + /** + * Hook to shutdown launcher + * + * @throws Exception if any problem + */ + protected abstract void onShutdown() throws Exception; + + /** + * Hook to shutdown launcher when an exception occurs on clsoing. + * + * @param ex the error catched while closing launcher + */ + protected abstract void onShutdown(Exception ex); + + /** + * Hook when an error occurs in runner. + * + * @param e the error catched + */ + protected abstract void onError(Exception e); + + protected ApplicationRunner(String[] args) { + runner = this; + this.args = args; + + initOnce(); + + runnable = new Runnable() { + @Override + public void run() { + startingTime = System.nanoTime(); + try { + + onInit(); + + onStart(); + + } catch (Exception e) { + error = e; + onError(e); + unlock(); + } + } + }; + + Thread shutdownHook = new Thread(new Runnable() { + + @Override + public void run() { + try { + + //onClose(false); + onShutdown(); + + } catch (Exception e) { + error = e; + onShutdown(e); + } + } + }, "ShutDown " + getClass().getSimpleName()); + + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + public boolean isReload() { + return reload; + } + + public void setReload(boolean reload) { + this.reload = reload; + } + + protected Thread mainThread; + + public final void launch() { + + // au demarrage le reload est toujours desactive + reload = false; + + // preparation du thread de l'application principale + // que l'on démarre + mainThread = new Thread(runnable, getClass().getSimpleName()); + mainThread.start(); + + try { + + // on attend que l'application se termine ou demande un redémarrage + lock(); + + // on va libérer le runner + log.info("Application [" + mainThread + "] is closing..."); + + } catch (InterruptedException e) { + if (log.isErrorEnabled()) { + log.error(mainThread + " was interrupted for reason " + e.getMessage(), e); + } + } finally { + + close(); + + } + } + + public final void close() { + boolean reload = isReload(); + + try { + + // fermeture du runner + onClose(reload); + + if (reload) { + + // redemarrage du runner + + if (log.isInfoEnabled()) { + log.info("Will reload application"); + } + + System.runFinalization(); + + launch(); + } + + } catch (Exception e) { + onError(e); + } finally { + if (!reload) { + if (log.isDebugEnabled()) { + log.debug("Will shutdown application ..."); + } + + unlock(); + + // force to shutdown + Runtime.getRuntime().exit(0); + } + } + } + + +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/application/ApplicationRunner.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Modified: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionModel.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionModel.java 2010-06-02 10:27:55 UTC (rev 1945) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionModel.java 2010-06-04 03:53:17 UTC (rev 1946) @@ -1,3 +1,27 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ package jaxx.runtime.swing.wizard; import jaxx.runtime.JAXXUtil;
participants (1)
-
tchemit@users.nuiton.org