001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.http.commons.test.util;
007
008import static org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer;
009import static org.slf4j.LoggerFactory.getLogger;
010
011import java.net.URI;
012import java.util.Collection;
013
014import javax.annotation.PostConstruct;
015import javax.annotation.PreDestroy;
016import javax.xml.bind.JAXBContext;
017import javax.xml.bind.Unmarshaller;
018
019import com.google.common.base.Strings;
020import org.fcrepo.http.commons.webxml.WebAppConfig;
021import org.fcrepo.http.commons.webxml.bind.ContextParam;
022import org.fcrepo.http.commons.webxml.bind.Filter;
023import org.fcrepo.http.commons.webxml.bind.FilterMapping;
024import org.fcrepo.http.commons.webxml.bind.InitParam;
025import org.fcrepo.http.commons.webxml.bind.Listener;
026import org.fcrepo.http.commons.webxml.bind.Servlet;
027import org.fcrepo.http.commons.webxml.bind.ServletMapping;
028import org.glassfish.grizzly.http.server.HttpServer;
029import org.glassfish.grizzly.servlet.FilterRegistration;
030import org.glassfish.grizzly.servlet.ServletRegistration;
031import org.glassfish.grizzly.servlet.WebappContext;
032import org.slf4j.Logger;
033import org.springframework.beans.BeansException;
034import org.springframework.beans.factory.annotation.Value;
035import org.springframework.context.ApplicationContext;
036import org.springframework.context.ApplicationContextAware;
037import org.springframework.web.context.support.WebApplicationContextUtils;
038
039/**
040 * <p>ContainerWrapper class.</p>
041 *
042 * @author awoods
043 */
044public class ContainerWrapper implements ApplicationContextAware {
045
046    private static final Logger logger = getLogger(ContainerWrapper.class);
047
048    private static final int DEFAULT_PORT = 8080;
049
050    @Value("${fcrepo.dynamic.test.port:" + DEFAULT_PORT + "}")
051    private String port;
052
053    private HttpServer server;
054
055    private WebappContext appContext;
056
057    private String configLocation;
058
059    public void setConfigLocation(final String configLocation) {
060        this.configLocation = configLocation.replaceFirst("^classpath:", "/");
061    }
062
063    public void setPort(final int port) {
064        this.port = Integer.toString(port);
065    }
066
067    private int resolvePort() {
068        /*
069         This nonsense is necessary, rather than using @Value(${fcrepo.dynamic.test.port:8080}) because Intellij is
070          smart enough to attempt to set fcrepo.dynamic.test.port based on the pom but too dumb to run the
071         build-helper-maven-plugin plugin that actually determines its value. As a result, it's populated with an empty
072         value rather than null, and Spring will only default null property values.
073         */
074        if (Strings.isNullOrEmpty(port)) {
075            return DEFAULT_PORT;
076        }
077        return Integer.parseInt(port);
078    }
079
080    @PostConstruct
081    public void start() throws Exception {
082
083        final JAXBContext context = JAXBContext.newInstance(WebAppConfig.class);
084        final Unmarshaller u = context.createUnmarshaller();
085        final WebAppConfig o =
086                (WebAppConfig) u.unmarshal(getClass().getResource(
087                        this.configLocation));
088
089        final URI uri = URI.create("http://localhost:" + resolvePort());
090
091        server = createHttpServer(uri);
092
093        // create a "root" web application
094        appContext = new WebappContext(o.displayName(), "/");
095
096        for (final ContextParam p : o.contextParams()) {
097            appContext.addContextInitParameter(p.name(), p.value());
098        }
099
100        for (final Listener l : o.listeners()) {
101            appContext.addListener(l.className());
102        }
103
104        for (final Servlet s : o.servlets()) {
105            final ServletRegistration servlet =
106                    appContext.addServlet(s.servletName(), s.servletClass());
107
108            final Collection<ServletMapping> mappings =
109                    o.servletMappings(s.servletName());
110            for (final ServletMapping sm : mappings) {
111                servlet.addMapping(sm.urlPattern());
112            }
113            for (final InitParam p : s.initParams()) {
114                servlet.setInitParameter(p.name(), p.value());
115            }
116        }
117
118        for (final Filter f : o.filters()) {
119            final FilterRegistration filter =
120                    appContext.addFilter(f.filterName(), f.filterClass());
121
122            final Collection<FilterMapping> mappings =
123                    o.filterMappings(f.filterName());
124            for (final FilterMapping sm : mappings) {
125                final String urlPattern = sm.urlPattern();
126                final String servletName = sm.servletName();
127                if (urlPattern != null) {
128                    filter.addMappingForUrlPatterns(null, urlPattern);
129                } else {
130                    filter.addMappingForServletNames(null, servletName);
131                }
132
133            }
134            for (final InitParam p : f.initParams()) {
135                filter.setInitParameter(p.name(), p.value());
136            }
137        }
138
139        appContext.deploy(server);
140
141        logger.debug("started grizzly webserver endpoint at " +
142                server.getHttpHandler().getName());
143    }
144
145    @PreDestroy
146    public void stop() {
147        try {
148            appContext.undeploy();
149        } catch (final Exception e) {
150            logger.warn(e.getMessage(), e);
151        } finally {
152            server.shutdownNow();
153        }
154    }
155
156    public ApplicationContext getSpringAppContext() {
157        return WebApplicationContextUtils.findWebApplicationContext(appContext);
158    }
159
160    @Override
161    public void setApplicationContext(final ApplicationContext springAppContext)
162            throws BeansException {
163    }
164
165}