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
import java.util.Timer;
35

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

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

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

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

    
117
	private static final long serialVersionUID = 1L;
118

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

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

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

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

    
233
		try {
234

    
235
			String name = null;
236
			String[] value = null;
237
			Hashtable<String, String[]> params = new Hashtable<String, String[]>();
238

    
239
			Enumeration<String> paramlist = 
240
				(Enumeration<String>) request.getParameterNames();
241
			while (paramlist.hasMoreElements()) {
242

    
243
				name = paramlist.nextElement();
244
				value = request.getParameterValues(name);
245

    
246
				params.put(name, value);
247
			}
248

    
249
			// handle param is emptpy
250
			if (params.isEmpty() || params == null) {
251
				return;
252
			}
253

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

    
267
			String action = (params.get("action"))[0];
268
			logMetacat.info("WorkflowSchedulerServlet.handleGetOrPost - Action is: " + action);
269

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

    
277
			// handle login action
278
			if (action.equals("login")) {
279
				// PrintWriter out = response.getWriter();
280
				// handleLoginAction(out, params, request, response);
281
				// out.close();
282

    
283
				// handle logout action
284
			} else if (action.equals("logout")) {
285
				// PrintWriter out = response.getWriter();
286
				// handleLogoutAction(out, params, request, response);
287
				// out.close();
288

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

    
309
				// aware of session expiration on every request
310
			} else {
311
				SessionData sessionData = RequestUtil.getSessionData(request);
312

    
313
				userName = sessionData.getUserName();
314
				// password = sessionData.getPassword();
315
				groupNames = sessionData.getGroupNames();
316
				// sessionId = sessionData.getId();
317

    
318
				logMetacat.info("WorkflowSchedulerServlet.handleGetOrPost - The user is : " + userName);
319
			}
320

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