public enum Code {
    SUCCESS(0),
    INTERNAL_ERROR(100),
    NO_AVAILABLE_AGENT(101),
    NO_RESPONSE_FROM_AGENT(102),
    INVALID_RESPONSE_FROM_AGENT(103),
    AGENT_DID_NOT_UNDERSTAND_REQUEST(200),
    AGENT_DID_NOT_KNOW_ANSWER(201),
    AGENT_CANNOT_COMPLETE_ACTION(202),
    AGENT_INTERNAL_ERROR(203);

    private final int code;
    private Code(int code) {
        this.code = code;
    }

    /**
     * Get the value of the code
     *
     * @return the value
     */
    public int getValue() {
        return code;
    }

    /**
     * Get a Code enum member from an integer value
     *
     * @param value  the integer value
     * @return Code enum member
     */
    public static Code fromValue(int value) {
        for (Code code : Code.values()) {
            if (code.getValue() == value) {
                return code;
            }
        }
        return null;
    }
} public interface Agent {

    /**
     * Get the name of the agent
     *
     * @return name
     */
    public String getName();

    /**
     * Override the default name of the agent
     *
     * @param name  New name for the agent
     */
    public void setName(String name);

    /**
     * Get the description of the agent for human consumption
     *
     * @return Description of the agent
     */
    public Description getDescription();

    /**
     * Override the default description
     *
     * @param description  Description of the agent
     * @see Description
     */
    public void setDescription(Description description);
    
    /**
     * Process a request
     *
     * @param request  Request object
     * @return response to the request
     */
    public AgentResponse process(AgentRequest request);
} public class AgentRequest {
    private String text;
    private User user;

    public AgentRequest() {}
    
    /**
     * Create an agent request
     *
     * @param request  the request
     *
     */
    public AgentRequest(Request request) {
        this.text = request.getText();
        this.user = request.getUser();
    }

    /**
     * Create an agent request
     *
     * @param text  the text of the request
     */
    public AgentRequest(String text) {
        this.text = text;
    }
    
    /**
     * Create an agent request
     *
     * @param text  the text of the request
     * @param user  the User information
     *
     */
    public AgentRequest(String text, User user) {
        this.text = text;
        this.user = user;
    }


    /**
     * Set the text of the request
     *
     * @param text  the text of the request
     */
    public void setText(String text) {
        this.text = text;
    }

    /**
     * Get the text of the request
     *
     * @return the text of the request
     */
    public String getText() {
        return text;
    }
    
    /**
     * Get the user of the request
     *
     * @return the user of the request
     */
    public User getUser() {
        return user;
    }

    /**
     * Set the user of the request
     *
     * @param user  the user of the request
     */
    public void setUser(User user) {
        this.user = user;
    }
} public class AgentResponse {
    private final Response.Type type;
    private final String text;
    private final String payload;
    private final ResponseStatus status;

    /**
     * Create an agent response
     *
     * @param text  the text of the response
     */
    public AgentResponse(String text) {
        this.type = Response.Type.TEXT;
        this.text = text;
        this.payload = null;
        this.status = ResponseStatus.createSuccess();
    }

    /**
     * Create an agent response with payload
     *
     * @param type  the response type
     * @param text  the text of the response
     * @param payload  the payload of the response
     */
    public AgentResponse(Response.Type type, String text, String payload) {
        this.type = type;
        this.text = text;
        this.payload = payload;
        this.status = ResponseStatus.createSuccess();
    }

    /**
     * Create an agent response for an error
     *
     * @param code  the status code
     */
    public AgentResponse(ResponseStatus.Code code) {
        this.type = Response.Type.ERROR;
        this.text = null;
        this.payload = null;
        this.status = new ResponseStatus(code);
    }

    /**
     * Create an agent response for an error with custom message
     *
     * @param status  the status of the response
     */
    public AgentResponse(ResponseStatus status) {
        this.type = Response.Type.ERROR;
        this.text = null;
        this.payload = null;
        this.status = status;
    }

    /**
     * Get the response type
     *
     * @return the response type
     */
    public Response.Type getType() {
        return type;
    }

    /**
     * Get the text of the response
     *
     * @return text of the response
     */
    public String getText() {
        return text;
    }

    /**
     * Get the payload of the response
     * <p>
     * The payload data varies according to the response type
     *
     * @return payload string or null if no payload
     */
    public String getPayload() {
        return payload;
    }

    /**
     * Get the status
     *
     * @return the status code
     */
    public ResponseStatus getStatus() {
        return status;
    }

    /**
     * Is this a successful response?
     *
     * @return true if success
     */
    public boolean isSuccess() {
        return status.isSuccess();
    }

    /**
     * Is this a valid response?
     *
     * @return true if valid
     */
    public boolean isValid() {
        if (type == null || status == null) { 
            return false;
        }
        if (Response.Type.usesPayload(type) && payload == null) {
            return false;
        }
        return !(isSuccess() && text == null);
    }
} public interface RequestFilter {

    /**
     * Filter the request object
     *
     * @param request  current request object
     * @return filtered request object
     */
    public Request filter(Request request);

} public interface ResponseFilter {

    /**
     * Filter the response object
     *
     * @param response  current response object
     * @return filtered response object
     */
    public Response filter(Response response);

} public class NullReporter implements Reporter {

    @Override
    public void store(Report report) {
    }

    @Override
    public Report[] retrieve(ReportQuery query) {
        return new Report[0];
    }

} public class Report {
    public static final int NO_RESPONSE = -1;

    protected Date timestamp;
    protected String requestId;
    protected String requestText;
    protected String agentName;
    protected String responseText;
    protected int responseCode;
    protected long routeTime;
    protected long agentTime;

    /**
     * Default zero argument constructor to support usage as bean
     * <p>
     * For bean usage only
     */
    public Report() {}

    /**
     * Record of handling a request
     *
     * @param request  Request object
     */
    public Report(Request request) {
        timestamp = new Date();
        requestId = request.getId();
        requestText = request.getText();
        routeTime = 0;
        agentTime = 0;
        agentName = "";
        responseText = "";
        responseCode = NO_RESPONSE;
    }

    /**
     * Copy constructor
     *
     * @param report  the report to copy
     */
    public Report(Report report) {
        timestamp = report.timestamp;
        requestId = report.requestId;
        requestText = report.requestText;
        agentName = report.agentName;
        responseText = report.responseText;
        responseCode = report.responseCode;
        routeTime = report.routeTime;
        agentTime = report.agentTime;
    }

    /**
     * Set the request identifier
     * <p>
     * For bean use only
     *
     * @param id  request identifier
     */
    public void setRequestId(String id) {
        requestId = id;
    }

    /**
     * Get the request identifier
     *
     * @return request identifier
     * @see Request#MAX_ID_LENGTH length limitation of identifier
     */
    public String getRequestId() {
        return requestId;
    }

    /**
     * Set the request text
     * <p>
     * For bean use only
     *
     * @param text  request text
     */
    public void setRequestText(String text) {
        requestText = text;
    }

    /**
     * Get the text of the request
     *
     * @return text of the request
     */
    public String getRequestText() {
        return requestText;
    }

    /**
     * Set the length of time that the routing took
     * <p>
     * Use System.nanoTime() to get the start and stop times.
     * 
     * @param start  The time the routing started
     * @param stop  The time the routing stopped
     */
    public void setRouteTime(long start, long stop) {
        routeTime = stop - start;
    }

    /**
     * Set the length of time that the routing took
     *
     * @param time  The length of time for the routing 
     */
    public void setRouteTime(long time) {
        routeTime = time;
    }

    /**
     * Get the length of time that the routing took
     *
     * @return time in nano-seconds
     */
    public long getRouteTime() {
        return routeTime;
    }

    /**
     * Set the length of time the agent took to handle the request
     * <p>
     * Use System.nanoTime() to get the start and stop times.
     *
     * @param start  The time the agent started
     * @param stop  The time the agent stopped
     */
    public void setAgentTime(long start, long stop) {
        agentTime = stop - start;
    }

    /**
     * Set the length of time that the agent took
     *
     * @param time  The length of time for agent processing 
     */
    public void setAgentTime(long time) {
        agentTime = time;
    }

    /**
     * Get the length of time the agent took to handle the request
     *
     * @return time in nano-seconds
     */
    public long getAgentTime() {
        return agentTime;
    }

    /**
     * Set the agent that handled the request
     *
     * @param agent  Agent object
     */
    public void setAgent(Agent agent) {
        agentName = agent.getName();
    }

    /**
     * Set the agent name that handled the request
     *
     * @param name  the name of the agent
     */
    public void setAgentName(String name) {
        agentName = name;
    }

    /**
     * Get the agent that handled the request
     *
     * @return name of the agent
     */
    public String getAgentName() {
        return agentName;
    }

    /**
     * Set the text of the response
     *
     * @param response  Response object
     */
    public void setResponse(Response response) {
        if (response.getText() != null) {
            responseText = response.getText();
        }
        responseCode = response.getStatus().getCode().getValue();
    }

    /**
     * Set the text of the response
     *
     * @param text  Text of the response
     */
    public void setResponseText(String text) {
        responseText = text;
    }

    /**
     * Get the text of the response
     *
     * @return text of the response
     */
    public String getResponseText() {
        return responseText;
    }

    /**
     * Set the response code
     *
     * @param code  response code
     */
    public void setResponseCode(int code) {
        responseCode = code;
    }

    /**
     * Get the response code
     *
     * @return response code or -1 if not set
     */
    public int getResponseCode() {
        return responseCode;
    }

    /**
     * Set the timestamp of the report
     * <p>
     * For bean use only
     *
     * @param ts  time of the request being received
     */
    public void setTimestamp(Date ts) {
        timestamp = new Date(ts.getTime());
    }

    /**
     * Get the timestamp of the report
     *
     * @return Date of the report
     */
    public Date getTimestamp() {
        return new Date(timestamp.getTime());
    }
} public interface Reporter {

    /**
     * Store a report
     *
     * @param report  The report to store
     */
    public void store(Report report);

    /**
     * Retrieve reports
     *
     * @param query  Query object
     * @return Array of reports
     */
    public Report[] retrieve(ReportQuery query);
} public interface Router {

    /**
     * Get an array of agents to send the request to
     *
     * @param request  the request object
     * @return array of agents (empty array if no agent found)
     */
    public Agent[] route(Request request);

    /**
     * Get an array of the agents for this router
     *
     * @return array of agents
     */
    public Agent[] getAgents();
} public class User {

    public static String ID = "Dorset-id";
    public static String USERNAME = "Dorset-userName";
    public static String FIRSTNAME = "Dorset-firstName";
    public static String LASTNAME = "Dorset-lastName";
    public static String LOCATION = "Dorset-location";
    public static String EMAIL = "Dorset-email";
    public static String DOB = "Dorset-dob";

    protected Map<String, String> userInformation = new HashMap<String, String>();

    public String getId() {
        return userInformation.get(ID);
    }

    public void setId(String id) {
        this.setUserInformation(ID, id);
    }

    public String getUserName() {
        return userInformation.get(USERNAME);
    }

    public void setUserName(String userName) {
        this.setUserInformation(USERNAME, userName);
    }

    public String getFirstName() {
        return userInformation.get(FIRSTNAME);
    }

    public void setFirstName(String firstName) {
        this.setUserInformation(FIRSTNAME, firstName);
    }

    public String getLastName() {
        return userInformation.get(LASTNAME);
    }

    public void setLastName(String lastName) {
        this.setUserInformation(LASTNAME, lastName);
    }

    public String getLocation() {
        return userInformation.get(LOCATION);
    }

    public void setLocation(String location) {
        this.setUserInformation(LOCATION, location);
    }

    public String getEmail() {
        return userInformation.get(EMAIL);
    }

    public void setEmail(String email) {
        this.setUserInformation(EMAIL, email);
    }

    public String getDob() {
        return userInformation.get(DOB);
    }

    public void setDob(String dob) {
        this.setUserInformation(DOB, dob);
    }

    public void setUserInformation(String key, String value) {
        userInformation.put(key, value);
    }

    public String getUserInformation(String key) {
        return userInformation.get(key);
    }

    public Set<String> getUserInformationKeys() {
        return userInformation.keySet();
    }
    
    public void removeUserInformation(String key) {
        userInformation.remove(key);
    }
}
import edu.jhuapl.dorset.reporting.Reporter;
import edu.jhuapl.dorset.routing.Router;
import edu.jhuapl.dorset.users.User;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.jhuapl.dorset.ResponseStatus.Code;
import edu.jhuapl.dorset.agents.Agent;
import edu.jhuapl.dorset.agents.AgentRequest;
import edu.jhuapl.dorset.agents.AgentResponse;
import edu.jhuapl.dorset.filters.RequestFilter;
import edu.jhuapl.dorset.filters.ResponseFilter;
import edu.jhuapl.dorset.reporting.NullReporter;
import edu.jhuapl.dorset.reporting.Report;
/*
 * Copyright 2016 The Johns Hopkins University Applied Physics Laboratory LLC
 * All rights reserved.
 *
 * 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 edu.jhuapl.dorset;




/**
 * Dorset Application
 * <p>
 * The application manages the state of the Dorset framework. An application
 * processes requests and returns responses. The requests are handled by agents.
 * A router determines which agent handles a request. Each request-response
 * cycle can be stored as a report for further analysis.
 *
 * A basic application has at least one agent, a router, and methods for getting
 * requests and sending responses:
 * 
 * <pre>
 * Agent agent = new CalculatorAgent();
 * Router router = new SingleAgentRouter(agent);
 * Application app = new Application(router);
 * 
 * while (true) {
 *     Request request = yourMethodToGetRequests();
 *     Response response = app.process(request);
 *     yourMethodToSendResponse(response);
 * }
 * </pre>
 */
public class Application {
    private final Logger logger = LoggerFactory.getLogger(Application.class);

    protected Agent[] agents;
    protected Router router;
    protected Reporter reporter;