r1311 - in trunk/isis-fish/src/java/fr/ifremer/isisfish: datastore simulator/launcher simulator/launcher/doc-files ui/simulator ui/widget
Author: bpoussin Date: 2008-08-27 17:07:00 +0000 (Wed, 27 Aug 2008) New Revision: 1311 Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/JDKPriorityBlockingQueue.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationQueue.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/doc-files/ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/doc-files/isis-simulation.png trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/package.html trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/widget/VCSConnectionState.java Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/datastore/SimulationStorage.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationExecutor.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationJob.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationService.java trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationServiceTableModel.java trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/Queue.java trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorAction.java trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorListeners.java Log: - nouvelle implantation de la queue pour permettre a l'utilisateur d'utiliser le bon executor lorsqu'il choisi un launcher - ajout de doc sur le nouveau simulation service - modif d'erreur dans le model de table de queue Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/datastore/SimulationStorage.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/datastore/SimulationStorage.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/datastore/SimulationStorage.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -94,7 +94,7 @@ protected boolean useLog; /** * Pour la lecture d'une simulation existante - * @param directory repertoire de base du storage + * @param directory repertoire de base du storage (inclu le nom de la sim) * @param name le nom de la simulation * @param parameter les paramètres de la simulation */ @@ -579,9 +579,13 @@ renameFrom = "^.*?/(.*)$"; renameTo = newName + "/$1"; } + log.info(_("Import simulation file %s in directory %s and rename from %s to %s", + file, directory, renameFrom, renameTo)); String lastEntry = ZipUtil.uncompressAndRename(file, directory, renameFrom, renameTo); String name = lastEntry.substring(0, lastEntry.indexOf("/")); - SimulationStorage result = new SimulationStorage(directory, name, null); + log.info(_("Last entry was %s extract name %s", lastEntry, name)); + File simDir = new File(directory, name); + SimulationStorage result = new SimulationStorage(simDir, name, null); if (result != null) { File data = result.getDataBackupFile(); if (file.exists()) { Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -75,7 +75,7 @@ SimulationControl control, File simulationZip) throws RemoteException{ String id = control.getId(); - + log.info(_("simulate %s with file %s", id, simulationZip)); SimulationStorage simulation = null; try { simulation = SimulationStorage.importAndRenameZip(simulationZip, id); Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/JDKPriorityBlockingQueue.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/JDKPriorityBlockingQueue.java (rev 0) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/JDKPriorityBlockingQueue.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -0,0 +1,553 @@ +/* *##% + * Copyright (C) 2002-2008 Code Lutin, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + *##%*/ + +package fr.ifremer.isisfish.simulator.launcher; + + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.PriorityQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/////////////////////////////////////////////////////////////////////////// +// +// not modified code from PriorityBlockingQueue +// +/////////////////////////////////////////////////////////////////////////// +/** + * It's based on PriorityBlockingQueue code, + * because PriorityBlockingQueue use private field for ReentrantLock :( + * + * @author poussin + * @param E + */ +public class JDKPriorityBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { + + private static final long serialVersionUID = 5595510919245408276L; + protected final PriorityQueue<E> q; + protected final ReentrantLock lock = new ReentrantLock(true); + protected final Condition notEmpty = lock.newCondition(); + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the default + * initial capacity (11) that orders its elements according to + * their {@linkplain Comparable natural ordering}. + */ + public JDKPriorityBlockingQueue() { + q = new PriorityQueue<E>(); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the specified + * initial capacity that orders its elements according to their + * {@linkplain Comparable natural ordering}. + * + * @param initialCapacity the initial capacity for this priority queues + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public JDKPriorityBlockingQueue(int initialCapacity) { + q = new PriorityQueue<E>(initialCapacity, null); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> with the specified initial + * capacity that orders its elements according to the specified + * comparator. + * + * @param initialCapacity the initial capacity for this priority queues + * @param comparator the comparator that will be used to order this + * priority queues. If {@code null}, the {@linkplain Comparable + * natural ordering} of the elements will be used. + * @throws IllegalArgumentException if <tt>initialCapacity</tt> is less + * than 1 + */ + public JDKPriorityBlockingQueue(int initialCapacity, + Comparator<? super E> comparator) { + q = new PriorityQueue<E>(initialCapacity, comparator); + } + + /** + * Creates a <tt>PriorityBlockingQueue</tt> containing the elements + * in the specified collection. If the specified collection is a + * {@link SortedSet} or a {@link PriorityQueue}, this + * priority queues will be ordered according to the same ordering. + * Otherwise, this priority queues will be ordered according to the + * {@linkplain Comparable natural ordering} of its elements. + * + * @param c the collection whose elements are to be placed + * into this priority queues + * @throws ClassCastException if elements of the specified collection + * cannot be compared to one another according to the priority + * queues's ordering + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public JDKPriorityBlockingQueue(Collection<? extends E> c) { + q = new PriorityQueue<E>(c); + } + + /** + * Inserts the specified element into this priority queues. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Collection#add}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queues according to the + * priority queues's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean add(E e) { + return offer(e); + } + + /** + * Inserts the specified element into this priority queues. + * + * @param e the element to add + * @return <tt>true</tt> (as specified by {@link Queue#offer}) + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queues according to the + * priority queues's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + boolean ok = q.offer(e); + assert ok; + notEmpty.signal(); + return true; + } finally { + lock.unlock(); + } + } + + /** + * Inserts the specified element into this priority queues. As the queues is + * unbounded this method will never block. + * + * @param e the element to add + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queues according to the + * priority queues's ordering + * @throws NullPointerException if the specified element is null + */ + public void put(E e) { + offer(e); // never need to block + } + + /** + * Inserts the specified element into this priority queues. As the queues is + * unbounded this method will never block. + * + * @param e the element to add + * @param timeout This parameter is ignored as the method never blocks + * @param unit This parameter is ignored as the method never blocks + * @return <tt>true</tt> + * @throws ClassCastException if the specified element cannot be compared + * with elements currently in the priority queues according to the + * priority queues's ordering + * @throws NullPointerException if the specified element is null + */ + public boolean offer(E e, long timeout, TimeUnit unit) { + return offer(e); // never need to block + } + + public E poll() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.poll(); + } finally { + lock.unlock(); + } + } + + public E take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + try { + while (q.size() == 0) { + notEmpty.await(); + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + E x = q.poll(); + assert x != null; + return x; + } finally { + lock.unlock(); + } + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + E x = q.poll(); + if (x != null) { + return x; + } + if (nanos <= 0) { + return null; + } + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + public E peek() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.peek(); + } finally { + lock.unlock(); + } + } + + /** + * Returns the comparator used to order the elements in this queues, + * or <tt>null</tt> if this queues uses the {@linkplain Comparable + * natural ordering} of its elements. + * + * @return the comparator used to order the elements in this queues, + * or <tt>null</tt> if this queues uses the natural + * ordering of its elements + */ + public Comparator<? super E> comparator() { + return q.comparator(); + } + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.size(); + } finally { + lock.unlock(); + } + } + + /** + * Always returns <tt>Integer.MAX_VALUE</tt> because + * a <tt>PriorityBlockingQueue</tt> is not capacity constrained. + * @return <tt>Integer.MAX_VALUE</tt> + */ + public int remainingCapacity() { + return Integer.MAX_VALUE; + } + + /** + * Removes a single instance of the specified element from this queues, + * if it is present. More formally, removes an element {@code e} such + * that {@code o.equals(e)}, if this queues contains one or more such + * elements. Returns {@code true} if and only if this queues contained + * the specified element (or equivalently, if this queues changed as a + * result of the call). + * + * @param o element to be removed from this queues, if present + * @return <tt>true</tt> if this queues changed as a result of the call + */ + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.remove(o); + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this queues contains the specified element. + * More formally, returns {@code true} if and only if this queues contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this queues + * @return <tt>true</tt> if this queues contains the specified element + */ + public boolean contains(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.contains(o); + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queues. + * The returned array elements are in no particular order. + * + * <p>The returned array will be "safe" in that no references to it are + * maintained by this queues. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + * <p>This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this queues + */ + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(); + } finally { + lock.unlock(); + } + } + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toString(); + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while ((e = q.poll()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public int drainTo(Collection<? super E> c, int maxElements) { + if (c == null) { + throw new NullPointerException(); + } + if (c == this) { + throw new IllegalArgumentException(); + } + if (maxElements <= 0) { + return 0; + } + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = 0; + E e; + while (n < maxElements && (e = q.poll()) != null) { + c.add(e); + ++n; + } + return n; + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this queues. + * The queues will be empty after this call returns. + */ + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + q.clear(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this queues; the + * runtime type of the returned array is that of the specified array. + * The returned array elements are in no particular order. + * If the queues fits in the specified array, it is returned therein. + * Otherwise, a new array is allocated with the runtime type of the + * specified array and the size of this queues. + * + * <p>If this queues fits in the specified array with room to spare + * (i.e., the array has more elements than this queues), the element in + * the array immediately following the end of the queues is set to + * <tt>null</tt>. + * + * <p>Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + * <p>Suppose <tt>x</tt> is a queues known to contain only strings. + * The following code can be used to dump the queues into a newly + * allocated array of <tt>String</tt>: + * + * <pre> + * String[] y = x.toArray(new String[0]);</pre> + * + * Note that <tt>toArray(new Object[0])</tt> is identical in function to + * <tt>toArray()</tt>. + * + * @param a the array into which the elements of the queues are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this queues + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this queues + * @throws NullPointerException if the specified array is null + */ + public <T> T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return q.toArray(a); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this queues. The + * iterator does not return the elements in any particular order. + * The returned <tt>Iterator</tt> is a "weakly consistent" + * iterator that will never throw {@link + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. + * + * @return an iterator over the elements in this queues + */ + public Iterator<E> iterator() { + return new Itr(toArray()); + } + + /** + * Snapshot iterator that works off copy of underlying q array. + */ + private class Itr implements Iterator<E> { + + final Object[] array; // Array of all elements + int cursor; // index of next element to return; + int lastRet; // index of last element, or -1 if no such + + Itr(Object[] array) { + lastRet = -1; + this.array = array; + } + + public boolean hasNext() { + return cursor < array.length; + } + + public E next() { + if (cursor >= array.length) { + throw new NoSuchElementException(); + } + lastRet = cursor; + return (E) array[cursor++]; + } + + public void remove() { + if (lastRet < 0) { + throw new IllegalStateException(); + } + Object x = array[lastRet]; + lastRet = -1; + // Traverse underlying queues to find == element, + // not just a .equals element. + lock.lock(); + try { + for (Iterator it = q.iterator(); it.hasNext();) { + if (it.next() == x) { + it.remove(); + return; + } + } + } finally { + lock.unlock(); + } + } + } + + /** + * Saves the state to a stream (that is, serializes it). This + * merely wraps default serialization within lock. The + * serialization strategy for items is left to underlying + * Queue. Note that locking is not needed on deserialization, so + * readObject is not defined, just relying on default. + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + lock.lock(); + try { + s.defaultWriteObject(); + } finally { + lock.unlock(); + } + } +} + Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationExecutor.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationExecutor.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationExecutor.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -61,10 +61,11 @@ /** le launcher a utilise pour les simulations */ protected SimulatorLauncher launcher; - public SimulationExecutor(SimulationService simulationService, SimulatorLauncher launcher, - BlockingQueue<Runnable> workQueue) { + public SimulationExecutor(SimulationService simulationService, + SimulatorLauncher launcher, + SimulationQueue workQueue) { super(launcher.maxSimulationThread(), launcher.maxSimulationThread(), - 0L, TimeUnit.MILLISECONDS, workQueue); + 0L, TimeUnit.MILLISECONDS, (BlockingQueue)workQueue); this.simulationService = simulationService; this.launcher = launcher; lastCorePoolSize = prestartAllCoreThreads(); Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationJob.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationJob.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationJob.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -52,6 +52,7 @@ /** to use log facility, just put in your code: log.info(\"...\"); */ static private Log log = LogFactory.getLog(SimulationJob.class); + transient protected String id; /** l'ensemble des post actions a effectuer pour ce job */ protected Set<PostAction> postActions = new HashSet<PostAction>(); /** Le {@link SimulationService} dans lequel a ete cree ce job */ @@ -85,6 +86,13 @@ this.postActions.remove(postAction); } + public String getId() { + if (id == null) { + id = getItem().getControl().getId(); + } + return id; + } + /** * demande l'annulation/arret de ce job. Si ce job n'etait pas encore actif * un {@link SimulationServiceListener#simulationStop} est leve. Sinon @@ -97,11 +105,11 @@ // on essaie d'enlever ce job de la queue, au cas ou il ne serait pas // encore lance if (simulationService.cancel(this)) { - // on a pu annuler avec le lancement, on notify un stop puisqu'on + // on a pu annuler avant le lancement, on notify un stop puisqu'on // ne passera jamais dans le run() simulationService.fireStopEvent(this); } - item.getControl().stopSimulation(); + item.getControl().setStopSimulationRequest(true); } public SimulationJob getParentJob() { @@ -125,7 +133,11 @@ } public int compareTo(SimulationJob o) { - return this.priority - o.priority; + int result = this.priority - o.priority; + if (result == 0) { + result = this.getId().compareTo(o.getId()); + } + return result; } /** @@ -137,8 +149,12 @@ public void run() { try { SimulationControl control = item.getControl(); + String id = control.getId(); + if (control.isStopSimulationRequest()) { + log.info(_("Not start simulation %s because user ask stop", id)); + return ; + } SimulationParameter param = item.getParameter(); - String id = control.getId(); log.debug("Start simulation: " + id); simulationService.fireStartEvent(this); @@ -147,7 +163,7 @@ // simulation les unes apres les autres Iterator<SimulationJob> i = new SimulationService.PrepareSimulationJob(simulationService, this); - while (i.hasNext()) { + while (!control.isStopSimulationRequest() && i.hasNext()) { log.info(_("Generate next simulation")); SimulationJob subjob = i.next(); subjob.setLauncher(getLauncher()); Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationQueue.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationQueue.java (rev 0) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationQueue.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -0,0 +1,160 @@ +/* *##% + * Copyright (C) 2002-2008 Code Lutin, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + *##%*/ + +package fr.ifremer.isisfish.simulator.launcher; + + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Multi tail PriorityBlockingQueue. + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class SimulationQueue extends JDKPriorityBlockingQueue<SimulationJob> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(SimulationQueue.class); + protected SimulationQueue parent = null; + protected List<SimulationQueue> childs = new LinkedList<SimulationQueue>(); + + public SimulationQueue() { + } + + + public SimulationQueue(SimulationQueue parent) { + parent.addChild(this); + } + + public void addChild(SimulationQueue c) { + childs.add(c); + c.parent = this; + } + + @Override + public boolean remove(Object o) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + boolean result = false; + for (SimulationQueue child : childs) { + result = child.remove(o) || result; + } + result = q.remove(o) || result; + return result; + } finally { + lock.unlock(); + } + } + + + @Override + public boolean offer(SimulationJob e) { + boolean result = super.offer(e); + for (SimulationQueue child : childs) { + final ReentrantLock lock = child.lock; + lock.lock(); + try { + child.notEmpty.signal(); + } finally { + lock.unlock(); + } + } + return result; + } + + @Override + public SimulationJob peek() { + SimulationJob result = super.peek(); + if (result == null && parent != null) { + result = parent.peek(); + } + return result; + } + + @Override + public SimulationJob poll() { + SimulationJob result = super.poll(); + if (result == null && parent != null) { + result = parent.peek(); + } + return result; + } + + @Override + public SimulationJob take() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + SimulationJob result = null; + try { + try { + while (q.size() == 0 && parent != null && null == parent.poll()) { + notEmpty.await(); + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + if (result == null) { + result = q.poll(); + } + assert result != null; + return result; + } finally { + lock.unlock(); + } + } + + @Override + public SimulationJob poll(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + for (;;) { + SimulationJob result = poll(); + if (result != null) { + return result; + } + if (nanos <= 0) { + return null; + } + try { + nanos = notEmpty.awaitNanos(nanos); + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + } + } finally { + lock.unlock(); + } + } + + +} Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationService.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationService.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationService.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -117,14 +117,19 @@ // (sans doute ajoute un boolean, simulationListAsQueue = true|false) protected boolean autoLaunch = true; - /** L'executor utilise pour creer toutes les sous simulations des plans independants */ - protected ExecutorService subSimulationComputationExecutor = Executors.newSingleThreadExecutor(); - /** Tous les types de {@link SimulatorLauncher} disponibles, et leur executors associe */ - protected Map<SimulatorLauncher, SimulationExecutor> executors; + /** L'executor utilise pour creer toutes les sous simulations des plans + * independants */ + protected ExecutorService subSimulationComputationExecutor = + Executors.newSingleThreadExecutor(); + /** Tous les types de {@link SimulatorLauncher} disponibles, et leur + * executors associe */ + protected Map<SimulatorLauncher, SimulationExecutor> executors = + new LinkedHashMap<SimulatorLauncher, SimulationExecutor>(); /** Le nombre d'erreur pour les SimulatorLauncher */ - protected Map<SimulatorLauncher, MutableInt> launcherError; + protected Map<SimulatorLauncher, MutableInt> launcherError = + new HashMap<SimulatorLauncher, MutableInt>(); /** La queue contenant toutes les simulations a faire */ - protected PriorityBlockingQueue<Runnable> queue = new PriorityBlockingQueue<Runnable>(); + protected SimulationQueue queue = new SimulationQueue(); /** Contient les identifiants des simulations presentes dans {@ link #jobs}*/ protected Set<String> idJobs = new HashSet<String>(); @@ -139,21 +144,30 @@ */ protected SimulationService() { // on cree un executor par type SimulatorLauncher - executors = new LinkedHashMap<SimulatorLauncher, SimulationExecutor>(); - launcherError = new HashMap<SimulatorLauncher, MutableInt>(); Properties prop = IsisFish.config.getOptionStartsWith(SIMULATION_LAUNCHER); for (String key : prop.stringPropertyNames()) { String value = prop.getProperty(key); try { SimulatorLauncher sl = (SimulatorLauncher) ObjectUtil.newInstance(value); - SimulationExecutor se = new SimulationExecutor(this, sl, queue); - executors.put(sl, se); - launcherError.put(sl, new MutableInt(0)); + addSimulationLauncher(sl); } catch (Exception eee) { log.warn(_("Can't instantiate %s", value), eee); } } } + + /** + * Permet d'ajouter un nouveau SimulatorLauncher. Cela cree automatiquement + * un executor pour ce SimulatorLauncher. S'il y avait deja un + * SimulatorLauncher de ce type un nouveau est ajoute. + * @param sl le SimulatorLauncher a ajouter + */ + public void addSimulationLauncher(SimulatorLauncher sl) { + SimulationQueue executorQueue = new SimulationQueue(queue); + SimulationExecutor se = new SimulationExecutor(this, sl, executorQueue); + executors.put(sl, se); + launcherError.put(sl, new MutableInt(0)); + } public Collection<SimulationExecutor> getSimulationExecutors() { return executors.values(); @@ -313,11 +327,27 @@ // l'item est fini d'etre initialise, on peut l'ajouter a la queue // sauf si c'etait un plan independant ou se seront les sous simu // qui seront dans la queue - queue.add(job); + submit(job); } } + protected void submit(SimulationJob job) { + SimulatorLauncher launcher = job.getLauncher(); + // on ajoute a la queue qui utilise le launcher defini dans le job + if (launcher != null) { + for (SimulatorLauncher l : executors.keySet()) { + if (launcher == l) { + SimulationExecutor executor = executors.get(l); + executor.execute(job); + return; + } + } + } + // dernier recours on ajoute a la queue sans launcher + queue.add(job); + } + /** * Permet de resoumettre un job qui a ete pris par un thread mais qu'il * ne peut pas traiter. Cela arrive lorsque l'executor est en pause, ou @@ -327,7 +357,7 @@ * @param item l'item a resoumettre */ protected void resubmit(SimulationJob job) { - queue.add(job); + submit(job); } /** @@ -337,7 +367,7 @@ * @param job */ protected void submitSubJob(SimulationJob job) { - queue.add(job); + submit(job); } /** @@ -377,7 +407,8 @@ e.pause(); } // il faut bien penser a supprimer le launcher pour qu'un autre executor - // puisse y mettre le sien + // puisse y mettre le sien. FIXME: est ce le bon choix si l'utilisateur avait + // force un launcher particulier, ne faudrait t'il pas prevenir l'utilisateur ? job.setLauncher(null); resubmit(job); } @@ -526,13 +557,6 @@ } } - static public void message(SimulationControl control, String message) { - log.info(message); - if (control != null) { - control.setText(message); - } - } - /** * Prepare les fichiers qui seront utils à la simulation: * <li> scripts @@ -573,12 +597,12 @@ // backup pour toutes les simulations, pour eviter que l'utilisateur // ne puisse le modifier en meme temps - message(control, _("isisfish.message.backup.database.progress")); + control.setText(_("isisfish.message.backup.database.progress")); RegionStorage region = RegionStorage.getRegion(param.getRegionName()); TopiaContext tc = region.getStorage().beginTransaction(); tc.backup(regionXML, true); tc.closeContext(); - message(control, _("isisfish.message.backup.database.finished")); + control.setText(_("isisfish.message.backup.database.finished")); // copie de toutes regles a utiliser List<Rule> rules = param.getRules(); @@ -652,7 +676,7 @@ */ protected void compileAllFile(SimulationControl control, File directory) { - message(control, "Scripts and rules Compilation"); + control.setText("Scripts and rules Compilation"); long currentTime = System.nanoTime(); // @@ -681,7 +705,7 @@ CompileHelper.compile(directory, fileToCompile, directory, null); long time = System.nanoTime() - currentTime; - message(control, _("isisfish.message.compilation.time", DurationFormatUtils.formatDuration(time / 1000000, "s'.'S"))); + control.setText(_("isisfish.message.compilation.time", DurationFormatUtils.formatDuration(time / 1000000, "s'.'S"))); } Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationServiceTableModel.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationServiceTableModel.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/SimulationServiceTableModel.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -19,13 +19,15 @@ package fr.ifremer.isisfish.simulator.launcher; +import static org.codelutin.i18n.I18nf._; + import fr.ifremer.isisfish.simulator.SimulationControl; import fr.ifremer.isisfish.simulator.SimulationParameter; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map; -import static org.codelutin.i18n.I18nf._; - -import java.util.Set; import java.util.WeakHashMap; import javax.swing.JProgressBar; import javax.swing.table.AbstractTableModel; @@ -33,6 +35,11 @@ import org.apache.commons.logging.LogFactory; /** + * Model de table pour suivre l'evolution des differentes simulations en cours. + * + * <p> + * <b>ATTENTION</b> Cette classe doit supporter les acces concurrents car + * plusieurs threads peuvent etre simultanement en train de faire de simulation * * @author poussin * @version $Revision$ @@ -52,17 +59,85 @@ _("isisfish.queue.status"), _("isisfish.queue.progression"), }; + /** columns types */ + protected Class[] columnClass = new Class[]{ + String.class, // id + String.class, // analyse plan number + String.class, // local, remote, batch + String.class, // text + JProgressBar.class // progress + }; + + protected SimulationService simulationService; protected ArrayList<SimulationJob> jobs; - /** progress bar (one for each row) */ + protected Map<String, SimulationJob> jobIds; + /** progress bar (one for each row) */ protected Map<SimulationJob, JProgressBar> progress = new WeakHashMap<SimulationJob, JProgressBar>(); - public SimulationServiceTableModel(SimulationService simulationService, Set<SimulationJob> jobs) { + protected AbstractJobListener jobListener; + protected ControlListener controlListener; + + public SimulationServiceTableModel(SimulationService simulationService, + boolean forDoToJobs) { this.simulationService = simulationService; - this.jobs = new ArrayList<SimulationJob>(jobs); + if (forDoToJobs) { + jobListener = new JobToDoListener(simulationService, this); + } else { + jobListener = new JobDoneListener(simulationService, this); + } + controlListener = new ControlListener(simulationService, this); + simulationService.addSimulationServiceListener(jobListener); + jobListener.setData(); } + + public void addJob(SimulationJob job) { + String id = job.getItem().getControl().getId(); + log.info("************* Try do add job " + id); + synchronized(jobs) { + log.info("++++++++++Try do add job" + id); + if (!contains(job)) { + log.info("----------Add job" + id); + jobs.add(job); + jobIds.put(id, job); + fireTableRowsInserted(jobs.size() - 1, jobs.size() - 1); + } + } + } + public void removeJob(SimulationJob job) { + synchronized(jobs) { + int index = jobs.indexOf(job); + if (index >= 0) { + jobs.remove(index); + fireTableRowsDeleted(index, index); + } + } + } + public ArrayList<SimulationJob> getJobs() { + return jobs; + } + + public void setJobs(ArrayList<SimulationJob> jobs) { + this.jobs = jobs; + synchronized(jobs) { + jobIds = new HashMap<String, SimulationJob>(jobs.size()); + for (SimulationJob job : jobs) { + jobIds.put(job.getItem().getControl().getId(), job); + } + fireTableDataChanged(); + } + } + + public boolean contains(SimulationJob job) { + String id = job.getItem().getControl().getId(); + synchronized (jobs) { + boolean result = jobIds.containsKey(id); + return result; + } + } + protected JProgressBar getProgressBar(SimulationJob job) { JProgressBar result = progress.get(job); if (result == null) { @@ -88,6 +163,16 @@ return result; } + @Override + public Class<?> getColumnClass(int columnIndex) { + return columnClass[columnIndex]; + } + + @Override + public String getColumnName(int column) { + return columnHeader[column]; + } + public Object getValueAt(int rowIndex, int columnIndex) { SimulationJob job = jobs.get(rowIndex); SimulationControl control = job.getItem().getControl(); @@ -107,7 +192,11 @@ } break; case 2: - result = job.getLauncher().toString(); + if (job.getLauncher() == null) { + result = "not started"; + } else { + result = job.getLauncher().toString(); + } break; case 3: if (control != null) { @@ -131,4 +220,91 @@ return result; } + protected interface AbstractJobListener extends SimulationServiceListener { + public void setData(); + } + + class JobDoneListener implements AbstractJobListener, SimulationServiceListener { + + protected SimulationService simulationService; + protected SimulationServiceTableModel model; + + public JobDoneListener(SimulationService simulationService, + SimulationServiceTableModel model) { + this.simulationService = simulationService; + this.model = model; + setData(); + } + + public void setData() { + model.setJobs(new ArrayList<SimulationJob>(simulationService.getJobDones())); + } + + public void simulationStart(SimulationJob job) { + // nothing to do + } + + public void simulationStop(SimulationJob job) { + model.addJob(job); + } + + } + + class JobToDoListener implements AbstractJobListener, SimulationServiceListener { + + protected SimulationService simulationService; + protected SimulationServiceTableModel model; + + public JobToDoListener(SimulationService simulationService, + SimulationServiceTableModel model) { + this.simulationService = simulationService; + this.model = model; + setData(); + } + + public void setData() { + model.setJobs(new ArrayList<SimulationJob>(simulationService.getJobs())); + for (SimulationJob job : model.getJobs()) { + job.getItem().getControl().addPropertyChangeListener( + controlListener); + } + } + + public void simulationStart(SimulationJob job) { + model.addJob(job); + job.getItem().getControl().addPropertyChangeListener( + model.controlListener); + } + + public void simulationStop(SimulationJob job) { + model.removeJob(job); + job.getItem().getControl().removePropertyChangeListener( + model.controlListener); + } + + } + + class ControlListener implements PropertyChangeListener { + + protected SimulationService simulationService; + protected SimulationServiceTableModel model; + + public ControlListener(SimulationService simulationService, SimulationServiceTableModel model) { + this.simulationService = simulationService; + this.model = model; + } + + public void propertyChange(PropertyChangeEvent evt) { + SimulationControl control = (SimulationControl)evt.getSource(); + String id = control.getId(); + synchronized(model.jobs) { + SimulationJob jobs = model.jobIds.get(id); + int index = model.getJobs().indexOf(id); + if (index >= 0) { + fireTableRowsUpdated(index, index); + } + } + } + + } } Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/doc-files/isis-simulation.png =================================================================== (Binary files differ) Property changes on: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/doc-files/isis-simulation.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/package.html =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/package.html (rev 0) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/simulator/launcher/package.html 2008-08-27 17:07:00 UTC (rev 1311) @@ -0,0 +1,118 @@ +<h1>Launcher</h1> + +<h2>To do</h2> +<li> voir pourquoi l'interface de visu des simulations en cours ne se +rafraichi pas +<li> supprimer le SimulationItem et tout mettre dans SimulationJob (reflechir +si au niveau design c'est une bonne chose +<li> faire une interface graphique de monitoring des Executors (nombre de +threads actif, nombre de simulations terminer, nombre de simulation +explicitement pour cet executor, afficher l'etat pause/resume/error et +permettre de modifier l'etat. Avec le nombre +de jobs dans la queue pour tous les Executors. Permettre de soumettre toutes +les simulations d'un executor sur un autre executor. (par exemple si un +executor est mis en pause a cause des erreurs, cela permet a l'utilisateur +d'utiliser un autre executor sans devoir annuler/relancer toutes ces +simulations. +<li> ajouter dans l'interface de vision des simulations en cours, de +modifier le launcher des simulations non lancee. +<li> tester les differents launcher +<li> trouver une solution pour que les jobs soumis pour un launcher +particulier soit bien executer par l'executor de ce launcher. (penser au +changement de priority avec resoumission si ce choix est pris, c-a-d que le +job s'appercoit qu'il va etre utilise par le mauvais Executor, il ne fait +pas la simu et la resoumet a queue en augmentant la priority pour que le job +qui devait etre fait maintenant ne le soit pas dans 10ans). +Une autre possibilite d'implantation est que chaque executor est une queue +propre, et lorsque celle-ci est vide il vont piocher dans la queue commune. +Pour cela, simplement implanter un nouveau type de queue qui permette +d'avoir une queue mere. Lors de la soumission au SimulationService soit le +job est directement soumis au bon executor soit ajoute a la queue general. +(ajouter un bool qui permette lors de report d'erreur de resoumettre un job +avec launcher fixe par l'utilisateur sur la queue general ou non. + +<h2>Architecture global</h2> +<img src="doc-files/isis-simulation.png" alt="archi"/> + +<h2>Principe general</h2> +<p> +Les simulations sont soumises au {@link SimulationService} via sa methode +submit. Un objet {@link SimulationJob} est alors cree et ajoute a la liste +des simulations presentes ({@link SimulationService#getJobs}). Si la +simulation est une simple simulation ou une simulation avec plan d'analyse +dependant, elle est alors directement ajoutee a la queue de simulation +(simulation a faire). Si +la simulation utilise un plan d'analyse independant, un thread est +specialement utilise pour generer toutes les simulations du plan, celles-ci +sont alors ajoutee a la queue, mais n'apparaitront dans la liste des +simulations qu'au moment ou un thread de simulation executera reellement le +job. +</p> + +<p> +Lorsqu'un thread recupere un job dans la queue, il leve un event {@link +SimulationListener#start}, la simulation est alors ajoutee a la liste des +simulations visibles si elle ne l'etait pas encore. +</p> + +<p> +Une fois terminees, les simulations finissent dans la liste des simulations +terminees. +</p> + +<p> +Le {@link SimulationService#autoLaunch} permet d'indique si le service est +actif ou non. S'il n'est pas actif, il accepte les simulations mais ne les +execute pas (elles sont en attente). S'il est actif alors les differents +{@link SimulationExecutor}) prenent les jobs de la queue pour faire les +simulations. +</p> + +<h2>SimulationExecutor</h2> +<p> +Lors de sa creation le {@link SimulationService} a initialise different +{@link SimulationExecutor} en fonction de la configuration. Ces {@link +SimulationExecutor} sont responsable de l'execution des simulations de la +queue. Chaque {@link SimulationExecutor} a un {@link SimulatorLauncher} +qu'il utilise si la simulation n'a pas encore de {@link SimulatorLauncher} +d'assigne. +</p> +<p> +Un {@link SimulationExecutor} peut etre mis en pause puis relance. Lorsqu'il +est en pause, il termine les simulations en cours mais n'en reprend pas de +nouvelle. Cela permet d'arrete un {@link SimulationExecutor} particulier +sans devoir arreter tout le service de simulation. +</p> +<p>Si un {@link SimulationExecutor} prend un job ayant deja un {@link +SimulatorLauncher} d'assigne, il utilise alors ce launcher plutot que le +sien. Ce choix est derangeant lorsque l'on souhaite utilise un nombre de +thread limite pour un launcher particulier, mais il est le plus raisonnable +car l'autre possibilite est que le job soit resoumis au {@link +SimulationService} jusqu'a ce que le bon {@link SimulationExecutor} le +prenne pour l'executer. On risque dans ce cas d'arriver a une forte +consommation CPU si le seul {@link SimulationExecutor} disponible ne gere +pas les jobs en queue. +</p> + +<h2>SimulationJob</h2> + +<p> +Le simulation Job encapsule l'appel pour que les implantantations des {@link +SimulatorLauncher} soit la plus simple possible. Il gere les simulations +avec plan dependant, les exports depandes par l'utilisateur, ainsi que +l'effacement des simulations si seul les exports interessait l'utilisateur. +</p> + +<p> +Si le job n'arrive pas a utilise le {@link SimulatorLauncher} il en notifie +le {@link SimulationService} qui resoumet le job dans la queue pour qu'un +autre {@link SimulationExecutor} prenne ce job. Si trop d'erreurs sont +notifiees pour un meme {@link SimulatorLauncher}, le {@link +SimulatorService} prend alors la decision d'arreter l'executor associe. +</p> +<p> +Pour les simulations ou l'utilisateur avait fixe un {@link +SimulatorLauncher} particulier en cas de notification d'erreur au {@link +SimulationService} ce {@link SimulatorLauncher} n'est plus pris en compte et +n'importe quel {@link SimulatorLauncher} peut faire cette simulation. +</p> Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/Queue.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/Queue.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/Queue.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -6,8 +6,31 @@ package fr.ifremer.isisfish.ui.simulator; +import fr.ifremer.isisfish.logging.SimulationLoggerUtil; +import java.util.logging.Level; +import java.util.logging.Logger; +import static org.codelutin.i18n.I18nf._; + +import fr.ifremer.isisfish.simulator.launcher.SimulationJob; import fr.ifremer.isisfish.simulator.launcher.SimulationService; import fr.ifremer.isisfish.simulator.launcher.SimulationServiceTableModel; +import java.awt.Component; +import javax.swing.GroupLayout; +import javax.swing.JProgressBar; +import javax.swing.JTable; +import javax.swing.LayoutStyle; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.ListSelectionModel; +import javax.swing.table.TableCellRenderer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.log.UserLog; +import org.jdesktop.beansbinding.AutoBinding; +import org.jdesktop.beansbinding.BeanProperty; +import org.jdesktop.beansbinding.Binding; +import org.jdesktop.beansbinding.BindingGroup; +import org.jdesktop.beansbinding.Bindings; +import org.jdesktop.beansbinding.ELProperty; /** * @@ -15,19 +38,60 @@ */ public class Queue extends javax.swing.JPanel { + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(SimulationServiceTableModel.class); + + public class JProgressBarTableCellRenderer implements TableCellRenderer { + public Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, + int row, int column) { + return (JProgressBar) value; + } + }// JProgressBarTableCellRenderer + /** Creates new form Queue */ public Queue() { initComponents(); SimulationService ss = SimulationService.getService(); - modelJobs = new SimulationServiceTableModel(ss, ss.getJobs()); - modelJobDones = new SimulationServiceTableModel(ss, ss.getJobDones()); + + modelJobs = new SimulationServiceTableModel(ss, true); + modelJobDones = new SimulationServiceTableModel(ss, false); + + tableJobs.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + tableJobs.setDefaultRenderer(JProgressBar.class, + new JProgressBarTableCellRenderer()); + tableJobDones.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + tableJobDones.setDefaultRenderer(JProgressBar.class, + new JProgressBarTableCellRenderer()); + tableJobs.setModel(modelJobs); tableJobDones.setModel(modelJobDones); } + private void stopSimulation(java.awt.event.ActionEvent evt) { + int i = tableJobs.getSelectedRow(); + if (i >= 0) { + SimulationJob job = modelJobs.getJob(i); + job.stop(); + log.info(_("User stop simulation %s", job.getItem().getControl().getId())); + } + } + + private void viewLog(java.awt.event.ActionEvent evt) { + int i = tableJobs.getSelectedRow(); + if (i >= 0) { + SimulationJob job = modelJobs.getJob(i); + String id = job.getItem().getControl().getId(); + try { + SimulationLoggerUtil.showSimulationLogConsole(id); + } catch (Exception eee) { + UserLog.error(_("Can't open log for %s", id), eee); + } + } + } private void initComponents() { - bindingGroup = new org.jdesktop.beansbinding.BindingGroup(); + bindingGroup = new BindingGroup(); tableJobsScroll = new javax.swing.JScrollPane(); tableJobs = new javax.swing.JTable(); @@ -43,12 +107,18 @@ autoLaunchButton.setText("Auto Launch"); - org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jButton1, org.jdesktop.beansbinding.ELProperty.create("${action.enabled}"), autoLaunchButton, org.jdesktop.beansbinding.BeanProperty.create("selected")); + Binding binding = Bindings.createAutoBinding( + AutoBinding.UpdateStrategy.READ_WRITE, + SimulationService.getService(), ELProperty.create("${autoLaunch}"), + autoLaunchButton, BeanProperty.create("selected")); bindingGroup.addBinding(binding); jButton1.setText("Stop simulation"); - binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, tableJobs, org.jdesktop.beansbinding.ELProperty.create("${selectedElement}"), jButton1, org.jdesktop.beansbinding.BeanProperty.create("enabled")); + binding = Bindings.createAutoBinding( + AutoBinding.UpdateStrategy.READ, + tableJobs, ELProperty.create("${selectedElement != null}"), + jButton1, BeanProperty.create("enabled")); binding.setSourceNullValue(false); binding.setSourceUnreadableValue(false); bindingGroup.addBinding(binding); @@ -61,7 +131,10 @@ jButton2.setText("View log"); - binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ, tableJobDones, org.jdesktop.beansbinding.ELProperty.create("${selectedElement}"), jButton2, org.jdesktop.beansbinding.BeanProperty.create("enabled")); + binding = Bindings.createAutoBinding( + AutoBinding.UpdateStrategy.READ, + tableJobDones, ELProperty.create("${selectedElement != null}"), + jButton2, BeanProperty.create("enabled")); binding.setSourceNullValue(false); binding.setSourceUnreadableValue(false); bindingGroup.addBinding(binding); @@ -72,33 +145,33 @@ } }); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + GroupLayout layout = new GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(12, 12, 12) .addComponent(autoLaunchButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton2)) - .addComponent(tableJobDonesScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE) - .addComponent(tableJobsScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)) + .addComponent(tableJobDonesScroll, GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE) + .addComponent(tableJobsScroll, GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(tableJobsScroll, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tableJobDonesScroll, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tableJobsScroll, GroupLayout.PREFERRED_SIZE, 140, Short.MAX_VALUE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(tableJobDonesScroll, GroupLayout.PREFERRED_SIZE, 140, Short.MAX_VALUE) + .addPreferredGap(ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(autoLaunchButton) .addComponent(jButton1) .addComponent(jButton2)) @@ -108,17 +181,6 @@ bindingGroup.bind(); } - private void stopSimulation(java.awt.event.ActionEvent evt) { - int i = tableJobs.getSelectedRow(); - if (i >= 0) { - modelJobs.getJob(i).stop(); - } - } - - private void viewLog(java.awt.event.ActionEvent evt) { - // TODO add your handling code here: - } - protected SimulationServiceTableModel modelJobs; protected SimulationServiceTableModel modelJobDones; protected javax.swing.JToggleButton autoLaunchButton; Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorAction.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorAction.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorAction.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -62,6 +62,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.codelutin.log.UserLog; /** @@ -76,8 +77,8 @@ static public Object opened(Context uiContext, AbstractFrame frame, TopiaContext isisContext, JTabbedPane tabs, - JButton start, JButton remove,JButton showLog, - JTable table,JTable tableDone, +// JButton start, JButton remove,JButton showLog, +// JTable table,JTable tableDone, JButton removeAnalysePlan, JList listAnalysePlan, JButton removeRule, @@ -124,14 +125,14 @@ tabs.setEnabledAt(1, false); // disable prescript tab tabs.setEnabledAt(2, false); // disable analyse plan tab - // add simulation queue button listeners - SimulatorListeners.initSimulQueueButtonsListener( - start, - remove, - showLog, - table, - tableDone - ); +// // add simulation queue button listeners +// SimulatorListeners.initSimulQueueButtonsListener( +// start, +// remove, +// showLog, +// table, +// tableDone +// ); // add rule around button listeners SimulatorListeners.initButtonRemoveIfItemSelected(removeRule, listRule); @@ -266,17 +267,14 @@ if (simulId == null || "".equals(simulId) || SimulationStorage.localyExists(simulId) || SimulationService.getService().exists(simulId)) { - log.error("Can't start simulation, bad id: " + simulId); - throw new SimulationException(_("isisfish.error.start")); - } - SimulationParameter p = param.copy(); + UserLog.error(_("Can't start simulation, bad id: %s", simulId)); + } else { + SimulationParameter p = param.copy(); - SimulationService.getService().submit(simulId, p, 0); - - selectTab(tabs, true, 6); - //TODO Voir si cela fonctionne - frame.refreshView("buttonSimulQueueShowLog"); - frame.refreshView("buttonSimulQueueRemove"); + SimulationService.getService().submit(simulId, p, 0); + + selectTab(tabs, true, 6); + } } catch (Exception eee) { log.error("Can't start simulation", eee); return new OutputView("Error.xml", "error", eee.getMessage()); Modified: trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorListeners.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorListeners.java 2008-08-22 22:46:00 UTC (rev 1310) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/simulator/SimulatorListeners.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -44,44 +44,44 @@ } - public static void initSimulQueueButtonsListener( - final JButton start, final JButton remove, final JButton showLog, - final JTable table, final JTable tableDone) { +// public static void initSimulQueueButtonsListener( +// final JButton start, final JButton remove, final JButton showLog, +// final JTable table, final JTable tableDone) { +// +// SimulationService.getService().addPropertyChangeListener("autoLaunch", +// new PropertyChangeListener() { +// public void propertyChange(PropertyChangeEvent evt) { +// start.setEnabled(isSimulStartButtonEnabled(table)); +// } +// }); +// +// table.getModel().addTableModelListener(new TableModelListener() { +// public void tableChanged(TableModelEvent e) { +// start.setEnabled(isSimulStartButtonEnabled(table)); +// } +// }); +// +// table.getSelectionModel().addListSelectionListener( +// new ListSelectionListener() { +// public void valueChanged(ListSelectionEvent e) { +// remove.setEnabled(isSimulRemoveButtonEnabled(table)); +// } +// }); +// +// tableDone.getSelectionModel().addListSelectionListener( +// new ListSelectionListener() { +// public void valueChanged(ListSelectionEvent e) { +// showLog.setEnabled(isSimulShowLogButtonEnabled(tableDone)); +// } +// } +// ); +// +// // apply it now +// start.setEnabled(isSimulStartButtonEnabled(table)); +// remove.setEnabled(isSimulRemoveButtonEnabled(table)); +// showLog.setEnabled(isSimulShowLogButtonEnabled(tableDone)); +// } - SimulationService.getService().addPropertyChangeListener("autoLaunch", - new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - start.setEnabled(isSimulStartButtonEnabled(table)); - } - }); - - table.getModel().addTableModelListener(new TableModelListener() { - public void tableChanged(TableModelEvent e) { - start.setEnabled(isSimulStartButtonEnabled(table)); - } - }); - - table.getSelectionModel().addListSelectionListener( - new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - remove.setEnabled(isSimulRemoveButtonEnabled(table)); - } - }); - - tableDone.getSelectionModel().addListSelectionListener( - new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - showLog.setEnabled(isSimulShowLogButtonEnabled(tableDone)); - } - } - ); - - // apply it now - start.setEnabled(isSimulStartButtonEnabled(table)); - remove.setEnabled(isSimulRemoveButtonEnabled(table)); - showLog.setEnabled(isSimulShowLogButtonEnabled(tableDone)); - } - public static void initButtonRemoveIfItemSelected( final JButton button, final JList list) { if (button == null || list == null) { Added: trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/widget/VCSConnectionState.java =================================================================== --- trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/widget/VCSConnectionState.java (rev 0) +++ trunk/isis-fish/src/java/fr/ifremer/isisfish/ui/widget/VCSConnectionState.java 2008-08-27 17:07:00 UTC (rev 1311) @@ -0,0 +1,54 @@ +/* *##% + * Copyright (C) 2002-2008 Code Lutin, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + *##%*/ + +package fr.ifremer.isisfish.ui.widget; + + +import fr.ifremer.isisfish.IsisFish; +import javax.swing.Icon; +import javax.swing.JLabel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.util.Resource; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class VCSConnectionState extends JLabel { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(VCSConnectionState.class); + + public VCSConnectionState() { + Icon icon; + boolean connected = IsisFish.vcs.isConnected(); + if (connected) { + icon = Resource.getIcon("images/stock_connect.png"); + } else { + icon = Resource.getIcon("images/stock_disconnect.png"); + } + setIcon(icon); + } + +}
participants (1)
-
bpoussin@users.labs.libre-entreprise.org