Java tutorial
/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.chrome.gwt.linker; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import javax.imageio.ImageIO; import com.chrome.gwt.client.Extension; import com.chrome.gwt.client.Extension.ManifestInfo; import com.chrome.gwt.linker.ExtensionArtifact.IconInfo; import com.google.gwt.core.ext.Generator; 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.core.ext.typeinfo.NotFoundException; import com.google.gwt.dev.util.Util; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; /** * Generator responsible for extracting the Specification annotations from * Extension subclasses. */ public class ExtensionGenerator extends Generator { private static IconInfo[] createIconResources(TreeLogger logger, GeneratorContext context, JClassType userType, String[] icons) throws UnableToCompleteException { final IconInfo[] result = new IconInfo[icons.length]; for (int i = 0, n = icons.length; i < n; ++i) { final String icon = icons[i]; // Open a stream for the icon resource. InputStream iconStream = ExtensionGenerator.class.getClassLoader() .getResourceAsStream(getResourcePath(userType, icon)); if (iconStream == null) { logger.log(TreeLogger.ERROR, "Resource not found on classpath: " + icon); throw new UnableToCompleteException(); } try { // Read the icon's byte data and decode it to determine the size. final byte[] iconData = getBytesFromStream(iconStream); assert iconData != null; final String strongname = Util.computeStrongName(iconData) + getIconExtension(icon); result[i] = new IconInfo(strongname, getImageSize(iconData)); // Write the icon's bytes into GWT resource. try { final OutputStream resStream = context.tryCreateResource(logger, strongname); if (resStream != null) { resStream.write(iconData); context.commitResource(logger, resStream); } } catch (IOException e) { logger.log(TreeLogger.ERROR, "Unable to write resource: " + icon, e); throw new UnableToCompleteException(); } } catch (IOException e) { logger.log(TreeLogger.ERROR, "Unable to read image: " + icon, e); throw new UnableToCompleteException(); } } return result; } private static String generateExtensionType(TreeLogger logger, GeneratorContext context, JClassType userType, ExtensionArtifact spec) { final String subclassName = userType.getSimpleSourceName().replace('.', '_') + "_generated"; final String packageName = userType.getPackage().getName(); final ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(packageName, subclassName); f.setSuperclass(userType.getQualifiedSourceName()); final PrintWriter pw = context.tryCreate(logger, packageName, subclassName); if (pw != null) { final SourceWriter sw = f.createSourceWriter(context, pw); final String version = (spec.getVersion() != null) ? spec.getVersion() : ""; sw.println("@Override public String getVersion() {"); sw.println(" return \"" + GeneratorUtils.toJavaLiteral(version) + "\";"); sw.println("}"); sw.commit(logger); } return f.getCreatedClassName(); } private static byte[] getBytesFromStream(InputStream stream) throws IOException { final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); int n; final byte[] buffer = new byte[2048]; while ((n = stream.read(buffer)) >= 0) { byteStream.write(buffer, 0, n); } return byteStream.toByteArray(); } private static String getIconExtension(String icon) { final int index = icon.lastIndexOf('.'); return (index < 0) ? "" : icon.substring(index); } private static int getImageSize(byte[] data) throws IOException { final InputStream stream = new ByteArrayInputStream(data); final BufferedImage image = ImageIO.read(stream); return Math.max(image.getWidth(), image.getHeight()); } private static String getResourcePath(JClassType userType, String name) { final String base = userType.getPackage().getName().replace('.', '/'); return base + "/" + name; } private static ExtensionArtifact getSpecification(TreeLogger logger, GeneratorContext context, JClassType userType) throws UnableToCompleteException { final ManifestInfo spec = userType.getAnnotation(Extension.ManifestInfo.class); if (spec != null) { return new ExtensionArtifact(spec.name(), spec.description(), spec.version(), spec.permissions(), spec.updateUrl(), createIconResources(logger, context, userType, spec.icons()), spec.optionsPage()); } logger.log(TreeLogger.ERROR, "You need a @Extension.Specification annotation on " + userType.getQualifiedSourceName() + " or else I'll have to make up a silly name for it."); throw new UnableToCompleteException(); } @Override public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { try { final JClassType userType = context.getTypeOracle().getType(typeName); final ExtensionArtifact spec = getSpecification(logger, context, userType); context.commitArtifact(logger, spec); return generateExtensionType(logger, context, userType, spec); } catch (NotFoundException e) { // TODO(knorton): Better error message. logger.log(TreeLogger.ERROR, "Unknown Type: " + typeName); throw new UnableToCompleteException(); } } }