View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.sys.context;
17  
18  
19  import java.util.Arrays;
20  
21  
22  /**
23   * BatchStepTrigger writes .run files containing a job name and step name for BatchContainerStep to read. 
24   * It loops and sleeps until either a .success or an .error file is written for the Step. Once a result file is found tt logs the results and exits. 
25   * 
26   * BatchStepTrigger also checks for BatchContainerStep's .runlock file. If it doesn't find one (indicating the batch container is not running) it exits.
27   * BatchStepTrigger adds a ConsoleAppender to its Logger if one hasn't been configured.
28   * 
29   * Note that this class runs without starting the SpringContext. KFS Services and Beans are not available for use.
30   *
31   */
32  public class BatchStepTrigger {
33      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BatchStepTrigger.class);
34      
35      private static BatchStepTriggerParameters batchStepTriggerParameters;
36      
37      /**
38       * BatchStepTrigger is instantiated for each step in a brte script. 
39       * The value used when exiting the system tells the brte script how to handle failures.
40       * 0: okay, 4: the step returned false, 8: an exception occurred in the execution of the step or the trigger
41       *
42       * - verify that the batch container is running, exit with an 8 if not
43       * - for each step
44       *   - write a RUN semaphore file
45       *   - wait and listen for a result file (either SUCCESS or ERROR)
46       *   - if the result file is null the batch container is not running so remove the run file and exit with an 8
47       *   - if the result file is an ERROR
48       *     - if the file is EMPTY remove the result file and exit with a 4
49       *     - otherwise log the error contained in the result file, remove the result file, and exit with an 8
50       *   - otherwise remove the result file and exit with a 0  
51       * 
52       * @param args - refer to BatchStepTriggerParameters for details
53       */
54      public static void main(String[] args) {
55          try {            
56              Log4jConfigurer.configureLogging(false);
57              BatchLogger.addConsoleAppender(LOG);
58              
59          	batchStepTriggerParameters = new BatchStepTriggerParameters(args);
60          	
61          	String[] stepNames = getStepNames();            
62              String jobName = getJobName();            
63              int stepIndex = getStepIndex();
64              long sleepInterval = getSleepInterval();            
65              BatchContainerDirectory batchContainerDirectory = getBatchContainerDirectory();
66              
67              LOG.info("Executing Job: " + jobName + ", STEP"+ stepIndex +", Step(s): " + Arrays.toString(stepNames));
68              
69  			if (!batchContainerDirectory.isBatchContainerRunning()) {
70  				//an instance of the batch container is not running - exit. Exit status: 8
71  				LOG.error("The BatchContainer is not running - exiting without executing the steps: "+ Arrays.toString(stepNames));
72  	            LOG.info("Exit status: 8");
73  				System.exit(8);
74  			}
75              
76  			//Need to humanize 'i'; the index 
77              for (int i = (stepIndex-1); i < stepNames.length; i++) {
78                  String stepName = stepNames[i];
79              	BatchStepFileDescriptor batchStepFile = new BatchStepFileDescriptor(jobName, stepName, BatchStepFileDescriptor.getFileExtensionRun());
80              	
81              	//write step start file
82              	batchContainerDirectory.writeBatchStepRunFile(batchStepFile, i);
83  
84              	//wait for a result file from BatchContainer
85              	BatchStepFileDescriptor resultFile = listenForResultFile(batchContainerDirectory, batchStepFile, sleepInterval);
86              	
87              	if (resultFile == null) {
88              		//result file is null - something unexpected happened. Exit status: 8             		
89              		batchContainerDirectory.removeBatchStepFileFromSystem(batchStepFile);            		
90              		
91              		LOG.error("No result files were returned- exiting without knowing whether the Step was executed");
92                      LOG.info("Exit status: 8");
93          			System.exit(8);
94              	}
95              	
96              	if (resultFile.isStepFileAnErrorResultFile()) {            		
97              		
98              		if (batchContainerDirectory.isFileEmpty(resultFile)) {
99                  		//do not execute any more steps, but job should succeed. Exit status: 4                		
100             			LOG.error(batchStepFile +" failed");
101             			batchContainerDirectory.removeBatchStepFileFromSystem(resultFile);
102             			
103                         LOG.info("Exit status: 4");
104                 		System.exit(4);
105             		}
106             		else {
107             			
108                 		//if file is not empty do not execute any more steps and fail job (write exception to log). Exit status: 8
109             			LOG.error(batchStepFile +" failed with the following error message: ");
110             			batchContainerDirectory.logFileContents(resultFile, LOG);
111             			batchContainerDirectory.removeBatchStepFileFromSystem(resultFile);
112 
113                         LOG.info("Exit status: 8");
114                     	System.exit(8);            		            			
115             		}
116             	}
117             	
118     			batchContainerDirectory.removeBatchStepFileFromSystem(resultFile);
119                 LOG.info("Exiting "+ batchStepFile);
120                 
121             }
122             
123             //continue executing steps in the job. Exit status: 0
124             LOG.info("Exit status: 0");
125             
126             System.exit(0);
127         }
128         catch (Throwable t) {
129             System.err.println("ERROR: Exception caught: ");
130             t.printStackTrace(System.err);
131             LOG.error(t);
132             
133             System.exit(8);
134         }
135     }
136     
137     /**
138      * Loop - look for a result file in the directory, if none is found then sleep. 
139      * If the batch container is not running then write an error result file and return it.
140      * 
141      * @param batchContainerDirectory the directory in which the semaphore files are located
142      * @param batchStepFile the step descriptor for the current step
143      * @param sleepInterval the amount of time to sleep while waiting for a result file
144      * @return the step descriptor of the result file
145      */
146     private static BatchStepFileDescriptor listenForResultFile(BatchContainerDirectory batchContainerDirectory, BatchStepFileDescriptor batchStepFile, long sleepInterval) {
147         if (LOG.isDebugEnabled()) {
148             LOG.debug("Waiting for result file for "+ batchStepFile);
149         }
150     	
151     	while (true) {    		
152 	    	//look for a result file in file-system
153 	    	BatchStepFileDescriptor resultFile = batchContainerDirectory.getResultFile(batchStepFile);
154 	    	if (resultFile != null) {
155     	        LOG.info("Found result file: "+ resultFile.getName());
156 	    		
157 	    		return resultFile;
158 	    	}
159 	    	
160 	    	if (batchContainerDirectory.isBatchContainerRunning()) {	    	
161 		    	sleep(sleepInterval);    		    		
162 	    	}
163 	    	else {
164 	    		//the batch container is not running - return an error file with an exception
165 	    		batchContainerDirectory.writeBatchStepErrorResultFile(batchStepFile, new RuntimeException("The BatchContainer is not running - exiting without knowing whether the Step executed"));
166 	    		
167 	    		resultFile = batchContainerDirectory.getResultFile(batchStepFile);
168     			return resultFile;
169 	    	}
170     	}     	
171     }    
172     
173     /**
174      * Sleep for the specified amount of time
175      * 
176      * @param sleepInterval the amount of time (in milliseconds) to wait before looking for a result file
177      */
178     private static void sleep(long sleepInterval) {
179         if (LOG.isDebugEnabled()) {
180             LOG.debug("Sleeping...");
181         }
182         try {
183             Thread.sleep(sleepInterval);
184         }
185         catch (InterruptedException e) {
186             throw new RuntimeException("BatchStepTrigger encountered interrupt exception while trying to wait for the specified batch step semaphore processing interval", e);
187         }
188     }
189     
190     /**
191      * @return the names of the steps to be executed
192      */
193     private static String[] getStepNames() {
194     	return batchStepTriggerParameters.getStepNames();
195     }
196     
197     /**
198      * @return the name of the job in which the steps are running
199      */
200     private static String getJobName() {
201     	return batchStepTriggerParameters.getJobName();
202     }
203     
204     /**
205      * @return the index of the step in the job
206      */
207     private static int getStepIndex() {
208         return batchStepTriggerParameters.getStepIndex();
209     }
210     
211     /**
212      * @return the amount of time to sleep (in milliseconds) while waiting for a result file
213      */
214     private static long getSleepInterval() {
215     	return batchStepTriggerParameters.getSleepInterval();
216     }
217     
218     /**
219      * @return the directory in which the semaphore files are located
220      */
221     private static BatchContainerDirectory getBatchContainerDirectory() {
222     	return batchStepTriggerParameters.getBatchContainerDirectory();
223     }
224 }