All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.uni.freiburg.iig.telematik.sepia.petrinet.abstr.AbstractPlace Maven / Gradle / Ivy

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 AbstractTransition, S> incoming : incomingRelations) { if (!this.containsRelationFrom(incoming.getTransition())) return false; } for (AbstractFlowRelation, ? 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 AbstractTransition, S> r : outgoingRelations.values()) { r.getTransition().checkState(); } for (AbstractFlowRelation, ? 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