/*
* The MIT License
*
* Copyright 2015 Tim Boudreau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.mastfrog.acteurbase;
import java.util.Arrays;
/**
* Base class for State objects for AbstractActeurs
*
* @see AbstractActeur
* @param <T> The public type
* @param <R> The implementation type
*/
public class ActeurState<T, R extends T> {
private final Object[] context;
private final boolean rejected;
AbstractActeur<T, R, ?> acteur;
protected Throwable creationStackTrace;
private ActeurState(boolean rejected, Object... context) {
this.context = context;
this.rejected = rejected;
boolean asserts = false;
assert asserts = true;
if (asserts) {
creationStackTrace = new Throwable();
}
}
/**
* Create a state with the passed objects available for injection into
* subsequent acteurs in a chain.
*
* @param context Objects for injection to be passed between acteurs. The
* types of these need to be bound with Guice in the scope used with chains.
*/
public ActeurState(Object... context) {
this(false, context);
}
/**
* Create a state with no context objects which either rejects or finishes
* the chain.
*
* @param rejected If true, the acteur producing this state will be the last
* one executed on this chain
*/
public ActeurState(boolean rejected) {
this(rejected, (Object[]) null);
}
/**
* Determine if this state is a rejection of the input - meaning that
* subsequent acteurs should not be created/invoked.
*
* @return Whether or not it is rejected
*/
protected boolean isRejected() {
return rejected;
}
/**
* Any context objects this state makes available to subsequent acteurs in
* the chain. May return null if not set.
*
* @return An array of objects or null
*/
protected Object[] context() {
return context;
}
/**
* Get the acteur that produced this state.
* @return the acteur, never null
*/
protected AbstractActeur<T, R, ?> getActeur() {
return acteur;
}
/**
* Determines if this state indicates successful conclusion of the
* work of the chain of acteurs that produced it.
*
* @return true if the {@link ActeurResponseFactory} associated with the
* producing {@link AbstractActeur} says that the response object's state
* indicates it is finished.
*/
public boolean isFinished() {
AbstractActeur<T, R, ?> acteur = getActeur();
if (getActeur() == null) {
IllegalStateException ex = new IllegalStateException(getClass().getName() + " does not have its acteur set");
if (creationStackTrace != null) {
ex.initCause(creationStackTrace);
}
ex.printStackTrace();
throw ex;
}
R r = getActeur().getResponse();
return r != null && getActeur().factory.isFinished(r);
}
/**
* Get the response object, if it has been created and if the
* {@link ActeurResponseFactory} says it has been modified.
*
* @return the response object or null
*/
R response() {
R r = getActeur().getResponse();
return r != null && getActeur().factory.isModified(r) ? r : null;
}
public String toString() {
return getClass().getName() + " rej? " + rejected + " for " + getActeur() + " with " + (context == null ? " (none0)" : Arrays.asList(context).toString());
}
}