jaxx.runtime.swing.wizard.WizardOperationActionThread Maven / Gradle / Ivy
/*
* *##%
* JAXX Runtime
* Copyright (C) 2008 - 2009 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
* .
* ##%*
*/
package jaxx.runtime.swing.wizard;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Date;
import javax.swing.SwingWorker.StateValue;
import jaxx.runtime.JAXXContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Thread qui réalise les opérations.
*
* Pour exécuter une nouvelle opération, on utilise la méthode
* {@link #launchOperation(WizardOperationStep)}.
*
* Note: Pour bloquer (ou débloquer) le thread, on utilise la méthode {@link #setWaiting(boolean)}
*
* @param le type des etapes
* @param le type de modele
* @param le type d'action d'operation
*
* @author tony
* @since 1.3
*/
public abstract class WizardOperationActionThread, A extends WizardOperationAction> extends Thread implements PropertyChangeListener {
/** to use log facility, just put in your code: log.info(\"...\"); */
private static final Log log = LogFactory.getLog(WizardOperationActionThread.class);
/**
* l'état du thread si annulé
*/
private boolean canceled;
protected Class modelClass;
protected A currentAction;
/**
* un lock pour permettre la suspension et la reprise du thread
* lors du mode interactif.
*/
private final Object LOCK = new Object();
protected abstract M getModel();
protected abstract JAXXContext getContext();
public WizardOperationActionThread(Class modelClass) throws IllegalArgumentException {
super(WizardOperationActionThread.class.getSimpleName() + " " + new Date());
this.modelClass = modelClass;
}
public void cancel() {
log.info("cancel " + this);
this.canceled = true;
// on annule le modele
getModel().cancel();
// on rend la main au thread
setWaiting(false);
}
@SuppressWarnings("unchecked")
public A launchOperation(E operation) {
if (currentAction != null && (!currentAction.isDone() || currentAction.operationState == WizardOperationState.RUNNING)) {
// on ne peut traiter qu'une seule opération à la fois
throw new IllegalStateException("can not add a operation when thread is busy, or has another operation to be done");
}
currentAction = (A) getModel().getOperationAction(operation);
// on libere le thread pour qu'il execute l'opération
setWaiting(false);
return currentAction;
}
public A getCurrentAction() {
return currentAction;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
log.trace(evt.getPropertyName() + " <" + evt.getOldValue() + " - " + evt.getNewValue() + ">");
if ("state".equals(evt.getPropertyName())) {
StateValue state = (StateValue) evt.getNewValue();
if (state == StateValue.DONE) {
// on rend la main au thread pour qu'il attende une prochaine operation
setWaiting(false);
}
}
}
@Override
public void run() {
try {
// on vérifie que le context contient bien le modèle
if (getModel() == null) {
throw new NullPointerException("could not find model " + modelClass + " for " + this);
}
while (!canceled) {
if (canceled) {
// une annulation a été demandé
// donc même si une opération est demandée, on ne la traite
// pas
break;
}
// en attente qu'une opération
// le block est bloqué jusqu'à arrivée d'une opération
// ou une demande d'annulation
setWaiting(true);
// le thread a repris la main, donc plus en attente
log.trace("no more waiting " + this);
if (!canceled) {
// une opération a été demandée
// le thread écoute les modifications de l'action
currentAction.addPropertyChangeListener(this);
// l'opération passe en etant en cours
getModel().setOperationState(WizardOperationState.RUNNING);
// démarrage de l'opération dans un worker
currentAction.start(getContext());
// le thread est bloqué jusqu'à la fin de l'opération
// ou une demande d'annulation
setWaiting(true);
// le thread reprend la main des que l'operation
// 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());
}
// le thread n'écoute plus l'action car elle est terminée
// ou annulée
currentAction.removePropertyChangeListener(this);
// suppression de l'action
//currentAction = null;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
unlockThread();
log.trace(this + " will close...");
close();
}
}
/**
* La méthode pour nettoyer le thread, a la fermeture.
*
*/
protected void close() {
// par defaut, on ne fait rien
log.trace(this);
}
protected void setWaiting(boolean waiting) {
if (waiting && !canceled) {
// locking thread
try {
lockThread();
} catch (InterruptedException ex) {
log.error(ex.getMessage(), ex);
canceled = true;
}
}
if (!waiting) {
// release lock
unlockThread();
}
}
protected void lockThread() throws InterruptedException {
synchronized (LOCK) {
log.trace(this);
// lock
LOCK.wait();
}
}
protected void unlockThread() {
synchronized (LOCK) {
log.trace(this);
// unlock
LOCK.notify();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy