/* Copyright 2012 Thorben Lindhauer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.unipotsdam.hpi.thorben.ppi.measure.instance;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.util.ClockUtil;
import org.activiti.engine.repository.ProcessDefinition;
import de.unipotsdam.hpi.thorben.ppi.condition.PPICondition;
import de.unipotsdam.hpi.thorben.ppi.condition.event.ConditionEvent;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.SingleTimeMeasureValue;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.TimeMeasureInstance;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.command.GetSingleTimeValueCommand;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.command.GetTimeMeasureInstanceCommand;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.command.InsertSingleTimeValueCommand;
import de.unipotsdam.hpi.thorben.ppi.measure.instance.entity.command.InsertTimeInstanceCommand;
import de.unipotsdam.hpi.thorben.ppi.measure.query.TimeMeasureInstanceQuery;
public class TimeMeasure extends EventListeningBaseMeasure<TimeMeasureInstance> {
private PPICondition fromCondition;
private PPICondition toCondition;
private Map<String, TimeMeasureInstance> instancesCache = new HashMap<String, TimeMeasureInstance>();
public TimeMeasure(String id, ProcessDefinition processDefinition) {
super(id, processDefinition);
}
public void setFromCondition(PPICondition fromCondition) {
this.fromCondition = fromCondition;
}
public void setToCondition(PPICondition toCondition) {
this.toCondition = toCondition;
}
@Override
public void update(ConditionEvent event) {
CommandContext commandContext = Context.getCommandContext();
String processInstanceId = event.getProcessInstanceId();
if (fromCondition.isFulfilledBy(event)) {
TimeMeasureInstance timeMeasureValue = findCachedTimeMeasureInstance(processInstanceId);
SingleTimeMeasureValue singleValue = new SingleTimeMeasureValue();
singleValue.setFrom(ClockUtil.getCurrentTime());
singleValue.setTimeMeasureId(timeMeasureValue.getId());
timeMeasureValue.getSingleValues().add(singleValue);
new InsertSingleTimeValueCommand(singleValue)
.execute(commandContext);
}
if (toCondition.isFulfilledBy(event)) {
TimeMeasureInstance timeMeasureValue = findCachedTimeMeasureInstance(processInstanceId);
for (SingleTimeMeasureValue singleValue : timeMeasureValue
.getSingleValues()) {
if (singleValue.getTo() == null) {
// TODO refactor, this is hardly understandable
// The following is null, if the value was not commited into
// the database yet, but is still in Activiti's cache.
SingleTimeMeasureValue persistedValue = new GetSingleTimeValueCommand(
singleValue.getId()).execute(commandContext);
if (persistedValue == null) {
// this is the case that the single value was recently
// created.
// It should then be in the DBSqlSession cache and this
// update should be sufficient.
singleValue.setTo(ClockUtil.getCurrentTime());
} else {
persistedValue.setTo(ClockUtil.getCurrentTime());
}
break;
}
}
}
}
/**
* Finds a count measure instance (or creates one) and ensures that it is in
* Activiti's cache.
* It is also added to a local cache in this TimeMeasure, as the select commands do not access the Activiti cache.
* Otherwise a TimeMeasureInstance that was already created before, but not committed, could not be found.
*
* Note: The in the TimeMeasureInstance referenced SingleTimeMeasureValues are loaded to Activiti's cache
* when the owning TimeMeasureInstance is loaded. This means,
* that if you later want to ensure that they are added to Activiti's cache,
* you have to explicitly load them again from the database.
*
* @param processInstanceId
* @return
*/
private TimeMeasureInstance findCachedTimeMeasureInstance(
String processInstanceId) {
CommandContext commandContext = Context.getCommandContext();
TimeMeasureInstance timeMeasureValue = new GetTimeMeasureInstanceCommand(
id, processInstanceId).execute(commandContext);
if (timeMeasureValue == null) {
timeMeasureValue = instancesCache.get(processInstanceId);
}
if (timeMeasureValue == null) {
timeMeasureValue = new TimeMeasureInstance();
timeMeasureValue.setMeasureId(id);
timeMeasureValue.setProcessInstanceId(processInstanceId);
new InsertTimeInstanceCommand(timeMeasureValue)
.execute(commandContext);
}
instancesCache.put(processInstanceId, timeMeasureValue);
return timeMeasureValue;
}
@Override
public List<TimeMeasureInstance> getAllValues() {
CommandContext context = Context.getCommandContext();
TimeMeasureInstanceQuery query = context.getBaseMeasureManager()
.createNewTimeMeasureInstanceQuery()
.processDefinitionId(processDefinition.getId()).measureId(id);
return query.list();
}
}