blob: 9e74f89eae2ff1955ece445cb7d13eef88416605 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2012 Innoopract Informationssysteme GmbH and others.
* 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
* Frank Appel - replaced singletons and static fields (Bug 337787)
******************************************************************************/
package org.eclipse.rwt.internal.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.rwt.RWT;
import org.eclipse.rwt.branding.AbstractBranding;
import org.eclipse.rwt.branding.Header;
import org.eclipse.rwt.client.WebClient;
import org.eclipse.rwt.internal.RWTMessages;
import org.eclipse.rwt.internal.application.RWTFactory;
import org.eclipse.rwt.internal.branding.BrandingUtil;
import org.eclipse.rwt.internal.lifecycle.EntryPointUtil;
import org.eclipse.rwt.internal.protocol.ProtocolMessageWriter;
import org.eclipse.rwt.internal.resources.ResourceRegistry;
import org.eclipse.rwt.internal.service.StartupPageTemplateHolder.Variable;
import org.eclipse.rwt.internal.textsize.MeasurementUtil;
import org.eclipse.rwt.internal.theme.Theme;
import org.eclipse.rwt.internal.theme.ThemeManager;
import org.eclipse.rwt.internal.theme.ThemeUtil;
import org.eclipse.rwt.internal.util.HTTP;
import org.eclipse.rwt.internal.util.ParamCheck;
import org.eclipse.rwt.resources.IResource;
final class StartupPageConfigurer {
private static final String PACKAGE_NAME = StartupPageConfigurer.class.getPackage().getName();
private final static String FOLDER = PACKAGE_NAME.replace( '.', '/' );
private final static String INDEX_TEMPLATE = FOLDER + "/rwt-index.html";
private static final String DISPLAY_TYPE = "rwt.Display";
private static final String PROPERTY_FONTS = "fonts";
private static final String METHOD_PROBE = "probe";
private static final String PROPERTY_URL = "url";
private static final String PROPERTY_ROOT_ID = "rootId";
private static final String METHOD_INIT = "init";
private final ResourceRegistry resourceRegistry;
private final List<String> jsLibraries;
private final List<String> themeDefinitions;
private StartupPageTemplateHolder template;
StartupPageConfigurer( ResourceRegistry resourceRegistry ) {
this.resourceRegistry = resourceRegistry;
jsLibraries = new ArrayList<String>();
themeDefinitions = new ArrayList<String>();
}
////////////////////////////////////////////////////
// ILifeCycleServiceHandlerConfigurer implementation
public StartupPageTemplateHolder getTemplate() throws IOException {
readContent();
template.reset();
applyBranding();
applyEntryPointProperties();
applyLocalizeableMessages();
addThemeDefinitions();
template.replace( StartupPageTemplateHolder.VAR_LIBRARIES, getJsLibraries() );
template.replace( StartupPageTemplateHolder.VAR_APPSCRIPT, getAppScript() );
return template;
}
public void addJsLibrary( String location ) {
ParamCheck.notNull( location, "resource" );
jsLibraries.add( location );
}
///////////////////////////////////////
// Helping methods to load startup page
private void readContent() throws IOException {
if( template == null ) {
InputStream stream = loadTemplateFile();
InputStreamReader streamReader = new InputStreamReader( stream, HTTP.CHARSET_UTF_8 );
BufferedReader reader = new BufferedReader( streamReader );
try {
String line = reader.readLine();
StringBuilder buffer = new StringBuilder();
while( line != null ) {
buffer.append( line );
buffer.append( '\n' );
line = reader.readLine();
}
template = new StartupPageTemplateHolder( buffer.toString() );
} finally {
reader.close();
}
}
}
private static InputStream loadTemplateFile() throws IOException {
ClassLoader classLoader = StartupPageConfigurer.class.getClassLoader();
InputStream result = classLoader.getResourceAsStream( INDEX_TEMPLATE );
if ( result == null ) {
throw new IOException( "Failed to startup page: " + INDEX_TEMPLATE );
}
return result;
}
/////////////////////////////////////////
// Helping methods to adjust startup page
private static String getAppScript() {
StringBuilder code = new StringBuilder();
code.append( "org.eclipse.rwt.protocol.Processor.processMessage( " );
code.append( getStartupProtocolMessage( "w1" ) );
// TODO: The /*EOM*/ is needed for the native clients to determine where is the boot message in
// the initial start HTML page. Remove it when custom native clients boot process is implemented
code.append( " );/*EOM*/" );
return code.toString();
}
private static String getStartupProtocolMessage( String id ) {
ProtocolMessageWriter writer = new ProtocolMessageWriter();
appendCreateDisplay( id, writer );
appendStartupTextSizeProbe( id, writer );
appendInitDisplay( id, writer );
return writer.createMessage();
}
private static void appendCreateDisplay( String id, ProtocolMessageWriter writer ) {
writer.appendCreate( id, DISPLAY_TYPE );
}
private static void appendStartupTextSizeProbe( String id, ProtocolMessageWriter writer ) {
Object startupTextSizeProbeObject = getStartupTextSizeProbeObject();
if( startupTextSizeProbeObject != null ) {
Map<String, Object> args = new HashMap<String, Object>();
args.put( PROPERTY_FONTS, startupTextSizeProbeObject );
writer.appendCall( id, METHOD_PROBE, args );
}
}
private static void appendInitDisplay( String id, ProtocolMessageWriter writer ) {
Map<String, Object> args = new HashMap<String, Object>();
args.put( PROPERTY_URL, getUrl() );
args.put( PROPERTY_ROOT_ID, id ); // TODO [tb] : refactor client to remove this line
writer.appendCall( id, METHOD_INIT, args );
}
private static Object getStartupTextSizeProbeObject() {
return MeasurementUtil.getStartupProbeObject();
}
private static String getUrl() {
HttpServletRequest request = ContextProvider.getRequest();
String url = request.getServletPath().substring( 1 );
return ContextProvider.getResponse().encodeURL( url );
}
//////////////////////////
// Branding helper methods
private void applyBranding() throws IOException {
AbstractBranding branding = BrandingUtil.determineBranding();
BrandingUtil.registerResources( branding );
if( branding.getThemeId() != null ) {
ThemeUtil.setCurrentThemeId( branding.getThemeId() );
} else {
ThemeUtil.setCurrentThemeId( RWT.DEFAULT_THEME_ID );
}
replacePlaceholder( template, StartupPageTemplateHolder.VAR_BODY, branding.getBody() );
replacePlaceholder( template, StartupPageTemplateHolder.VAR_TITLE, branding.getTitle() );
String headers = BrandingUtil.headerMarkup( branding );
replacePlaceholder( template, StartupPageTemplateHolder.VAR_HEADERS, headers );
}
private void applyEntryPointProperties() {
Map<String, String> properties = EntryPointUtil.getCurrentEntryPointProperties();
if( !properties.isEmpty() ) {
String themeId = properties.get( WebClient.THEME_ID );
if( themeId != null && themeId.length() > 0 ) {
ThemeUtil.setCurrentThemeId( themeId );
}
String bodyHtml = properties.get( WebClient.BODY_HTML );
replacePlaceholder( template, StartupPageTemplateHolder.VAR_BODY, bodyHtml );
String title = properties.get( WebClient.PAGE_TITLE );
replacePlaceholder( template, StartupPageTemplateHolder.VAR_TITLE, title );
String headerMarkup = "";
String favIcon = properties.get( WebClient.FAVICON );
if( favIcon != null && favIcon.length() > 0 ) {
Header header = BrandingUtil.createHeaderForFavIcon( favIcon );
headerMarkup += BrandingUtil.createMarkupForHeaders( header );
}
String headHtml = properties.get( WebClient.HEAD_HTML );
if( headHtml != null ) {
headerMarkup += headHtml;
}
replacePlaceholder( template, StartupPageTemplateHolder.VAR_HEADERS, headerMarkup );
}
}
private void applyLocalizeableMessages() {
String noScriptWarning = RWTMessages.getMessage( "RWT_NoScriptWarning" );
replacePlaceholder( template, StartupPageTemplateHolder.VAR_NO_SCRIPT_MESSAGE, noScriptWarning );
}
private void addThemeDefinitions() {
themeDefinitions.clear();
ThemeManager themeManager = RWTFactory.getThemeManager();
Theme fallbackTheme = themeManager.getTheme( ThemeManager.FALLBACK_THEME_ID );
themeDefinitions.add( fallbackTheme.getRegisteredLocation() );
Theme theme = ThemeUtil.getCurrentTheme();
themeDefinitions.add( theme.getRegisteredLocation() );
}
private String getJsLibraries() {
StringBuilder buffer = new StringBuilder();
for( String location : jsLibraries ) {
writeScriptTag( buffer, location );
}
for( String location : themeDefinitions ) {
writeScriptTag( buffer, location );
}
IResource[] resources = resourceRegistry.get();
for( IResource resource : resources ) {
if( resource.isJSLibrary() && resource.isExternal() ) {
writeScriptTag( buffer, resource.getLocation() );
}
}
String location = RWTFactory.getJSLibraryConcatenator().getLocation();
writeScriptTag( buffer, location );
return buffer.toString();
}
static void replacePlaceholder( StartupPageTemplateHolder template,
Variable variable,
String replacement )
{
String safeReplacement = replacement == null ? "" : replacement;
template.replace( variable, safeReplacement );
}
private static void writeScriptTag( StringBuilder buffer, String library ) {
if( library != null ) {
buffer.append( "<script type=\"text/javascript\" src=\"" );
buffer.append( library );
buffer.append( "\" charset=\"" );
buffer.append( HTTP.CHARSET_UTF_8 );
buffer.append( "\"></script>\n" );
}
}
}