495 lines
13 KiB
Java
495 lines
13 KiB
Java
/*
|
|
* Copyright 2015 Martin Smock <martin.smock@bluewin.ch>
|
|
*
|
|
* 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 li.strolch.model.activity;
|
|
|
|
import li.strolch.exception.StrolchModelException;
|
|
import li.strolch.exception.StrolchPolicyException;
|
|
import li.strolch.model.*;
|
|
import li.strolch.model.Locator.LocatorBuilder;
|
|
import li.strolch.model.parameter.Parameter;
|
|
import li.strolch.model.policy.PolicyDef;
|
|
import li.strolch.model.policy.PolicyDefs;
|
|
import li.strolch.model.timevalue.IValue;
|
|
import li.strolch.model.timevalue.IValueChange;
|
|
import li.strolch.model.visitor.StrolchElementVisitor;
|
|
import li.strolch.utils.dbc.DBC;
|
|
|
|
import java.text.MessageFormat;
|
|
import java.util.*;
|
|
|
|
import static li.strolch.model.StrolchModelConstants.BAG_PARAMETERS;
|
|
import static li.strolch.model.StrolchModelConstants.BAG_RELATIONS;
|
|
import static li.strolch.model.StrolchModelConstants.PolicyConstants.BAG_OBJECTIVES;
|
|
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
|
import static li.strolch.utils.helper.StringHelper.trimOrEmpty;
|
|
|
|
/**
|
|
* An {@link Action} represents a single step within an {@link Activity}, that is, one that is not further decomposed
|
|
* within the {@link Activity}. A {@link Activity} applies {@link IValueChange} objects at the start and end time of the
|
|
* {@link Activity}.
|
|
*
|
|
* @author Martin Smock <martin.smock@bluewin.ch>
|
|
*/
|
|
public class Action extends GroupedParameterizedElement implements IActivityElement, PolicyContainer {
|
|
|
|
protected Locator locator;
|
|
protected Activity parent;
|
|
protected String resourceId;
|
|
protected String resourceType;
|
|
protected State state;
|
|
protected PolicyDefs policyDefs;
|
|
|
|
protected List<IValueChange<? extends IValue<?>>> changes;
|
|
|
|
/**
|
|
* Empty constructor - for marshalling only!
|
|
*/
|
|
public Action() {
|
|
super();
|
|
}
|
|
|
|
public Action(String id, String name, String type) {
|
|
super(trimOrEmpty(id).intern(), trimOrEmpty(name).intern(), trimOrEmpty(type));
|
|
this.state = State.CREATED;
|
|
}
|
|
|
|
@Override
|
|
public void setId(String id) {
|
|
super.setId(trimOrEmpty(id).intern());
|
|
}
|
|
|
|
@Override
|
|
public void setName(String name) {
|
|
super.setName(trimOrEmpty(name).intern());
|
|
}
|
|
|
|
public Action(String id, String name, String type, String resourceId, String resourceType) {
|
|
super(id, name, type);
|
|
this.resourceId = resourceId;
|
|
this.resourceType = trimOrEmpty(resourceType).intern();
|
|
this.state = State.CREATED;
|
|
}
|
|
|
|
private void initChanges() {
|
|
if (this.changes == null)
|
|
this.changes = new ArrayList<>();
|
|
}
|
|
|
|
@Override
|
|
public boolean isAction() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isActivity() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return the id of the {@link Resource} the {@link Action} acts on
|
|
*/
|
|
public String getResourceId() {
|
|
return this.resourceId;
|
|
}
|
|
|
|
/**
|
|
* @param resourceId the id of the {@link Resource} the {@link Action} acts on
|
|
*/
|
|
public void setResourceId(String resourceId) {
|
|
assertNotReadonly();
|
|
this.resourceId = resourceId;
|
|
}
|
|
|
|
/**
|
|
* @return the current {@code State} of the a {@code Action}
|
|
*/
|
|
@Override
|
|
public State getState() {
|
|
return this.state;
|
|
}
|
|
|
|
/**
|
|
* @param state the target {@code State} of the a {@code Action}
|
|
*/
|
|
public void setState(State state) {
|
|
assertNotReadonly();
|
|
this.state = state;
|
|
}
|
|
|
|
/**
|
|
* @return the type of the {@code Resource} this {@code Action} acts on
|
|
*/
|
|
public String getResourceType() {
|
|
return this.resourceType;
|
|
}
|
|
|
|
/**
|
|
* @param resourceType the resource type
|
|
*/
|
|
public void setResourceType(String resourceType) {
|
|
assertNotReadonly();
|
|
this.resourceType = trimOrEmpty(resourceType).intern();
|
|
}
|
|
|
|
/**
|
|
* Sets the resource type and id from the given {@link Resource}
|
|
*
|
|
* @param resource the resource from which to get the type and id
|
|
*/
|
|
public void setResource(Resource resource) {
|
|
assertNotReadonly();
|
|
this.resourceType = resource.getType();
|
|
this.resourceId = resource.getId();
|
|
}
|
|
|
|
/**
|
|
* @deprecated use {@link #isResourceDefined()}
|
|
*/
|
|
@Deprecated
|
|
public boolean hasResourceDefined() {
|
|
return isNotEmpty(this.resourceType) && isNotEmpty(this.resourceId);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the {@link #getResourceType()} and {@link #getResourceId()} have defined values
|
|
*
|
|
* @return true if the {@link #getResourceType()} and {@link #getResourceId()} have defined values
|
|
*/
|
|
public boolean isResourceDefined() {
|
|
return isNotEmpty(this.resourceType) && isNotEmpty(this.resourceId);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link Locator} for the {@link Resource} for this action
|
|
*
|
|
* @return the {@link Locator} for the {@link Resource} for this action
|
|
*
|
|
* @throws IllegalStateException if the resource is not defined
|
|
*/
|
|
public Locator getResourceLocator() {
|
|
if (!isResourceDefined())
|
|
throw new IllegalStateException("Resource not set on " + getLocator());
|
|
return Resource.locatorFor(this.resourceType, this.resourceId);
|
|
}
|
|
|
|
/**
|
|
* Returns true if this {@link Action} contains any {@link IValueChange changes}, false if not
|
|
*
|
|
* @return true if this {@link Action} contains any {@link IValueChange changes}, false if not
|
|
*/
|
|
public boolean hasChanges() {
|
|
return this.changes != null && !this.changes.isEmpty();
|
|
}
|
|
|
|
/**
|
|
* @param change {@code IValueChange} to be applied to the {@code Resource}
|
|
*
|
|
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
|
*/
|
|
public boolean addChange(IValueChange<? extends IValue<?>> change) {
|
|
assertNotReadonly();
|
|
initChanges();
|
|
return this.changes.add(change);
|
|
}
|
|
|
|
/**
|
|
* Clears the current list of {@link IValueChange IValueChanges}
|
|
*/
|
|
public void clearChanges() {
|
|
if (this.changes != null)
|
|
this.changes.clear();
|
|
}
|
|
|
|
/**
|
|
* @return the list of {@code IValueChange} attached to the {@code Action} start
|
|
*/
|
|
public List<IValueChange<? extends IValue<?>>> getChanges() {
|
|
if (this.changes == null)
|
|
return Collections.emptyList();
|
|
return this.changes;
|
|
}
|
|
|
|
/**
|
|
* @return the iterator of {@code IValueChange} attached to the {@code Action} start
|
|
*/
|
|
public Iterator<IValueChange<? extends IValue<?>>> changesIterator() {
|
|
if (this.changes == null)
|
|
return Collections.emptyIterator();
|
|
return this.changes.iterator();
|
|
}
|
|
|
|
@Override
|
|
public Activity getParent() {
|
|
return this.parent;
|
|
}
|
|
|
|
@Override
|
|
public Activity getRootElement() {
|
|
return (this.parent == null) ? null : this.parent.getRootElement();
|
|
}
|
|
|
|
@Override
|
|
public boolean isRootElement() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Action getClone() {
|
|
Action clone = new Action();
|
|
super.fillClone(clone);
|
|
clone.resourceId = this.resourceId;
|
|
clone.resourceType = this.resourceType;
|
|
clone.state = this.state;
|
|
clone.locator = this.locator;
|
|
|
|
if (this.changes != null) {
|
|
for (IValueChange<? extends IValue<?>> change : getChanges()) {
|
|
clone.addChange(change.getClone());
|
|
}
|
|
}
|
|
|
|
if (this.policyDefs != null)
|
|
clone.policyDefs = this.policyDefs.getClone();
|
|
return clone;
|
|
}
|
|
|
|
@Override
|
|
public void setReadOnly() {
|
|
if (this.policyDefs != null)
|
|
this.policyDefs.setReadOnly();
|
|
if (this.changes != null) {
|
|
for (IValueChange<? extends IValue<?>> change : changes) {
|
|
change.setReadOnly();
|
|
}
|
|
}
|
|
super.setReadOnly();
|
|
}
|
|
|
|
@Override
|
|
public PolicyDefs getPolicyDefs() {
|
|
if (this.policyDefs == null)
|
|
throw new StrolchPolicyException(getLocator() + " has no Policies defined!");
|
|
return this.policyDefs;
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef getPolicyDef(Class<?> clazz) {
|
|
return getPolicyDefs().getPolicyDef(clazz);
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef getPolicyDef(String type) {
|
|
return getPolicyDefs().getPolicyDef(type);
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef getPolicyDef(Class<?> clazz, PolicyDef defaultDef) {
|
|
if (!hasPolicyDefs())
|
|
return defaultDef;
|
|
return getPolicyDefs().getPolicyDef(clazz, defaultDef);
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef getPolicyDef(String type, PolicyDef defaultDef) {
|
|
if (!hasPolicyDefs())
|
|
return defaultDef;
|
|
return getPolicyDefs().getPolicyDef(type, defaultDef);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasPolicyDefs() {
|
|
return this.policyDefs != null;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasPolicyDef(String type) {
|
|
return this.policyDefs != null && this.policyDefs.hasPolicyDef(type);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasPolicyDef(Class<?> clazz) {
|
|
return this.policyDefs != null && this.policyDefs.hasPolicyDef(clazz);
|
|
}
|
|
|
|
@Override
|
|
public void setPolicyDefs(PolicyDefs policyDefs) {
|
|
assertNotReadonly();
|
|
this.policyDefs = policyDefs;
|
|
this.policyDefs.setParent(this);
|
|
}
|
|
|
|
@Override
|
|
public void addOrUpdate(PolicyDef policyDef) {
|
|
assertNotReadonly();
|
|
DBC.PRE.assertNotNull("policyDef", policyDef);
|
|
if (this.policyDefs == null) {
|
|
this.policyDefs = new PolicyDefs();
|
|
this.policyDefs.setParent(this);
|
|
}
|
|
this.policyDefs.addOrUpdate(policyDef);
|
|
}
|
|
|
|
@Override
|
|
public Locator getLocator() {
|
|
if (this.locator == null) {
|
|
LocatorBuilder lb = new LocatorBuilder();
|
|
if (this.parent != null)
|
|
this.parent.fillLocator(lb);
|
|
fillLocator(lb);
|
|
this.locator = lb.build();
|
|
}
|
|
return this.locator;
|
|
}
|
|
|
|
@Override
|
|
protected void fillLocator(LocatorBuilder locatorBuilder) {
|
|
locatorBuilder.append(this.id);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null || getClass() != obj.getClass())
|
|
return false;
|
|
Action a = (Action) obj;
|
|
return this.parent == a.parent && this.type.equals(a.type) && this.id.equals(a.id);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hash(parent, type, id);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return getLocator() + ", resourceId: " + this.resourceId + ", state=" + this.state;
|
|
}
|
|
|
|
@Override
|
|
public void setParent(Activity activity) {
|
|
assertNotReadonly();
|
|
this.parent = activity;
|
|
this.locator = null;
|
|
}
|
|
|
|
@Override
|
|
public Long getStart() {
|
|
long start = Long.MAX_VALUE;
|
|
if (this.changes == null)
|
|
return start;
|
|
for (IValueChange<?> change : this.changes) {
|
|
start = Math.min(start, change.getTime());
|
|
}
|
|
return start;
|
|
}
|
|
|
|
@Override
|
|
public Long getEnd() {
|
|
long end = 0L;
|
|
if (this.changes == null)
|
|
return end;
|
|
for (IValueChange<?> change : this.changes) {
|
|
end = Math.max(end, change.getTime());
|
|
}
|
|
return end;
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findObjectivesParam(String paramKey) {
|
|
return findParameter(BAG_OBJECTIVES, paramKey);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findObjectivesParam(String paramKey, boolean assertExists) {
|
|
return findParameter(BAG_OBJECTIVES, paramKey, assertExists);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findRelationParam(String paramKey) {
|
|
return findParameter(BAG_RELATIONS, paramKey);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findRelationParam(String paramKey, boolean assertExists) {
|
|
return findParameter(BAG_RELATIONS, paramKey, assertExists);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findParameter(String paramKey) {
|
|
return findParameter(BAG_PARAMETERS, paramKey);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findParameter(String paramKey, boolean assertExists) {
|
|
return findParameter(BAG_PARAMETERS, paramKey, assertExists);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findParameter(String bagKey, String paramKey) {
|
|
|
|
T parameter = getParameter(bagKey, paramKey);
|
|
if (parameter != null)
|
|
return parameter;
|
|
|
|
return this.parent.findParameter(bagKey, paramKey);
|
|
}
|
|
|
|
@Override
|
|
public <U, T extends Parameter<U>> T findParameter(String bagKey, String paramKey, boolean assertExists)
|
|
throws StrolchModelException {
|
|
|
|
T parameter = getParameter(bagKey, paramKey);
|
|
if (parameter != null)
|
|
return parameter;
|
|
|
|
parameter = this.parent == null ? null : this.parent.findParameter(bagKey, paramKey);
|
|
if (assertExists && parameter == null) {
|
|
String msg = "The Parameter {0} does not exist";
|
|
throw new StrolchModelException(MessageFormat.format(msg, getLocator().append(Tags.BAG, bagKey, paramKey)));
|
|
}
|
|
|
|
return parameter;
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef findPolicy(Class<?> clazz, PolicyDef defaultDef) throws StrolchModelException {
|
|
return findPolicy(clazz.getSimpleName(), defaultDef);
|
|
}
|
|
|
|
@Override
|
|
public PolicyDef findPolicy(String className, PolicyDef defaultDef) throws StrolchModelException {
|
|
if (hasPolicyDef(className))
|
|
return getPolicyDef(className);
|
|
|
|
if (this.parent == null) {
|
|
if (defaultDef != null)
|
|
return defaultDef;
|
|
|
|
String msg = "The PolicyDef {0} does not exist";
|
|
throw new StrolchModelException(MessageFormat.format(msg, className));
|
|
}
|
|
|
|
return this.parent.findPolicy(className, defaultDef);
|
|
}
|
|
|
|
@Override
|
|
public <T> T accept(StrolchElementVisitor<T> visitor) {
|
|
return visitor.visitAction(this);
|
|
}
|
|
}
|