blob: c16139304989fafd807ef8267df2895e2ab98764 [file] [log] [blame]
/*
* Copyright (c) 2008, Richard Wallace. All Rights Reserved.
* 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.apache.zest.library.http;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
import java.util.UUID;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletContextListener;
import org.apache.zest.api.service.ServiceComposite;
import org.apache.zest.bootstrap.AssemblyException;
import org.apache.zest.bootstrap.ModuleAssembly;
import org.apache.zest.library.http.ConstraintInfo.Constraint;
import org.apache.zest.library.http.ConstraintInfo.HttpMethod;
import org.apache.zest.library.http.Dispatchers.Dispatcher;
import static org.apache.zest.api.common.Visibility.layer;
public final class Servlets
{
private Servlets()
{
}
public static ContextListenerDeclaration listen()
{
return new ContextListenerDeclaration();
}
public static ContextListenerAssembler addContextListeners( ContextListenerDeclaration... contextListenerDeclarations )
{
return new ContextListenerAssembler( contextListenerDeclarations );
}
public static class ContextListenerAssembler
{
final ContextListenerDeclaration[] contextListenerDeclarations;
ContextListenerAssembler( ContextListenerDeclaration... eventListenerDeclarations )
{
this.contextListenerDeclarations = eventListenerDeclarations;
}
public void to( ModuleAssembly module )
throws AssemblyException
{
for ( ContextListenerDeclaration contextListenerDeclaration : contextListenerDeclarations ) {
module.services( contextListenerDeclaration.contextListener() ).
setMetaInfo( contextListenerDeclaration.contextListenerInfo() ).
instantiateOnStartup().visibleIn( layer );
}
}
}
public static class ContextListenerDeclaration
{
Class<? extends ServiceComposite> contextListener;
Map<String, String> initParams = Collections.emptyMap();
public <T extends ServletContextListener & ServiceComposite> ContextListenerDeclaration with( Class<T> contextListener )
{
this.contextListener = contextListener;
return this;
}
public Class<? extends ServiceComposite> contextListener()
{
return contextListener;
}
public ContextListenerDeclaration withInitParams( Map<String, String> initParams )
{
this.initParams = initParams;
return this;
}
private ContextListenerInfo contextListenerInfo()
{
return new ContextListenerInfo( initParams );
}
}
public static ServletDeclaration serve( String path )
{
return new ServletDeclaration( path );
}
public static ServletAssembler addServlets( ServletDeclaration... servletDeclarations )
{
return new ServletAssembler( servletDeclarations );
}
public static class ServletAssembler
{
final ServletDeclaration[] servletDeclarations;
ServletAssembler( ServletDeclaration... servletDeclarations )
{
this.servletDeclarations = servletDeclarations;
}
public void to( ModuleAssembly module )
throws AssemblyException
{
for ( ServletDeclaration servletDeclaration : servletDeclarations ) {
module.services( servletDeclaration.servlet() ).
setMetaInfo( servletDeclaration.servletInfo() ).
instantiateOnStartup().visibleIn( layer );
}
}
}
public static class ServletDeclaration
{
String path;
Class<? extends ServiceComposite> servlet;
Map<String, String> initParams = Collections.emptyMap();
ServletDeclaration( String path )
{
this.path = path;
}
public <T extends Servlet & ServiceComposite> ServletDeclaration with( Class<T> servlet )
{
this.servlet = servlet;
return this;
}
public ServletDeclaration withInitParams( Map<String, String> initParams )
{
this.initParams = initParams;
return this;
}
Class<? extends ServiceComposite> servlet()
{
return servlet;
}
ServletInfo servletInfo()
{
return new ServletInfo( path, initParams );
}
}
public static FilterAssembler filter( String path )
{
return new FilterAssembler( path );
}
public static FilterDeclaration addFilters( FilterAssembler... filterAssemblers )
{
return new FilterDeclaration( filterAssemblers );
}
public static class FilterDeclaration
{
final FilterAssembler[] filterAssemblers;
FilterDeclaration( FilterAssembler... filterAssemblers )
{
this.filterAssemblers = filterAssemblers;
}
@SuppressWarnings( "unchecked" )
public void to( ModuleAssembly module )
throws AssemblyException
{
for ( FilterAssembler filterAssembler : filterAssemblers ) {
module.services( filterAssembler.filter() ).
setMetaInfo( filterAssembler.filterInfo() ).
instantiateOnStartup().visibleIn( layer );
}
}
}
public static class FilterAssembler
{
String path;
Class<? extends ServiceComposite> filter;
EnumSet<DispatcherType> dispatchers;
Map<String, String> initParams = Collections.emptyMap();
FilterAssembler( String path )
{
this.path = path;
}
public <T extends Filter & ServiceComposite> FilterAssembler through(
Class<T> filter )
{
this.filter = filter;
return this;
}
public FilterAssembler on( DispatcherType first, DispatcherType... rest )
{
dispatchers = EnumSet.of( first, rest );
return this;
}
@Deprecated
public FilterAssembler on( Dispatcher first, Dispatcher... rest )
{
EnumSet<DispatcherType> dispatch = EnumSet.noneOf( DispatcherType.class );
for ( Dispatcher each : Dispatchers.dispatchers( first, rest ) ) {
switch ( each ) {
case FORWARD:
dispatch.add( DispatcherType.FORWARD );
break;
case REQUEST:
dispatch.add( DispatcherType.REQUEST );
break;
}
}
dispatchers = dispatch;
return this;
}
public FilterAssembler withInitParams( Map<String, String> initParams )
{
this.initParams = initParams;
return this;
}
Class<? extends ServiceComposite> filter()
{
return filter;
}
FilterInfo filterInfo()
{
return new FilterInfo( path, initParams, dispatchers );
}
}
public static ConstraintAssembler constrain( String path )
{
return new ConstraintAssembler( path );
}
public static ConstraintDeclaration addConstraints( ConstraintAssembler... constraintAssemblers )
{
return new ConstraintDeclaration( constraintAssemblers );
}
public static class ConstraintDeclaration
{
private final ConstraintAssembler[] constraintAssemblers;
private ConstraintDeclaration( ConstraintAssembler[] constraintAssemblers )
{
this.constraintAssemblers = constraintAssemblers;
}
public void to( ModuleAssembly module )
throws AssemblyException
{
// TODO Refactor adding Map<ServiceAssembly,T> ServiceDeclaration.getMetaInfos( Class<T> type ); in bootstrap & runtime
// This would allow removing the ConstraintServices instances and this horrible hack with random UUIDs
for ( ConstraintAssembler eachAssembler : constraintAssemblers ) {
module.addServices( ConstraintService.class ).identifiedBy( UUID.randomUUID().toString() ).setMetaInfo( eachAssembler.constraintInfo() );
}
}
}
public static class ConstraintAssembler
{
private final String path;
private Constraint constraint;
private HttpMethod[] omittedHttpMethods = new HttpMethod[]{};
private ConstraintAssembler( String path )
{
this.path = path;
}
public ConstraintAssembler by( Constraint constraint )
{
this.constraint = constraint;
return this;
}
public ConstraintAssembler butNotOn( HttpMethod... omittedHttpMethods )
{
this.omittedHttpMethods = omittedHttpMethods;
return this;
}
ConstraintInfo constraintInfo()
{
return new ConstraintInfo( path, constraint, omittedHttpMethods );
}
}
}