/*******************************************************************************
* Copyright (c) 2011, 2014 EclipseSource 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:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.rap.rwt.jstest.internal;
import static java.util.Arrays.asList;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.jstest.TestContribution;
import org.eclipse.rap.rwt.service.ServiceHandler;
public class ClientResourcesServiceHandler implements ServiceHandler {
private static final String PARAM_CONTRIBUTION = "contribution";
private static final String PARAM_FILE = "file";
private static final String PARAM_NOCACHE = "nocache";
private static final String PARAM_JASMINE = "jasmine";
public static final String ID = "clientResources";
public Map<String, TestContribution> getContributions() {
return Activator.getContributions();
}
public void service( HttpServletRequest request, HttpServletResponse response )
throws IOException
{
String fileParameter = request.getParameter( PARAM_FILE );
String contributionParameter = request.getParameter( PARAM_CONTRIBUTION );
boolean isJasmine = "true".equals( request.getParameter( PARAM_JASMINE ) );
if( fileParameter != null && contributionParameter != null ) {
deliverResource( response, contributionParameter, fileParameter );
} else if( contributionParameter != null ) {
deliverFilesList( response, asList( getContributions().get( contributionParameter ) ), isJasmine );
} else {
deliverFilesList( response, getNonSetupContributions(), isJasmine );
}
}
private Collection<TestContribution> getNonSetupContributions() {
ArrayList<TestContribution> jasmineContributions = new ArrayList<TestContribution>();
Collection<TestContribution> contributions = getContributions().values();
for( TestContribution contribution : contributions ) {
if( !isSetupContribution( contribution ) ) {
jasmineContributions.add( contribution );
}
}
return jasmineContributions;
}
private static boolean isSetupContribution( TestContribution contribution ) {
return asList( "rwt", "test-fixture", "test-runner" ).contains( contribution.getName() );
}
private void deliverResource( HttpServletResponse response, String contributionName, String file )
throws IOException
{
TestContribution contribution = getContributions().get( contributionName );
if( contribution != null ) {
deliverResource( response, contribution, file );
} else {
writeError( response, HttpServletResponse.SC_BAD_REQUEST, "Unknown contribution" );
}
}
private void deliverFilesList( HttpServletResponse response,
Collection<TestContribution> contributions,
boolean isJasmine ) throws IOException
{
response.setContentType( "text/javascript" );
response.setCharacterEncoding( "UTF-8" );
PrintWriter writer = response.getWriter();
writer.write( "( function() {\n" );
for( TestContribution contribution : contributions ) {
writeIncludeResources( writer, contribution, isJasmine );
}
writer.write( "} )();\n" );
}
private void deliverResource( HttpServletResponse response,
TestContribution contribution,
String resource ) throws IOException
{
response.setContentType( "text/javascript" );
response.setCharacterEncoding( "UTF-8" );
InputStream inputStream = contribution.getResourceAsStream( resource );
if( inputStream != null ) {
try {
PrintWriter writer = response.getWriter();
copyContents( inputStream, writer );
} finally {
inputStream.close();
}
} else {
writeError( response, HttpServletResponse.SC_NOT_FOUND, "Resource not found" );
}
}
private static void writeError( HttpServletResponse response, int statusCode, String message )
throws IOException
{
response.setContentType( "text/html" );
response.setStatus( statusCode );
PrintWriter writer = response.getWriter();
writer.write( "<html><h1>HTTP " + statusCode + "</h1><p>" + message + "</p></html>" );
}
private static void writeIncludeResources( PrintWriter writer,
TestContribution contribution,
boolean isJasmine ) throws IOException
{
String[] clientResources = contribution.getResources();
for( String resource : clientResources ) {
if( isJasmine ? !resource.endsWith( "Test.js" ) : !resource.endsWith( "spec.js" ) ) {
writeIncludeResource( writer, contribution, resource );
}
}
}
private static void writeIncludeResource( PrintWriter writer,
TestContribution contribution,
String resource ) throws IOException
{
String location = getResourceLocation( contribution, resource );
writeIncludeResource( writer, location );
}
private static void writeIncludeResource( PrintWriter writer, String resource ) {
writer.write( "includeTestResource( \"" );
writer.write( resource );
writer.write( "\" );\n" );
}
private static String getResourceLocation( TestContribution contribution, String resource )
throws IOException
{
StringBuilder url = new StringBuilder( RWT.getServiceManager().getServiceHandlerUrl( ID ) );
appendParameter( url, PARAM_CONTRIBUTION, contribution.getName() );
appendParameter( url, PARAM_FILE, resource );
appendParameter( url, PARAM_NOCACHE, getResourceHash( contribution, resource ) );
return url.toString();
}
private static void appendParameter( StringBuilder stringBuilder, String name, String value ) {
stringBuilder.append( '&' );
stringBuilder.append( name );
stringBuilder.append( '=' );
stringBuilder.append( value );
}
private static String getResourceHash( TestContribution contribution, String resource )
throws IOException
{
int hash = 0;
InputStream inputStream = contribution.getResourceAsStream( resource );
if( inputStream != null ) {
try {
hash = getHashCode( inputStream );
} finally {
inputStream.close();
}
}
return Integer.toHexString( hash );
}
private static int getHashCode( InputStream inputStream ) throws IOException {
int hash = 0;
byte[] buffer = new byte[ 8096 ];
int read = inputStream.read( buffer );
while( read != -1 ) {
for( int i = 0; i < read; i++ ) {
hash = 31 * hash + buffer[ i++ ];
}
read = inputStream.read( buffer );
}
return hash;
}
private static void copyContents( InputStream inputStream, PrintWriter writer )
throws IOException
{
try {
Reader reader = new BufferedReader( new InputStreamReader( inputStream, "UTF-8" ) );
char[] buffer = new char[ 8192 ];
int count = reader.read( buffer );
while( count != -1 ) {
writer.write( buffer, 0, count );
count = reader.read( buffer );
}
} catch( UnsupportedEncodingException unexpected ) {
throw new RuntimeException( unexpected );
}
}
}