/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.server.service.admin.mvc.controller;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.context.support.ServletContextResource;
import org.springframework.web.servlet.ModelAndView;
import com.google.common.base.Preconditions;
import com.enonic.cms.core.AdminConsoleTranslationService;
import com.enonic.cms.core.portal.rendering.tracing.DataTraceInfo;
import com.enonic.cms.core.portal.rendering.tracing.PagePortletTraceInfo;
import com.enonic.cms.core.portal.rendering.tracing.PageTraceInfo;
import com.enonic.cms.core.portal.rendering.tracing.RenderTrace;
import com.enonic.cms.core.portal.rendering.tracing.RenderTraceInfo;
import com.enonic.cms.core.security.user.User;
import com.enonic.cms.core.service.AdminService;
import com.enonic.cms.core.structure.SiteKey;
import com.enonic.cms.core.structure.portlet.PortletKey;
/**
* This class implements the debug controller.
*/
public final class SiteDebugInfoController
extends SiteDebugController
{
private AdminService adminService;
@Autowired
public void setAdminService( AdminService value )
{
this.adminService = value;
}
/**
* Handle the request.
*/
protected ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response )
throws Exception
{
String key = request.getParameter( "key" );
String type = request.getParameter( "type" );
if ( ( key == null ) || ( type == null ) )
{
return null;
}
final RenderTraceInfo renderTraceInfo = findRenderTraceInfo( key );
if ( "javascript".equals( type ) )
{
serveJavaScriptFile( renderTraceInfo, request, response );
}
else if ( "css".equals( type ) )
{
serveCssFile( response );
}
else if ( "renderXml".equals( type ) )
{
serveRenderXml( findDataTraceInfo( renderTraceInfo, key ), response );
}
else if ( "renderTrace".equals( type ) )
{
serveRenderTrace( findDataTraceInfo( renderTraceInfo, key ), response );
}
return null;
}
/**
* Serve bootstrap info.
*/
private void serveJavaScriptFile( RenderTraceInfo info, HttpServletRequest request, HttpServletResponse response )
throws Exception
{
response.setContentType( "text/javascript; charset=utf-8" );
response.setCharacterEncoding( "utf-8" );
PrintWriter writer = new PrintWriter( response.getWriter() );
writer.println( localizeScript( request, readStaticFile( "admin/ice/ice.js" ) ) );
writer.println( "cms.ice.Setup.setBaseUrl('" + getAdminBaseUrl( request ) + "');" );
writer.println( createSetPageInfoStatement( info.getKey(), info.getPageInfo(), request ) );
for ( PagePortletTraceInfo objectInfo : info.getPageInfo().getPortlets() )
{
writer.println( createAddPageObjectInfoStatement( info.getKey() + "-" + objectInfo.getKey(), objectInfo, request ) );
}
writer.close();
}
/**
* Create set page info statement.
*/
private String createSetPageInfoStatement( String key, PageTraceInfo info, HttpServletRequest request )
{
String title = StringEscapeUtils.escapeJavaScript( info.getTitle() );
String infoMenu = StringEscapeUtils.escapeJavaScript( createDataInfoMenu( key, info, request, true ) );
StringBuffer str = new StringBuffer();
str.append( "cms.ice.Setup.setPageInfo('" ).append( key ).append( "', '" );
str.append( title ).append( "', \"" ).append( infoMenu ).append( "\");" );
return str.toString();
}
/**
* Create add page info statement.
*/
private String createAddPageObjectInfoStatement( String key, PagePortletTraceInfo info, HttpServletRequest request )
{
String title = StringEscapeUtils.escapeJavaScript( info.getTitle() );
String infoMenu = StringEscapeUtils.escapeJavaScript( createDataInfoMenu( key, info, request, false ) );
StringBuffer str = new StringBuffer();
str.append( "cms.ice.Setup.addPortletInfo('" ).append( key ).append( "', '" );
str.append( title ).append( "', \"" ).append( infoMenu ).append( "\", " ).append( String.valueOf( info.isCacheable() ) ).append(
");" );
return str.toString();
}
/**
* Create data info menu.
*/
private String createDataInfoMenu( String key, DataTraceInfo info, HttpServletRequest request, boolean isPage )
{
User user = securityService.getLoggedInPortalUser();
SiteKey siteKey = info.getSiteKey();
boolean hasAdmin = adminService.isSiteAdmin( user, siteKey );
boolean hasDev = adminService.isDeveloper( user );
String adminBaseUrl = getAdminBaseUrl( request );
String baseUrl = getDebugBaseUrlWithHost( request, "__info__?key=" + key );
StringBuffer str = new StringBuffer();
// Header
final String title = StringEscapeUtils.escapeHtml( info.getTitle() );
if ( isPage )
{
str.append( "<div style='float: left; width: 70%'><h3>" ).append( title ).append( "</h3></div>" );
str.append( "<div style='float: left; width: 30%' id='ice-on-of-container'></div>" );
}
else
{
str.append( "<div><h3>" ).append( title ).append( "</h3></div>" );
}
if ( !info.getContentInfo().isEmpty() || hasAdmin )
{
str.append( "<div class='ice-divider'><!-- --></div>" );
}
// Content Wizard
String contentWizardUrl = adminBaseUrl + "adminpage?page=960&op=createcontentwizard_step1&source=ice";
str.append( "<a href='javascript:void(0)'" );
str.append( " onclick='javascript:cms.ice.Utils.openWindow(\"" ).append( contentWizardUrl ).append( "\", 900, 600)'" );
str.append( " style='background-image:url(" ).append( adminBaseUrl ).append( "ice/images/icon_state_unsaved_draft.gif);'" );
str.append( ">" );
str.append( "<span class='ice-lang-placeholder-create-content'><!-- --></span>" );
str.append( "</a>" );
if ( !info.getContentInfo().isEmpty() )
{
str.append( "<div class='ice-divider'><!-- --></div>" );
}
// Edit content
if ( !info.getContentInfo().isEmpty() )
{
str.append( "<div class='ice-menu-item-content-container'>" );
for ( int contentKey : info.getContentInfo().keySet() )
{
str.append( createEditContentLink( adminBaseUrl, info.getContentInfo().get( contentKey ), contentKey ) );
}
str.append( "</div>" );
}
// View render XML and View render trace
if ( hasAdmin || hasDev )
{
boolean showDivider = !info.getContentInfo().isEmpty() && hasAdmin || hasDev;
if ( showDivider )
{
str.append( "<div class='ice-divider'><!-- --></div>" );
}
String menuItemViewTraceText = isPage
? "<span class='ice-lang-placeholder-page-trace'><!-- --></span>"
: "<span class='ice-lang-placeholder-portlet-trace'><!-- --></span>";
String menuItemViewXMLText = isPage
? "<span class='ice-lang-placeholder-page-xml'><!-- --></span>"
: "<span class='ice-lang-placeholder-portlet-xml'><!-- --></span>";
str.append( createMenuInfoLink( menuItemViewTraceText, baseUrl + "&type=renderTrace", "_blank",
adminBaseUrl + "ice/images/icon_xml.gif", null ) );
str.append(
createMenuInfoLink( menuItemViewXMLText, baseUrl + "&type=renderXml", "_blank", adminBaseUrl + "ice/images/icon_xml.gif",
null ) );
}
// Edit object
if ( info instanceof PagePortletTraceInfo && hasAdmin )
{
PagePortletTraceInfo pageObjectTraceInfo = (PagePortletTraceInfo) info;
SiteKey pageObjectSiteKey = pageObjectTraceInfo.getSiteKey();
PortletKey portletKey = pageObjectTraceInfo.getKey();
String editPortletUrl =
adminBaseUrl + "adminpage?page=900&op=form&subop=popup&key=" + portletKey + "&menukey=" + pageObjectSiteKey.toInt() +
"&fieldname=null&fieldrow=-1&callback=cms.ice.Utils.reloadPage";
if ( hasDev )
{
str.append( "<div class='ice-divider'><!-- --></div>" );
}
str.append( "<a href='javascript:void(0)'" );
str.append( " onclick='cms.ice.Utils.openWindow(\"" ).append( editPortletUrl ).append( "\", 900, 600)'" );
str.append( " style='background-image:url(" ).append( adminBaseUrl ).append( "ice/images/icon_object.gif);'>" );
str.append( "<span class='ice-lang-placeholder-edit-portlet'><!-- --></span>" );
str.append( "</a>" );
}
return str.toString();
}
/**
* Create edit content link.
*/
private String createEditContentLink( String baseUrl, String name, int contentKey )
{
StringBuffer str = new StringBuffer();
String editContentUrl = baseUrl + "adminpage?page=993&op=form&key=" + contentKey +
"&versionkey=-1&subop=popup&fieldname=null&fieldrow=-1&callback=cms.ice.Utils.reloadPage&logread=true";
str.append( "<a href='javascript: void(0)'" );
str.append( " onclick='javascript: cms.ice.Utils.openWindow(\"" ).append( editContentUrl ).append( "\", 900, 600)'" );
str.append( " style='background-image: url(" ).append( baseUrl ).append( "ice/images/edit.gif);'>" );
str.append( StringEscapeUtils.escapeHtml( name ) );
str.append( "</a>" );
return str.toString();
}
/**
* Create info menu link.
*/
private String createMenuInfoLink( String name, String link, String target, String pathToIcon, String onClick )
{
StringBuffer str = new StringBuffer();
if ( link == null )
{
link = "void(0)";
}
str.append( "<a href='" ).append( link ).append( "'" );
if ( target != null )
{
str.append( " target='" ).append( target ).append( "'" );
}
if ( onClick != null )
{
str.append( " onclick='" ).append( onClick ).append( "'" );
}
if ( pathToIcon != null )
{
str.append( " style='background-image:url(" ).append( pathToIcon ).append( ");'" );
}
str.append( ">" ).append( name ).append( "</a>" );
return str.toString();
}
/**
* Serve bootstrap info.
*/
private void serveCssFile( HttpServletResponse response )
throws Exception
{
response.setContentType( "text/css" );
PrintWriter writer = new PrintWriter( response.getWriter() );
writer.println( readStaticFile( "admin/ice/ice.css" ) );
writer.close();
}
/**
* Read external javascript file.
*/
private String readStaticFile( String path )
throws Exception
{
return readStaticFile( new ServletContextResource( getServletContext(), path ) );
}
/**
* Translate javascript localization.
*/
private String localizeScript( HttpServletRequest request, String script )
throws Exception
{
String languageCode = (String) request.getSession( true ).getAttribute( "languageCode" );
Map translationMap = AdminConsoleTranslationService.getInstance().getTranslationMap( languageCode );
StringWriter result = new StringWriter();
StringReader source = new StringReader( script );
TranslationWriter dest = new TranslationWriter( translationMap, result );
FileCopyUtils.copy( source, dest );
return result.toString();
}
/**
* Read external javascript file.
*/
private String readStaticFile( Resource path )
throws Exception
{
StringWriter out = new StringWriter();
InputStreamReader in = new InputStreamReader( path.getInputStream() );
FileCopyUtils.copy( in, out );
return out.getBuffer().toString();
}
/**
* Find render trace info.
*/
private RenderTraceInfo findRenderTraceInfo( String key )
{
int pos = key.indexOf( '-' );
if ( pos > -1 )
{
key = key.substring( 0, pos );
}
return RenderTrace.getRenderTraceInfo( key );
}
/**
* Find render trace info.
*/
private DataTraceInfo findDataTraceInfo( RenderTraceInfo renderTraceInfo, String key )
{
Preconditions.checkNotNull( renderTraceInfo, "renderTraceInfo is unexpectedly null" );
PageTraceInfo pageInfo = renderTraceInfo.getPageInfo();
int pos = key.indexOf( '-' );
if ( pos > -1 )
{
return pageInfo.getPortlet( new PortletKey( key.substring( pos + 1 ) ) );
}
else
{
return pageInfo;
}
}
/**
* Serve render xml.
*/
private void serveRenderXml( DataTraceInfo info, HttpServletResponse response )
throws Exception
{
response.setContentType( "text/xml; charset=UTF-8" );
response.getWriter().println( info.getDataSourceResult().getAsString() );
}
/**
* Serve render trace.
*/
private void serveRenderTrace( DataTraceInfo info, HttpServletResponse response )
throws Exception
{
response.setContentType( "text/xml; charset=UTF-8" );
response.getWriter().println( info.getRenderTraceAsXml().getAsString() );
}
}