View Javadoc
1   package org.kuali.common.util.runonce.smart;
2   
3   import static com.google.common.base.Preconditions.checkArgument;
4   import static com.google.common.base.Preconditions.checkNotNull;
5   import static com.google.common.base.Preconditions.checkState;
6   
7   import java.io.File;
8   import java.util.Properties;
9   
10  import org.apache.commons.lang3.StringUtils;
11  import org.kuali.common.util.PropertyUtils;
12  import org.kuali.common.util.file.CanonicalFile;
13  import org.kuali.common.util.log.LoggerUtils;
14  import org.slf4j.Logger;
15  
16  public final class PropertiesFileRunOnce implements RunOnce {
17  
18  	private static final Logger logger = LoggerUtils.make();
19  
20  	private final File file;
21  	private final String encoding;
22  	private final String key;
23  
24  	private Properties properties;
25  	private boolean runonce;
26  	private boolean initialized = false;
27  
28  	@Override
29  	public synchronized void initialize() {
30  		checkState(!initialized, "Already initialized");
31  		logger.info("--- Initializing properties file backed RunOnce ---");
32  		this.properties = getProperties();
33  		this.runonce = getBoolean(properties, key);
34  		showConfig();
35  		logger.info("--- Properties file backed RunOnce initialized. ---");
36  		this.initialized = true;
37  	}
38  
39  	@Override
40  	public synchronized boolean isTrue() {
41  		checkState(initialized, "Not initialized");
42  		return runonce;
43  	}
44  
45  	@Override
46  	public synchronized void changeState(RunOnceState state) {
47  		checkState(initialized, "Not initialized");
48  		checkNotNull(state, "'state' cannot be null");
49  		properties.setProperty(key, state.name());
50  		PropertyUtils.store(properties, file, encoding);
51  		this.properties = PropertyUtils.load(file, encoding);
52  		this.runonce = getBoolean(properties, key);
53  		checkState(!isTrue(), "isTrue() must return false");
54  		logger.info("Transitioned RunOnce to - [{}]", state.name());
55  	}
56  
57  	private boolean getBoolean(Properties properties, String key) {
58  		String value = properties.getProperty(key);
59  		return Boolean.parseBoolean(value);
60  	}
61  
62  	protected void showConfig() {
63  		logger.info("Properties file: [{}]", file);
64  		logger.info("Properties file exists: {}", file.exists());
65  		logger.info("Property: [{}]=[{}]", key, properties.get(key));
66  		logger.info("RunOnce: [{}]", runonce);
67  	}
68  
69  	protected Properties getProperties() {
70  		if (file.exists()) {
71  			return PropertyUtils.load(file, encoding);
72  		} else {
73  			return new Properties();
74  		}
75  	}
76  
77  	private PropertiesFileRunOnce(Builder builder) {
78  		this.file = builder.file;
79  		this.encoding = builder.encoding;
80  		this.key = builder.key;
81  	}
82  
83  	public static Builder builder(File file, String encoding, String key) {
84  		return new Builder(file, encoding, key);
85  	}
86  
87  	public static class Builder {
88  
89  		private final File file;
90  		private final String key;
91  		private final String encoding;
92  
93  		public Builder(File file, String encoding, String key) {
94  			this.file = new CanonicalFile(file);
95  			this.encoding = encoding;
96  			this.key = key;
97  		}
98  
99  		public PropertiesFileRunOnce build() {
100 			PropertiesFileRunOnce instance = new PropertiesFileRunOnce(this);
101 			validate(instance);
102 			return instance;
103 		}
104 
105 		private void validate(PropertiesFileRunOnce instance) {
106 			checkNotNull(instance.getFile(), "file cannot be null");
107 			checkArgument(!StringUtils.isBlank(instance.getEncoding()), "encoding cannot be blank");
108 			checkArgument(!StringUtils.isBlank(instance.getKey()), "key cannot be blank");
109 		}
110 	}
111 
112 	public File getFile() {
113 		return file;
114 	}
115 
116 	public String getEncoding() {
117 		return encoding;
118 	}
119 
120 	public String getKey() {
121 		return key;
122 	}
123 
124 }