Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements a metadata catalog as a java Servlet
4
 *  Copyright: 2006 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones, Dan Higgins, Jivka Bojilova, Chad Berkley, Matthew Perry
7
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2009-08-07 10:35:18 -0700 (Fri, 07 Aug 2009) $'
10
 * '$Revision: 5018 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.workflowscheduler;
28

    
29
import java.io.IOException;
30
import java.io.PrintWriter;
31
import java.sql.SQLException;
32
import java.util.Enumeration;
33
import java.util.Hashtable;
34

    
35
import javax.servlet.ServletConfig;
36
import javax.servlet.ServletContext;
37
import javax.servlet.ServletException;
38
import javax.servlet.http.HttpServlet;
39
import javax.servlet.http.HttpServletRequest;
40
import javax.servlet.http.HttpServletResponse;
41
import javax.servlet.http.HttpSession;
42

    
43
import org.apache.log4j.Logger;
44
import org.apache.log4j.PropertyConfigurator;
45

    
46
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
47
import edu.ucsb.nceas.metacat.properties.PropertyService;
48
import edu.ucsb.nceas.metacat.scheduler.SchedulerService;
49
import edu.ucsb.nceas.metacat.service.SessionService;
50
import edu.ucsb.nceas.metacat.shared.BaseException;
51
import edu.ucsb.nceas.metacat.shared.ServiceException;
52
import edu.ucsb.nceas.metacat.util.ErrorSendingErrorException;
53
import edu.ucsb.nceas.metacat.util.RequestUtil;
54
import edu.ucsb.nceas.metacat.util.ResponseUtil;
55
import edu.ucsb.nceas.metacat.util.SessionData;
56
import edu.ucsb.nceas.utilities.FileUtil;
57

    
58
/**
59
 * A workflow scheduling server implemented as a Java Servlet
60
 *
61
 * Valid actions are:
62
 * 
63
 * action=scheduleWorkflow -- Schedule a workflow to be run.  Scheduling a workflow 
64
 *                            registers it with the scheduling engine and creates a row
65
 *                            in the scheduled_job table.  Note that this may be 
66
 *                            extracted into a separate servlet.
67
 *     delay -- The amount of time from now before the workflow should be run.  The 
68
 *              delay can be expressed in number of seconds, minutes, hours and days, 
69
 *              for instance 30s, 2h, etc.
70
 *     starttime -- The time that the workflow should first run.  If both are provided
71
 *                  this takes precedence over delay.  The time should be expressed as: 
72
 *                  MM/dd/yyyy HH:mm:ss with the timezone assumed to be that of the OS.
73
 *     endtime -- The time when the workflow should end. The time should be expressed as: 
74
 *                  MM/dd/yyyy HH:mm:ss with the timezone assumed to be that of the OS.
75
 *     intervalvalue -- The numeric value of the interval between runs
76
 *     intervalunit -- The unit of the interval between runs.  Can be s, m, h, d for 
77
 *                     seconds, minutes, hours and days respectively
78
 *     workflowid -- The lsid of the workflow that we want to schedule.  This workflow
79
 *                   must already exist in the database.
80
 *     karid -- The karid for the workflow that we want to schedule.
81
 *     workflowname -- The name of the workflow.
82
 *     forwardto -- If provided, forward to this page when processing is done.
83
 *     qformat -- If provided, render results using the stylesheets associated with
84
 *                this skin.  Default is xml.
85
 * action=unscheduleWorkflow -- Unschedule a workflow.  Unscheduling a workflow 
86
 *                            removes it from the scheduling engine and changes the 
87
 *                            status in the scheduled_job table to " unscheduled.  Note 
88
 *                            that this may be extracted into a separate servlet.
89
 *     workflowjobname -- The job ID for the workflow run that we want to unschedule.  This
90
 *                      is held in the database as scheduled_job.name
91
 *     forwardto -- If provided, forward to this page when processing is done.
92
 *     qformat -- If provided, render results using the stylesheets associated with
93
 *                this skin.  Default is xml.
94
 * action=rescheduleWorkflow -- Unschedule a workflow.  Rescheduling a workflow 
95
 *                            registers it with the scheduling engine and changes the 
96
 *                            status in the scheduled_job table to " scheduled.  Note 
97
 *                            that this may be extracted into a separate servlet.
98
 *     workflowjobname -- The job ID for the workflow run that we want to reschedule.  This
99
 *                      is held in the database as scheduled_job.name
100
 *     forwardto -- If provided, forward to this page when processing is done.
101
 *     qformat -- If provided, render results using the stylesheets associated with
102
 *                this skin.  Default is xml.
103
 * action=deleteScheduledWorkflow -- Delete a workflow.  Deleting a workflow 
104
 *                            removes it from the scheduling engine and changes the 
105
 *                            status in the scheduled_job table to " deleted.  Note 
106
 *                            that this may be extracted into a separate servlet.
107
 *     workflowjobname -- The job ID for the workflow run that we want to delete.  This
108
 *                      is held in the database as scheduled_job.name
109
 *     forwardto -- If provided, forward to this page when processing is done.
110
 *     qformat -- If provided, render results using the stylesheets associated with
111
 *                this skin.  Default is xml.
112
 *     
113
 */
114
public class WorkflowSchedulerServlet extends HttpServlet {
115

    
116
	private static final long serialVersionUID = 1L;
117
    
118
    // Constants -- these should be final in a servlet
119
    private static String LOG_CONFIG_NAME = null;
120
    
121
    public static final String APPLICATION_NAME = "workflowscheduler";
122
    
123
    /**
124
     * Initialize the servlet by creating appropriate database connections
125
     */
126
    public void init(ServletConfig config) throws ServletException {
127
    	Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class);
128
    	try {
129
    		
130
            super.init(config);
131
            
132
            ServletContext context = config.getServletContext();
133
            context.setAttribute("APPLICATION_NAME", APPLICATION_NAME);
134
            
135
            // Initialize the properties file
136
            String dirPath = context.getRealPath("WEB-INF");
137
            
138
            LOG_CONFIG_NAME = dirPath + FileUtil.getFS() + "log4j.properties";
139
        	PropertyConfigurator.configureAndWatch(LOG_CONFIG_NAME);
140
            
141
            PropertyService.getInstance(context);
142
            SessionService.getInstance();
143
            SchedulerService.getInstance();
144
            
145
			// initialize DBConnection pool
146
			DBConnectionPool connPool = DBConnectionPool.getInstance();
147
			logMetacat.debug("WorkflowSchedulerServlet.init - DBConnection pool initialized: " + connPool.toString());
148
            
149
    	} catch (ServiceException se) {
150
        	String errorMessage = 
151
        		"WorkflowSchedulerServlet.init - Service problem while intializing WorkflowScheduler Servlet: " + se.getMessage();
152
            logMetacat.error(errorMessage);
153
            throw new ServletException(errorMessage);
154
        } catch (SQLException e) {
155
			String errorMessage = "WorkflowSchedulerServlet.init - SQL problem while intializing WorkflowScheduler Servlet: "
156
					+ e.getMessage();
157
			logMetacat.error(errorMessage);
158
			throw new ServletException(errorMessage);
159
        } 
160
    }
161
    
162
    /**
163
	 * Close all db connections from the pool
164
	 */
165
    public void destroy() {
166
    	Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class);
167
    	
168
    	try {
169
    		SchedulerService.getInstance().stop();
170
    	} catch (ServiceException se) {
171
    		logMetacat.warn("WorkflowSchedulerServlet.destroy - Could not stop scheduler service: " + se.getMessage());
172
    	}
173
    	
174
        // Close all db connection
175
        logMetacat.warn("WorkflowSchedulerServlet.destroy - Destroying WorkflowSchedulerServlet");
176
//        IndexingQueue.getInstance().setMetacatRunning(false);
177
        DBConnectionPool.release();
178
    }
179
    
180
    /** Handle "GET" method requests from HTTP clients */
181
    public void doGet(HttpServletRequest request, HttpServletResponse response)
182
    throws ServletException, IOException {
183
        
184
        // Process the data and send back the response
185
        handleGetOrPost(request, response);
186
    }
187
    
188
    /** Handle "POST" method requests from HTTP clients */
189
    public void doPost(HttpServletRequest request, HttpServletResponse response)
190
    throws ServletException, IOException {
191
        
192
        // Process the data and send back the response
193
        handleGetOrPost(request, response);
194
    }
195
    
196
    /**
197
	 * Control servlet response depending on the action parameter specified
198
	 */
199
	private void handleGetOrPost(HttpServletRequest request, HttpServletResponse response)
200
			throws ServletException, IOException {
201
		Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class);
202

    
203
		// Update the last update time for this user if they are not new
204
		HttpSession httpSession = request.getSession(false);
205
		if (httpSession != null) {
206
			SessionService.touchSession(httpSession.getId());
207
		}
208

    
209
		/*
210
		 * logMetacat.debug("Connection pool size: "
211
		 * +connPool.getSizeOfDBConnectionPool(),10); logMetacat.debug("Free
212
		 * DBConnection number: "
213
		 */
214
		// If all DBConnection in the pool are free and DBConnection pool
215
		// size is greater than initial value, shrink the connection pool
216
		// size to initial value
217
		DBConnectionPool.shrinkDBConnectionPoolSize();
218

    
219
		// Debug message to print out the method which have a busy DBConnection
220
		try {
221
			DBConnectionPool pool = DBConnectionPool.getInstance();
222
//			pool.printMethodNameHavingBusyDBConnection();
223
		} catch (SQLException sqle) {
224
			logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error getting DBConnectionPool: "
225
					+ sqle.getMessage());
226
			sqle.printStackTrace();
227
		}
228

    
229
		try {
230

    
231
			String name = null;
232
			String[] value = null;
233
			Hashtable<String, String[]> params = new Hashtable<String, String[]>();
234

    
235
			Enumeration<String> paramlist = 
236
				(Enumeration<String>) request.getParameterNames();
237
			while (paramlist.hasMoreElements()) {
238

    
239
				name = paramlist.nextElement();
240
				value = request.getParameterValues(name);
241

    
242
				params.put(name, value);
243
			}
244

    
245
			// handle param is emptpy
246
			if (params.isEmpty() || params == null) {
247
				return;
248
			}
249

    
250
			// if the user clicked on the input images, decode which image
251
			// was clicked then set the action.
252
			if (params.get("action") == null) {
253
				PrintWriter out = response.getWriter();
254
				response.setContentType("text/xml");
255
				out.println("<?xml version=\"1.0\"?>");
256
				out.println("<error>");
257
				out.println("Action not specified");
258
				out.println("</error>");
259
				out.close();
260
				return;
261
			}
262

    
263
			String action = (params.get("action"))[0];
264
			logMetacat.info("WorkflowSchedulerServlet.handleGetOrPost - Action is: " + action);
265

    
266
			// This block handles session management for the servlet
267
			// by looking up the current session information for all actions
268
			// other than "login" and "logout"
269
			String userName = null;
270
			String[] groupNames = null;
271
			name = null;
272

    
273
			// handle login action
274
			if (action.equals("login")) {
275
				// PrintWriter out = response.getWriter();
276
				// handleLoginAction(out, params, request, response);
277
				// out.close();
278

    
279
				// handle logout action
280
			} else if (action.equals("logout")) {
281
				// PrintWriter out = response.getWriter();
282
				// handleLogoutAction(out, params, request, response);
283
				// out.close();
284

    
285
				// handle shrink DBConnection request
286
			} else if (action.equals("shrink")) {
287
				PrintWriter out = response.getWriter();
288
				boolean success = false;
289
				// If all DBConnection in the pool are free and DBConnection
290
				// pool
291
				// size is greater than initial value, shrink the connection
292
				// pool
293
				// size to initial value
294
				success = DBConnectionPool.shrinkConnectionPoolSize();
295
				if (success) {
296
					// if successfully shrink the pool size to initial value
297
					out.println("DBConnection Pool shrunk successfully.");
298
				}// if
299
				else {
300
					out.println("DBConnection pool not shrunk successfully.");
301
				}
302
				// close out put
303
				out.close();
304

    
305
				// aware of session expiration on every request
306
			} else {
307
				SessionData sessionData = RequestUtil.getSessionData(request);
308

    
309
				userName = sessionData.getUserName();
310
				// password = sessionData.getPassword();
311
				groupNames = sessionData.getGroupNames();
312
				// sessionId = sessionData.getId();
313

    
314
				logMetacat.info("WorkflowSchedulerServlet.handleGetOrPost - The user is : " + userName);
315
			}
316

    
317
			if (action.equals("scheduleWorkflow")) {
318
				try {
319
					WorkflowScheduler.getInstance().scheduleJob(request, response,
320
							params);
321
					return;
322
				} catch (BaseException be) {
323
					logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error when scheduling" 
324
							+ "workflow", be);
325
					ResponseUtil.sendErrorXML(response,
326
							ResponseUtil.SCHEDULE_WORKFLOW_ERROR, be);
327
					return;
328
				}
329
			} else if (action.equals("unscheduleWorkflow")) {
330
				try {
331
					WorkflowScheduler.getInstance().unscheduleJob(request, response,
332
							params, userName, groupNames);
333
					return;
334
				} catch (BaseException be) {
335
					logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error when unscheduling" 
336
							+ "workflow", be);
337
					ResponseUtil.sendErrorXML(response,
338
							ResponseUtil.UNSCHEDULE_WORKFLOW_ERROR, be);
339
					return;
340
				}
341
			} else if (action.equals("rescheduleWorkflow")) {
342
				try {
343
					WorkflowScheduler.getInstance().rescheduleJob(request, response,
344
							params, userName, groupNames);
345
					return;
346
				} catch (BaseException be) {
347
					logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error when rescheduling" 
348
							+ "workflow", be);
349
					ResponseUtil.sendErrorXML(response,
350
							ResponseUtil.RESCHEDULE_WORKFLOW_ERROR, be);
351
					return;
352
				}
353
			} else if (action.equals("getScheduledWorkflow")) {
354
				try {
355
					WorkflowScheduler.getInstance().getJobs(request, response, params,
356
							userName, groupNames);
357
					return;
358
				} catch (BaseException be) {
359
					logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error when getting" 
360
							+ "scheduled workflows", be);
361
					ResponseUtil.sendErrorXML(response,
362
							ResponseUtil.GET_SCHEDULED_WORKFLOW_ERROR, be);
363
					return;
364
				}
365
			} else if (action.equals("deleteScheduledWorkflow")) {
366
				try {
367
					WorkflowScheduler.getInstance().deleteJob(request, response, params,
368
							userName, groupNames);
369
					return;
370
				} catch (BaseException be) {
371
					logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - error when deleting" 
372
							+ "workflow", be);
373
					ResponseUtil.sendErrorXML(response,
374
							ResponseUtil.DELETE_SCHEDULED_WORKFLOW_ERROR, be);
375
					return;
376
				}
377
			} else {
378
				logMetacat.error("WorkflowSchedulerServlet.handleGetOrPost - unregistered action: " 
379
						+ action);
380
				PrintWriter out = response.getWriter();
381
				out.println("<?xml version=\"1.0\"?>");
382
				out.println("<error>");
383
				out.println("Error: action not registered.  Please report this error.");
384
				out.println("</error>");
385
				out.close();
386
			}
387
		} catch (ErrorSendingErrorException esee) {
388
			String errorString = "WorkflowSchedulerServlet.handleGetOrPost - Error sending error message: " + esee.getMessage();
389
			logMetacat.error(errorString);
390
			throw new ServletException(errorString);
391
		}
392
	}
393
    
394
// // LOGIN & LOGOUT SECTION
395
// /**
396
// * Handle the login request. Create a new session object. Do user
397
//	 * authentication through the session.
398
//	 */
399
//    private void handleLoginAction(PrintWriter out, Hashtable<String, String[]> params,
400
//            HttpServletRequest request, HttpServletResponse response) {
401
//        Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class);
402
//        AuthSession sess = null;
403
//        
404
//        if(params.get("username") == null){
405
//            response.setContentType("text/xml");
406
//            out.println("<?xml version=\"1.0\"?>");
407
//            out.println("<error>");
408
//            out.println("Username not specified");
409
//            out.println("</error>");
410
//            return;
411
//        }
412
//        
413
//        // }
414
//        
415
//        if(params.get("password") == null){
416
//            response.setContentType("text/xml");
417
//            out.println("<?xml version=\"1.0\"?>");
418
//            out.println("<error>");
419
//            out.println("Password not specified");
420
//            out.println("</error>");
421
//            return;
422
//        }
423
//        
424
//        String un = (params.get("username"))[0];
425
//        logMetacat.info("user " + un + " is trying to login");
426
//        String pw = (params.get("password"))[0];
427
//        
428
//        String qformat = "xml";
429
//        if(params.get("qformat") != null){
430
//            qformat = (params.get("qformat"))[0];
431
//        }
432
//        
433
//        try {
434
//            sess = new AuthSession();
435
//        } catch (Exception e) {
436
//        	String errorMsg = "Problem in WorkflowSchedulerServlet.handleLoginAction() authenicating session: "
437
//                + e.getMessage();
438
//            logMetacat.error(errorMsg);
439
//            out.println(errorMsg);
440
//            return;
441
//        }
442
//        boolean isValid = sess.authenticate(request, un, pw);
443
//        
444
//        //if it is authernticate is true, store the session
445
//        if (isValid) {
446
//            HttpSession session = sess.getSessions();
447
//            String id = session.getId();
448
//            logMetacat.debug("Store session id " + id
449
//                    + " which has username" + session.getAttribute("username")
450
//                    + " into hash in login method");
451
//            try {
452
//				SessionService.registerSession(id, (String) session
453
//						.getAttribute("username"), (String[]) session
454
//						.getAttribute("groupnames"), (String) session
455
//						.getAttribute("password"));
456
//			} catch (ServiceException se) {
457
//				String errorMsg = "Problem in WorkflowSchedulerServlet.handleLoginAction() registering session: "
458
//						+ se.getMessage();
459
//				logMetacat.error(errorMsg);
460
//				out.println(errorMsg);
461
//				return;
462
//			}
463
//        }
464
//        
465
//        // format and transform the output
466
//        if (qformat.equals("xml")) {
467
//            response.setContentType("text/xml");
468
//            out.println(sess.getMessage());
469
//        } else {
470
//            try {
471
//                DBTransform trans = new DBTransform();
472
//                response.setContentType("text/html");
473
//                trans.transformXMLDocument(sess.getMessage(),
474
//                        "-//NCEAS//login//EN", "-//W3C//HTML//EN", qformat,
475
//                        out, null, null);
476
//            } catch (Exception e) {               
477
//                logMetacat.error("Error in WorkflowSchedulerServlet.handleLoginAction: "
478
//                        + e.getMessage());
479
//            }
480
//        }
481
//    }
482
//    
483
//    /**
484
//     * Handle the logout request. Close the connection.
485
//     */
486
//    private void handleLogoutAction(PrintWriter out, Hashtable<String, String[]> params,
487
//            HttpServletRequest request, HttpServletResponse response) {
488
//        Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class);
489
//        String qformat = "xml";
490
//        if(params.get("qformat") != null){
491
//            qformat = params.get("qformat")[0];
492
//        }
493
//        
494
//        // close the connection
495
//        HttpSession sess = request.getSession(false);
496
//        logMetacat.info("After get session in logout request");
497
//        if (sess != null) {
498
//            logMetacat.info("The session id " + sess.getId()
499
//            + " will be invalidate in logout action");
500
//            logMetacat.info("The session contains user "
501
//                    + sess.getAttribute("username")
502
//                    + " will be invalidate in logout action");
503
//            sess.invalidate();
504
//            SessionService.unRegisterSession(sess.getId());
505
//        }
506
//        
507
//        // produce output
508
//        StringBuffer output = new StringBuffer();
509
//        output.append("<?xml version=\"1.0\"?>");
510
//        output.append("<logout>");
511
//        output.append("User logged out");
512
//        output.append("</logout>");
513
//        
514
//        //format and transform the output
515
//        if (qformat.equals("xml")) {
516
//            response.setContentType("text/xml");
517
//            out.println(output.toString());
518
//        } else {
519
//            try {
520
//                DBTransform trans = new DBTransform();
521
//                response.setContentType("text/html");
522
//                trans.transformXMLDocument(output.toString(),
523
//                        "-//NCEAS//login//EN", "-//W3C//HTML//EN", qformat,
524
//                        out, null, null);
525
//            } catch (Exception e) {
526
//                logMetacat.error(
527
//                        "Error in WorkflowSchedulerServlet.handleLogoutAction"
528
//                        + e.getMessage());
529
//            }
530
//        }
531
//    }
532
}
(3-3/3)