001/**
002 * Copyright 2005-2014 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 */
016package org.kuali.rice.xml.ingest;
017
018import static com.google.common.base.Preconditions.checkArgument;
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkState;
021
022import org.apache.commons.lang3.StringUtils;
023import org.kuali.common.util.log.LoggerUtils;
024import org.kuali.common.util.runonce.smart.RunOnce;
025import org.kuali.common.util.runonce.smart.RunOnceState;
026import org.kuali.rice.core.api.util.Truth;
027import org.kuali.rice.coreservice.api.parameter.Parameter;
028import org.kuali.rice.coreservice.api.parameter.ParameterType;
029import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
030import org.kuali.rice.coreservice.framework.parameter.ParameterService;
031import org.slf4j.Logger;
032
033import com.google.common.base.Optional;
034
035public final class ParameterServiceRunOnce implements RunOnce {
036
037        private static final Logger logger = LoggerUtils.make();
038
039        private final String applicationId;
040        private final String namespace;
041        private final String component;
042        private final String name;
043        private final Optional<String> description;
044        private final boolean runOnMissingParameter;
045
046        //
047        private boolean initialized = false;
048        private boolean runonce = false;
049        private ParameterService service;
050
051        private static final String CONFIGURATION_PARAMETER_TYPE = "CONFG";
052        private static final String YES = "Y";
053
054        @Override
055        public synchronized void initialize() {
056                checkState(!initialized, "Already initialized");
057                this.service = CoreFrameworkServiceLocator.getParameterService();
058                Optional<Parameter> parameter = Optional.fromNullable(service.getParameter(namespace, component, name));
059                if (!parameter.isPresent() && runOnMissingParameter) {
060                        parameter = Optional.of(createParameter());
061                }
062                this.runonce = isRunOnce(parameter);
063                showConfig(parameter);
064                this.initialized = true;
065        }
066
067        @Override
068        public synchronized boolean isTrue() {
069                checkState(initialized, "Not initialized");
070                return runonce;
071        }
072
073        @Override
074        public synchronized void changeState(RunOnceState state) {
075                // Ensure things are as they should be
076                checkState(initialized, "Not initialized");
077                checkNotNull(state, "'state' cannot be null");
078
079                // Get the existing parameter
080                Parameter existingParameter = service.getParameter(namespace, component, name);
081
082                // Can't change the state of a non-existent parameter
083                // The isRunOnce() method called during initialization cannot return true unless a parameter exists and it's value is set to 'Y'
084                checkNotNull(existingParameter, "'existingParameter' cannot be null");
085
086                // Update the parameter
087                logger.info("Updating parameter: [{}]", name);
088                Parameter.Builder builder = Parameter.Builder.create(existingParameter);
089                builder.setValue(state.name());
090                Parameter updatedParameter = service.updateParameter(builder.build());
091
092                // This must always return false here
093                this.runonce = isRunOnce(updatedParameter);
094                checkState(!isTrue(), "isTrue() must return false");
095
096                // Emit a log message indicating the change in state
097                logger.info("Transitioned RunOnce to - [{}]", updatedParameter.getValue());
098        }
099
100        protected boolean isRunOnce(Optional<Parameter> parameter) {
101                if (parameter.isPresent()) {
102                        return isRunOnce(parameter.get());
103                } else {
104                        return false;
105                }
106        }
107
108        protected boolean isRunOnce(Parameter parameter) {
109                return Boolean.parseBoolean(Truth.strToBooleanIgnoreCase(parameter.getValue()) + "");
110        }
111
112        protected Parameter createParameter() {
113                logger.info("Creating parameter: [{}]=[{}]", name, YES);
114                Parameter.Builder builder = Parameter.Builder.create(applicationId, namespace, component, name, ParameterType.Builder.create(CONFIGURATION_PARAMETER_TYPE));
115                builder.setValue(YES);
116                if (description.isPresent()) {
117                        builder.setDescription(description.get());
118                }
119                return service.createParameter(builder.build());
120        }
121
122        protected void showConfig(Optional<Parameter> optional) {
123                logger.info(String.format("Parameter Metadata: [%s:%s:%s]", applicationId, namespace, component));
124                if (optional.isPresent()) {
125                        Parameter parameter = optional.get();
126                        logger.info("Parameter: [{}]=[{}]", name, parameter.getValue());
127                } else {
128                        logger.info("Parameter [{}] does not exist", name);
129                }
130                logger.info("RunOnce: [{}]", runonce);
131        }
132
133        private ParameterServiceRunOnce(Builder builder) {
134                this.applicationId = builder.applicationId;
135                this.namespace = builder.namespace;
136                this.component = builder.component;
137                this.name = builder.name;
138                this.description = builder.description;
139                this.runOnMissingParameter = builder.runOnMissingParameter;
140        }
141
142        public static Builder builder() {
143                return new Builder();
144        }
145
146        public static class Builder {
147
148                private String applicationId;
149                private String namespace;
150                private String component;
151                private String name;
152                private Optional<String> description;
153                private boolean runOnMissingParameter;
154
155                public Builder runOnMissingParameter(boolean runOnMissingParameter) {
156                        this.runOnMissingParameter = runOnMissingParameter;
157                        return this;
158                }
159
160                public Builder applicationId(String applicationId) {
161                        this.applicationId = applicationId;
162                        return this;
163                }
164
165                public Builder namespace(String namespace) {
166                        this.namespace = namespace;
167                        return this;
168                }
169
170                public Builder component(String component) {
171                        this.component = component;
172                        return this;
173                }
174
175                public Builder name(String name) {
176                        this.name = name;
177                        return this;
178                }
179
180                public Builder description(String name) {
181                        this.description = Optional.fromNullable(name);
182                        return this;
183                }
184
185                public ParameterServiceRunOnce build() {
186                        ParameterServiceRunOnce instance = new ParameterServiceRunOnce(this);
187                        validate(instance);
188                        return instance;
189                }
190
191                private static void validate(ParameterServiceRunOnce instance) {
192                        checkArgument(!StringUtils.isBlank(instance.getApplicationId()), "'application' id cannot be null");
193                        checkArgument(!StringUtils.isBlank(instance.getNamespace()), "'namespace' cannot be null");
194                        checkArgument(!StringUtils.isBlank(instance.getComponent()), "'component' cannot be null");
195                        checkArgument(!StringUtils.isBlank(instance.getName()), "'name' cannot be null");
196                        checkNotNull(instance.description, "'description' cannot be null");
197                }
198
199                public String getApplicationId() {
200                        return applicationId;
201                }
202
203                public void setApplicationId(String applicationId) {
204                        this.applicationId = applicationId;
205                }
206
207                public String getNamespace() {
208                        return namespace;
209                }
210
211                public void setNamespace(String namespace) {
212                        this.namespace = namespace;
213                }
214
215                public String getComponent() {
216                        return component;
217                }
218
219                public void setComponent(String component) {
220                        this.component = component;
221                }
222
223                public String getName() {
224                        return name;
225                }
226
227                public void setName(String name) {
228                        this.name = name;
229                }
230
231                public Optional<String> getDescription() {
232                        return description;
233                }
234
235                public void setDescription(Optional<String> description) {
236                        this.description = description;
237                }
238
239        }
240
241        public String getApplicationId() {
242                return applicationId;
243        }
244
245        public String getNamespace() {
246                return namespace;
247        }
248
249        public String getComponent() {
250                return component;
251        }
252
253        public String getName() {
254                return name;
255        }
256
257        public Optional<String> getDescription() {
258                return description;
259        }
260
261        public boolean isRunOnMissingParameter() {
262                return runOnMissingParameter;
263        }
264
265}