/*
* Copyright (c) 2011, Paul Merlin. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.qi4j.library.http;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import javax.management.MBeanServer;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.qi4j.api.service.ServiceReference;
import org.qi4j.functional.Iterables;
import org.qi4j.library.http.Interface.Protocol;
import static org.qi4j.library.http.JettyConfigurationHelper.*;
public abstract class AbstractJettyMixin
implements HttpService, JettyActivation
{
private final String identity;
private final Iterable<ServiceReference<ServletContextListener>> contextListeners;
private final Iterable<ServiceReference<Servlet>> servlets;
private final Iterable<ServiceReference<Filter>> filters;
private final MBeanServer mBeanServer;
private Server server;
public AbstractJettyMixin( String identity, Server jettyServer,
Iterable<ServiceReference<ServletContextListener>> contextListeners,
Iterable<ServiceReference<Servlet>> servlets,
Iterable<ServiceReference<Filter>> filters,
MBeanServer mBeanServer )
{
this.identity = identity;
this.server = jettyServer;
this.contextListeners = Iterables.unique( contextListeners );
this.servlets = Iterables.unique( servlets );
this.filters = Iterables.unique( filters );
this.mBeanServer = mBeanServer;
}
protected abstract JettyConfiguration configuration();
protected Connector buildConnector()
{
return new SelectChannelConnector();
}
protected SecurityHandler buildSecurityHandler()
{
return null;
}
protected abstract Protocol servedProtocol();
@Override
public final void startJetty()
throws Exception
{
// Prepare ServletContext
ServletContextHandler root = new ServletContextHandler( server,
"/",
new SessionHandler(),
buildSecurityHandler(),
new ServletHandler(),
new ErrorHandler() );
root.setDisplayName( identity );
configureContext( root, configuration() );
// Register ContextListeners, Servlets and Filters
addContextListeners( root, contextListeners );
addServlets( root, servlets );
addFilters( root, filters );
// Prepare Connector
Connector connector = buildConnector();
configureConnector( connector, configuration() );
// Prepare Server
configureServer( server, configuration() );
server.addConnector( connector );
if ( mBeanServer != null ) {
server.getContainer().addEventListener( new MBeanContainer( mBeanServer ) );
}
// Start
server.start();
}
@Override
public final void stopJetty()
throws Exception
{
server.stop();
for ( Connector connector : server.getConnectors() ) {
connector.close();
}
server = null;
}
@Override
public final Interface[] interfacesServed()
{
Connector[] connectors = server.getConnectors();
Interface[] result = new Interface[ connectors.length ];
int index = 0;
for ( Connector connector : connectors ) {
String host = configuration().hostName().get();
if ( host == null ) {
host = connector.getHost();
if ( host == null ) // If serving all interfaces.
{
try {
host = InetAddress.getLocalHost().getHostAddress();
} catch ( UnknownHostException e ) {
InternalError error = new InternalError( "UnknownHost for local interface." );
error.initCause( e );
throw error;
}
}
}
result[ index++] = new InterfaceImpl( host, connector.getPort(), servedProtocol() );
}
return result;
}
protected static void addContextListeners( ServletContextHandler root, Iterable<ServiceReference<ServletContextListener>> contextListeners )
{
// Iterate the available context listeners and add them to the server
for ( ServiceReference<ServletContextListener> contextListener : contextListeners ) {
ContextListenerInfo contextListenerInfo = contextListener.metaInfo( ContextListenerInfo.class );
Map<String, String> initParams = contextListenerInfo.initParams();
for( Map.Entry<String, String> entry : initParams.entrySet() )
{
root.setInitParameter( entry.getKey(), entry.getValue() );
}
root.addEventListener( contextListener.get() );
}
}
protected static void addServlets( ServletContextHandler root, Iterable<ServiceReference<Servlet>> servlets )
{
// Iterate the available servlets and add it to the server
for ( ServiceReference<Servlet> servlet : servlets ) {
ServletInfo servletInfo = servlet.metaInfo( ServletInfo.class );
String servletPath = servletInfo.getPath();
Servlet servletInstance = servlet.get();
ServletHolder holder = new ServletHolder( servletInstance );
holder.setInitParameters( servletInfo.initParams() );
root.addServlet( holder, servletPath );
}
}
protected static void addFilters( ServletContextHandler root, Iterable<ServiceReference<Filter>> filters )
{
// Iterate the available filters and add them to the server
for ( ServiceReference<Filter> filter : filters ) {
FilterInfo filterInfo = filter.metaInfo( FilterInfo.class );
String filterPath = filterInfo.getPath();
Filter filterInstance = filter.get();
FilterHolder holder = new FilterHolder( filterInstance );
holder.setInitParameters( filterInfo.initParameters() );
root.addFilter( holder, filterPath, filterInfo.dispatchers() );
}
}
}