1   package org.kuali.ole.sys.context;
2   
3   
4   import java.io.File;
5   import java.util.ArrayList;
6   import java.util.Date;
7   import java.util.List;
8   
9   import org.apache.commons.lang.StringUtils;
10  import org.apache.log4j.Appender;
11  import org.apache.log4j.FileAppender;
12  import org.apache.log4j.Logger;
13  import org.apache.log4j.NDC;
14  import org.kuali.ole.sys.OLEConstants;
15  import org.kuali.ole.sys.batch.Job;
16  import org.kuali.ole.sys.batch.Step;
17  import org.kuali.rice.core.api.config.property.ConfigurationService;
18  import org.kuali.rice.core.api.datetime.DateTimeService;
19  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
20  import org.kuali.rice.krad.service.KualiModuleService;
21  import org.kuali.rice.krad.service.ModuleService;
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  public class BatchStepExecutor implements Runnable {
32      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BatchStepExecutor.class);
33  
34  	private ParameterService parameterService;
35  	private DateTimeService dateTimeService;
36  	private BatchContainerDirectory batchContainerDirectory;
37  	private BatchStepFileDescriptor batchStepFile;
38  	private Step step;
39  	private int stepIndex;
40  
41  	private Appender ndcAppender;
42  	private boolean ndcSet;
43  	private String logFileName;
44  
45  	private List<ContainerStepListener> containerStepListeners;
46  
47  	
48  
49  
50  
51  
52  
53  
54  
55  	public BatchStepExecutor(ParameterService parameterService, DateTimeService dateTimeService, BatchContainerDirectory batchContainerDirectory, BatchStepFileDescriptor batchStepFile, Step step, int stepIndex) {
56  	    BatchLogger.addConsoleAppender(LOG);
57  
58  		this.parameterService = parameterService;
59  		this.dateTimeService = dateTimeService;
60  
61  		this.batchContainerDirectory = batchContainerDirectory;
62  		this.batchStepFile = batchStepFile;
63  		this.step = step;
64  		this.stepIndex = stepIndex;
65  
66  		this.containerStepListeners = new ArrayList<ContainerStepListener>();
67  
68  		LOG.info("Initialized thread executor for "+ batchStepFile);
69  	}
70  
71  	
72  
73  
74  
75  	@Override
76      public void run() {
77  	    Date stepRunDate = dateTimeService.getCurrentDate();
78  	    batchStepFile.setStartedDate(stepRunDate);
79  	    batchStepFile.setStepIndex(new Integer(stepIndex));
80  
81  		setupNDCLogging();
82  		notifyStepStarted();
83  
84  		try {
85  			LOG.info("Running "+ batchStepFile);
86  
87  			boolean result = Job.runStep(parameterService, batchStepFile.getJobName(), stepIndex, step, stepRunDate);
88  
89  			if (result) {
90  				LOG.info("Step returned true");
91  				batchContainerDirectory.writeBatchStepSuccessfulResultFile(batchStepFile);
92  			}
93  			else {
94  				LOG.info("Step returned false");
95  				batchContainerDirectory.writeBatchStepErrorResultFile(batchStepFile);
96  			}
97  
98  		} catch (Throwable throwable) {
99  			LOG.info("Step threw an error: ", throwable);
100 			batchContainerDirectory.writeBatchStepErrorResultFile(batchStepFile, throwable);
101 
102 		} finally {
103 
104 		    notifyStepFinished();
105 			resetNDCLogging();
106 		}
107 	}
108 
109 	
110 
111 
112 
113 
114 	public void addContainerStepListener(ContainerStepListener listener) {
115 	    this.containerStepListeners.add(listener);
116 	}
117 
118 	
119 
120 
121 	private void setupNDCLogging() {
122         String nestedDiagnosticContext = getNestedDiagnosticContext();
123         logFileName = getLogFileName(nestedDiagnosticContext);
124 
125         ndcAppender = null;
126         ndcSet = false;
127         try {
128             ndcAppender = new FileAppender(BatchLogger.getLogFileAppenderLayout(), logFileName);
129             ndcAppender.addFilter(new NDCFilter(nestedDiagnosticContext));
130             Logger.getRootLogger().addAppender(ndcAppender);
131             NDC.push(nestedDiagnosticContext);
132             ndcSet = true;
133         } catch (Exception ex) {
134             LOG.warn("Could not initialize custom logging for step: " + step.getName(), ex);
135         }
136 	}
137 
138 	
139 
140 
141 	private void resetNDCLogging() {
142         if ( ndcSet ) {
143             ndcAppender.close();
144             Logger.getRootLogger().removeAppender(ndcAppender);
145             NDC.pop();
146         }
147 	}
148 
149 	
150 
151 
152 
153 
154 
155     private String getLogFileName(String nestedDiagnosticContext) {
156         return SpringContext.getBean( ConfigurationService.class ).getPropertyValueAsString(OLEConstants.REPORTS_DIRECTORY_KEY)
157                 + File.separator
158                 + nestedDiagnosticContext + ".log";
159     }
160 
161     
162 
163 
164 	@SuppressWarnings("unchecked")
165     private String getNestedDiagnosticContext() {
166         Step unProxiedStep = (Step) ProxyUtils.getTargetIfProxied(step);
167         Class stepClass = unProxiedStep.getClass();
168         ModuleService module = SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService( stepClass );
169 
170         String nestedDiagnosticContext =
171                 StringUtils.substringAfter( module.getModuleConfiguration().getNamespaceCode(), "-").toLowerCase()
172                 + File.separator + step.getName()
173                 + "-" + dateTimeService.toDateTimeStringForFilename(dateTimeService.getCurrentDate());
174 
175         return nestedDiagnosticContext;
176     }
177 
178 	
179 
180 
181 	private void notifyStepStarted() {
182 	    String shortLogFileName = getShortLogFileName();
183 
184 	    for(ContainerStepListener listener : this.containerStepListeners) {
185 	        listener.stepStarted(batchStepFile, shortLogFileName);
186 	    }
187 	}
188 
189 	
190 
191 
192 	private void notifyStepFinished() {
193 	    BatchStepFileDescriptor resultFile = batchContainerDirectory.getResultFile(batchStepFile);
194 	    resultFile.setCompletedDate(dateTimeService.getCurrentDate());
195 	    resultFile.setStepIndex(new Integer(stepIndex));
196 
197         String shortLogFileName = getShortLogFileName();
198 
199 	    for(ContainerStepListener listener : this.containerStepListeners) {
200 	        listener.stepFinished(resultFile, shortLogFileName);
201 	    }
202 	}
203 
204 	
205 
206 
207 
208 
209 	private String getShortLogFileName() {
210         String shortLogFileName = logFileName;
211 
212         File logFile = new File(logFileName);
213         if (logFile.exists()) {
214             shortLogFileName = logFile.getName();
215         }
216         return shortLogFileName;
217 	}
218 }