/*
* Copyright 2014 Effektif GmbH.
*
* 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 com.effektif.workflow.impl.workflow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.effektif.workflow.api.Configuration;
import com.effektif.workflow.api.workflow.Activity;
import com.effektif.workflow.api.workflow.Extensible;
import com.effektif.workflow.api.workflow.Scope;
import com.effektif.workflow.api.workflow.Timer;
import com.effektif.workflow.api.workflow.Transition;
import com.effektif.workflow.api.workflow.Variable;
import com.effektif.workflow.impl.WorkflowParser;
public abstract class ScopeImpl extends Extensible {
public ScopeImpl parent;
public Configuration configuration;
public WorkflowImpl workflow;
public Map<String, ActivityImpl> activities;
public Map<String, VariableImpl> variables;
public List<TimerImpl> timers;
public List<TransitionImpl> transitions;
public void parse(Scope scope, ScopeImpl parentImpl, WorkflowParser parser) {
this.properties = scope.getProperties()!=null ? new HashMap<>(scope.getProperties()) : null;
this.configuration = parser.configuration;
if (parentImpl!=null) {
this.parent = parentImpl;
this.workflow = parentImpl.workflow;
}
List<Variable> variables = scope.getVariables();
if (variables!=null && !variables.isEmpty()) {
int i = 0;
for (Variable variable: variables) {
VariableImpl variableImpl = new VariableImpl();
parser.pushContext("variables", variable, variableImpl, i);
variableImpl.parse(variable, this, parser);
addVariable(variableImpl);
parser.popContext();
i++;
}
} else {
// ensures there are not empty collections in the persistent storage
scope.setVariables(null);
}
List<Timer> timers = scope.getTimers();
if (timers!=null && !timers.isEmpty()) {
int i = 0;
for (Timer timer: timers) {
TimerImpl timerImpl = new TimerImpl();
parser.pushContext("timers", timer, timerImpl, i);
timerImpl.parse(timer, this, parser);
addTimer(timerImpl);
parser.popContext();
i++;
}
} else {
// ensures there are not empty collections in the persistent storage
scope.setTimers(null);
}
Map<String, ActivityImpl> activitiesByDefaultTransitionId = new HashMap<>();
List<Activity> activities = scope.getActivities();
if (activities!=null && !activities.isEmpty()) {
int i = 0;
for (Activity activity: activities) {
ActivityImpl activityImpl = new ActivityImpl();
parser.pushContext("activities", activity, activityImpl, i);
if (activity.getDefaultTransitionId()!=null) {
activitiesByDefaultTransitionId.put(activity.getDefaultTransitionId(), activityImpl);
}
activityImpl.parse(activity, scope, this, parser);
addActivity(activityImpl);
parser.popContext();
i++;
}
} else {
// ensures there are not empty collections in the persistent storage
scope.setActivities(null);
}
List<Transition> transitions = scope.getTransitions();
if (transitions!=null && !transitions.isEmpty()) {
int i = 0;
for (Transition transition: transitions) {
TransitionImpl transitionImpl = new TransitionImpl();
parser.pushContext("transitions", transition, transitionImpl, i);
transitionImpl.parse(transition, this, activitiesByDefaultTransitionId, parser);
addTransition(transitionImpl);
parser.popContext();
i++;
}
} else {
// ensures there are not empty collections in the persistent storage
scope.setTransitions(null);
}
if (this.activities!=null) {
// some activity types need to validate incoming and outgoing transitions,
// that's why they are validated after the transitions.
int i = 0;
for (ActivityImpl activityImpl : this.activities.values()) {
Activity activity = activities.get(i);
if (activityImpl.activityType != null) {
parser.pushContext("activities", activity, activityImpl, i);
activityImpl.activityType.parse(activityImpl, activity, parser);
parser.popContext();
}
i++;
}
}
if (!activitiesByDefaultTransitionId.isEmpty()) {
for (String nonExistingDefaultTransitionId: activitiesByDefaultTransitionId.keySet()) {
ActivityImpl activity = activitiesByDefaultTransitionId.get(nonExistingDefaultTransitionId);
parser.addWarning("Activity '%s' has non existing default transition id '%s'", activity.id, nonExistingDefaultTransitionId);
}
}
}
public void addTimer(TimerImpl timer) {
if (timers==null) {
timers = new ArrayList<>();
}
timers.add(timer);
timer.parent = this;
}
public void addVariable(VariableImpl variable) {
if (variables==null) {
variables = new LinkedHashMap<>();
}
variables.put(variable.id, variable);
variable.parent = this;
}
public void addTransition(TransitionImpl transition) {
if (transitions==null) {
transitions = new ArrayList<>();
}
transitions.add(transition);
transition.parent = this;
}
public void addActivity(ActivityImpl activity) {
if (activities==null) {
activities = new LinkedHashMap<>();
}
activities.put(activity.id, activity);
activity.parent = this;
}
public TransitionImpl findTransitionByIdLocal(String transitionId) {
if (transitions!=null) {
for (TransitionImpl transition: transitions) {
if (transitionId.equals(transition.id)) {
return transition;
}
}
}
return null;
}
public ActivityImpl findActivityByIdLocal(String activityId) {
return activities.get(activityId);
}
public boolean isWorkflow() {
return parent!=null;
}
public boolean hasActivitiesLocal() {
return activities!=null && !activities.isEmpty();
}
public boolean hasVariablesLocal() {
return variables!=null && !variables.isEmpty();
}
public boolean hasTransitionsLocal() {
return transitions!=null && !transitions.isEmpty();
}
public boolean hasVariableRecursive(String variableId) {
if (hasVariableLocal(variableId)) {
return true;
}
if (parent!=null) {
return parent.hasVariableRecursive(variableId);
}
return false;
}
public boolean hasVariableLocal(String variableId) {
return variables!=null && variables.containsKey(variableId);
}
public ActivityImpl getActivityByIdLocal(String activityId) {
return activities!=null ? activities.get(activityId) : null;
}
public VariableImpl findVariableByIdLocal(String variableId) {
return variables!=null ? variables.get(variableId) : null;
}
public VariableImpl findVariableByIdRecursive(String variableId) {
if (variables!=null && variables.containsKey(variableId)) {
return variables.get(variableId);
}
if (parent!=null) {
return parent.findVariableByIdRecursive(variableId);
}
return null;
}
public ActivityImpl getNextActivity(ActivityImpl previous) {
if (activities!=null) {
// this depends on the map being a *Linked*HashMap that preserves the order
Iterator<ActivityImpl> iterator = activities.values().iterator();
while (iterator.hasNext()) {
ActivityImpl activity = iterator.next();
if (previous==activity) {
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
}
}
return null;
}
public ScopeImpl getParent() {
return parent;
}
public Configuration getConfiguration() {
return configuration;
}
public WorkflowImpl getWorkflow() {
return workflow;
}
public Map<String, ActivityImpl> getActivities() {
return activities;
}
public Map<String, VariableImpl> getVariables() {
return variables;
}
public List<TimerImpl> getTimers() {
return timers;
}
public List<TransitionImpl> getTransitions() {
return transitions;
}
public abstract String getIdText();
}