001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: /*
066: * EventHandler.java
067: *
068: * Copyright 1999, 2000, 2001 Jcorporate Ltd.
069: */
070: package com.jcorporate.expresso.core.misc;
071:
072: import com.jcorporate.expresso.core.db.DBException;
073: import com.jcorporate.expresso.core.registry.ExpressoThread;
074: import com.jcorporate.expresso.core.security.User;
075: import com.jcorporate.expresso.services.dbobj.Event;
076: import org.apache.log4j.Logger;
077:
078: import java.util.Vector;
079:
080: /**
081: * The EventHandler is an asynchronous handler for email Event notifications - it accepts
082: * requests to trigger an event, then sends them "eventually" in a seperate thread
083: *
084: * @author Michael Nash
085: */
086: public class EventHandler extends ExpressoThread {
087: private static Vector queue = new Vector(3);
088: private static EventHandler myInstance = null;
089:
090: /**
091: * Event Handler shuts down it's background thread when it's been
092: * idle for a while
093: */
094: private static int idleTimes = 0;
095: private static int maxIdleTimes = 10;
096:
097: /**
098: * Don't process more than a certain number of Event entries, it slows
099: * the system down too much
100: */
101: private static int maxWrites = 5;
102:
103: /**
104: * How long to sleep between checking the queue
105: */
106: private static int sleepTime = 30;
107: private static Logger log = Logger.getLogger(EventHandler.class);
108: private static final String this Class = EventHandler.class
109: .getName()
110: + ".";
111:
112: /**
113: * Constructor
114: */
115: public EventHandler() {
116:
117: } /* EventHandler() */
118:
119: /**
120: * Actually check the event queue and trigger the events or send
121: * notices (electronic mail pertaining to registering Expresso
122: * Framework users)
123: *
124: * @throws DBException upon error.
125: */
126: private synchronized void checkQueue() throws DBException {
127: String myName = (this Class + "checkQueue()");
128:
129: if (queue.size() == 0) {
130: idleTimes++;
131:
132: if (log.isDebugEnabled()) {
133: log.debug("Event queue empty - idle " + idleTimes
134: + " times");
135: }
136:
137: return;
138: }
139: if (log.isDebugEnabled()) {
140: log.debug("Checking event queue. " + queue.size()
141: + " entries");
142: }
143:
144: EventQueueEntry oneEventQueueEntry = null;
145:
146: try {
147: int writeCount = 0;
148:
149: // Process all pending entries in the queue. Iterate
150: // through the queue until all elements are processed.
151: while (queue.size() > 0) {
152: oneEventQueueEntry = (EventQueueEntry) queue
153: .firstElement();
154: queue.removeElementAt(0);
155:
156: // Is this a queue entry an event or a notice?
157: if (oneEventQueueEntry.isNotice()) {
158: // It is a notice, send electronic mail
159: User myUser = new User();
160: myUser.setDataContext(oneEventQueueEntry
161: .getDataContext());
162: myUser.setUid(oneEventQueueEntry.getUid());
163:
164: if (myUser.find()) {
165: myUser.notify(oneEventQueueEntry.getSubject(),
166: oneEventQueueEntry.getTheMessage(),
167: false /*htmlMail*/, oneEventQueueEntry
168: .getAttachments());
169: } else {
170: log.error("Unable to send notice to user "
171: + oneEventQueueEntry.getUid()
172: + ": No such user");
173: }
174: } else {
175: // It is a event, process accordingly
176: new Event(oneEventQueueEntry.getDataContext(),
177: oneEventQueueEntry.getTheEvent(),
178: oneEventQueueEntry.getTheMessage(),
179: oneEventQueueEntry.isSuccess());
180: }
181:
182: writeCount++;
183:
184: if (writeCount > maxWrites) {
185: break;
186: }
187: } /* for each queue entry */
188:
189: } catch (Exception de) {
190: log.error("Error sending event from queue", de);
191: throw new DBException(myName
192: + ":Error sending event from queue", de);
193: }
194: } /* checkQueue() */
195:
196: /**
197: * Queue the requested event for later processing
198: *
199: * @param dbName the database context
200: * @param theEvent the subject line of the event
201: * @param theMessage the message text
202: * @param success the boolean status flag
203: */
204: public static void Event(String dbName, String theEvent,
205: String theMessage, boolean success) {
206:
207: if (log.isDebugEnabled()) {
208: log
209: .debug("New event queued:" + theEvent + ":"
210: + theMessage);
211: }
212:
213: EventQueueEntry newEntry = new EventQueueEntry(theEvent,
214: theMessage, success);
215: newEntry.setDataContext(dbName);
216: queue.addElement(newEntry);
217: startUp();
218: } /* Event(String, String, String, boolean) */
219:
220: /**
221: * @throws DBException
222: */
223: public static void flush() throws DBException {
224: startUp();
225: myInstance.checkQueue();
226: } /* flush() */
227:
228: /**
229: * Send a user a notification via e-mail with virtual data source attachments.
230: *
231: * @param dbName data context name
232: * @param uid the user id
233: * @param subject Subject of the e-mail
234: * @param message Message to send in body of e-mail
235: */
236: public static void notify(String dbName, int uid, String subject,
237: String message) {
238: notify(dbName, uid, subject, message, null);
239: }
240:
241: /**
242: * Send a user a notification via e-mail with virtual data source attachments.
243: *
244: * @param dbName data context name
245: * @param uid the user id
246: * @param subject Subject of the e-mail
247: * @param message Message to send in body of e-mail
248: * @param attachments the array list of virtual byte array data sources
249: */
250: public static void notify(String dbName, int uid, String subject,
251: String message, ByteArrayDataSource attachments[]) {
252: if (log.isDebugEnabled()) {
253: String msg = "";
254: if (attachments != null) {
255: msg = " with " + attachments.length
256: + " virtual data source attachments.";
257: }
258:
259: log.debug("Queueing notice to user " + uid + " of '"
260: + subject + "'" + msg);
261: }
262:
263: EventQueueEntry newEntry = new EventQueueEntry("", message,
264: true);
265: newEntry.setSubject(subject);
266: newEntry.setUid(uid);
267: newEntry.setNotice(true); /*!*/
268: newEntry.setDataContext(dbName);
269: newEntry.setAttachments(attachments);
270: queue.addElement(newEntry);
271: startUp();
272: } /* notify(String, String, String, String, ByteArrayDataSource[]) */
273:
274: /**
275: * Main thread process of the EventHandler process
276: */
277: public void run() {
278: super .run();
279: log.info("Event Handler starts");
280: try {
281: while (true) {
282: if (idleTimes >= maxIdleTimes) {
283: log.info("Event handler idle more than "
284: + maxIdleTimes + " times - shutting down");
285: return;
286: }
287: try {
288: checkQueue();
289: } catch (DBException ae) {
290: log.error("Unable to check event queue", ae);
291: }
292:
293: yield();
294: sleep(sleepTime * 1000);
295: } /* forever */
296:
297: } catch (InterruptedException ie) {
298: log.error("EventHandler was interrupted", ie);
299: }
300: } /* run() */
301:
302: /**
303: * Code to start up the event handler, which is normally run on
304: * framework thread.
305: */
306: public synchronized static void startUp() {
307: idleTimes = 0;
308:
309: boolean restart = false;
310:
311: if (myInstance == null) {
312: restart = true;
313: } else {
314: if (!myInstance.isAlive()) {
315: restart = true;
316: }
317: }
318: if (restart) {
319: myInstance = new EventHandler();
320: myInstance.start();
321: }
322: } /* startUp() */
323:
324: } /* EventHandler */
|