/*******************************************************************************
* Copyright (c) 2008, 2010 Innoopract Informationssysteme 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:
* Innoopract Informationssysteme GmbH - initial API and implementation
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.rwt.internal.service;
import java.io.*;
import java.text.MessageFormat;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.rwt.Adaptable;
import org.eclipse.rwt.RWT;
import org.eclipse.rwt.internal.*;
import org.eclipse.rwt.internal.resources.JsConcatenator;
import org.eclipse.rwt.internal.resources.ResourceManager;
import org.eclipse.rwt.internal.util.HTML;
import org.eclipse.rwt.resources.IResourceManager;
import org.eclipse.rwt.service.IServiceHandler;
/**
* <p>This class is used to deliver the concatenated Javascript libraries that
* are needed to run RWT on the client in one request.</p>
* <p>Depending on the 'Accept-Encoding' header of the request and the
* configuration settings the content is either sent uncompressed or compressed.
* The latter should be the normal case, since this reduces the size of the
* content that has to be sent over the wire.</p>
* <p>As the filename of the delivered Javascript has a version postfix the
* browser is informed to store the Javascript in its cache.</p>
*/
public class JSLibraryServiceHandler implements IServiceHandler {
public static final String HANDLER_ID
= JSLibraryServiceHandler.class.getName();
public final static String CONTENT_ENCODING = "Content-Encoding";
public final static String ENCODING_GZIP = "gzip";
public final static String ACCEPT_ENCODING = "Accept-Encoding";
private static final String EXPIRES = "Expires";
static final String EXPIRES_NEVER = "Sun, 17 Jan 2038 19:14:07 GMT";
private static final String REQUEST_PATTERN = "{0}?{1}={2}&hash={3}";
private static String hashCode;
private static byte[] unCompressed;
private static byte[] compressed;
public static String getRequestURL() throws IOException {
initializeOutput();
Object[] param = new Object[] {
RWT.getRequest().getServletPath().substring( 1 ),
IServiceHandler.REQUEST_PARAM,
HANDLER_ID,
hashCode
};
return MessageFormat.format( REQUEST_PATTERN, param );
}
public void service() throws IOException, ServletException {
initializeOutput();
HttpServletResponse response = RWT.getResponse();
response.setHeader( HTML.CONTENT_TYPE, HTML.CONTENT_TEXT_JAVASCRIPT );
response.setHeader( EXPIRES, EXPIRES_NEVER );
response.setCharacterEncoding( HTML.CHARSET_NAME_UTF_8 );
if( isAcceptEncoding() && getInitProps().isCompression()) {
writeCompressedOutput();
} else {
writeUnCompressedOutput();
}
}
private static void writeCompressedOutput() throws IOException {
RWT.getResponse().setHeader( JSLibraryServiceHandler.CONTENT_ENCODING, JSLibraryServiceHandler.ENCODING_GZIP );
HttpServletResponse response = RWT.getResponse();
OutputStream out = new BufferedOutputStream( response.getOutputStream() );
write( out, compressed );
}
private static void writeUnCompressedOutput() throws IOException {
HttpServletResponse response = RWT.getResponse();
OutputStream out = new BufferedOutputStream( response.getOutputStream() );
write( out, unCompressed );
}
private static void write( final OutputStream out, final byte[] content )
throws IOException
{
for( int i = 0; i < content.length; i++ ) {
out.write( content[ i ] );
}
out.flush();
}
private static void initializeOutput()
throws IOException
{
// Note [fappel]: We do not close all streams or writers, since this is
// not so crucial here as we only do in-memory opperations.
synchronized( JSLibraryServiceHandler.class ) {
if( unCompressed == null ) {
String content = getJsConcatenator().getContent();
unCompressed = content.getBytes( HTML.CHARSET_NAME_UTF_8 );
hashCode = "H" + content.hashCode();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream( baos );
write( gzipStream, unCompressed );
gzipStream.close();
compressed = baos.toByteArray();
}
}
}
private static boolean isAcceptEncoding() {
String encodings = RWT.getRequest().getHeader( JSLibraryServiceHandler.ACCEPT_ENCODING );
return encodings != null && encodings.indexOf( JSLibraryServiceHandler.ENCODING_GZIP ) != -1;
}
private static IInitialization getInitProps() {
IConfiguration configuration = ConfigurationReader.getConfiguration();
return configuration.getInitialization();
}
private static JsConcatenator getJsConcatenator() {
IResourceManager manager = ResourceManager.getInstance();
Adaptable adaptable = ( Adaptable )manager;
Object adapter = adaptable.getAdapter( JsConcatenator.class );
return ( JsConcatenator )adapter;
}
}