/** * */ package com.google.gwt.chrome.crx.linker.emiter; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.util.LinkedHashSet; import java.util.Set; import com.google.gwt.chrome.crx.client.GwtContentScript; import com.google.gwt.chrome.crx.linker.ContentScriptGeneratedResource; import com.google.gwt.chrome.crx.linker.GwtContentScriptGenerator; import com.google.gwt.chrome.crx.linker.artifact.GwtContentScriptArtifact; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.dev.cfg.ModuleDef; /** * {@link GwtContentScriptEmiter} is responsible for creation of content script * from Java source code using GWT compiler and including it into manifest.json * file. * * @author Izzet_Mustafayev * */ public class GwtContentScriptEmiter extends AbstractEmiter { private static final String CLEAR_CACHE_GIF = "clear.cache.gif"; private static final String WEB_INF = "WEB-INF/"; private ModuleDefinitionLoader loader; public GwtContentScriptEmiter(final ModuleDefinitionLoader loader) { this.loader = loader; } /* * (non-Javadoc) * * @see * com.google.gwt.chrome.crx.linker.emiter.Emiter#emit(com.google.gwt.core * .ext.TreeLogger, com.google.gwt.core.ext.GeneratorContext, * com.google.gwt.core.ext.typeinfo.JClassType, java.lang.String) */ @Override public String emit(final TreeLogger logger, final GeneratorContext context, final JClassType userType, final String typeName) throws UnableToCompleteException { GwtContentScript.ManifestInfo spec = userType.getAnnotation(GwtContentScript.ManifestInfo.class); Validator<GwtContentScript.ManifestInfo> validator; validator = new Validator<GwtContentScript.ManifestInfo>(logger, GwtContentScript.class.getName(), typeName); validator.ensureAnnotatedWithManifest(spec); String moduleName = spec.module(); ModuleDef moduleDef = loader.loadModule(logger, moduleName); if (null == moduleDef) { notifyFailure(logger, "Module was not loaded: " + moduleName); } emitModuleResources(logger, context, moduleDef); String moduleJavaScriptFile = moduleDef.getName() + ".js"; emitScriptDef(logger, context, spec, moduleJavaScriptFile); return typeName; } private void emitScriptDef(final TreeLogger logger, final GeneratorContext context, GwtContentScript.ManifestInfo spec, String moduleJavaScriptFile) throws UnableToCompleteException { GwtContentScriptArtifact artifact; artifact = new GwtContentScriptArtifact(moduleJavaScriptFile, spec.matches(), spec.runAt(), spec.allFrames()); context.commitArtifact(logger, artifact); } private void emitModuleResources(final TreeLogger logger, final GeneratorContext context, final ModuleDef moduleDef) throws UnableToCompleteException { // TODO: (webdizz) Need to have more independent logic URL path = Thread.currentThread().getContextClassLoader().getResource("./"); String moduleName = moduleDef.getName(); String pathToModule = null; if (null != path && path.getPath().contains(WEB_INF)) { String modulePath = path.getPath(); pathToModule = modulePath.substring(0, modulePath.indexOf(WEB_INF)) + moduleName + "/"; } if (null == pathToModule) { logger.log(TreeLogger.ERROR, "Unable to resolve path to module : " + moduleName); notifyFailure(logger, "You can add WEB-INF directory as first in the Classpath->User Entries list of the Eclipse launcher."); } File moduleDir = new File(pathToModule); if (!moduleDir.exists()) { notifyFailure(logger, "Module directory does not exist : " + moduleName); } File[] files = moduleDir.listFiles(); processResources(logger, context, moduleName, files); } protected void notifyFailure(final TreeLogger logger, String message) throws UnableToCompleteException { logger.log(TreeLogger.ERROR, message); throw new UnableToCompleteException(); } private void processResources(final TreeLogger logger, final GeneratorContext context, String moduleName, File[] files) throws UnableToCompleteException { if (null != files) { Set<ContentScriptGeneratedResource> resources = new LinkedHashSet<ContentScriptGeneratedResource>(); for (File file : files) { if (CLEAR_CACHE_GIF.equals(file.getName())) { continue; } readAndCreateResource(logger, context, resources, file.getName(), file.getAbsolutePath()); } if (resources.isEmpty()) { notifyFailure(logger, "Module does not contain any resource : " + moduleName); } for (ContentScriptGeneratedResource resource : resources) { context.commitArtifact(logger, resource); } } } private void readAndCreateResource(final TreeLogger logger, final GeneratorContext context, Set<ContentScriptGeneratedResource> resources, final String fileName, final String pathToFile) { try { BufferedReader reader; reader = new BufferedReader(new FileReader(pathToFile)); ByteArrayOutputStream out = new ByteArrayOutputStream(4096); try { boolean eof = false; while (!eof) { int input = reader.read(); if (input == -1) { eof = true; break; } out.write(input); } } finally { reader.close(); } byte[] data = out.toByteArray(); if (data.length > 0) { ContentScriptGeneratedResource resource; resource = new ContentScriptGeneratedResource(GwtContentScriptGenerator.class, fileName, data); resources.add(resource); } } catch (FileNotFoundException e) { logger.log(TreeLogger.WARN, "Unable to find generated javascript file: " + pathToFile); } catch (IOException e) { logger.log(TreeLogger.WARN, "Unable to read generated javascript file: " + pathToFile); } } }