/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.vertical.adminweb.handlers.preview;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.joda.time.DateTime;
import com.enonic.esl.containers.ExtendedMap;
import com.enonic.esl.servlet.http.HttpServletRequestWrapper;
import com.enonic.vertical.engine.handlers.MenuHandler;
import com.enonic.cms.core.Attribute;
import com.enonic.cms.core.Path;
import com.enonic.cms.core.content.ContentAndVersion;
import com.enonic.cms.core.content.ContentEntity;
import com.enonic.cms.core.content.ContentKey;
import com.enonic.cms.core.content.ContentLocation;
import com.enonic.cms.core.content.ContentLocationSpecification;
import com.enonic.cms.core.content.ContentLocations;
import com.enonic.cms.core.content.ContentVersionEntity;
import com.enonic.cms.core.content.ContentVersionKey;
import com.enonic.cms.core.language.LanguageEntity;
import com.enonic.cms.core.language.LanguageResolver;
import com.enonic.cms.core.portal.PageRequestType;
import com.enonic.cms.core.portal.ReservedLocalPaths;
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.RegionsResolver;
import com.enonic.cms.core.portal.rendering.RenderedPageResult;
import com.enonic.cms.core.portal.ticket.TicketGenerator;
import com.enonic.cms.core.preview.ContentPreviewContext;
import com.enonic.cms.core.preview.PreviewContext;
import com.enonic.cms.core.preview.PreviewService;
import com.enonic.cms.core.resolver.ResolverContext;
import com.enonic.cms.core.resolver.deviceclass.DeviceClassResolverService;
import com.enonic.cms.core.resolver.locale.LocaleResolverService;
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.page.Regions;
import com.enonic.cms.core.structure.page.template.PageTemplateEntity;
import com.enonic.cms.core.time.TimeService;
import com.enonic.cms.store.dao.ContentDao;
import com.enonic.cms.store.dao.ContentVersionDao;
/**
* Feb 22, 2010
*/
public class PreviewContentHandler
{
private HttpServletRequest httpRequest;
private HttpSession session;
private TimeService timeService;
private PreviewService previewService;
private PageRendererFactory pageRendererFactory;
private ContentDao contentDao;
private ContentVersionDao contentVersionDao;
private LocaleResolverService localeResolverService;
private DeviceClassResolverService deviceClassResolverService;
private MenuHandler menuHandler;
private ExtendedMap formItems;
private UserEntity previewer;
private SiteEntity site;
private PageTemplateEntity pageTemplate;
private final ContentKey contentKey;
private final boolean contentIsNew;
public PreviewContentHandler( ContentKey contentKey, MenuHandler menuHandler )
{
this.contentKey = contentKey;
this.contentIsNew = contentKey == null;
this.menuHandler = menuHandler;
}
public RenderedPageResult renderPreview()
{
final ContentAndVersion contentAndVersion = resolveContentAndVersion();
final ContentEntity content = contentAndVersion.getContent();
if ( content.getKey() == null )
{
throw new IllegalArgumentException( "Preview of unsaved content is not supported" );
}
//final XMLDocument contentXml = createXml( contentAndVersion );
final MenuItemEntity menuItem = resolveContentHome( content );
// Override base path
final SitePath sitePath = new SitePath( site.getKey(), Path.ROOT.appendPath( ReservedLocalPaths.PATH_PAGE ) );
httpRequest.setAttribute( Attribute.ORIGINAL_SITEPATH, sitePath );
httpRequest.setAttribute( Attribute.PREVIEW_ENABLED, "true" );
// wrap and modify request
HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper( httpRequest );
wrappedRequest.setServletPath( "/site" );
wrappedRequest.setParameter( "id", menuItem.getKey().toString() );
if ( this.contentKey != null )
{
wrappedRequest.setParameter( "key", contentKey.toString() );
}
ServletRequestAccessor.setRequest( wrappedRequest );
ContentPreviewContext contentPreviewContext = new ContentPreviewContext( contentAndVersion );
PreviewContext previewContext = new PreviewContext( contentPreviewContext );
previewService.setPreviewContext( previewContext );
// prepare data source result processors
//final DataSourceProcessor[] dsrProcessors = createDataSourceProcessor( contentXml );
final UserEntity runAsUser = resolveRunAsUser( menuItem );
final Regions regionsInPage = RegionsResolver.resolveRegionsForPageRequest( menuItem, pageTemplate, PageRequestType.CONTENT );
final LanguageEntity language = LanguageResolver.resolve( content, site, menuItem );
final ResolverContext resolverContext = createResolverContext( menuItem, wrappedRequest, language );
final Locale locale = localeResolverService.getLocale( resolverContext );
final String deviceClass = deviceClassResolverService.getDeviceClass( resolverContext );
sitePath.addParam( "id", menuItem.getKey().toString() );
if ( this.contentKey != null )
{
sitePath.addParam( "key", contentKey.toString() );
}
PageRendererContext pageRendererContext = new PageRendererContext();
pageRendererContext.setDeviceClass( deviceClass );
pageRendererContext.setForceNoCacheUsage( true );
pageRendererContext.setHttpRequest( wrappedRequest );
pageRendererContext.setLanguage( language );
pageRendererContext.setLocale( locale );
pageRendererContext.setMenuItem( menuItem );
pageRendererContext.setContentFromRequest( content );
pageRendererContext.setOriginalSitePath( sitePath );
pageRendererContext.setPageRequestType( PageRequestType.CONTENT );
pageRendererContext.setPreviewContext( previewContext );
pageRendererContext.setRegionsInPage( regionsInPage );
pageRendererContext.setRenderer( previewer );
pageRendererContext.setRequestTime( new DateTime() );
pageRendererContext.setRunAsUser( runAsUser );
pageRendererContext.setTicketId( TicketGenerator.getOrGenerate( httpRequest ) );
pageRendererContext.setSite( site );
pageRendererContext.setSitePath( sitePath );
// render page
PageRenderer renderer = pageRendererFactory.createPageRenderer( pageRendererContext );
return renderer.renderPage( pageTemplate );
}
private ContentAndVersion resolveContentAndVersion()
{
ContentAndVersion contentAndVersion;
final boolean previewNewContentOrVersionBeeingEdited = contentIsNew || formItems.getBoolean( "sessiondata", false );
final boolean previewOfSpecifiedApprovedOrArchivedVersion = formItems.containsKey( "versionkey" );
if ( previewNewContentOrVersionBeeingEdited )
{
// preview of content being edited, either new or existing requested
contentAndVersion = resolveContentAndVersionForNewContentOrEditedVersion();
}
else if ( previewOfSpecifiedApprovedOrArchivedVersion )
{
// preview of archived or approved version requested...
contentAndVersion = resolveContentAndVersionForArchivedOrApprovedVersion();
}
else
{
// preview of main version...
contentAndVersion = resolveContentAndVersionForMainVersion();
}
final ContentEntity content = contentAndVersion.getContent();
// Ensure available from is set when not, cause many rendering templates are depending on that, since that will be the normal situation when rendering
if ( content.getAvailableFrom() == null )
{
content.setAvailableFrom( timeService.getNowAsDateTime().toDate() );
}
return contentAndVersion;
}
private ContentAndVersion resolveContentAndVersionForNewContentOrEditedVersion()
{
ContentAndVersion contentAndVersion;
ContentAndVersion contentAndVersionFromSession = (ContentAndVersion) session.getAttribute( "_preview-content-and-version" );
ContentEntity content = new ContentEntity( contentAndVersionFromSession.getContent() );
ContentVersionEntity version = contentAndVersionFromSession.getVersion();
if ( contentIsNew )
{
// apply not-yet set (but needed) meta data on the new content
final Date timeNow = timeService.getNowAsDateTime().toDate();
content.setCreatedAt( timeNow );
content.setTimestamp( timeNow );
content.setOwner( previewer );
version.setModifiedBy( previewer );
version.setModifiedAt( timeNow );
}
else
{
// ensure edited content are having the same menu locations as the existing one
ContentEntity existingContent = contentDao.findByKey( contentKey );
content.setDirectMenuItemPlacements( existingContent.getDirectMenuItemPlacements() );
content.setSectionContents( existingContent.getSectionContents() );
content.setContentHomes( existingContent.getContentHomesAsMap() );
}
contentAndVersion = new ContentAndVersion( content, version );
return contentAndVersion;
}
private ContentAndVersion resolveContentAndVersionForArchivedOrApprovedVersion()
{
ContentAndVersion contentAndVersion;
ContentEntity existingContent = contentDao.findByKey( contentKey );
ContentEntity content = new ContentEntity( existingContent );
ContentVersionKey versionKey = new ContentVersionKey( formItems.getInt( "versionkey" ) );
ContentVersionEntity version = contentVersionDao.findByKey( versionKey );
contentAndVersion = new ContentAndVersion( content, version );
content.setMainVersion( version );
version.setContent( content );
return contentAndVersion;
}
private ContentAndVersion resolveContentAndVersionForMainVersion()
{
ContentAndVersion contentAndVersion;
ContentEntity existingContent = contentDao.findByKey( contentKey );
ContentEntity content = new ContentEntity( existingContent );
ContentVersionEntity version = content.getMainVersion();
contentAndVersion = new ContentAndVersion( content, version );
content.setMainVersion( version );
version.setContent( content );
return contentAndVersion;
}
private MenuItemEntity resolveContentHome( ContentEntity content )
{
if ( contentIsNew )
{
// fallback when previewing new content
return getSiteFrontPageOrFirstMenuItem();
}
ContentLocationSpecification contentLocationSpec = new ContentLocationSpecification();
contentLocationSpec.setSiteKey( site.getKey() );
contentLocationSpec.setIncludeInactiveLocationsInSection( false );
ContentLocations contentLocations = content.getLocations( contentLocationSpec );
ContentLocation contentLocation = contentLocations.getHomeLocation( site.getKey() );
if ( contentLocation != null )
{
return contentLocation.getMenuItem();
}
// fallback
return getSiteFrontPageOrFirstMenuItem();
}
private MenuItemEntity getSiteFrontPageOrFirstMenuItem()
{
if ( site.getFrontPage() != null )
{
return site.getFrontPage();
}
return site.getFirstMenuItem();
}
private UserEntity resolveRunAsUser( MenuItemEntity menuItem )
{
UserEntity runAsUser = menuItem.resolveRunAsUser( previewer, true, menuHandler );
if ( runAsUser == null )
{
runAsUser = previewer;
}
return runAsUser;
}
private ResolverContext createResolverContext( MenuItemEntity menuItem, HttpServletRequestWrapper wrappedRequest,
LanguageEntity language )
{
final ResolverContext resolverContext = new ResolverContext( wrappedRequest, site, menuItem, language );
resolverContext.setUser( previewer );
return resolverContext;
}
public void setPageRendererFactory( PageRendererFactory pageRendererFactory )
{
this.pageRendererFactory = pageRendererFactory;
}
public void setHttpRequest( HttpServletRequest httpRequest )
{
this.httpRequest = httpRequest;
}
public void setSession( HttpSession session )
{
this.session = session;
}
public void setContentDao( ContentDao contentDao )
{
this.contentDao = contentDao;
}
public void setContentVersionDao( ContentVersionDao contentVersionDao )
{
this.contentVersionDao = contentVersionDao;
}
public void setLocaleResolverService( LocaleResolverService localeResolverService )
{
this.localeResolverService = localeResolverService;
}
public void setDeviceClassResolverService( DeviceClassResolverService deviceClassResolverService )
{
this.deviceClassResolverService = deviceClassResolverService;
}
public void setFormItems( ExtendedMap formItems )
{
this.formItems = formItems;
}
public void setPreviewer( UserEntity previewer )
{
this.previewer = previewer;
}
public void setSite( SiteEntity site )
{
this.site = site;
}
public void setPageTemplate( PageTemplateEntity pageTemplate )
{
this.pageTemplate = pageTemplate;
}
public void setTimeService( TimeService timeService )
{
this.timeService = timeService;
}
public void setPreviewService( PreviewService previewService )
{
this.previewService = previewService;
}
}