001: // serverInstantThread.java
002: // -----------------------
003: // (C) by Michael Peter Christen; mc@anomic.de
004: // first published on http://www.anomic.de
005: // Frankfurt, Germany, 2005
006: // last major change: 14.03.2005
007: //
008: // This program is free software; you can redistribute it and/or modify
009: // it under the terms of the GNU General Public License as published by
010: // the Free Software Foundation; either version 2 of the License, or
011: // (at your option) any later version.
012: //
013: // This program is distributed in the hope that it will be useful,
014: // but WITHOUT ANY WARRANTY; without even the implied warranty of
015: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: // GNU General Public License for more details.
017: //
018: // You should have received a copy of the GNU General Public License
019: // along with this program; if not, write to the Free Software
020: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: //
022: // Using this software in any meaning (reading, learning, copying, compiling,
023: // running) means that you agree that the Author(s) is (are) not responsible
024: // for cost, loss of data or any harm that may be caused directly or indirectly
025: // by usage of this softare or this documentation. The usage of this software
026: // is on your own risk. The installation and usage (starting/running) of this
027: // software may allow other people or application to access your computer and
028: // any attached devices and is highly dependent on the configuration of the
029: // software which must be done by the user of the software; the author(s) is
030: // (are) also not responsible for proper configuration and usage of the
031: // software, even if provoked by documentation provided together with
032: // the software.
033: //
034: // Any changes to this file according to the GPL as documented in the file
035: // gpl.txt aside this file in the shipment you received can be done to the
036: // lines that follows this copyright notice here, but changes must not be
037: // done inside the copyright notive above. A re-distribution must contain
038: // the intact and unchanged copyright notice.
039: // Contributions and changes to the program code must be marked as such.
040:
041: package de.anomic.server;
042:
043: import java.lang.reflect.InvocationTargetException;
044: import java.lang.reflect.Method;
045: import java.util.TreeMap;
046:
047: import de.anomic.server.logging.serverLog;
048:
049: public final class serverInstantThread extends serverAbstractThread
050: implements serverThread {
051:
052: private Method jobExecMethod, jobCountMethod, freememExecMethod;
053: private Object environment;
054: private Long handle;
055:
056: public static int instantThreadCounter = 0;
057: public static TreeMap<Long, String> jobs = new TreeMap<Long, String>();
058:
059: public serverInstantThread(Object env, String jobExec,
060: String jobCount, String freemem) {
061: // jobExec is the name of a method of the object 'env' that executes the one-step-run
062: // jobCount is the name of a method that returns the size of the job
063: // freemem is the name of a method that tries to free memory and returns void
064: Class<?> theClass = (env instanceof Class) ? (Class<?>) env
065: : env.getClass();
066: try {
067: this .jobExecMethod = theClass.getMethod(jobExec,
068: new Class[0]);
069: } catch (NoSuchMethodException e) {
070: throw new RuntimeException(
071: "serverInstantThread, wrong declaration of jobExec: "
072: + e.getMessage());
073: }
074: try {
075: if (jobCount == null)
076: this .jobCountMethod = null;
077: else
078: this .jobCountMethod = theClass.getMethod(jobCount,
079: new Class[0]);
080:
081: } catch (NoSuchMethodException e) {
082: throw new RuntimeException(
083: "serverInstantThread, wrong declaration of jobCount: "
084: + e.getMessage());
085: }
086: try {
087: if (freemem == null)
088: this .freememExecMethod = null;
089: else
090: this .freememExecMethod = theClass.getMethod(freemem,
091: new Class[0]);
092:
093: } catch (NoSuchMethodException e) {
094: throw new RuntimeException(
095: "serverInstantThread, wrong declaration of freemem: "
096: + e.getMessage());
097: }
098: this .environment = (env instanceof Class) ? null : env;
099: this .setName(theClass.getName() + "." + jobExec);
100: this .handle = new Long(System.currentTimeMillis()
101: + this .getName().hashCode());
102: }
103:
104: public int getJobCount() {
105: if (this .jobCountMethod == null)
106: return Integer.MAX_VALUE;
107: try {
108: Object result = jobCountMethod.invoke(environment,
109: new Object[0]);
110: if (result instanceof Integer)
111: return ((Integer) result).intValue();
112: else
113: return -1;
114: } catch (IllegalAccessException e) {
115: return -1;
116: } catch (IllegalArgumentException e) {
117: return -1;
118: } catch (InvocationTargetException e) {
119: serverLog.logSevere("SERVER",
120: "invocation serverInstantThread of thread '"
121: + this .getName() + "': " + e.getMessage(),
122: e);
123: return -1;
124: }
125: }
126:
127: public boolean job() throws Exception {
128: instantThreadCounter++;
129: //System.out.println("started job " + this.handle + ": " + this.getName());
130: synchronized (jobs) {
131: jobs.put(this .handle, this .getName());
132: }
133: boolean jobHasDoneSomething = false;
134: try {
135: Object result = jobExecMethod.invoke(environment,
136: new Object[0]);
137: if (result == null)
138: jobHasDoneSomething = true;
139: else if (result instanceof Boolean)
140: jobHasDoneSomething = ((Boolean) result).booleanValue();
141: } catch (IllegalAccessException e) {
142: serverLog.logSevere("SERVER",
143: "Internal Error in serverInstantThread.job: "
144: + e.getMessage());
145: serverLog.logSevere("SERVER", "shutting down thread '"
146: + this .getName() + "'");
147: this .terminate(false);
148: } catch (IllegalArgumentException e) {
149: serverLog.logSevere("SERVER",
150: "Internal Error in serverInstantThread.job: "
151: + e.getMessage());
152: serverLog.logSevere("SERVER", "shutting down thread '"
153: + this .getName() + "'");
154: this .terminate(false);
155: } catch (InvocationTargetException e) {
156: String targetException = e.getTargetException()
157: .getMessage();
158: e.getTargetException().printStackTrace();
159: e.printStackTrace();
160: if ((targetException != null)
161: && ((targetException.indexOf("heap space") > 0) || (targetException
162: .indexOf("NullPointerException") > 0)))
163: e.getTargetException().printStackTrace();
164: serverLog.logSevere("SERVER",
165: "Runtime Error in serverInstantThread.job, thread '"
166: + this .getName() + "': " + e.getMessage()
167: + "; target exception: " + targetException,
168: e.getTargetException());
169: e.getTargetException().printStackTrace();
170: } catch (OutOfMemoryError e) {
171: serverLog.logSevere("SERVER",
172: "OutOfMemory Error in serverInstantThread.job, thread '"
173: + this .getName() + "': " + e.getMessage());
174: e.printStackTrace();
175: freemem();
176: }
177: instantThreadCounter--;
178: synchronized (jobs) {
179: jobs.remove(this .handle);
180: }
181: return jobHasDoneSomething;
182: }
183:
184: public void freemem() {
185: if (freememExecMethod == null)
186: return;
187: try {
188: freememExecMethod.invoke(environment, new Object[0]);
189: } catch (IllegalAccessException e) {
190: serverLog.logSevere("SERVER",
191: "Internal Error in serverInstantThread.freemem: "
192: + e.getMessage());
193: serverLog.logSevere("SERVER", "shutting down thread '"
194: + this .getName() + "'");
195: this .terminate(false);
196: } catch (IllegalArgumentException e) {
197: serverLog.logSevere("SERVER",
198: "Internal Error in serverInstantThread.freemem: "
199: + e.getMessage());
200: serverLog.logSevere("SERVER", "shutting down thread '"
201: + this .getName() + "'");
202: this .terminate(false);
203: } catch (InvocationTargetException e) {
204: String targetException = e.getTargetException()
205: .getMessage();
206: if (targetException.indexOf("heap space") > 0)
207: e.getTargetException().printStackTrace();
208: serverLog.logSevere("SERVER",
209: "Runtime Error in serverInstantThread.freemem, thread '"
210: + this .getName() + "': " + e.getMessage()
211: + "; target exception: " + targetException,
212: e.getTargetException());
213: e.getTargetException().printStackTrace();
214: } catch (OutOfMemoryError e) {
215: serverLog.logSevere("SERVER",
216: "OutOfMemory Error in serverInstantThread.freemem, thread '"
217: + this .getName() + "': " + e.getMessage());
218: e.printStackTrace();
219: }
220: }
221:
222: public static serverThread oneTimeJob(Object env, String jobExec,
223: serverLog log, long startupDelay) {
224: // start the job and execute it once as background process
225: serverThread thread = new serverInstantThread(env, jobExec,
226: null, null);
227: thread.setStartupSleep(startupDelay);
228: thread.setIdleSleep(-1);
229: thread.setBusySleep(-1);
230: thread.setMemPreReqisite(0);
231: thread.setLog(log);
232: thread.start();
233: return thread;
234: }
235:
236: public static serverThread oneTimeJob(Runnable thread,
237: long startupDelay) {
238: serverLog log = new serverLog(thread.getClass().getName()
239: + "/run");
240: log.setLevel(java.util.logging.Level.INFO);
241: return oneTimeJob(thread, "run", log, startupDelay);
242: }
243:
244: public static serverThread oneTimeJob(Runnable thread,
245: long startupDelay, int maxJobs) {
246: while (instantThreadCounter >= maxJobs)
247: try {
248: Thread.sleep(100);
249: } catch (InterruptedException e) {
250: break;
251: }
252: return oneTimeJob(thread, startupDelay);
253: }
254:
255: }
|