001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.maven.xmlcodegen;
017:
018: import org.eclipse.xsd.XSDSchema;
019: import org.geotools.xml.Schemas;
020:
021: import java.io.BufferedInputStream;
022: import java.io.BufferedOutputStream;
023: import java.io.File;
024: import java.io.FileInputStream;
025: import java.io.FileOutputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.OutputStream;
029: import java.lang.reflect.Method;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.logging.Logger;
034:
035: /**
036: * Abstract base class for code generators.
037: *
038: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
039: *
040: */
041: public abstract class AbstractGenerator {
042: static Logger logger = org.geotools.util.logging.Logging
043: .getLogger("org.geotools.xml");
044:
045: /**
046: * Package base
047: */
048: String packageBase;
049:
050: /**
051: * location to write out files
052: */
053: String location;
054:
055: /**
056: * Flag determining if generator will overwrite existing files.
057: */
058: boolean overwriting = false;
059:
060: /**
061: * lookup directories for schemas
062: */
063: File[] schemaLookupDirectories;
064:
065: /**
066: * Sets the base package for generated classes.
067: *
068: * @param packageBase Dot seperate package name, or <code>null</code> for
069: * no package.
070: */
071: public void setPackageBase(String packageBase) {
072: this .packageBase = packageBase;
073: }
074:
075: public String getPackageBase() {
076: return packageBase;
077: }
078:
079: /**
080: * Sets the location to write out generated java classes.
081: *
082: * @param location A file path.
083: */
084: public void setLocation(String location) {
085: this .location = location;
086: }
087:
088: public String getLocation() {
089: return location;
090: }
091:
092: /**
093: * Flag controlling the behaviour of the generator when a generated file
094: * already exists.
095: * <p>
096: * If set to <code>true</code>, the generator will overwrite existing files.
097: * if set to <code>false</code>, the generator will not overwrite the file
098: * and issue a warning.
099: * </p>
100: *
101: * @param overwriting overwrite flag.
102: */
103: public void setOverwriting(boolean overwriting) {
104: this .overwriting = overwriting;
105: }
106:
107: /**
108: * Sets the directories to use when attempting to locate a schema via a
109: * relative reference.
110: *
111: * @param schemaLookupDirectories An array of directories.
112: */
113: public void setSchemaLookupDirectories(
114: File[] schemaLookupDirectories) {
115: this .schemaLookupDirectories = schemaLookupDirectories;
116: }
117:
118: /**
119: * Writes out a string to a file.
120: * <p>
121: * THe file written out is located under {@link #location}, with the path
122: * generated from {@link #packageBase} appended.
123: * </p>
124: *
125: * @param result Result to write to the files.
126: * @param className The name of the file to write out.
127: */
128: protected void write(String result, String className)
129: throws IOException {
130: //convert package to a path
131: File location = outputLocation();
132:
133: location.mkdirs();
134: location = new File(location, className + ".java");
135:
136: //check for existing file
137: if (location.exists() && !overwriting) {
138: logger.warning("Generated file: " + location
139: + " already exists.");
140:
141: return;
142: }
143:
144: BufferedOutputStream out = new BufferedOutputStream(
145: new FileOutputStream(location));
146:
147: if (packageBase != null) {
148: out.write(("package " + packageBase + ";\n\n").getBytes());
149: }
150:
151: out.write(result.getBytes());
152:
153: out.flush();
154: out.close();
155: }
156:
157: /**
158: * Copues a file to the output location.
159: * <p>
160: * THe file written out is located under {@link #location}, with the path
161: * generated from {@link #packageBase} appended.
162: * </p>
163: *
164: * @param file The file to copy.
165: */
166: protected void copy(File file) throws IOException {
167: File dest = new File(outputLocation(), file.getName());
168:
169: logger.info("Copying " + file + " to " + dest);
170:
171: //check for existing file
172: if (dest.exists() && !overwriting) {
173: logger.warning("Generated file: " + dest
174: + " already exists.");
175:
176: return;
177: }
178:
179: InputStream in = new BufferedInputStream(new FileInputStream(
180: file));
181: OutputStream out = new BufferedOutputStream(
182: new FileOutputStream(dest));
183:
184: int b = -1;
185:
186: while ((b = in.read()) != -1)
187: out.write(b);
188:
189: out.flush();
190: out.close();
191: in.close();
192: }
193:
194: /**
195: * Attempts to locate a schema file by name by iterating through
196: * {@link #schemaLookupDirectories}.
197: *
198: * @param path The path of the file.
199: *
200: */
201: protected File findSchemaFile(String path) throws IOException {
202: File file = new File(path);
203: if (file.isAbsolute()) {
204: return file;
205: }
206:
207: if (schemaLookupDirectories != null) {
208: for (int i = 0; i < schemaLookupDirectories.length; i++) {
209: File dir = schemaLookupDirectories[i];
210: file = new File(dir, path);
211: if (file.exists()) {
212: return file;
213: }
214: }
215: }
216:
217: return null;
218: }
219:
220: /**
221: * Convenience method for generating the output location of generated files based on
222: * {@link #getLocation()}
223: */
224: protected File outputLocation() {
225: File location = null;
226:
227: if (this .location != null) {
228: location = new File(this .location);
229: } else {
230: location = new File(System.getProperty("user.dir"));
231: }
232:
233: if (packageBase != null) {
234: String path = packageBase.replace('.', File.separatorChar);
235: location = new File(location, path);
236: }
237:
238: return location;
239: }
240:
241: /**
242: * Executes a code generation template.
243: * <p>
244: * The class of the template is formed by prepending
245: * <code>org.geotools.xml.codegen.</code> to <code>name</code>.
246: * <p>
247: *
248: * @param templateName The non-qualified class name of the template.
249: * @param input The input to the template.
250: *
251: * @return The result of the code generator
252: *
253: * @throws ClassNotFoundException If the template class could not be
254: * found.
255: *
256: * @throws RuntimeException If any exceptions ( ex, relection) occur.
257: * while attempting to execute the template.
258: *
259: */
260: protected String execute(String templateName, Object input)
261: throws ClassNotFoundException, RuntimeException {
262: Class c = Class
263: .forName("org.geotools.maven.xmlcodegen.templates."
264: + templateName);
265:
266: try {
267: Object template = c.newInstance();
268:
269: Method generate = c.getMethod("generate",
270: new Class[] { Object.class });
271:
272: return (String) generate.invoke(template,
273: new Object[] { input });
274: } catch (Exception e) {
275: throw new RuntimeException(e);
276: }
277: }
278:
279: String prefix(XSDSchema schema) {
280: return Schemas.getTargetPrefix(schema);
281: }
282: }
|