Package org.mule.module.jersey

Source Code of org.mule.module.jersey.JerseyResourcesComponent

/*
* Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/

package org.mule.module.jersey;

import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
import org.mule.api.component.JavaComponent;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.transformer.TransformerException;
import org.mule.api.transport.OutputHandler;
import org.mule.component.AbstractComponent;
import org.mule.module.jersey.exception.FallbackErrorMapper;
import org.mule.transport.http.HttpConnector;
import org.mule.transport.http.HttpConstants;
import org.mule.util.ClassUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;

import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.ExceptionMapper;

import org.glassfish.hk2.utilities.Binder;
import org.glassfish.jersey.internal.MapPropertiesDelegate;
import org.glassfish.jersey.jackson1.Jackson1Feature;
import org.glassfish.jersey.server.ApplicationHandler;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.ServerRuntime;
import org.glassfish.jersey.server.spi.ResponseErrorMapper;

/**
* Wraps a set of components which can get invoked by Jersey. This component will
* map the MuleMessage format to the internal Jersey format. Jersey will then select
* the appropriate component to invoke based on the request parameters/URI.
*/
public class JerseyResourcesComponent extends AbstractComponent
{

    protected static final String JERSEY_RESPONSE = "jersey_response";

    /**
     * Default dummy security context.
     */
    private static final SecurityContext DEFAULT_SECURITY_CONTEXT = new SecurityContext()
    {

        @Override
        public boolean isUserInRole(final String role)
        {
            return false;
        }

        @Override
        public boolean isSecure()
        {
            return false;
        }

        @Override
        public Principal getUserPrincipal()
        {
            return null;
        }

        @Override
        public String getAuthenticationScheme()
        {
            return null;
        }
    };

    private List<JavaComponent> components;
    private ScheduledExecutorService backgroundScheduler;
    private List<ExceptionMapper<?>> exceptionMappers = new ArrayList<>();
    private List<ContextResolver<?>> contextResolvers = new ArrayList<>();
    private Set<String> packages = new HashSet<>();
    private Map<String, Object> properties = new HashMap<>();

    private ApplicationHandler application;
    private ResourceConfig resourceConfig;

    @Override
    protected void doInitialise() throws InitialisationException
    {
        super.doInitialise();

        final Set<Class<?>> resources = new HashSet<>();

        if (components == null)
        {
            throw new IllegalStateException("There must be at least one component in the Jersey resources.");
        }

        initializeResources(resources);
        initializeOtherResources(exceptionMappers, resources);
        initializeOtherResources(contextResolvers, resources);

        application = createApplication(resources);
        try
        {
            ServerRuntime serverRuntime = ClassUtils.getFieldValue(application, "runtime", false);
            backgroundScheduler = ClassUtils.getFieldValue(serverRuntime, "backgroundScheduler", false);
        }
        catch (Exception e)
        {
            throw new InitialisationException(e, this);
        }
    }

    protected void initializeResources(Set<Class<?>> resources) throws InitialisationException
    {
        // Initialize the Jersey resources using the components
        for (JavaComponent component : components)
        {
            Class<?> c;
            try
            {
                c = component.getObjectType();
                resources.add(c);
            }
            catch (Exception e)
            {
                throw new InitialisationException(e, this);
            }
        }
    }

    protected void initializeOtherResources(List<?> newResources, final Set<Class<?>> resources)
    {
        for (Object resource : newResources)
        {
            resources.add(resource.getClass());
        }
    }

    protected ApplicationHandler createApplication(final Set<Class<?>> resources)
    {
        if (!properties.containsKey(ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED))
        {
            properties.put(ServerProperties.PROCESSING_RESPONSE_ERRORS_ENABLED, true);
        }

        resourceConfig = new ResourceConfig();

        for (String pkg : packages)
        {
            resourceConfig.packages(pkg);
        }

        resourceConfig.addProperties(properties)
                .registerClasses(resources)
                .register(Jackson1Feature.class);

        if (!resourceConfig.isRegistered(ResponseErrorMapper.class))
        {
            resourceConfig.register(new FallbackErrorMapper());
        }

        return new ApplicationHandler(resourceConfig, getComponentProvider());
    }

    @Override
    protected Object doInvoke(MuleEvent event) throws Exception
    {
        ContainerRequest req = buildRequest(event);
        req.setSecurityContext(DEFAULT_SECURITY_CONTEXT);

        MuleMessage message = event.getMessage();
        req.setEntityStream(getInputStream(message));
        copyProperties(message, req);

        return execute(req, event);
    }

    private Object execute(final ContainerRequest request, MuleEvent event)
    {
        final MuleResponseWriter writer = new MuleResponseWriter(event, request.getMethod(), backgroundScheduler);

        request.setWriter(writer);
        application.handle(request);

        return new OutputHandler()
        {
            @Override
            public void write(MuleEvent event, OutputStream out) throws IOException
            {
                writer.getOutputStream().setDelegate(out);
            }
        };
    }

    protected void copyProperties(MuleMessage message, ContainerRequest request)
    {
        for (Object prop : message.getInboundPropertyNames())
        {
            if (prop.equals(HttpConnector.HTTP_COOKIES_PROPERTY))
            {
                org.apache.commons.httpclient.Cookie[] apacheCookies = message.getInboundProperty(HttpConnector.HTTP_COOKIES_PROPERTY);
                for (org.apache.commons.httpclient.Cookie apacheCookie : apacheCookies)
                {
                    Cookie cookie = new Cookie(apacheCookie.getName(), apacheCookie.getValue());
                    request.header(HttpConstants.HEADER_COOKIE, cookie);
                }
            }
            else
            {
                Object property = message.getInboundProperty(prop.toString());
                if (property != null)
                {
                    request.header(prop.toString(), property.toString());
                }
            }
        }
    }

    private InputStream getInputStream(MuleMessage message) throws TransformerException
    {
        return message.getPayload(InputStream.class);
    }

    protected Binder getComponentProvider()
    {
        return new MuleComponentBinder(muleContext, components);
    }

    private ContainerRequest buildRequest(MuleEvent event) throws URISyntaxException
    {
        MuleMessage message = event.getMessage();
        String path = message.getInboundProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
        String contextPath = message.getInboundProperty(HttpConnector.HTTP_CONTEXT_PATH_PROPERTY);
        String query = null;
        int queryIdx = path.indexOf('?');
        if (queryIdx != -1)
        {
            query = path.substring(queryIdx + 1);
            path = path.substring(0, queryIdx);
        }

        URI endpointUri = event.getMessageSourceURI();
        String host = message.getInboundProperty("Host", endpointUri.getHost());
        String method = message.getInboundProperty(HttpConnector.HTTP_METHOD_PROPERTY);

        String scheme;
        if ("servlet".equals(endpointUri.getScheme()))
        {
            scheme = "http";
        }
        else
        {
            scheme = endpointUri.getScheme();
        }

        URI baseUri = getBaseUri(scheme, host, contextPath);
        URI completeUri = getCompleteUri(endpointUri, scheme, host, path, query);

        if (logger.isDebugEnabled())
        {
            logger.debug("Base URI: " + baseUri);
            logger.debug("Complete URI: " + completeUri);
        }

        return new ContainerRequest(baseUri, completeUri, method, null, new MapPropertiesDelegate());
    }

    private URI getCompleteUri(URI endpointUri,
                               String scheme,
                               String host,
                               String path,
                               String query) throws URISyntaxException
    {
        String uri = scheme + "://" + host + path;
        if (query != null)
        {
            uri += "?" + query;
        }

        return new URI(uri);
    }

    private URI getBaseUri(String scheme, String host, String contextPath) throws URISyntaxException
    {
        if (!contextPath.endsWith("/"))
        {
            contextPath += "/";
        }

        return new URI(scheme + "://" + host + contextPath);
    }

    public List<JavaComponent> getComponents()
    {
        return components;
    }

    public void setComponents(List<JavaComponent> components)
    {
        this.components = components;
    }

    public void setMessageProcessors(List<MessageProcessor> messageProcessors)
    {
        List<JavaComponent> javaComponents = new ArrayList<>();
        for (MessageProcessor mp : messageProcessors)
        {
            if (mp instanceof JavaComponent)
            {
                javaComponents.add((JavaComponent) mp);
            }
            else
            {
                throw new IllegalStateException("Only JavaComponents are allowed as MessageProcessors. Type "
                                                + mp.getClass().getName() + " is not allowed.");
            }
        }
        setComponents(javaComponents);
    }

    protected ResourceConfig getResourceConfig()
    {
        return resourceConfig;
    }

    public void setExceptionMappers(List<ExceptionMapper<?>> exceptionMappers)
    {
        this.exceptionMappers.addAll(exceptionMappers);
    }

    public void setContextResolvers(List<ContextResolver<?>> contextResolvers)
    {
        this.contextResolvers.addAll(contextResolvers);
    }

    public void setPackages(Set<String> packages)
    {
        this.packages = packages;
    }

    public void setProperties(Map<String, Object> properties)
    {
        this.properties = properties;
    }
}
TOP

Related Classes of org.mule.module.jersey.JerseyResourcesComponent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.