View Javadoc
1   /**
2    * Copyright 2005-2015 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.rice.xml.ingest;
17  
18  import static com.google.common.base.Preconditions.checkArgument;
19  import static com.google.common.base.Preconditions.checkNotNull;
20  import static com.google.common.base.Preconditions.checkState;
21  
22  import org.apache.commons.lang3.StringUtils;
23  import org.kuali.common.util.log.LoggerUtils;
24  import org.kuali.common.util.runonce.smart.RunOnce;
25  import org.kuali.common.util.runonce.smart.RunOnceState;
26  import org.kuali.rice.core.api.util.Truth;
27  import org.kuali.rice.coreservice.api.parameter.Parameter;
28  import org.kuali.rice.coreservice.api.parameter.ParameterType;
29  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
30  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
31  import org.slf4j.Logger;
32  
33  import com.google.common.base.Optional;
34  
35  /**
36   * Locates workflow XML documents available on the classpath and ingests them.
37   *
38   * @author Kuali Rice Team (rice.collab@kuali.org)
39   */
40  public final class ParameterServiceRunOnce implements RunOnce {
41  
42  	private static final Logger logger = LoggerUtils.make();
43  
44      private static final String CONFIGURATION_PARAMETER_TYPE = "CONFG";
45      private static final String YES = "Y";
46  
47      private ParameterService parameterService;
48  	private final String applicationId;
49  	private final String namespace;
50  	private final String component;
51  	private final String name;
52  	private final Optional<String> description;
53  
54      private final boolean runOnMissingParameter;
55  
56  	private boolean initialized;
57  	private boolean runonce;
58  
59      /**
60       * {@inheritDoc}
61       */
62  	@Override
63  	public synchronized void initialize() {
64  		checkState(!initialized, "Already initialized");
65  
66  		parameterService = CoreFrameworkServiceLocator.getParameterService();
67  
68  		Optional<Parameter> parameter = Optional.fromNullable(parameterService.getParameter(namespace, component, name));
69  		if (!parameter.isPresent() && runOnMissingParameter) {
70  			parameter = Optional.of(createParameter());
71  		}
72  		runonce = isRunOnce(parameter);
73  		showConfig(parameter);
74  
75  		initialized = true;
76  	}
77  
78      /**
79       * {@inheritDoc}
80       */
81  	@Override
82  	public synchronized boolean isTrue() {
83  		checkState(initialized, "Not initialized");
84  
85          return runonce;
86  	}
87  
88      /**
89       * {@inheritDoc}
90       */
91  	@Override
92  	public synchronized void changeState(RunOnceState state) {
93  		// Ensure things are as they should be
94  		checkState(initialized, "Not initialized");
95  		checkNotNull(state, "'state' cannot be null");
96  
97  		// Get the existing parameter
98  		Parameter existingParameter = parameterService.getParameter(namespace, component, name);
99  
100 		// Can't change the state of a non-existent parameter
101 		// The isRunOnce() method called during initialization cannot return true unless a parameter exists and it's value is set to 'Y'
102 		checkNotNull(existingParameter, "'existingParameter' cannot be null");
103 
104 		// Update the parameter
105 		logger.info("Updating parameter: [{}]", name);
106 		Parameter.Builder builder = Parameter.Builder.create(existingParameter);
107 		builder.setValue(state.name());
108 		Parameter updatedParameter = parameterService.updateParameter(builder.build());
109 
110 		// This must always return false here
111 		runonce = isRunOnce(updatedParameter);
112 		checkState(!isTrue(), "isTrue() must return false");
113 
114 		// Emit a log message indicating the change in state
115 		logger.info("Transitioned RunOnce to - [{}]", updatedParameter.getValue());
116 	}
117 
118 	private boolean isRunOnce(Optional<Parameter> parameter) {
119 		return parameter.isPresent() && isRunOnce(parameter.get());
120 	}
121 
122 	private boolean isRunOnce(Parameter parameter) {
123 		return Truth.strToBooleanIgnoreCase(parameter.getValue(), Boolean.FALSE).booleanValue();
124 	}
125 
126 	private Parameter createParameter() {
127 		logger.info("Creating parameter: [{}]=[{}]", name, YES);
128         ParameterType.Builder parameterTypeBuilder = ParameterType.Builder.create(CONFIGURATION_PARAMETER_TYPE);
129 		Parameter.Builder parameterBuilder = Parameter.Builder.create(applicationId, namespace, component, name, parameterTypeBuilder);
130         parameterBuilder.setValue(YES);
131 		if (description.isPresent()) {
132             parameterBuilder.setDescription(description.get());
133 		}
134 
135 		return parameterService.createParameter(parameterBuilder.build());
136 	}
137 
138 	private void showConfig(Optional<Parameter> optional) {
139 		logger.info(String.format("Parameter Metadata: [%s:%s:%s]", applicationId, namespace, component));
140 		if (optional.isPresent()) {
141 			Parameter parameter = optional.get();
142 			logger.info("Parameter: [{}]=[{}]", name, parameter.getValue());
143 		} else {
144 			logger.info("Parameter [{}] does not exist", name);
145 		}
146 		logger.info("RunOnce: [{}]", Boolean.valueOf(runonce));
147 	}
148 
149     /**
150      * Returns the application identifier of the parameter.
151      *
152      * @return the application identifier of the parameter
153      */
154     public String getApplicationId() {
155         return applicationId;
156     }
157 
158     /**
159      * Returns the namespace of the parameter.
160      *
161      * @return the namespace of the parameter
162      */
163     public String getNamespace() {
164         return namespace;
165     }
166 
167     /**
168      * Returns the component of the parameter.
169      *
170      * @return the component of the parameter
171      */
172     public String getComponent() {
173         return component;
174     }
175 
176     /**
177      * Returns the name of the parameter.
178      *
179      * @return the name of the parameter
180      */
181     public String getName() {
182         return name;
183     }
184 
185     /**
186      * Returns the optional description.
187      *
188      * @return the optional description
189      */
190     public Optional<String> getDescription() {
191         return description;
192     }
193 
194 	private ParameterServiceRunOnce(Builder builder) {
195 		this.applicationId = builder.applicationId;
196 		this.namespace = builder.namespace;
197 		this.component = builder.component;
198 		this.name = builder.name;
199 		this.description = builder.description;
200 		this.runOnMissingParameter = builder.runOnMissingParameter;
201 	}
202 
203     /**
204      * Returns the builder for this {@code ParameterServiceRunOnce}.
205      *
206      * @param applicationId the application identifier of the parameter
207      * @param namespace namespace of the parameter
208      * @param component component of the parameter
209      * @param name name of the parameter
210      *
211      * @return the builder for this {@code ParameterServiceRunOnce}
212      */
213     public static Builder builder(String applicationId, String namespace, String component, String name) {
214         return new Builder(applicationId, namespace, component, name);
215     }
216 
217     /**
218      * Builds this {@link ParameterServiceRunOnce}.
219      */
220 	public static class Builder {
221 
222         // Required
223 		private String applicationId;
224 		private String namespace;
225 		private String component;
226 		private String name;
227 
228         // Optional
229 		private Optional<String> description = Optional.absent();
230 		private boolean runOnMissingParameter;
231 
232         /**
233          * Builds the {@link ParameterServiceRunOnce}.
234          *
235          * @param applicationId the application identifier of the parameter
236          * @param namespace namespace of the parameter
237          * @param component component of the parameter
238          * @param name name of the parameter
239          */
240         public Builder(String applicationId, String namespace, String component, String name) {
241             this.applicationId = applicationId;
242             this.namespace = namespace;
243             this.component = component;
244             this.name = name;
245         }
246 
247         /**
248          * Sets the description of the parameter.
249          *
250          * @param description the description to set
251          *
252          * @return this {@code Builder}
253          */
254 		public Builder description(String description) {
255 			this.description = Optional.fromNullable(description);
256 			return this;
257 		}
258 
259         /**
260          * Sets whether or not to add the parameter if it is missing.
261          *
262          * @param runOnMissingParameter whether or not to add the parameter if it is missing
263          *
264          * @return this {@code Builder}
265          */
266         public Builder runOnMissingParameter(boolean runOnMissingParameter) {
267             this.runOnMissingParameter = runOnMissingParameter;
268             return this;
269         }
270 
271         /**
272          * Builds the {@link ParameterServiceRunOnce}.
273          *
274          * @return the built {@link ParameterServiceRunOnce}
275          */
276 		public ParameterServiceRunOnce build() {
277 			ParameterServiceRunOnce instance = new ParameterServiceRunOnce(this);
278 			validate(instance);
279 			return instance;
280 		}
281 
282 		private static void validate(ParameterServiceRunOnce instance) {
283 			checkArgument(!StringUtils.isBlank(instance.getApplicationId()), "'application' id cannot be null");
284 			checkArgument(!StringUtils.isBlank(instance.getNamespace()), "'namespace' cannot be null");
285 			checkArgument(!StringUtils.isBlank(instance.getComponent()), "'component' cannot be null");
286 			checkArgument(!StringUtils.isBlank(instance.getName()), "'name' cannot be null");
287 			checkNotNull(instance.getDescription(), "'description' cannot be null");
288 		}
289 
290 	}
291 
292 }