View Javadoc
1   /******************************************************************************
2    * BatchManager.java - Serialize heavy Pic processing.  Insure single threadedness
3    * (two copies could lead to _heavens_ out of memory
4    * 
5    * PicMan - The BuckoSoft Picture Manager in Java
6    * Copyright(c) 2007 - Dick Balaska
7    * 
8    */
9   package com.buckosoft.PicMan.business;
10  
11  import java.util.Date;
12  import java.util.LinkedList;
13  import java.util.List;
14  
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  
18  import com.buckosoft.PicMan.business.util.MD5SumUpdater;
19  import com.buckosoft.PicMan.business.util.MlbFilterFixer;
20  import com.buckosoft.PicMan.business.util.PicSizeUpdater;
21  import com.buckosoft.PicMan.domain.JobLogEntry;
22  
23  /** Batch processing of pic jobs.  Serializes heavy Pic processing.
24   * Insure single threadedness (two copies could lead to, <i>heavens</i>, out of memory)
25   * @author Dick Balaska
26   * @since 2007/12/01
27   * @see <a href="http://cvs.buckosoft.com/Projects/PicMan/PicMan/src/main/java/com/buckosoft/PicMan/business/BatchManager.java">BatchManager.java</a>
28   */
29  public class BatchManager {
30  	@SuppressWarnings("unused")
31  	private static boolean DEBUG = false;
32  	private static boolean DEBUGENTRY = false;
33  
34  	protected final Log logger = LogFactory.getLog(getClass());
35  
36  	private	boolean			isRunning = false;
37  	private	boolean			syncRunning = false;
38  	private boolean			picSizeRunning = false;
39  	private	boolean			mlbFiltersRunning = false;
40  	private	boolean			md5sumRunning = false;
41  	private	boolean			mosaicVectorRunning = false;
42  	private	boolean			mosaicBuilderRunning = false;
43  	private	boolean			thumbCacheBuilderRunning = false;
44  	private	boolean			contactsRunning = false;
45  	private	PicManFacade	pmf;
46  	private	Date			batchRunStarted;
47  	@SuppressWarnings("unused")
48  	private	Date			batchRunEnded;
49  
50  	
51  	private	ContactManager contactManager = new ContactManager();
52  
53  	private	PicSizeUpdater	picSizeUpdater = null;
54  	private	MlbFilterFixer	mlbFilterFixer = null;
55  	private	MD5SumUpdater	md5sumUpdater = null;
56  
57  	/** Set the reference to the PicMan API.
58  	 * @param pmf The PicManFacade
59  	 */
60  	public	void setPicMan(PicManFacade pmf) {
61  		this.pmf = pmf;
62  		this.contactManager.setPicMan(pmf);
63  	}
64  
65  	/** Enable logger output on this module
66  	 * @param debugFlag true == turn on debugging.
67  	 */
68  	public void setDEBUG(boolean debugFlag) {
69  		DEBUG = debugFlag;
70  	}
71  
72  	/** Enable logger output on this module
73  	 * @param debugFlag true == turn on debugging.
74  	 */
75  	public void setDEBUGEntry(boolean debugFlag) {
76  		DEBUGENTRY = debugFlag;
77  	}
78  
79  	/** Fetch a reference to the ContactManager
80  	 * @return the contactManager
81  	 */
82  	public ContactManager getContactManager() {
83  		return contactManager;
84  	}
85  
86  	synchronized private boolean okToRun() { 
87  		if (isRunning == true)
88  			return(false);
89  		isRunning = true;
90  		return(true);
91  	}
92  	synchronized private void exitRun() {
93  		isRunning = false;
94  	}
95  	
96  	/** Return a short status of the engine's state.
97  	 * @return A one or two word String
98  	 */
99  	public	String	engineRunningShortStatus() {
100 		if (isRunning) {
101 			if (contactsRunning)
102 				return("run (" + contactManager.getContactRunning() + ")");
103 			else if (picSizeRunning)
104 				return("PicSize #" + this.picSizeUpdater.getPicProcessing());
105 			else if (this.mlbFiltersRunning)
106 				return("mlbFilters #" + this.mlbFilterFixer.getPicProcessing());
107 			else if (mosaicVectorRunning)
108 				return("MosaicVector #" + pmf.getMosaicMan().getMosaicManDevelopment().getPicProcessing());
109 			else if (this.thumbCacheBuilderRunning)
110 				return("BuildThumbCache #" + pmf.getThumbCache().getPicProcessing());
111 			else if (mosaicBuilderRunning)
112 				return("Mosaic: " + pmf.getMosaicMan().getMosaicEngine().getName());
113 			else if (syncRunning)
114 				return("Sync");
115 			else if (this.md5sumRunning)
116 				return("md5sum #" + this.md5sumUpdater.getPicProcessing());
117 			else return("InvalidState?");
118 		}
119 		else if (!pmf.getDB().getSystem().isEngineOn())
120 			return("off");
121 		else
122 			return("idle");
123 	}
124 
125 	/** Get a list of other jobs queued.  Useful for reports.
126 	 * @return A list of work to do.
127 	 */
128 	public List<String>	getOtherJobsQueued() {
129 		LinkedList<String> list = new LinkedList<String>();
130 		if (pmf.getDB().getSystem().isUpdatePicSize())
131 			list.add("Update Pic Sizes");
132 		if (pmf.getDB().getSystem().isUpdateMlbFilters())
133 			list.add("Update Mlb Filters");
134 		if (pmf.getDB().getSystem().isCalcMosaicVectors())
135 			list.add("Calc Mosaic Vectors");
136 		if (pmf.getThumbCache().isBuildThumbCache())
137 			list.add("Build Thumb Cache");
138 		if (pmf.getDB().getSystem().isUpdateMD5Sums())
139 			list.add("Update MD5sums");
140 		return(list);
141 	}
142 
143 	/** Entry point to the BatchManager. <br>
144 	 * This runs on the cron tick and will insure single-threadedness of itself.
145 	 */
146 	public	void	run() throws Exception {
147 		if (DEBUGENTRY)
148 			logger.info("run!");
149 		if (!pmf.getDB().getSystem().isEngineOn()) {	// turned off by user
150 			if (DEBUGENTRY)
151 				logger.info("Turned off");
152 			return;
153 		}
154 		if (!okToRun()) {
155 			if (DEBUGENTRY)
156 				logger.info("Not ok to run");
157 			return;
158 		}
159 		// from here on, you *must* call exitRun() to decrement the reference counter
160 		
161 		if (pmf.getDB().getSystem().isEngineRunOnce() && batchRunStarted != null)	{ //only run once per lifetime
162 			if (DEBUGENTRY)
163 				logger.info("Ran once");
164 			exitRun();
165 			return;
166 		}
167 
168 		batchRunStarted = new Date();
169 		boolean writeJobLog = false;
170 		boolean	workDone;
171 		JobLogEntry jle = new JobLogEntry();
172 		while (true) {
173 			if (!pmf.getDB().getSystem().isEngineOn())	// turned off by user
174 				break;
175 			workDone = false;
176 			if (pmf.getDB().getSystem().isSyncEnable()) {
177 				this.syncRunning = true;
178 				this.pmf.getSyncManager().run();
179 				this.syncRunning = false;
180 			}
181 			if (pmf.getDB().getSystem().isUpdatePicSize()) {
182 				this.picSizeRunning = true;
183 				this.picSizeUpdater = new PicSizeUpdater();
184 				this.picSizeUpdater.setPicMan(pmf);
185 				try {
186 					this.picSizeUpdater.run();
187 				} catch (Exception e) {
188 					pmf.addError(e);
189 					e.printStackTrace();
190 				}
191 				pmf.getDB().getSystem().setUpdatePicSize(false);
192 				this.picSizeUpdater = null;
193 				this.picSizeRunning = false;
194 				workDone = true;
195 			} else if (pmf.getDB().getSystem().isUpdateMlbFilters()) {
196 				this.mlbFiltersRunning = true;
197 				this.mlbFilterFixer = new MlbFilterFixer();
198 				this.mlbFilterFixer.setPicMan(pmf);
199 				try {
200 					this.mlbFilterFixer.run();
201 				} catch (Exception e) {
202 					pmf.addError(e);
203 					e.printStackTrace();
204 				}
205 				pmf.getDB().getSystem().setUpdateMlbFilters(false);
206 				this.mlbFilterFixer = null;
207 				this.mlbFiltersRunning = false;
208 				workDone = true;
209 			} else if (pmf.getDB().getSystem().isUpdateMD5Sums()) {
210 				this.md5sumRunning = true;
211 				this.md5sumUpdater = new MD5SumUpdater();
212 				this.md5sumUpdater.setPicMan(pmf);
213 				try {
214 					this.md5sumUpdater.run();
215 				} catch (Exception e) {
216 					pmf.addError(e);
217 					e.printStackTrace();
218 				}
219 				pmf.getDB().getSystem().setUpdateMD5Sums(false);
220 				this.md5sumUpdater = null;
221 				this.md5sumRunning = false;
222 				workDone = true;
223 			} else if (pmf.getDB().getSystem().isCalcMosaicVectors()) {
224 				this.mosaicVectorRunning = true;
225 				try {
226 					pmf.getMosaicMan().getMosaicManDevelopment().runVectors();
227 				} catch (Exception e) {
228 					pmf.addError(e);
229 					e.printStackTrace();
230 				}
231 				this.mosaicVectorRunning = false;
232 				pmf.getDB().getSystem().setCalcMosaicVectors(false);
233 				workDone = true;
234 			}
235 			if (pmf.getThumbCache().isBuildThumbCache()) {
236 				this.thumbCacheBuilderRunning = true;
237 				try {
238 					pmf.getThumbCache().batchBuildCache();
239 				} catch (Exception e) {
240 					logger.error("Build cache died", e);
241 					Exception ex = new Exception("Build Thumb Cache died", e);
242 					pmf.addError(ex);
243 				}
244 				pmf.getThumbCache().setBuildThumbCache(false);
245 				this.thumbCacheBuilderRunning = false;
246 				workDone = true;
247 			}
248 			if (pmf.getMosaicMan().hasWorkToDo()) {
249 				this.mosaicBuilderRunning = true;
250 				try {
251 					@SuppressWarnings("unused")
252 					boolean moreWork = pmf.getMosaicMan().runBuilder();
253 					workDone = true;
254 				} catch (Exception e) {
255 					logger.error("Build Mosaic died", e);
256 					Exception ex = new Exception("Build Mosaic died", e);
257 					pmf.addError(ex);
258 				}
259 				this.mosaicBuilderRunning = false;
260 			}  /* always check the contacts */ {
261 				this.contactsRunning = true;
262 				try {
263 					workDone = contactManager.makeContacts() | workDone;
264 				} catch (Throwable t) {
265 					batchRunEnded = new Date();
266 					this.contactsRunning = false;
267 					pmf.addError(t);
268 				}
269 				this.contactsRunning = false;
270 			}
271 			if (workDone)
272 				writeJobLog = true;
273 			if (!workDone)
274 				break;
275 		}
276 		batchRunEnded = new Date();
277 		exitRun();
278 		if (writeJobLog) {
279 			jle.setType(JobLogEntry.DONE);
280 			jle.setColor(JobLogEntry.COLOR_OK);
281 			jle.setEndTime(new Date());
282 			pmf.addJobToLog(jle);
283 			
284 		}
285 	}
286 }