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}