strolch/model/src/main/java/li/strolch/model/activity/Action.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);
}
}