/******************************************************************************* * Copyright (c) 2012, 2015 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.internal.resources; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import org.eclipse.rap.json.JsonObject; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.SingletonUtil; import org.eclipse.rap.rwt.internal.protocol.JsonUtil; import org.eclipse.rap.rwt.internal.protocol.ProtocolMessageWriter; import org.eclipse.rap.rwt.internal.service.ContextProvider; import org.eclipse.rap.rwt.internal.util.ClassUtil; import org.eclipse.rap.rwt.service.ApplicationContext; import org.eclipse.rap.rwt.service.ResourceManager; public class JavaScriptModuleLoaderImpl implements JavaScriptModuleLoader { private static final String MODULES_KEY = JavaScriptModuleRegistry.class.getName() + "#instance"; private static final Object LOCK = new Object(); @Override public void ensureModule( Class< ? extends JavaScriptModule> type ) { if( !isLoaded( type ) ) { if( !isRegistered( type ) ) { registerModule( type ); } loadModule( type ); } } private static void registerModule( Class< ? extends JavaScriptModule> type ) { JavaScriptModule module = ClassUtil.newInstance( type ); String[] fileNames = module.getFileNames(); if( fileNames.length == 0 ) { throw new IllegalStateException( "No JavaScript files found!" ); } String[] filePaths = new String[ fileNames.length ]; try { // TODO [tb] : check for duplicates? for( int i = 0; i < fileNames.length; i++ ) { filePaths[ i ] = registerFile( module, fileNames[ i ] ); } } catch( IOException ioe ) { throw new IllegalArgumentException( "Failed to load resources", ioe ); } getApplicationModules().put( type, filePaths ); } private static String registerFile( JavaScriptModule module, String fileName ) throws IOException { String localPath = getLocalPath( module, fileName ); InputStream inputStream = module.getLoader().getResourceAsStream( localPath ); if( inputStream == null ) { throw new IOException( "File " + localPath + " does not exist." ); } ResourceManager resourceManager = RWT.getResourceManager(); String publicPath = getPublicPath( module, fileName ); try { // TODO [tb] : ensure that content is not concatenated to core js library resourceManager.register( publicPath, inputStream ); } finally { inputStream.close(); } return resourceManager.getLocation( publicPath ); } private static void loadModule( Class<? extends JavaScriptModule> type ) { String[] files = getApplicationModules().get( type ); ProtocolMessageWriter writer = ContextProvider.getProtocolWriter(); JsonObject parameters = new JsonObject().add( "files", JsonUtil.createJsonArray( files ) ); writer.appendCall( "rwt.client.JavaScriptLoader", "load", parameters ); getSessionModules().put( type, files ); } private static String getPublicPath( JavaScriptModule module, String fileName ) { Class<?> type = module.getClass(); return type.getSimpleName() + type.hashCode() + "/" + fileName; } private static String getLocalPath( JavaScriptModule module, String fileName ) { return module.getDirectory() + "/" + fileName; } private static boolean isRegistered( Class<? extends JavaScriptModule> clazz ) { return getApplicationModules().get( clazz ) != null; } private static boolean isLoaded( Class<? extends JavaScriptModule> clazz ) { return getSessionModules().get( clazz ) != null; } private static JavaScriptModuleRegistry getApplicationModules() { ApplicationContext context = RWT.getApplicationContext(); synchronized( LOCK ) { JavaScriptModuleRegistry result = (JavaScriptModuleRegistry)context.getAttribute( MODULES_KEY ); if( result == null ) { result = new JavaScriptModuleRegistry(); context.setAttribute( MODULES_KEY, result ); } return result; } } private static JavaScriptModuleRegistry getSessionModules() { return SingletonUtil.getSessionInstance( JavaScriptModuleRegistry.class ); } static private class JavaScriptModuleRegistry { private final Map<Class<? extends JavaScriptModule>, String[]> map = new HashMap<>(); public void put( Class<? extends JavaScriptModule> type, String[] files ) { map.put( type, files ); } public String[] get( Class<? extends JavaScriptModule> type ) { return map.get( type ); } } }