View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2008 utgenome.org
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *--------------------------------------------------------------------------*/
16  //--------------------------------------
17  // utgb-shell Project
18  //
19  // ScaffoldGenerator.java
20  // Since: Jun 2, 2008
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.shell;
26  
27  import java.io.BufferedReader;
28  import java.io.ByteArrayInputStream;
29  import java.io.File;
30  import java.io.FileInputStream;
31  import java.io.FileOutputStream;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.InputStreamReader;
35  import java.util.ArrayList;
36  import java.util.HashSet;
37  import java.util.List;
38  import java.util.Properties;
39  
40  import org.utgenome.config.UTGBConfig;
41  import org.utgenome.shell.Create.OverwriteMode;
42  import org.utgenome.shell.Create.ScaffoldFileFilter;
43  import org.xerial.util.FileResource;
44  import org.xerial.util.io.VirtualFile;
45  import org.xerial.util.log.Logger;
46  import org.xerial.util.text.Template;
47  
48  /**
49   * Scaffold generator
50   * 
51   * @author leo
52   * 
53   */
54  public class ScaffoldGenerator {
55  
56  	private static Logger _logger = Logger.getLogger(ScaffoldGenerator.class);
57  
58  	private String outputFolder;
59  	static OverwriteMode overwriteMode = OverwriteMode.INTERACTIVE;
60  	private final Properties property = new Properties();
61  	private ScaffoldFileFilter generateFileFilter = null;
62  
63  	public ScaffoldGenerator(String outputFolder, ScaffoldFileFilter generateFileFilter) {
64  		this.outputFolder = outputFolder;
65  		if (this.outputFolder == null)
66  			this.outputFolder = ".";
67  		this.generateFileFilter = generateFileFilter;
68  	}
69  
70  	public void prepareTemplatePropeties(UTGBConfig config) {
71  		property.put("projectName", config.projectName);
72  		property.put("package", config.javaPackage);
73  		property.put("group", config.group);
74  		String moduleName = config.javaPackage + ".gwt.Browser";
75  		property.setProperty("moduleName", moduleName);
76  		property.setProperty("modulePath", moduleName.replaceAll("\\.", "/") + ".gwt.xml");
77  		property.put("explodedWebappDir", UTGBShellCommand.EXPLODED_WEBAPP_DIR);
78  
79  		// properties for the GWT interface code
80  		String clientPackageName = config.javaPackage + ".gwt.client";
81  		String serverPackageName = config.javaPackage + ".gwt.server";
82  		String entryPoint = clientPackageName + ".Browser";
83  
84  		property.setProperty("packageName", config.javaPackage);
85  		property.setProperty("clientPackageName", clientPackageName);
86  		property.setProperty("serverPackageName", serverPackageName);
87  		property.setProperty("moduleName", moduleName);
88  		property.setProperty("entryPoint", entryPoint);
89  
90  		property.setProperty("utgbVersion", UTGBShell.getVersion());
91  	}
92  
93  	public void createProjectScaffold(UTGBConfig config) throws IOException, UTGBShellException {
94  		prepareTemplatePropeties(config);
95  
96  		// compute class path entries for the Eclipse project
97  		// create src and test folders
98  		mkdirs(new File(outputFolder, "src/main/java"));
99  		mkdirs(new File(outputFolder, "src/test/java"));
100 
101 		// copy template codes into the output folder
102 		copyScaffold("org.utgenome.shell.template.java.scaffold", outputFolder);
103 
104 		// GWT module folder
105 		mkdirs(new File(outputFolder, "war/utgb"));
106 
107 		// create a Eclipse launch file to start UTGB Portable
108 		createEclipseLaunchFile(config.projectName, "template/java/server.launch.template", "server");
109 	}
110 
111 	public void createGWTModuleScaffold(UTGBConfig config) throws IOException, UTGBShellException {
112 
113 		prepareTemplatePropeties(config);
114 
115 		String gwtOutputFolder = outputFolder + "/src/main/java/" + config.javaPackage.replaceAll("\\.", "/");
116 		copyScaffold("org.utgenome.shell.template.java.gwtscaffold", gwtOutputFolder);
117 
118 		createEclipseLaunchFile(config.projectName, "template/java/gwt.launch.template", "gwt");
119 	}
120 
121 	public void createEclipseLaunchFile(String projectName, String templatePath, String suffix) throws IOException, UTGBShellException {
122 		String launchFileLogicalName = "eclipse/" + projectName + "-" + suffix + ".launch";
123 		File launchFile = new File(outputFolder, launchFileLogicalName);
124 		if (canOverwrite(launchFile, launchFileLogicalName))
125 			UTGBShellCommand.createFileFromTemplate(UTGBShell.class, templatePath, outputFolder, launchFileLogicalName, property, true);
126 	}
127 
128 	/**
129 	 * Creates the folder structure for the Tomcat
130 	 * 
131 	 * @param catalinaBase
132 	 * @throws IOException
133 	 */
134 	public void copyScaffold(String inputResourcePacakge, String outputDir) throws IOException {
135 		_logger.info("output folder: " + outputFolder);
136 		for (Object keyObj : property.keySet()) {
137 			String key = keyObj.toString();
138 			_logger.info(key + "\t = " + property.getProperty(key));
139 		}
140 
141 		// create the base folder for the scaffold
142 		File outputFolder = new File(outputDir);
143 		List<VirtualFile> scaffoldResourcesList = FileResource.listResources(inputResourcePacakge);
144 		// remove duplicates from resources
145 		ArrayList<VirtualFile> scaffoldResources = new ArrayList<VirtualFile>();
146 		{
147 			HashSet<String> observedPath = new HashSet<String>();
148 			for (VirtualFile vf : scaffoldResourcesList) {
149 				if (!observedPath.contains(vf.getLogicalPath())) {
150 					observedPath.add(vf.getLogicalPath());
151 					scaffoldResources.add(vf);
152 				}
153 			}
154 		}
155 		if (scaffoldResources.size() <= 0)
156 			throw new IllegalStateException(inputResourcePacakge + " is not found");
157 		// sync scaffoldDir with the output folder
158 		for (VirtualFile vf : scaffoldResources) {
159 			String srcLogicalPath = vf.getLogicalPath();
160 			if (vf.isDirectory()) {
161 				mkdirs(new File(outputFolder, srcLogicalPath));
162 			}
163 			else {
164 				boolean isTemplate = false;
165 				String outputFileName = srcLogicalPath;
166 				// is template?
167 				int extIndex = srcLogicalPath.lastIndexOf(".");
168 				if (extIndex > 0) {
169 					String fileExt = srcLogicalPath.substring(extIndex + 1);
170 					if (fileExt.equals("template")) {
171 						isTemplate = true;
172 						outputFileName = srcLogicalPath.substring(0, extIndex);
173 					}
174 				}
175 				File targetFile = new File(outputFolder, outputFileName);
176 				File parentFolder = targetFile.getParentFile();
177 				mkdirs(parentFolder);
178 				// copy the file content
179 				if (canOverwrite(targetFile, outputFileName)) {
180 					InputStream reader = null;
181 					if (isTemplate) {
182 						// fill variables in the template
183 						InputStream templateReader = vf.getURL().openStream();
184 						Template template = new Template(templateReader);
185 						String result = template.apply(property);
186 						reader = new ByteArrayInputStream(result.getBytes());
187 					}
188 					else
189 						reader = vf.getURL().openStream();
190 					_logger.info("create a file: " + getPath(targetFile));
191 					copyFile(reader, targetFile);
192 				}
193 			}
194 		}
195 	}
196 
197 	private BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
198 
199 	/**
200 	 * Tests overwriting of the file is allowed.
201 	 * 
202 	 * If allowed, rename the old file to (original name).tmp, and returns true.
203 	 * 
204 	 * @param targetFile
205 	 *            the file to be written.
206 	 * @return true if overwriting is allowed, false otherwise
207 	 * @throws IOException
208 	 */
209 	private boolean canOverwrite(File targetFile, String logicalPath) throws IOException {
210 		if (!generateFileFilter.accept(logicalPath))
211 			return false;
212 		if (!targetFile.exists())
213 			return true;
214 		if (overwriteMode == OverwriteMode.NO_TO_ALL)
215 			return false;
216 		if (overwriteMode != OverwriteMode.YES_TO_ALL) {
217 			System.out.println("File " + getPath(targetFile) + " already exists.");
218 			System.out.print("Overwrite it? (y: yes, n: no, A: yes to all, X: no to all) [n]: ");
219 			String input = cin.readLine();
220 			System.out.println();
221 			if (input == null)
222 				return false;
223 			input = input.trim();
224 			if (input.length() <= 0)
225 				return false;
226 			switch (input.charAt(0)) {
227 			case 'n':
228 				return false;
229 			case 'A':
230 				overwriteMode = OverwriteMode.YES_TO_ALL;
231 				break;
232 			case 'X':
233 				overwriteMode = OverwriteMode.NO_TO_ALL;
234 				return false;
235 			case 'y':
236 				break;
237 			default:
238 				return false;
239 			}
240 		}
241 		if (!targetFile.getName().endsWith(".jar")) // do not take a back up of the jar file
242 		{
243 			// rename the old file to (old file name).tmp
244 			File tempFile = new File(targetFile + ".old");
245 			_logger.info("previous file was copied as " + getPath(tempFile));
246 			copyFile(new FileInputStream(targetFile), tempFile);
247 		}
248 		return true;
249 	}
250 
251 	public static void copyFile(InputStream in, File dest) throws IOException {
252 		FileOutputStream writer = new FileOutputStream(dest);
253 		byte[] buffer = new byte[1024];
254 		int bytesRead = 0;
255 		while ((bytesRead = in.read(buffer)) > 0) {
256 			writer.write(buffer, 0, bytesRead);
257 		}
258 		writer.flush();
259 		writer.close();
260 	}
261 
262 	/**
263 	 * Create directories including its parent folders if not exist
264 	 * 
265 	 * @param dir
266 	 */
267 	public static void mkdirs(File dir) {
268 		if (!dir.exists()) {
269 			_logger.info("create a directory: " + getPath(dir));
270 			dir.mkdirs();
271 		}
272 	}
273 
274 	public static String getPath(File f) {
275 		return UTGBShellCommand.getPath(f);
276 	}
277 }