All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.everrest.exoplatform.container.ComponentsFinder Maven / Gradle / Ivy

There is a newer version: 1.12.3
Show newest version
/*******************************************************************************
 * Copyright (c) 2012-2014 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package org.everrest.exoplatform.container;

import org.everrest.core.impl.header.MediaTypeHelper;
import org.everrest.core.provider.ProviderDescriptor;
import org.everrest.core.resource.AbstractResourceDescriptor;
import org.everrest.core.uri.UriPattern;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.Parameter;
import org.picocontainer.PicoContainer;
import org.picocontainer.defaults.AbstractPicoVisitor;

import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;

/**
 * Base implementation of PicoVisitor for lookup JAX-RS components by annotation.
 *
 * @author andrew00x
 */
abstract class ComponentsFinder extends AbstractPicoVisitor {
    private static final Set COMPONENT_FILTERS = new LinkedHashSet<>();

    static {
        for (ComponentFilter f : ServiceLoader.load(ComponentFilter.class)) {
            COMPONENT_FILTERS.add(f);
        }
    }

    static List withFilters(List source) {
        if (source.size() == 0 || COMPONENT_FILTERS.size() == 0) {
            return source;
        }
        List result = new ArrayList<>();
        for (ComponentAdapter component : source) {
            for (ComponentFilter f : COMPONENT_FILTERS) {
                if (f.accept(component)) {
                    result.add(component);
                }
            }
        }
        return result;
    }

    final Class annotation;

    ComponentsFinder(Class annotation) {
        this.annotation = annotation;
    }

    @Override
    public final void visitComponentAdapter(ComponentAdapter componentAdapter) {
        checkTraversal();
    }

    @Override
    public final void visitParameter(Parameter parameter) {
        checkTraversal();
    }

    final static class ResourceFinder extends ComponentsFinder {
        private final String       requestPath;
        private final List parameterValues;
        private final List components = new ArrayList<>();

        ResourceFinder(Class annotation, String requestPath, List parameterValues) {
            super(annotation);
            this.requestPath = requestPath;
            this.parameterValues = parameterValues;
        }

        @Override
        public Object traverse(Object container) {
            components.clear();
            try {
                super.traverse(container);
                Map matched = new HashMap<>();
                for (ComponentAdapter adapter : components) {
                    if (adapter instanceof RestfulComponentAdapter) {
                        AbstractResourceDescriptor resource =
                                (AbstractResourceDescriptor)((RestfulComponentAdapter)adapter).getObjectModel();
                        if (resource.getUriPattern().match(requestPath, parameterValues)) {
                            String tail = parameterValues.get(parameterValues.size() - 1);
                            if (tail == null //
                                || "/".equals(tail) //
                                || (resource.getSubResourceMethods().size() + resource.getSubResourceLocators().size()) > 0) {
                                matched.put(resource.getUriPattern(), adapter);
                            }
                        }
                    }
                }
                if (matched.isEmpty()) {
                    return null;
                } else if (matched.size() == 1) {
                    ComponentAdapter componentAdapter = matched.values().iterator().next();
                    matched.clear();
                    return componentAdapter;
                } else {
                    UriPattern[] keys = matched.keySet().toArray(new UriPattern[matched.size()]);
                    Arrays.sort(keys, UriPattern.URIPATTERN_COMPARATOR);
                    ComponentAdapter componentAdapter = matched.get(keys[0]);
                    matched.clear();
                    return componentAdapter;
                }
            } finally {
                components.clear();
            }
        }

        @Override
        public void visitContainer(PicoContainer pico) {
            checkTraversal();
            components.addAll(
                    withFilters(
                            ((RestfulContainer)pico).getComponentAdapters(annotation)
                               )
                             );
        }
    }

    final static class WriterFinder extends ComponentsFinder {
        private final Class     entityType;
        private final Type         genericEntityType;
        private final MediaType    mediaType;
        private final Annotation[] annotations;
        private final List components = new ArrayList<>();

        WriterFinder(Class annotation, Class entityType, Type genericEntityType, Annotation[] annotations,
                     MediaType mediaType) {
            super(annotation);
            this.entityType = entityType;
            this.genericEntityType = genericEntityType;
            this.annotations = annotations;
            this.mediaType = mediaType;
        }

        @SuppressWarnings({"unchecked"})
        @Override
        public Object traverse(Object container) {
            components.clear();
            try {
                super.traverse(container);
                MediaTypeHelper.MediaTypeRange mediaTypeRange = new MediaTypeHelper.MediaTypeRange(mediaType);
                while (mediaTypeRange.hasNext()) {
                    MediaType next = mediaTypeRange.next();
                    for (ComponentAdapter adapter : components) {
                        if (adapter instanceof RestfulComponentAdapter) {
                            ProviderDescriptor provider = (ProviderDescriptor)((RestfulComponentAdapter)adapter).getObjectModel();
                            if (provider.produces().contains(next)) {
                                MessageBodyWriter writer = (MessageBodyWriter)adapter.getComponentInstance((PicoContainer)container);
                                if (writer.isWriteable(entityType, genericEntityType, annotations, next)) {
                                    return writer;
                                }
                            }
                        }
                    }
                }
                return null;
            } finally {
                components.clear();
            }
        }

        @Override
        public void visitContainer(PicoContainer pico) {
            checkTraversal();
            components.addAll(
                    withFilters(
                            ((RestfulContainer)pico).getComponentAdaptersOfType(MessageBodyWriter.class, annotation)
                               )
                             );
        }
    }

    final static class ReaderFinder extends ComponentsFinder {
        private final Class     entityType;
        private final Type         genericEntityType;
        private final MediaType    mediaType;
        private final Annotation[] annotations;
        private final List components = new ArrayList<>();

        ReaderFinder(Class annotation, Class entityType, Type genericEntityType, Annotation[] annotations,
                     MediaType mediaType) {
            super(annotation);
            this.entityType = entityType;
            this.genericEntityType = genericEntityType;
            this.annotations = annotations;
            this.mediaType = mediaType;
        }

        @SuppressWarnings({"unchecked"})
        @Override
        public Object traverse(Object container) {
            components.clear();
            try {
                super.traverse(container);
                MediaTypeHelper.MediaTypeRange mediaTypeRange = new MediaTypeHelper.MediaTypeRange(mediaType);
                while (mediaTypeRange.hasNext()) {
                    MediaType next = mediaTypeRange.next();
                    for (ComponentAdapter adapter : components) {
                        if (adapter instanceof RestfulComponentAdapter) {
                            ProviderDescriptor provider =
                                    (ProviderDescriptor)((RestfulComponentAdapter)adapter).getObjectModel();
                            if (provider.consumes().contains(next)) {
                                MessageBodyReader reader = (MessageBodyReader)adapter.getComponentInstance((PicoContainer)container);
                                if (reader.isReadable(entityType, genericEntityType, annotations, next)) {
                                    return reader;
                                }
                            }
                        }
                    }
                }
                return null;
            } finally {
                components.clear();
            }
        }

        @Override
        public void visitContainer(PicoContainer pico) {
            checkTraversal();
            components.addAll(
                    withFilters(
                            ((RestfulContainer)pico).getComponentAdaptersOfType(MessageBodyReader.class, annotation)
                               )
                             );
        }
    }

    final static class ExceptionMapperFinder extends ComponentsFinder {
        private final Class exceptionType;
        private final List components = new ArrayList<>();

        ExceptionMapperFinder(Class annotation, Class exceptionType) {
            super(annotation);
            this.exceptionType = exceptionType;
        }

        @Override
        public Object traverse(Object container) {
            components.clear();
            try {
                super.traverse(container);
                for (ComponentAdapter adapter : components) {
                    if (adapter instanceof RestfulComponentAdapter) {
                        ParameterizedType[] implementedInterfaces = ((RestfulComponentAdapter)adapter).getImplementedInterfaces();
                        for (ParameterizedType genericInterface : implementedInterfaces) {
                            if (ExceptionMapper.class == genericInterface.getRawType()
                                && exceptionType == genericInterface.getActualTypeArguments()[0]) {
                                return adapter.getComponentInstance((PicoContainer)container);
                            }
                        }
                    }
                }
                return null;
            } finally {
                components.clear();
            }
        }

        @Override
        public void visitContainer(PicoContainer pico) {
            checkTraversal();
            components.addAll(
                    withFilters(
                            ((RestfulContainer)pico).getComponentAdaptersOfType(ExceptionMapper.class, annotation)
                               )
                             );
        }
    }

    final static class ContextResolverFinder extends ComponentsFinder {
        private final Class  contextType;
        private final MediaType mediaType;
        private final List components = new ArrayList<>();

        ContextResolverFinder(Class annotation, Class contextType, MediaType mediaType) {
            super(annotation);
            this.contextType = contextType;
            this.mediaType = mediaType;
        }

        @Override
        public Object traverse(Object container) {
            components.clear();
            try {
                super.traverse(container);
                MediaTypeHelper.MediaTypeRange mediaTypeRange = new MediaTypeHelper.MediaTypeRange(mediaType);
                while (mediaTypeRange.hasNext()) {
                    MediaType next = mediaTypeRange.next();
                    for (ComponentAdapter adapter : components) {
                        if (adapter instanceof RestfulComponentAdapter) {
                            ProviderDescriptor provider =
                                    (ProviderDescriptor)((RestfulComponentAdapter)adapter).getObjectModel();
                            if (provider.produces().contains(next)) {
                                ParameterizedType[] implementedInterfaces = ((RestfulComponentAdapter)adapter).getImplementedInterfaces();
                                for (ParameterizedType genericInterface : implementedInterfaces) {
                                    Type rawType = genericInterface.getRawType();
                                    Class actualType;
                                    try {
                                        actualType = (Class)genericInterface.getActualTypeArguments()[0];
                                    } catch (ClassCastException e) {
                                        continue;
                                    }
                                    if (ContextResolver.class == rawType && contextType.isAssignableFrom(actualType)) {
                                        return adapter.getComponentInstance((PicoContainer)container);
                                    }
                                }
                            }
                        }
                    }
                }
                return null;
            } finally {
                components.clear();
            }
        }

        @Override
        public void visitContainer(PicoContainer pico) {
            checkTraversal();
            components.addAll(
                    withFilters(
                            ((RestfulContainer)pico).getComponentAdaptersOfType(ContextResolver.class, annotation)
                               )
                             );
        }
    }

    static ComponentAdapter findResource(PicoContainer pico, String requestPath, List parameterValues) {
        return (ComponentAdapter)new ResourceFinder(Path.class, requestPath, parameterValues).traverse(pico);
    }

    @SuppressWarnings("unchecked")
    static  MessageBodyWriter findWriter(PicoContainer pico, Class entityType, Type genericEntityType,
                                               Annotation[] annotations, MediaType mediaType) {
        return (MessageBodyWriter)new WriterFinder<>(Provider.class, entityType, genericEntityType, annotations, mediaType)
                .traverse(pico);
    }

    @SuppressWarnings("unchecked")
    static  MessageBodyReader findReader(PicoContainer pico, Class entityType, Type genericEntityType,
                                               Annotation[] annotations, MediaType mediaType) {
        return (MessageBodyReader)new ReaderFinder<>(Provider.class, entityType, genericEntityType, annotations, mediaType)
                .traverse(pico);
    }

    @SuppressWarnings("unchecked")
    static  ExceptionMapper findExceptionMapper(PicoContainer pico, Class exceptionType) {
        return (ExceptionMapper)new ExceptionMapperFinder<>(Provider.class, exceptionType).traverse(pico);
    }

    @SuppressWarnings("unchecked")
    static  ContextResolver findContextResolver(PicoContainer pico, Class contextType, MediaType mediaType) {
        return (ContextResolver)new ContextResolverFinder<>(Provider.class, contextType, mediaType).traverse(pico);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy