@Override
	public void service( HttpServletRequest req, HttpServletResponse res )
	throws IOException, ServletException {
		MadProps settings = new MadProps( this.settings );
		Map<String, String> headers = new LinkedHashMap<String, String>( 16, 0.75F );
		@SuppressWarnings("unchecked")
		Enumeration<String> names = req.getHeaderNames();
		for ( ; names.hasMoreElements(); ) {
			String name = names.nextElement();
			headers.put( name.trim().toLowerCase(), req.getHeader( name ) );
		}
		req.setAttribute( "headers", headers );
		
		String prefix = req.getContextPath() + req.getServletPath();
		String path = req.getPathInfo();
		if ( path == null || path.length() == 0 ) {
			res.sendRedirect(  prefix + "/" );
			return;
		}
		String query = req.getQueryString();
		if ( query == null ) {
			query = "";
		} else {
			query = "?" + query;
		}
		req.setAttribute( "prefix", prefix );
		req.setAttribute( "path", path );
		req.setAttribute( "query", query );
		
		Store store;
		if ( settings.getBooleanProperty( "gae" ) ) {
			store = new TwigStore();
		} else {
			store = new FileStore();
		}
		req.setAttribute( "store", store );
		
		if ( settings.getBooleanProperty( "debug" ) ) {
			StringBuffer buffer = new StringBuffer( 256 );
			buffer.append( "\nRequest settings:" );
			@SuppressWarnings("unchecked")
			Enumeration<String> props = (Enumeration<String>) settings.propertyNames();
			for ( ; props.hasMoreElements() ; ) {
				String name = props.nextElement();
				buffer.append( "\n  " + name + " = " + settings.getProperty( name ) );
			}
			logger.info( buffer.toString() );
		}
		
		req.setAttribute( "settings", settings );
		super.service( req, res ); // this will delegate to doGet, doPost, etc.
	}