/*******************************************************************************
* Copyright (c) 2014, 2015 IBH SYSTEMS GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBH SYSTEMS GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.packagedrone.web.controller;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.packagedrone.utils.profiler.Profile;
import org.eclipse.packagedrone.utils.profiler.Profile.Handle;
import org.eclipse.packagedrone.web.ModelAndView;
import org.eclipse.packagedrone.web.RequestHandler;
import org.eclipse.packagedrone.web.ViewResolver;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ModelAndViewRequestHandler implements RequestHandler
{
private final static Logger logger = LoggerFactory.getLogger ( ModelAndViewRequestHandler.class );
private final ModelAndView modelAndView;
private final Class<?> controllerClazz;
private final Method method;
public ModelAndViewRequestHandler ( final ModelAndView modelAndView, final Class<?> controllerClazz, final Method method )
{
this.modelAndView = modelAndView;
this.controllerClazz = controllerClazz;
this.method = method;
}
public ModelAndView getModelAndView ()
{
return this.modelAndView;
}
@Override
public void process ( final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException
{
final String redir = this.modelAndView.getRedirect ();
if ( redir != null )
{
logger.debug ( "Processed redirect: {}", redir );
response.sendRedirect ( redir );
return;
}
if ( this.modelAndView.isReferer () )
{
final String ref = request.getHeader ( "Referer" );
if ( ref == null )
{
response.sendRedirect ( this.modelAndView.getReferer () );
}
final URL url = new URL ( ref );
String path = url.getPath ();
if ( path.startsWith ( request.getContextPath () ) )
{
path = path.substring ( request.getContextPath ().length () );
}
response.sendRedirect ( path );
return;
}
ViewResolver viewResolver = null;
Class<?> resourceClazz = this.controllerClazz;
if ( this.modelAndView.getAlternateViewResolver () != null )
{
viewResolver = this.modelAndView.getAlternateViewResolver ().getAnnotation ( ViewResolver.class );
resourceClazz = this.modelAndView.getAlternateViewResolver ();
}
if ( viewResolver == null && this.method != null )
{
viewResolver = this.method.getAnnotation ( ViewResolver.class );
}
if ( viewResolver == null && this.controllerClazz != null )
{
viewResolver = this.controllerClazz.getAnnotation ( ViewResolver.class );
}
if ( viewResolver == null )
{
throw new IllegalStateException ( String.format ( "View resolver for %s not declared. Missing @%s annotation?", this.controllerClazz.getName (), ViewResolver.class.getSimpleName () ) );
}
final Bundle bundle = FrameworkUtil.getBundle ( resourceClazz );
final StringBuilder pathBuilder = new StringBuilder ( "/bundle/" );
pathBuilder.append ( bundle.getBundleId () );
final String fullViewName = String.format ( viewResolver.value (), this.modelAndView.getViewName () );
if ( !fullViewName.startsWith ( "/" ) )
{
pathBuilder.append ( '/' );
}
pathBuilder.append ( fullViewName );
final String path = normalize ( pathBuilder.toString () );
logger.debug ( "Render: {}", path );
setModelAsRequestAttributes ( request, this.modelAndView.getModel () );
try ( Handle handle = Profile.start ( "render:" + this.modelAndView.getViewName () ) )
{
render ( request, response, path );
}
}
private static String normalize ( final String string )
{
final int len = string.length ();
final StringBuilder sb = new StringBuilder ( len );
boolean slash = false;
for ( int i = 0; i < len; i++ )
{
final char c = string.charAt ( i );
if ( c == '/' )
{
if ( !slash )
{
slash = true;
sb.append ( c );
}
}
else
{
sb.append ( c );
slash = false;
}
}
return sb.toString ();
}
private void render ( final HttpServletRequest request, final HttpServletResponse response, final String path ) throws ServletException, IOException
{
final RequestDispatcher rd = request.getRequestDispatcher ( path );
if ( response.isCommitted () )
{
logger.trace ( "Including" );
rd.include ( request, response );
}
else
{
logger.trace ( "Forwarding" );
rd.forward ( request, response );
}
}
private void setModelAsRequestAttributes ( final HttpServletRequest request, final Map<String, Object> model )
{
for ( final Map.Entry<String, Object> entry : model.entrySet () )
{
request.setAttribute ( entry.getKey (), entry.getValue () );
}
}
@Override
public String toString ()
{
return String.format ( "[RequestHandler/ModelAndView - %s]", this.modelAndView );
}
}