001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 * http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.atteo.moonshine.jersey;
015
016import java.util.HashMap;
017import java.util.Map;
018
019import javax.ws.rs.Path;
020import javax.ws.rs.ext.Provider;
021import javax.xml.bind.annotation.XmlElement;
022import javax.xml.bind.annotation.XmlIDREF;
023import javax.xml.bind.annotation.XmlRootElement;
024
025import org.atteo.classindex.ClassIndex;
026import org.atteo.moonshine.TopLevelService;
027import org.atteo.moonshine.services.ImportService;
028
029import com.google.inject.Binder;
030import com.google.inject.Module;
031import com.google.inject.PrivateModule;
032import com.sun.jersey.core.util.FeaturesAndProperties;
033import com.sun.jersey.freemarker.FreemarkerViewProcessor;
034import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
035import com.sun.jersey.spi.container.servlet.ServletContainer;
036
037/**
038 * Starts Jersey JAX-RS implementation.
039 */
040@XmlRootElement(name = "jersey")
041public class Jersey extends TopLevelService {
042    @XmlElement
043    @XmlIDREF
044    @ImportService
045    private org.atteo.moonshine.webserver.ServletContainer servletContainer;
046
047    /**
048     * Prefix under which JAX-RS resources should be registered.
049     */
050    @XmlElement
051    private String prefix = "";
052
053    /**
054     * Automatically register in Jersey any class marked with
055     * @{@link Path} or @{@link Provider} annotations.
056     * To manually register them simply {@link Binder#bind(Class) bind} them in Guice.
057     */
058    @XmlElement
059    private boolean discoverResources = true;
060
061    /**
062     * If true, returned XML documents will be formatted for human readability.
063     */
064    @XmlElement
065    private boolean formatOutput = false;
066
067    @Override
068    public Module configure() {
069        return new PrivateModule() {
070            @Override
071            protected void configure() {
072                Map<String, String> params = new HashMap<>();
073                params.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, "true");
074                if (formatOutput) {
075                    params.put(FeaturesAndProperties.FEATURE_FORMATTED, "true");
076                }
077                params.put(ServletContainer.PROPERTY_FILTER_CONTEXT_PATH, prefix);
078                params.put(FreemarkerViewProcessor.FREEMARKER_TEMPLATES_BASE_PATH, "templates");
079
080                bind(GuiceContainer.class);
081                servletContainer.addFilter(getProvider(GuiceContainer.class), params, prefix + "/*");
082
083                if (discoverResources) {
084                    for (Class<?> klass : ClassIndex.getAnnotated(Path.class)) {
085                        bind(klass);
086                    }
087                    for (Class<?> klass : ClassIndex.getAnnotated(Provider.class)) {
088                        bind(klass);
089                    }
090                }
091            }
092        };
093    }
094}