org.openhim.mediator.engine.MediatorRequestHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.openhim.mediator.engine.MediatorRequestHandler.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.openhim.mediator.engine;

import akka.actor.*;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.apache.http.HttpStatus;
import org.openhim.mediator.engine.messages.*;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * <p>The request handler actor launched whenever a request is received.
 * Handles the routing based on the configured RoutingTable and handles the response finalization.</p>
 * <p>
 * Messages supported:
 * <ul>
 * <li>FinishRequestMessage</li>
 * <li>ExceptErrorMessage</li>
 * <li>AcceptedAsyncRequest</li>
 * <li>AddOrchestrationToCoreResponseMessage</li>
 * <li>PutPropertyInCoreResponse</li>
 * </ul>
 * </p>
 *
 * @see RoutingTable
 */
public class MediatorRequestHandler extends UntypedActor {

    public static final String OPENHIM_MIME_TYPE = "application/json+openhim";

    LoggingAdapter log = Logging.getLogger(getContext().system(), this);

    protected ActorRef requestCaller;
    protected CoreResponse response = new CoreResponse();
    protected String coreTransactionID;
    protected boolean async = false;
    //finalizingRequest becomes true as soon as we "respondAndEnd()"
    protected boolean finalizingRequest = false;

    protected final MediatorConfig config;

    public MediatorRequestHandler(MediatorConfig config) {
        this.config = config;

        try {
            if (config.getRegistrationConfig() != null) {
                response.setUrn(config.getRegistrationConfig().getURN());
            }
        } catch (RegistrationConfig.InvalidRegistrationContentException ex) {
            log.error(ex, "Could not read URN");
            log.warning("'x-mediator-urn' will not be included in the mediator response");
        }
    }

    private void routeToActor(Class<? extends Actor> clazz, MediatorHTTPRequest request) {
        ActorRef actor = null;
        try {
            //can we pass the mediator config through?
            if (clazz.getConstructor(MediatorConfig.class) != null) {
                actor = getContext().actorOf(Props.create(clazz, config));
            }
        } catch (NoSuchMethodException | SecurityException ex) {
            //no matter. use default
            actor = getContext().actorOf(Props.create(clazz));
        }

        actor.tell(request, getSelf());
    }

    private void routeRequest(MediatorHTTPRequest request) {
        log.info("Received request: " + request.getMethod() + " " + request.getPath());

        Class<? extends Actor> routeTo = config.getRoutingTable().getActorClassForPath(request.getPath());
        if (routeTo != null) {
            routeToActor(routeTo, request);
        } else {
            CoreResponse.Response resp = new CoreResponse.Response();
            resp.setStatus(HttpStatus.SC_NOT_FOUND);
            resp.setBody(request.getPath() + " not found");
            resp.putHeader("Content-Type", "text/plain");
            response.setResponse(resp);
            respondAndEnd(HttpStatus.SC_NOT_FOUND);
        }
    }

    private void enableAsyncProcessing() {
        if (coreTransactionID == null || coreTransactionID.isEmpty()) {
            exceptError(new RuntimeException(
                    "Cannot enable asynchronous processing if X-OpenHIM-TransactionID is unknown"));
            return;
        }

        log.info("Accepted async request. Responding to client.");
        async = true;

        //store existing response
        CoreResponse.Response _resp = response.getResponse();

        //respond with 202
        CoreResponse.Response accepted = new CoreResponse.Response();
        accepted.setStatus(HttpStatus.SC_ACCEPTED);
        accepted.setBody("Accepted request");
        response.setResponse(accepted);

        respondToCaller(HttpStatus.SC_ACCEPTED);

        //restore response
        response.setResponse(_resp);
    }

    private void processFinishRequestMessage(FinishRequest msg) {
        if (response.getResponse() == null) {
            CoreResponse.Response resp = new CoreResponse.Response();
            resp.setBody(msg.getResponse());
            if (msg.getResponseMimeType() != null) {
                resp.putHeader("Content-Type", msg.getResponseMimeType());
            }
            resp.setStatus(msg.getResponseStatus());
            response.setResponse(resp);
        }
        respondAndEnd(msg.getResponseStatus());
    }

    private void exceptError(Throwable t) {
        log.error(t, "Exception while processing request");

        if (response.getResponse() == null) {
            CoreResponse.Response resp = new CoreResponse.Response();
            resp.setBody(t.getMessage());
            resp.putHeader("Content-Type", "text/plain");
            resp.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
            response.setResponse(resp);
        }
        respondAndEnd(HttpStatus.SC_INTERNAL_SERVER_ERROR);
    }

    private void updateTransactionToCoreAPI() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");

        MediatorHTTPRequest request = new MediatorHTTPRequest(getSelf(), getSelf(), "core-api-update-transaction",
                "PUT", "https", config.getCoreHost(), config.getCoreAPIPort(), "/transactions/" + coreTransactionID,
                response.toJSON(), headers, null);

        log.info("Sending updated transaction (" + coreTransactionID + ") to core");
        ActorSelection coreConnector = getContext().actorSelection(config.userPathFor("core-api-connector"));
        coreConnector.tell(request, getSelf());
    }

    private void processResponseFromCoreAPI(MediatorHTTPResponse response) {
        try {
            log.info("Received response from core - status " + response.getStatusCode());
            log.info(response.getBody());
        } finally {
            endRequest();
        }
    }

    private void respondAndEnd(Integer status) {
        if (finalizingRequest) {
            return;
        }

        finalizingRequest = true;

        if (async) {
            updateTransactionToCoreAPI();
        } else {
            try {
                respondToCaller(status);
            } finally {
                endRequest();
            }
        }
    }

    private void respondToCaller(Integer status) {
        if (requestCaller != null) {
            if (response.getStatus() == null) {
                response.setStatus(response.getDescriptiveStatus());
            }

            Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
            headers.put("Content-Type", OPENHIM_MIME_TYPE);

            MediatorHTTPResponse serverResponse = new MediatorHTTPResponse(null, response.toJSON(), status,
                    headers);
            requestCaller.tell(serverResponse, getSelf());
            requestCaller = null;
        } else {
            log.warning("FinishRequestMessage received but request caller is gone");
        }
    }

    /**
     * To be called when the request handler is all done
     */
    private void endRequest() {
        getContext().stop(getSelf());
    }

    @Override
    public void onReceive(Object msg) throws Exception {
        if (msg instanceof MediatorHTTPRequest) {
            requestCaller = getSender();
            coreTransactionID = ((MediatorHTTPRequest) msg).getHeaders().get("X-OpenHIM-TransactionID");
            routeRequest((MediatorHTTPRequest) msg);
        } else if (msg instanceof AcceptedAsyncRequest) {
            enableAsyncProcessing();
        } else if (msg instanceof FinishRequest) {
            processFinishRequestMessage((FinishRequest) msg);
        } else if (msg instanceof ExceptError) {
            exceptError(((ExceptError) msg).getError());
        } else if (msg instanceof AddOrchestrationToCoreResponse) {
            if (!finalizingRequest) {
                response.addOrchestration(((AddOrchestrationToCoreResponse) msg).getOrchestration());
            }
        } else if (msg instanceof PutPropertyInCoreResponse) {
            if (!finalizingRequest) {
                response.putProperty(((PutPropertyInCoreResponse) msg).getName(),
                        ((PutPropertyInCoreResponse) msg).getValue());
            }
        } else if (msg instanceof MediatorHTTPResponse) {
            processResponseFromCoreAPI((MediatorHTTPResponse) msg);
        } else {
            unhandled(msg);
        }
    }
}