de.uni.freiburg.iig.telematik.sepia.petrinet.abstr.AbstractPlace Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SEPIA Show documentation
Show all versions of SEPIA Show documentation
SEPIA provides implementations for various types of Petri nets. Along Place/Transition-nets, it supports Petri nets with distinguishable token colors and defines coloured workflow nets, where coloured tokens are interpreted as data elements used during process execution. To support information flow analysis of processes, SEPIA defines so-called IF-Nets, tailored for security-oriented workflow modeling which enable users to assign security-levels (HIGH, LOW) to transitions, data elements and persons/agents participating in the process execution.
The newest version!
package de.uni.freiburg.iig.telematik.sepia.petrinet.abstr;
import java.io.Serializable;
import java.util.List;
import de.invation.code.toval.validate.ParameterException;
import de.invation.code.toval.validate.Validate;
import de.uni.freiburg.iig.telematik.sepia.event.CapacityEvent;
import de.uni.freiburg.iig.telematik.sepia.event.PlaceListener;
import de.uni.freiburg.iig.telematik.sepia.event.PlaceListenerSupport;
import de.uni.freiburg.iig.telematik.sepia.event.TokenListener;
import de.uni.freiburg.iig.telematik.sepia.event.TokenListenerSupport;
import de.uni.freiburg.iig.telematik.sepia.exception.PNValidationException;
/**
* Abstract class that defines general properties for Petri net places.
* This class inherits basic Petri net node properties from {@link AbstractPNNode}
* and defines additional properties:
*
* - Capacity: The maximum number of tokens that can reside in the place.
* A capacity of -1 is interpreted as unboundedness, i.e. the number and kind of tokens is not restricted.
*
*
* A place maintains a state of type S, which defines the number and kind of tokens in the place.
* The type S is used for the internal state of the place and for adding and removing tokens from the place. A place allows {@link TokenListener}s to register so that they can be notified on state changes,
* i.e. added/removed tokens.
*
* @author Thomas Stocker
*
* @param
* The type of flow relations connected to the place.
* @param
* Type for token number and type.
*/
public abstract class AbstractPlace,
? extends AbstractTransition, S>,
S extends Object>
extends AbstractPNNode implements Serializable{
private static final long serialVersionUID = -4942014250666222432L;
/**
* Support class for {@link TokenListener} handling.
*/
protected TokenListenerSupport> tokenListenerSupport = new TokenListenerSupport>();
/**
* Support class for {@link PlaceListener} handling.
*/
protected PlaceListenerSupport> placeListenerSupport = new PlaceListenerSupport>();
/**
* Capacity of the place, i.e. the maximum number of tokens the place can hold.
* A capacity of -1 is interpreted as unboundedness, i.e. the number and kind of tokens is not restricted.
*/
protected int capacity = -1;
/**
* The state of the place, i.e. the number and kind of tokens that reside in the place.
*/
protected S state = null;
// ------- Constructors --------------------------------------------------------------------------
// protected AbstractPlace() {
// super(PNNodeType.PLACE);
// }
/**
* Creates a new place with the given name.
* @param name The name for the new Place.
* @throws ParameterException If the given name is null
.
*/
public AbstractPlace(String name){
super(PNNodeType.PLACE, name);
}
/**
* Creates a new place with the given name and label.
*
* @param name
* The name for the new place.
* @param label
* The label for the new place.
*/
public AbstractPlace(String name, String label){
super(PNNodeType.PLACE, name, label);
}
// ------- Basic properties -----------------------------------------------------------------------
/**
* Returns the capacity of the place, i.e.
* the maximum number of tokens the place can hold.
*
* @return The capacity of the place.
*/
public int getCapacity() {
return capacity;
}
/**
* Sets the capacity of the place, i.e.
* the maximum number of tokens the place can hold.
* The capacity must be > 0.
*
* @param capacity
* The desired capacity.
*/
public void setCapacity(int capacity){
Validate.bigger(capacity, 0);
int oldCapacity = this.capacity;
this.capacity = capacity;
if (oldCapacity != capacity)
placeListenerSupport.notifyCapacityChanged(new CapacityEvent>(this, capacity));
}
/**
* Removes the capacity restriction of the place, i.e.
* the maximum number of tokens the place can hold.
*/
public void removeCapacity() {
capacity = -1;
}
/**
* Checks, if the place is bounded.
* Bounded places restrict the number and kind of tokens that can reside in the place.
* A capacity of -1 is interpreted as unboundedness.
*
* @return true
if the place is bounded,
* false
otherwise.
*/
public boolean isBounded() {
return getCapacity() > -1;
}
/**
* checks if this place and the given place have the same relations.
*
* @param otherPlace
* The place in question.
* @return true
if the two places have the same relations;
* false
otherwise.
*/
public boolean hasEqualRelations(AbstractPlace otherPlace){
Validate.notNull(otherPlace);
List incomingRelations = otherPlace.getIncomingRelations();
List outgoingRelations = otherPlace.getOutgoingRelations();
if ((this.incomingRelations.size() != incomingRelations.size()) || (this.outgoingRelations.size() != outgoingRelations.size())) {
return false;
}
for (AbstractFlowRelation extends AbstractPlace, ? extends AbstractTransition, S> incoming : incomingRelations) {
if (!this.containsRelationFrom(incoming.getTransition()))
return false;
}
for (AbstractFlowRelation extends AbstractPlace, ? extends AbstractTransition, S> outgoing : outgoingRelations) {
if (!this.containsRelationTo(outgoing.getTransition()))
return false;
}
return true;
}
// @Override
// protected void setName(String name){
// Validate.notNull(name);
// if(!placeListenerSupport.requestNameChangePermission(this, name))
// throw new ParameterException(ErrorCode.INCONSISTENCY, "A connected Petri net already contains a node with this name.\n Cancel renaming to avoid name clash.");
// this.name = name;
// }
public int outDegree(){
return getOutgoingRelations().size();
}
public int inDegree(){
return getIncomingRelations().size();
}
// ------- State manipulation -----------------------------------------------------------------------------
/**
* Returns the state of the place in terms of number and kind of tokens.
* The returned state should NOT be used to manually add or remove tokens from a place.
* Token adding/removal is done by Petri net transitions.
*
* @return The actual state of the place.
* @see AbstractPlace#state
*/
public abstract S getState();
/**
* Sets the state of the place in terms of number and kind of tokens if the place is not already in this state.
* Before the state is set, its validity is checked with the help of {@link #validateState(Object)}.
* On state changes, the place tells connected transitions to update their state
* and calls the method {@link #stateChange(Object, Object)} which can be
* overridden in subclasses to take further actions on state changes.
*
* @param state
* The desired state of the place.
* @return true
if the actual place state was changed to the given state;
* false
if the place is already in the given state.
* @see #initiateStateChecks()
*/
public boolean setState(S state){
validateState(state);
if (this.state.equals(state))
return false;
S oldState = this.state;
this.state = state;
// Tell outgoing transitions to update their state.
initiateStateChecks();
// Call state-change method
stateChange(oldState, state);
return true;
}
/**
* Adds all given tokens to the place.
* The number and type of tokens to add are defined by type S.
*
* @param tokens
* The number and type of tokens to add.
* @throws ParameterException
* If the given parameter is null
or invalid,
* or if the tokens cannot be added to the place, e.g. due to capacity restrictions.
*/
protected abstract void addTokens(S tokens);
/**
* Removes all given tokens from the place.
* The number and type of tokens to remove are defined by type S.
*
* @param tokens
* The number and type of tokens to remove.
* @throws ParameterException
* If the given parameter is null
or invalid,
* or if the tokens cannot be removed from the place.
*/
protected abstract void removeTokens(S tokens);
/**
* Checks, if the place can consume the given state, i.e.
* merging the actual state and the given state does not exceed the places' capacity.
* This method does NOT actually "add" the given state to the places' actual state.
*
* @param state
* The state to merge.
* @return true
if the place can consume the state;
* false
otherwise.
* @throws ParameterException
* if the given state is null
.
*/
public abstract boolean canConsume(S state);
/**
* Checks if the place state is empty, i.e. the place contains no tokens.
* Depending on the state representation this may require different check routines,
* which have to be implemented by subclasses.
*
* @return true
if the place contains not tokens;
* false
otherwise.
*/
public abstract boolean hasEmptyState();
/**
* Sets the state of the place in empty condition, i.e. removes all tokens from the place.
* Depending on the state representation this may require different check routines,
* which have to be implemented by subclasses.
* @see #getEmptyState()
*/
public boolean setEmptyState(){
S emptyState = getEmptyState();
if(getState().equals(emptyState))
return false;
S oldState = getState();
this.state = emptyState;
// Tell outgoing transitions to update their state.
initiateStateChecks();
// Call state-change method
stateChange(oldState, emptyState);
return true;
}
/**
* Gets the state of the place in empty condition.
*/
public abstract S getEmptyState();
/**
* This method is called by {@link #setState(Object)} in case of state changes.
* It can be overridden in subclasses to take further actions on state changes.
*
* @param oldState
* Old place state before change.
* @param newState
* New place state after change.
*/
protected abstract void stateChange(S oldState, S newState);
/**
* Tells outgoing transitions to update their state.
* Depending on token changes outgoing transitions may get enabled/disabled.
*/
protected void initiateStateChecks() {
for (AbstractFlowRelation extends AbstractPlace, ? extends AbstractTransition, S> r : outgoingRelations.values()) {
r.getTransition().checkState();
}
for (AbstractFlowRelation extends AbstractPlace, ? extends AbstractTransition, S> r : incomingRelations.values()) {
r.getTransition().checkState();
}
}
// ------- Validity -------------------------------------------------------------------------------
/**
* Checks if the Petri net place is valid.
* Subclasses may define the validity of a net place e.g. in terms of specific constraints and must throw PNValidationExceptions in case any constraint is violated.
*
* @throws PNValidationException
*/
public void checkValidity() throws PNValidationException {}
// ------- Validation methods ----------------------------------------------------------------------
/**
* Checks if the given state is valid.
* The exact definition of validity can be defined in subclasses by overriding this method.
* Default behavior is to check null
-pointers.
*
* @param state
* The state to validate.
* @throws ParameterException
* If the given state is null
.
*/
protected void validateState(S state){
Validate.notNull(state);
}
// ------- Listener support -----------------------------------------------------------------------
/**
* Adds a token listener.
*
* @param l
* The token listener to add.
* @throws ParameterException
* If the listener reference is null
.
*/
public void addTokenListener(TokenListener> l){
tokenListenerSupport.addListener(l);
}
/**
* Removes a token listener.
*
* @param l
* The token listener to remove.
* @throws ParameterException
* If the listener reference is null
.
*/
public void removeTokenListener(TokenListener> l){
tokenListenerSupport.removeListener(l);
}
/**
* Adds a capacity listener.
* @param l The capacity listener to add.
* @throws ParameterException If the listener reference is null
.
*/
public void addPlaceListener(PlaceListener> l){
placeListenerSupport.addListener(l);
}
/**
* Removes a capacity listener.
* @param l The capacity listener to remove.
* @throws ParameterException If the listener reference is null
.
*/
public void removePlaceListener(PlaceListener> l){
placeListenerSupport.removeListener(l);
}
@Override
protected abstract AbstractPlace newInstance(String name);
// ------- hashCode and equals --------------------------------------------------------------------
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + capacity;
result = prime * result + ((state == null) ? 0 : state.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
@SuppressWarnings("unchecked")
AbstractPlace other = (AbstractPlace) obj;
if (capacity != other.capacity) {
return false;
}
if (state == null) {
if (other.state != null) {
return false;
}
} else if (!state.equals(other.state)) {
return false;
}
return true;
}
// ------- clone ----------------------------------------------------------------------------------
@Override
public AbstractPlace clone() {
@SuppressWarnings("unchecked")
AbstractPlace result = (AbstractPlace) super.clone();
cloneCapacity(result);
result.setState(getState());
return result;
}
protected void cloneCapacity(AbstractPlace clone){
if (getCapacity() > 0)
clone.setCapacity(getCapacity());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy