001 /**
002 * Copyright 2010-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.common.util.execute;
017
018 import java.io.File;
019 import java.util.Properties;
020
021 import org.kuali.common.util.LocationUtils;
022 import org.kuali.common.util.PropertyUtils;
023 import org.slf4j.Logger;
024 import org.slf4j.LoggerFactory;
025 import org.springframework.util.Assert;
026
027 public class RunOnceExecutable implements Executable {
028
029 private static final Logger logger = LoggerFactory.getLogger(RunOnceExecutable.class);
030
031 Executable executable;
032 File propertiesFile;
033 String property;
034 String encoding;
035
036 @Override
037 public void execute() {
038 Assert.notNull(propertiesFile);
039 Assert.notNull(property);
040 Assert.notNull(executable);
041
042 if (!propertiesFile.exists()) {
043 logger.info("Skipping execution. File does not exist - [{}]", LocationUtils.getCanonicalPath(propertiesFile));
044 return;
045 }
046
047 logger.info("Examining run once property [{}] in [{}]", property, LocationUtils.getCanonicalPath(propertiesFile));
048 Properties properties = PropertyUtils.load(propertiesFile, encoding);
049 ExecutionMode mode = getExecutionMode(properties, property);
050 boolean runonce = isRunOnce(mode);
051 if (runonce) {
052 logger.info("{}={}", property, mode);
053 // Make sure we have the ability to successfully store updated properties back to the file
054 if (!isAlways(mode)) {
055 setState(properties, property, ExecutionMode.INPROGRESS);
056 }
057 try {
058 // Invoke execute now that we have successfully transitioned things to INPROGRESS
059 executable.execute();
060 // There is always a chance that the executable finishes correctly and we encounter some kind of
061 // issue just storing the properties back to the file. This should be pretty rare considering
062 // we were able to successfully store the properties just prior to the executable commencing
063 if (!isAlways(mode)) {
064 setState(properties, property, ExecutionMode.COMPLETED);
065 }
066 } catch (Exception e) {
067 if (!isAlways(mode)) {
068 setState(properties, property, ExecutionMode.FAILED);
069 }
070 throw new IllegalStateException("Unexpected execution error", e);
071 }
072 } else {
073 logger.info("Skipping execution - [{}={}]", property, mode);
074 }
075 }
076
077 protected boolean isAlways(ExecutionMode mode) {
078 return ExecutionMode.ALWAYS.equals(mode);
079 }
080
081 protected boolean isRunOnce(ExecutionMode mode) {
082 if (ExecutionMode.RUNONCE.equals(mode)) {
083 return true;
084 }
085 if (isAlways(mode)) {
086 return true;
087 }
088 return ExecutionMode.TRUE.equals(mode);
089 }
090
091 protected ExecutionMode getExecutionMode(Properties properties, String key) {
092 String value = properties.getProperty(property);
093 if (value == null) {
094 return ExecutionMode.NULL;
095 } else {
096 return ExecutionMode.valueOf(value.toUpperCase());
097 }
098
099 }
100
101 protected void setState(Properties properties, String key, ExecutionMode mode) {
102 logger.info("{}={}", key, mode);
103 properties.setProperty(property, mode.name());
104 PropertyUtils.store(properties, propertiesFile, encoding);
105 }
106
107 public Executable getExecutable() {
108 return executable;
109 }
110
111 public void setExecutable(Executable executable) {
112 this.executable = executable;
113 }
114
115 public File getPropertiesFile() {
116 return propertiesFile;
117 }
118
119 public void setPropertiesFile(File propertiesFile) {
120 this.propertiesFile = propertiesFile;
121 }
122
123 public String getProperty() {
124 return property;
125 }
126
127 public void setProperty(String property) {
128 this.property = property;
129 }
130
131 public String getEncoding() {
132 return encoding;
133 }
134
135 public void setEncoding(String encoding) {
136 this.encoding = encoding;
137 }
138 }