org.cleverbus.api.asynch.AsynchRouteBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.cleverbus.api.asynch.AsynchRouteBuilder.java

Source

/*
 * Copyright (C) 2015
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cleverbus.api.asynch;

import org.apache.camel.Expression;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.DataFormatDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.cleverbus.api.asynch.model.AsynchResponse;
import org.cleverbus.api.asynch.model.CallbackResponse;
import org.cleverbus.api.entity.Funnel;
import org.cleverbus.api.entity.Message;
import org.cleverbus.api.entity.ServiceExtEnum;
import org.cleverbus.api.route.AbstractBasicRoute;
import org.cleverbus.api.route.XPathValidator;
import org.cleverbus.common.expression.MultiValueExpression;
import org.springframework.util.Assert;

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;

import static org.apache.camel.builder.Builder.constant;
import static org.cleverbus.common.jaxb.JaxbDataFormatHelper.jaxb;

/**
 * Helper class for creating input route for asynch. messages.
 * <p/>
 * Create new instance with calling
 * {@link #newInstance(ServiceExtEnum, String, String, AsynchResponseProcessor, DataFormatDefinition)} method,
 * sets parameters and finally call {@link #build(RouteBuilder)} method for creating route definition.
 *
 * @author <a href="mailto:petr.juza@cleverlance.com">Petr Juza</a>
 * @author <a href="mailto:tomas.hanus@cleverlance.com">Tomas Hanus</a>
 */
public final class AsynchRouteBuilder {

    private String inUri;
    private ServiceExtEnum serviceType;
    private String operation;
    private @Nullable String routeId;
    private @Nullable Processor[] validators;
    private @Nullable Expression objectIdExpr;
    private @Nullable Collection<Expression> funnelValues;
    private boolean guaranteedOrder;
    private boolean excludeFailedState;
    private AsynchResponseProcessor responseProcessor;
    private DataFormatDefinition responseMarshalling;
    private @Nullable String policyRef;

    private AsynchRouteBuilder(String inUri, ServiceExtEnum serviceType, String operation,
            AsynchResponseProcessor responseProcessor, DataFormatDefinition responseMarshalling) {
        Assert.hasText(operation, "the operation must not be empty");
        Assert.notNull(inUri, "the inUri must not be empty");
        Assert.notNull(serviceType, "the serviceType must not be null");
        Assert.notNull(responseProcessor, "the responseProcessor must not be null");
        Assert.notNull(responseMarshalling, "the responseMarshalling must not be null");

        this.inUri = inUri;
        this.serviceType = serviceType;
        this.operation = operation;
        this.responseProcessor = responseProcessor;
        this.responseMarshalling = responseMarshalling;
    }

    /**
     * Creates new instance with basic mandatory parameters.
     *
     * @param serviceType service type
     * @param operation operation name with processing route
     * @param inUri the from URI of this route
     * @param responseProcessor the response processor
     * @param responseMarshalling the response marshalling
     * @return new instance
     */
    public static AsynchRouteBuilder newInstance(ServiceExtEnum serviceType, String operation, String inUri,
            AsynchResponseProcessor responseProcessor, DataFormatDefinition responseMarshalling) {
        return new AsynchRouteBuilder(inUri, serviceType, operation, responseProcessor, responseMarshalling);
    }

    /**
     * Sets route ID. If not defined then it will be created in standard way by
     * calling {@link AbstractBasicRoute#getInRouteId(ServiceExtEnum, String)}.
     *
     * @param routeId the route ID
     */
    public AsynchRouteBuilder withRouteId(@Nullable String routeId) {
        this.routeId = routeId;
        return this;
    }

    /**
     * Sets array of validators, for example {@link XPathValidator}.
     *
     * @param validator the validator
     */
    public AsynchRouteBuilder withValidator(@Nullable Processor... validator) {
        this.validators = validator;
        return this;
    }

    /**
     * Sets expression for evaluating object ID.
     *
     * @param objectIdExpr expression for evaluating object ID
     * @see Message#getObjectId()
     */
    public AsynchRouteBuilder withObjectIdExpr(@Nullable Expression objectIdExpr) {
        this.objectIdExpr = objectIdExpr;
        return this;
    }

    /**
     * Sets funnel value.
     *
     * @param funnelValue the funnel value
     * @see Funnel
     */
    public AsynchRouteBuilder withFunnelValue(@Nullable Expression funnelValue) {
        if (funnelValue == null) {
            return this;
        } else {
            return withFunnelValues(funnelValue);
        }
    }

    /**
     * Sets funnel values.
     * Between all funnel values is OR condition.
     *
     * @param funnelValues the funnel values
     * @see Funnel
     */
    public AsynchRouteBuilder withFunnelValues(Expression... funnelValues) {
        if (funnelValues != null && funnelValues.length != 0) {
            this.funnelValues = Arrays.asList(funnelValues);
        }
        return this;
    }

    /**
     * Marks the route for processing in guaranteed order by message timestamp.
     */
    public AsynchRouteBuilder withGuaranteedOrder() {
        this.guaranteedOrder = true;
        this.excludeFailedState = false;
        return this;
    }

    /**
     * Marks the route for processing in guaranteed order by message timestamp.
     */
    public AsynchRouteBuilder withGuaranteedOrderWithoutFailed() {
        this.guaranteedOrder = true;
        this.excludeFailedState = true;
        return this;
    }

    /**
     * Sets response processor. If not set then general response {@link AsynchResponse} will be used.
     *
     * @param responseProcessor   the response processor
     * @param responseMarshalling the response marshalling
     */
    public AsynchRouteBuilder withResponseProcessor(AsynchResponseProcessor responseProcessor,
            DataFormatDefinition responseMarshalling) {
        Assert.notNull(responseProcessor, "the responseProcessor must not be null");
        Assert.notNull(responseMarshalling, "the responseMarshalling must not be null");

        this.responseProcessor = responseProcessor;
        this.responseMarshalling = responseMarshalling;
        return this;
    }

    /**
     * Sets (Spring bean) reference to policy, e.g. authorization policy.
     *
     * @param policyRef the reference to policy
     */
    public AsynchRouteBuilder withPolicyRef(@Nullable String policyRef) {
        this.policyRef = policyRef;
        return this;
    }

    public String getInUri() {
        return inUri;
    }

    public ServiceExtEnum getServiceType() {
        return serviceType;
    }

    public String getOperation() {
        return operation;
    }

    @Nullable
    public String getRouteId() {
        return routeId;
    }

    @Nullable
    public Processor[] getValidators() {
        return validators;
    }

    @Nullable
    public Expression getObjectIdExpr() {
        return objectIdExpr;
    }

    @Nullable
    public Collection<Expression> getFunnelValues() {
        return funnelValues;
    }

    @Nullable
    public AsynchResponseProcessor getResponseProcessor() {
        return responseProcessor;
    }

    @Nullable
    public DataFormatDefinition getResponseMarshalling() {
        return responseMarshalling;
    }

    @Nullable
    public String getPolicyRef() {
        return policyRef;
    }

    /**
     * Builds new route definition for processing incoming asynchronous messages.
     *
     * @param route current route builder
     * @return route definition
     */
    public final RouteDefinition build(RouteBuilder route) {
        Assert.notNull(route, "the route must not be null");

        // check guaranteed order - funnel value must be filled
        if (guaranteedOrder && CollectionUtils.isEmpty(funnelValues)) {
            throw new IllegalStateException("There is no funnel value for guaranteed order.");
        }

        String finalRouteId = routeId;
        if (finalRouteId == null) {
            finalRouteId = AbstractBasicRoute.getInRouteId(serviceType, operation);
        }

        RouteDefinition routeDefinition = route.from(inUri).routeId(finalRouteId);

        if (validators != null) {
            for (Processor validator : validators) {
                routeDefinition.process(validator);
            }
        }

        if (policyRef != null) {
            routeDefinition.policy(policyRef);
        }

        if (objectIdExpr != null) {
            routeDefinition.setHeader(AsynchConstants.OBJECT_ID_HEADER, objectIdExpr);
        }

        if (!CollectionUtils.isEmpty(funnelValues)) {
            routeDefinition.setHeader(AsynchConstants.FUNNEL_VALUES_HEADER,
                    new MultiValueExpression(funnelValues, false));
        }

        if (guaranteedOrder) {
            routeDefinition.setHeader(AsynchConstants.GUARANTEED_ORDER_HEADER, constant(true));
        }

        if (excludeFailedState) {
            routeDefinition.setHeader(AsynchConstants.EXCLUDE_FAILED_HEADER, constant(true));
        }

        // header values
        routeDefinition.setHeader(AsynchConstants.SERVICE_HEADER, route.constant(serviceType));
        routeDefinition.setHeader(AsynchConstants.OPERATION_HEADER, route.constant(operation));

        // route the request to asynchronous processing
        routeDefinition.to(AsynchConstants.URI_ASYNCH_IN_MSG);

        // create response
        if (responseProcessor != null) {
            routeDefinition.process(responseProcessor);
        } else {
            // use default response, general for all asynch. requests
            routeDefinition.process(new AsynchResponseProcessor() {

                @Override
                protected Object setCallbackResponse(CallbackResponse callbackResponse) {
                    AsynchResponse asynchResponse = new AsynchResponse();
                    asynchResponse.setConfirmAsynchRequest(callbackResponse);

                    return asynchResponse;
                }
            });
        }

        // response -> XML
        if (responseMarshalling != null) {
            routeDefinition.marshal(responseMarshalling);
        } else {
            routeDefinition.marshal(jaxb(AsynchResponse.class));
        }

        return routeDefinition;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("inUri", inUri).append("serviceType", serviceType.getServiceName())
                .append("operation", operation).append("policyRef", policyRef).append("objectId", objectIdExpr)
                .append("funnelValues", funnelValues).toString();
    }
}