/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.portal;
import javax.servlet.http.HttpServletRequest;
import com.google.common.base.Preconditions;
import com.enonic.cms.core.RequestParameters;
import com.enonic.cms.core.RequestParametersMerger;
import com.enonic.cms.core.language.LanguageEntity;
import com.enonic.cms.core.language.LanguageKey;
import com.enonic.cms.core.portal.datasource.executor.DataSourceInvocationCache;
import com.enonic.cms.core.portal.livetrace.LivePortalTraceService;
import com.enonic.cms.core.portal.livetrace.PortalRequestTrace;
import com.enonic.cms.core.portal.livetrace.PortalRequestTracer;
import com.enonic.cms.core.portal.processor.AbstractPageRequestProcessor;
import com.enonic.cms.core.portal.processor.DirectiveRequestProcessor;
import com.enonic.cms.core.portal.processor.DirectiveRequestProcessorContext;
import com.enonic.cms.core.portal.processor.DirectiveRequestProcessorResult;
import com.enonic.cms.core.portal.processor.PageRequestProcessorContext;
import com.enonic.cms.core.portal.processor.PageRequestProcessorFactory;
import com.enonic.cms.core.portal.processor.PageRequestProcessorResult;
import com.enonic.cms.core.portal.rendering.PageRenderer;
import com.enonic.cms.core.portal.rendering.PageRendererContext;
import com.enonic.cms.core.portal.rendering.PageRendererFactory;
import com.enonic.cms.core.portal.rendering.RenderedPageResult;
import com.enonic.cms.core.portal.rendering.RenderedWindowResult;
import com.enonic.cms.core.portal.rendering.WindowRenderer;
import com.enonic.cms.core.portal.rendering.WindowRendererContext;
import com.enonic.cms.core.portal.rendering.WindowRendererFactory;
import com.enonic.cms.core.security.user.UserEntity;
import com.enonic.cms.core.servlet.ServletRequestAccessor;
import com.enonic.cms.core.structure.SiteEntity;
import com.enonic.cms.core.structure.SitePath;
import com.enonic.cms.core.structure.menuitem.MenuItemEntity;
import com.enonic.cms.core.structure.menuitem.MenuItemType;
import com.enonic.cms.core.structure.page.WindowKey;
import com.enonic.cms.core.structure.portlet.PortletEntity;
import com.enonic.cms.store.dao.ContentDao;
import com.enonic.cms.store.dao.LanguageDao;
import com.enonic.cms.store.dao.PortletDao;
import com.enonic.cms.store.dao.SiteDao;
import com.enonic.cms.store.dao.UserDao;
/**
* Class for processing portal requests. Create new instance for each use.
*/
public class PortalRequestProcessor
{
private final PortalRequest request;
private UserEntity requester;
private SiteDao siteDao;
private PortletDao portletDao;
private UserDao userDao;
private ContentDao contentDao;
private LanguageDao languageDao;
private PageRendererFactory pageRendererFactory;
private WindowRendererFactory windowRendererFactory;
private PortalAccessService portalAccessService;
private PageRequestProcessorFactory pageRequestProcessorFactory;
private LivePortalTraceService liveTraceService;
public PortalRequestProcessor( PortalRequest request )
{
this.request = request;
}
public PortalResponse processRequest()
{
final PortalRequestTrace portalRequestTrace = liveTraceService.getCurrentPortalRequestTrace();
PortalResponse portalResponse = null;
try
{
final SitePath sitePath = request.getSitePath();
requester = resolveRequester( request );
final SiteEntity requestedSite = resolveSite( sitePath );
PortalRequestTracer.traceRequestedSite( portalRequestTrace, requestedSite );
PortalRequestTracer.traceRequester( portalRequestTrace, requester );
PageRequestContextResolver pageRequestContextResolver = new PageRequestContextResolver( contentDao );
final PageRequestContext pageRequestContext = pageRequestContextResolver.resolvePageRequestContext( requestedSite, sitePath );
final MenuItemEntity menuItem = pageRequestContext.getRequestedMenuItem();
if ( menuItem == null )
{
throw new ResourceNotFoundException( sitePath.getSiteKey(), request.getOriginalUrl(), request.getHttpReferer() );
}
final MenuItemRequestType type = resolveMenuItemRequestType( menuItem, pageRequestContext );
if ( type == MenuItemRequestType.PAGE )
{
RequestParameters mergedRequestParameters =
RequestParametersMerger.mergeWithMenuItemRequestParameters( sitePath.getRequestParameters(),
menuItem.getRequestParameters() );
SitePath newSitePath = new SitePath( sitePath.getSiteKey(), sitePath.getLocalPath(), mergedRequestParameters );
newSitePath.setContentPath( pageRequestContext.getResolvedContentPath() );
request.setSitePath( newSitePath );
pageRequestContext.setSitePath( newSitePath );
portalResponse = processPageRequest( pageRequestContext );
}
else if ( type == MenuItemRequestType.DIRECTIVE )
{
portalResponse = processDirectiveRequest( request, menuItem );
}
else
{
throw new IllegalArgumentException(
"Menuitem request type not supported: " + type + ". The menuItem causing this problem is: " + menuItem.getKey() +
" - " + menuItem.getPathAsString() );
}
}
finally
{
PortalRequestTracer.tracePortalResponse( portalRequestTrace, portalResponse );
}
return portalResponse;
}
private PortalResponse processPageRequest( final PageRequestContext pageRequestContext )
{
Preconditions.checkNotNull( pageRequestContext.getRequestedMenuItem(), "Expected requested menuItem not to be null at this stage" );
Preconditions.checkNotNull( pageRequestContext.getPageRequestType(), "Expected pageRequestType not to be null at this stage" );
final AbstractPageRequestProcessor pageRequestProcessor = createPageRequestProcessor( request, pageRequestContext, requester );
final PageRequestProcessorResult processorResult = pageRequestProcessor.process();
if ( processorResult.getRedirectToSitePath() != null )
{
RedirectInstruction redirectInstruction = new RedirectInstruction( processorResult.getRedirectToSitePath() );
redirectInstruction.setPermanentRedirect( true );
return PortalResponse.createRedirect( redirectInstruction );
}
HttpServletRequest httpRequest = ServletRequestAccessor.getRequest();
if ( processorResult.getHttpRequest() != null )
{
httpRequest = processorResult.getHttpRequest();
}
ServletRequestAccessor.setRequest( httpRequest );
final SitePath sitePath = processorResult.getSitePath();
final PageRequestType pageRequestType = pageRequestContext.getPageRequestType();
final MenuItemEntity menuItem = pageRequestContext.getRequestedMenuItem();
final SiteEntity site = menuItem.getSite();
if ( sitePath.hasReferenceToWindow() )
{
final WindowReference windowReference = sitePath.getWindowReference();
final PortletEntity requestedPortlet =
portletDao.findBySiteKeyAndNameIgnoreCase( site.getKey(), windowReference.getPortletName() );
if ( requestedPortlet == null )
{
throw new ResourceNotFoundException( site.getKey(), sitePath.getLocalPath() );
}
final WindowRendererContext windowRendererContext = new WindowRendererContext();
windowRendererContext.setContentFromRequest( processorResult.getContentFromRequest() );
windowRendererContext.setDeviceClass( processorResult.getDeviceClass() );
windowRendererContext.setForceNoCacheUsage( false );
windowRendererContext.setEncodeURIs( request.isEncodeURIs() );
windowRendererContext.setHttpRequest( httpRequest );
windowRendererContext.setInvocationCache( new DataSourceInvocationCache() );
windowRendererContext.setLanguage( processorResult.getLanguage() );
windowRendererContext.setLocale( processorResult.getLocale() );
windowRendererContext.setMenuItem( menuItem );
windowRendererContext.setOriginalSitePath( request.getOriginalSitePath() );
windowRendererContext.setOriginalUrl( request.getOriginalUrl() );
windowRendererContext.setPageRequestType( pageRequestType );
windowRendererContext.setPreviewContext( request.getPreviewContext() );
windowRendererContext.setRegionsInPage( processorResult.getRegionsInPage() );
windowRendererContext.setRenderedInline( false );
windowRendererContext.setRenderer( requester );
windowRendererContext.setTicketId( request.getTicketId() );
windowRendererContext.setSite( site );
windowRendererContext.setSitePath( sitePath );
windowRendererContext.setVerticalSession( request.getVerticalSession() );
final WindowRenderer windowRenderer = windowRendererFactory.createPortletRenderer( windowRendererContext );
WindowKey requestedWindow = new WindowKey( menuItem.getKey(), requestedPortlet.getPortletKey() );
final RenderedWindowResult renderedWindowResult = windowRenderer.renderWindowDirect( requestedWindow );
return PortalResponse.createContent( renderedWindowResult );
}
else
{
final PageRendererContext pageRendererContext = new PageRendererContext();
pageRendererContext.setContentFromRequest( processorResult.getContentFromRequest() );
pageRendererContext.setDeviceClass( processorResult.getDeviceClass() );
pageRendererContext.setForceNoCacheUsage( false );
pageRendererContext.setHttpRequest( httpRequest );
pageRendererContext.setMenuItem( menuItem );
pageRendererContext.setLanguage( processorResult.getLanguage() );
pageRendererContext.setLocale( processorResult.getLocale() );
pageRendererContext.setOriginalUrl( request.getOriginalUrl() );
pageRendererContext.setOriginalSitePath( request.getOriginalSitePath() );
pageRendererContext.setRegionsInPage( processorResult.getRegionsInPage() );
pageRendererContext.setRenderer( requester );
pageRendererContext.setRequestTime( request.getRequestTime() );
pageRendererContext.setRunAsUser( processorResult.getRunAsUser() );
pageRendererContext.setPageRequestType( pageRequestType );
pageRendererContext.setPreviewContext( request.getPreviewContext() );
pageRendererContext.setProfile( request.getProfile() );
pageRendererContext.setTicketId( request.getTicketId() );
pageRendererContext.setSite( site );
pageRendererContext.setSitePath( sitePath );
pageRendererContext.setVerticalSession( request.getVerticalSession() );
PageRenderer pageRenderer = pageRendererFactory.createPageRenderer( pageRendererContext );
final RenderedPageResult result = pageRenderer.renderPage( processorResult.getPageTemplate() );
return PortalResponse.createContent( result );
}
}
private PortalResponse processDirectiveRequest( PortalRequest request, final MenuItemEntity menuItem )
{
final UserEntity requester = userDao.findByKey( request.getRequester() );
if ( requester == null )
{
throw new PortalRenderingException( "Requester not found, user key: " + request.getRequester() );
}
DirectiveRequestProcessorContext context = new DirectiveRequestProcessorContext();
context.setMenuItem( menuItem );
context.setOriginalSitePath( request.getOriginalSitePath() );
context.setSitePath( request.getSitePath() );
context.setRequester( requester );
context.setRequestParams( request.getRequestParams() );
DirectiveRequestProcessor directiveProcessor = new DirectiveRequestProcessor( context );
directiveProcessor.setPortalAccessService( portalAccessService );
DirectiveRequestProcessorResult result = directiveProcessor.process();
if ( result.getRedirectToAbsoluteURL() != null )
{
RedirectInstruction redirectInstruction = new RedirectInstruction( result.getRedirectToAbsoluteURL() );
redirectInstruction.setPermanentRedirect( false );
return PortalResponse.createRedirect( redirectInstruction );
}
else if ( result.getRedirectToSitePath() != null )
{
RedirectInstruction redirectInstruction = new RedirectInstruction( result.getRedirectToSitePath() );
redirectInstruction.setPermanentRedirect( true );
return PortalResponse.createRedirect( redirectInstruction );
}
else if ( result.getForwardToSitePath() != null )
{
return PortalResponse.createForward( result.getForwardToSitePath() );
}
else
{
throw new PortalRenderingException(
"Unexpected directive request processor result: nothing set for menuItem: " + menuItem.getKey() + " - " +
menuItem.getPathAsString() );
}
}
private MenuItemRequestType resolveMenuItemRequestType( MenuItemEntity menuItem, PageRequestContext pageRequestContext )
{
MenuItemType menuItemType = menuItem.getType();
if ( menuItemType == MenuItemType.PAGE )
{
return MenuItemRequestType.PAGE;
}
else if ( menuItemType == MenuItemType.CONTENT )
{
return MenuItemRequestType.PAGE;
}
else if ( menuItemType == MenuItemType.SHORTCUT )
{
return MenuItemRequestType.DIRECTIVE;
}
else if ( menuItemType == MenuItemType.URL )
{
return MenuItemRequestType.DIRECTIVE;
}
else if ( menuItemType == MenuItemType.SECTION )
{
if ( pageRequestContext.hasPathToContent() )
{
// request to a content is a PAGE request, even if under a SECTION (that normally do not support requests)
return MenuItemRequestType.PAGE;
}
else
{
throw new ResourceNotFoundException( pageRequestContext.getSitePath().getSiteKey(),
pageRequestContext.getSitePath().getLocalPath() );
}
}
else if ( menuItemType == MenuItemType.LABEL )
{
if ( pageRequestContext.hasPathToContent() )
{
// request to a content is a PAGE request, even if under a LABEL (that normally do not support requests)
return MenuItemRequestType.PAGE;
}
throw new PortalConfigurationException( "Menuitem (" + menuItem.getKey() + " - " + menuItem.getPathAsString() +
") of type label does not support requests. SitePath = " +
pageRequestContext.getSitePath().asString() );
}
else
{
String message = "The request for menuItem (" + menuItem.getKey() + " - " + menuItem.getPathAsString() +
") could not be completed for path : " +
( pageRequestContext.getSitePath() == null ? "unknown" : pageRequestContext.getSitePath().asString() ) +
" - Unhandled menuitem type for request:" + menuItemType;
throw new IllegalArgumentException( message );
}
}
private AbstractPageRequestProcessor createPageRequestProcessor( final PortalRequest request,
final PageRequestContext pageRequestContext,
final UserEntity requester )
{
final PageRequestProcessorContext pageRequestProcessorContext = new PageRequestProcessorContext();
pageRequestProcessorContext.setHttpRequest( ServletRequestAccessor.getRequest() );
pageRequestProcessorContext.setRequestTime( request.getRequestTime() );
pageRequestProcessorContext.setPageRequestType( pageRequestContext.getPageRequestType() );
pageRequestProcessorContext.setRequester( requester );
pageRequestProcessorContext.setSitePath( request.getSitePath() );
pageRequestProcessorContext.setSite( pageRequestContext.getRequestedMenuItem().getSite() );
pageRequestProcessorContext.setMenuItem( pageRequestContext.getRequestedMenuItem() );
pageRequestProcessorContext.setContentPath( pageRequestContext.getContentPath() );
pageRequestProcessorContext.setPreviewContext( request.getPreviewContext() );
if ( request.getOverridingLanguage() > -1 )
{
LanguageEntity overridingLanguage = languageDao.findByKey( new LanguageKey( request.getOverridingLanguage() ) );
pageRequestProcessorContext.setOverridingLanguage( overridingLanguage );
}
return pageRequestProcessorFactory.create( pageRequestProcessorContext );
}
private SiteEntity resolveSite( final SitePath sitePath )
{
final SiteEntity site = siteDao.findByKey( sitePath.getSiteKey() );
if ( site == null )
{
throw new SiteNotFoundException( sitePath.getSiteKey() );
}
return site;
}
private UserEntity resolveRequester( final PortalRequest request )
{
final UserEntity requester = userDao.findByKey( request.getRequester() );
if ( requester == null )
{
throw new PortalRenderingException( "Requester not found, user key: " + request.getRequester() );
}
return requester;
}
public void setSiteDao( SiteDao siteDao )
{
this.siteDao = siteDao;
}
public void setPortletDao( PortletDao portletDao )
{
this.portletDao = portletDao;
}
public void setUserDao( UserDao userDao )
{
this.userDao = userDao;
}
public void setContentDao( ContentDao contentDao )
{
this.contentDao = contentDao;
}
public void setLanguageDao( LanguageDao languageDao )
{
this.languageDao = languageDao;
}
public void setPageRendererFactory( PageRendererFactory pageRendererFactory )
{
this.pageRendererFactory = pageRendererFactory;
}
public void setWindowRendererFactory( WindowRendererFactory windowRendererFactory )
{
this.windowRendererFactory = windowRendererFactory;
}
public void setPortalAccessService( PortalAccessService portalAccessService )
{
this.portalAccessService = portalAccessService;
}
public void setPageRequestProcessorFactory( PageRequestProcessorFactory pageRequestProcessorFactory )
{
this.pageRequestProcessorFactory = pageRequestProcessorFactory;
}
public void setLiveTraceService( LivePortalTraceService liveTraceService )
{
this.liveTraceService = liveTraceService;
}
}