View Javadoc

1   /**********************************************
2    * Copyright (C) 2009 Lukas Laag
3    * This file is part of lib-gwt-svg-samples.
4    * 
5    * libgwtsvg-samples is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * libgwtsvg-samples is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with libgwtsvg-samples.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.svg.samples.generator;
19  
20  import java.io.BufferedReader;
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.io.OutputStream;
26  
27  import org.apache.tools.ant.filters.StringInputStream;
28  import org.vectomatic.svg.samples.client.SampleBase;
29  
30  import com.google.gwt.core.ext.Generator;
31  import com.google.gwt.core.ext.GeneratorContext;
32  import com.google.gwt.core.ext.TreeLogger;
33  import com.google.gwt.core.ext.UnableToCompleteException;
34  import com.google.gwt.core.ext.typeinfo.JClassType;
35  import com.google.gwt.core.ext.typeinfo.NotFoundException;
36  import com.uwyn.jhighlight.renderer.Renderer;
37  import com.uwyn.jhighlight.renderer.XhtmlRendererFactory;
38  
39  public class SourceGenerator extends Generator {
40  	/**
41  	 * The class loader used to get resources.
42  	 */
43  	private ClassLoader classLoader = null;
44  
45  	/**
46  	 * The generator context.
47  	 */
48  	private GeneratorContext context = null;
49  
50  	/**
51  	 * The {@link TreeLogger} used to log messages.
52  	 */
53  	private TreeLogger logger = null;
54  	
55  	@Override
56  	public String generate(TreeLogger logger, GeneratorContext context,
57  			String typeName) throws UnableToCompleteException {
58  	    this.logger = logger;
59  	    this.context = context;
60  	    this.classLoader = Thread.currentThread().getContextClassLoader();
61  
62  	    // Only generate files on the first permutation
63  	    if (!isFirstPass()) {
64  	      return null;
65  	    }
66  
67  		JClassType sampleClass = null;
68  		try {
69  			sampleClass = context.getTypeOracle().getType(
70  					SampleBase.class.getName());
71  		} catch (NotFoundException e) {
72  			logger.log(TreeLogger.ERROR, "Cannot find SampleBase class", e);
73  			throw new UnableToCompleteException();
74  		}
75  		JClassType[] types = sampleClass.getSubtypes();
76  
77  		// Generate the source and raw source files
78  		for (JClassType type : types) {
79  			generateSourceFile(type);
80  			generateUiBinderFile(type);
81  		}
82  		return null;
83  	}
84  
85  	private void generateSourceFile(JClassType type) throws UnableToCompleteException {
86  		Renderer javaRenderer = XhtmlRendererFactory.getRenderer(XhtmlRendererFactory.JAVA);
87  	    String filename = type.getQualifiedSourceName().replace('.', '/') + ".java";
88  		ByteArrayOutputStream byteArrayStream = null;
89  		InputStream javaStream = null;
90  		try {
91  			javaStream = new StringInputStream(getResourceContents(filename));
92  			byteArrayStream = new ByteArrayOutputStream();
93  			javaRenderer.highlight(null, javaStream, byteArrayStream, "UTF-8", true);
94  			javaStream.close();
95  			byteArrayStream.close();
96  			
97  		    // Save the source code to a file
98  		    String dstPath = SampleBase.HTML_SRC_DIR + type.getSimpleSourceName() + ".html";
99  		    String contents = new String(byteArrayStream.toByteArray(), "UTF-8");
100 		    createPublicResource(dstPath, contents);
101 		} catch (IOException e) {
102 			throw new RuntimeException(e);
103 		}
104 	}
105 
106 	private void generateUiBinderFile(JClassType type) throws UnableToCompleteException {
107 		Renderer javaRenderer = XhtmlRendererFactory.getRenderer(XhtmlRendererFactory.XML);
108 	    String filename = type.getQualifiedSourceName().replace('.', '/') + ".ui.xml";
109 		ByteArrayOutputStream byteArrayStream = null;
110 		InputStream javaStream = null;
111 		try {
112 			javaStream = new StringInputStream(getResourceContents(filename));
113 			byteArrayStream = new ByteArrayOutputStream();
114 			javaRenderer.highlight(null, javaStream, byteArrayStream, "UTF-8", true);
115 			javaStream.close();
116 			byteArrayStream.close();
117 			
118 		    // Save the source code to a file
119 		    String dstPath = SampleBase.UIBINDER_SRC_DIR + type.getSimpleSourceName() + ".html";
120 		    String contents = new String(byteArrayStream.toByteArray(), "UTF-8");
121 		    createPublicResource(dstPath, contents);
122 		} catch (IOException e) {
123 			throw new RuntimeException(e);
124 		}
125 	}
126 
127 	/**
128 	 * Set the full contents of a resource in the public directory.
129 	 * @param partialPath
130 	 * the path to the file relative to the public directory
131 	 * @param contents
132 	 * the file contents
133 	 */
134 	private void createPublicResource(String partialPath, String contents) {
135 		try {
136 			logger.log(TreeLogger.INFO, "Generating " + partialPath);
137 			OutputStream outStream = context.tryCreateResource(logger, partialPath);
138 			outStream.write(contents.getBytes());
139 			context.commitResource(logger, outStream);
140 		} catch (UnableToCompleteException e) {
141 			logger.log(TreeLogger.ERROR, "Failed while writing", e);
142 		} catch (IOException e) {
143 			logger.log(TreeLogger.ERROR, "Failed while writing", e);
144 		}
145 	}
146 	
147 
148 	  /**
149 	   * Get the full contents of a resource.
150 	   * @param path the path to the resource
151 	   * @return the contents of the resource
152 	   */
153 	private String getResourceContents(String path) throws UnableToCompleteException {
154 		InputStream in = classLoader.getResourceAsStream(path);
155 		if (in == null) {
156 			logger.log(TreeLogger.ERROR, "Resource not found: " + path);
157 			throw new UnableToCompleteException();
158 		}
159 
160 		StringBuffer fileContentsBuf = new StringBuffer();
161 		BufferedReader br = null;
162 		try {
163 			br = new BufferedReader(new InputStreamReader(in));
164 			String temp;
165 			while ((temp = br.readLine()) != null) {
166 				fileContentsBuf.append(temp).append('\n');
167 			}
168 		} catch (IOException e) {
169 			logger.log(TreeLogger.ERROR, "Cannot read resource", e);
170 			throw new UnableToCompleteException();
171 		} finally {
172 			if (br != null) {
173 				try {
174 					br.close();
175 				} catch (IOException e) {
176 				}
177 			}
178 		}
179 
180 		// Return the file contents as a string
181 		return fileContentsBuf.toString();
182 	}
183 	
184 
185 	  /**
186 	   * Ensure that we only generate files once by creating a placeholder file,
187 	   * then looking for it on subsequent generates.
188 	   * 
189 	   * @return true if this is the first pass, false if not
190 	   */
191 	  private boolean isFirstPass() {
192 	    String placeholder = SampleBase.HTML_SRC_DIR + "generated";
193 	    try {
194 	      OutputStream outStream = context.tryCreateResource(logger, placeholder);
195 	      if (outStream == null) {
196 	        return false;
197 	      } else {
198 	        context.commitResource(logger, outStream);
199 	      }
200 	    } catch (UnableToCompleteException e) {
201 	      logger.log(TreeLogger.ERROR, "Unable to generate", e);
202 	      return false;
203 	    }
204 	    return true;
205 	  }
206 
207 }