View Javadoc

1   /*
2   Karma core - Core of the Karma application
3   Copyright (C) 2004  Toolforge <www.toolforge.nl>
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  package nl.toolforge.karma.core.vc.threads;
20  
21  import nl.toolforge.karma.core.KarmaRuntimeException;
22  import nl.toolforge.karma.core.manifest.Manifest;
23  import nl.toolforge.karma.core.module.Module;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import java.lang.reflect.Constructor;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.Map;
31  
32  /***
33   * The ParallelRunner handles parallel <code>RunnerThread</code>s. This concept should be used when parallel read
34   * actions on version control repositories are possible to speed up the process of performing commands for
35   * <strong>each</strong> module in a manifest.
36   *
37   * @author D.A. Smedes
38   * @version $Id: ParallelRunner.java,v 1.10 2004/11/16 22:31:58 asmedes Exp $
39   */
40  public class ParallelRunner {
41  
42    Log logger = LogFactory.getLog(ParallelRunner.class);
43  
44    private Map results = null;
45  
46    private Manifest manifest = null;
47    private RunnerThread[] threads = null;
48  
49    private Class impl = null;
50  
51    /***
52     * Initializes this <code>ParallelRunner</code> with the correct <code>Manifest</code>. Call {@link #execute()} or
53     * {@link #execute(int, long)} to start all threads.
54     *
55     * @param manifest    The manifest.
56     * @param threadClass A Class instance, extending {@link Thread}.
57     */
58    public ParallelRunner(Manifest manifest, Class threadClass) {
59      this.manifest = manifest;
60      this.impl = threadClass;
61    }
62  
63    /***
64     * Starts all threads, and processes the results. Results can be retrieved by calling {@link #retrieveResults}.
65     *
66     * @param delayInMilliseconds  The delay in milliseconds between the start of each thread.
67     */
68    public void execute(long delayInMilliseconds) {
69      execute(0, delayInMilliseconds);
70    }
71  
72  
73    /***
74     * Starts all threads, and processes the results. Results can be retrieved by calling {@link #retrieveResults}. Note
75     * that no restriction is imposed on the amount of threads, and they are started as soon as possible.
76     *
77     * @see #execute(long)
78     * @see #execute(int, long)
79     */
80    public void execute() {
81      execute(0,0);
82    }
83  
84  
85    /***
86     * Starts all threads, and processes the results. Results can be retrieved by calling {@link #retrieveResults}.
87     *
88     * @param blockSize            Determines the amount of threads that will be started in one block, with a delay of
89     *                             <code>delayInMilliseconds</code>. If all threads should be started as one block, a
90     *                             negative <code>blockSize</code> should be provided. When a positive blocksize is
91     *                             provided, a default delay of 1000 milliseconds is used between blocks. <b>Note</b>
92     *                             this feature is currently ignored.
93     * @param delayInMilliseconds  The delay in milliseconds between threads in a block (or all threads if
94     *                             <code>blockSize</code> is negative.
95     */
96    public void execute(int blockSize, long delayInMilliseconds) {
97  
98      Map modules = manifest.getAllModules();
99  
100     // Initialize status overview map
101     //
102     results = new HashMap();
103 
104     // Initialize an array of threads.
105     //
106     threads = new RunnerThread[modules.size()];
107 
108     int index = 0;
109 
110     logger.debug("Starting " + modules.size() + " threads, with a delay of " + delayInMilliseconds + " ms.");
111 
112     // Start each task in parallel ...
113     //
114     for (Iterator i = modules.values().iterator(); i.hasNext();) {
115 
116       try {
117         Constructor constructor = impl.getConstructor(new Class[]{Module.class});
118         threads[index] = (RunnerThread) constructor.newInstance(new Object[]{(Module) i.next()});
119       } catch (Exception e) {
120         logger.error(e);
121         throw new KarmaRuntimeException("Could not start a RunnerThread instance.");
122       }
123 
124       threads[index].start();
125       try {
126         Thread.sleep(delayInMilliseconds);
127       } catch (InterruptedException e) {
128         //
129       }
130       index++;
131     }
132 
133     for (int i = 0; i < threads.length; i++) {
134 
135       try {
136         threads[i].join();
137         addResult(threads[i].getModule(), threads[i].getResult());
138       } catch (InterruptedException e) {
139         throw new KarmaRuntimeException(e.getMessage());
140       }
141     }
142   }
143 
144 
145   private void addResult(Module module, RunnerResult result) {
146     results.put(module, result);
147   }
148 
149 
150   /***
151    * Returns a map of {@link nl.toolforge.karma.core.vc.ModuleStatus} objects, each accessible by the the corresponding
152    * {@link nl.toolforge.karma.core.module.Module} instance.
153    *
154    * @return A map, containing {@link nl.toolforge.karma.core.vc.ModuleStatus} objects.
155    */
156   public Map retrieveResults() {
157     return results;
158   }
159 
160 }