View Javadoc

1   /**
2    * Copyright 2010-2013 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.common.util.execute;
17  
18  import java.io.File;
19  import java.util.Properties;
20  
21  import org.kuali.common.util.LocationUtils;
22  import org.kuali.common.util.PropertyUtils;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.springframework.util.Assert;
26  
27  public class RunOnceExecutable implements Executable {
28  
29  	private static final Logger logger = LoggerFactory.getLogger(RunOnceExecutable.class);
30  
31  	Executable executable;
32  	File propertiesFile;
33  	String property;
34  	String encoding;
35  	boolean skip;
36  
37  	@Override
38  	public void execute() {
39  		if (skip) {
40  			logger.info("Skipping execution");
41  			return;
42  		}
43  		Assert.notNull(propertiesFile);
44  		Assert.notNull(property);
45  		Assert.notNull(executable);
46  
47  		if (!propertiesFile.exists()) {
48  			logger.info("Skipping execution. File does not exist - [{}]", LocationUtils.getCanonicalPath(propertiesFile));
49  			return;
50  		}
51  
52  		logger.info("Examining run once property [{}] in [{}]", property, LocationUtils.getCanonicalPath(propertiesFile));
53  
54  		// Load the properties
55  		Properties properties = PropertyUtils.load(propertiesFile, encoding);
56  
57  		// Translate the property value into an execution mode
58  		ExecutionMode mode = getExecutionMode(properties, property);
59  
60  		// Are we going to run once?
61  		if (!isRunOnce(mode)) {
62  			logger.info("Skipping execution - [{}={}]", property, mode);
63  			return;
64  		}
65  
66  		// Show the execution mode we are in
67  		logger.info("{}={}", property, mode);
68  
69  		// Make sure we have the ability to successfully store updated properties back to the file
70  		if (!isAlways(mode)) {
71  			setState(properties, property, ExecutionMode.INPROGRESS);
72  		}
73  
74  		try {
75  			// Invoke execute now that we have successfully transitioned things to INPROGRESS
76  			executable.execute();
77  			// There is always a chance that the executable finishes correctly and we encounter some kind of
78  			// issue just storing the properties back to the file. This should be pretty rare considering
79  			// we were able to successfully store the properties just prior to the executable commencing.
80  			// In any event, the executable won't run again in the normal use case because we can only get to this point
81  			// if the original execution mode was "TRUE" and we were able to successfully change it to "INPROGRESS"
82  			if (!isAlways(mode)) {
83  				setState(properties, property, ExecutionMode.COMPLETED);
84  			}
85  		} catch (Exception e) {
86  			if (!isAlways(mode)) {
87  				setState(properties, property, ExecutionMode.FAILED);
88  			}
89  			throw new IllegalStateException("Unexpected execution error", e);
90  		}
91  	}
92  
93  	protected boolean isAlways(ExecutionMode mode) {
94  		return ExecutionMode.ALWAYS.equals(mode);
95  	}
96  
97  	protected boolean isRunOnce(ExecutionMode mode) {
98  		if (ExecutionMode.RUNONCE.equals(mode)) {
99  			return true;
100 		}
101 		if (isAlways(mode)) {
102 			return true;
103 		}
104 		return ExecutionMode.TRUE.equals(mode);
105 	}
106 
107 	protected ExecutionMode getExecutionMode(Properties properties, String key) {
108 		String value = properties.getProperty(property);
109 		if (value == null) {
110 			return ExecutionMode.NULL;
111 		} else {
112 			return ExecutionMode.valueOf(value.toUpperCase());
113 		}
114 
115 	}
116 
117 	protected void setState(Properties properties, String key, ExecutionMode mode) {
118 		logger.info("{}={}", key, mode);
119 		properties.setProperty(property, mode.name());
120 		PropertyUtils.store(properties, propertiesFile, encoding);
121 	}
122 
123 	public Executable getExecutable() {
124 		return executable;
125 	}
126 
127 	public void setExecutable(Executable executable) {
128 		this.executable = executable;
129 	}
130 
131 	public File getPropertiesFile() {
132 		return propertiesFile;
133 	}
134 
135 	public void setPropertiesFile(File propertiesFile) {
136 		this.propertiesFile = propertiesFile;
137 	}
138 
139 	public String getProperty() {
140 		return property;
141 	}
142 
143 	public void setProperty(String property) {
144 		this.property = property;
145 	}
146 
147 	public String getEncoding() {
148 		return encoding;
149 	}
150 
151 	public void setEncoding(String encoding) {
152 		this.encoding = encoding;
153 	}
154 
155 	public boolean isSkip() {
156 		return skip;
157 	}
158 
159 	public void setSkip(boolean skip) {
160 		this.skip = skip;
161 	}
162 }