| /* Copyright 2004 The Apache Software Foundation |
| * |
| * 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 org.apache.xmlbeans.impl.tool; |
| |
| import org.apache.xmlbeans.SchemaTypeSystem; |
| import org.apache.xmlbeans.SchemaType; |
| import org.apache.xmlbeans.impl.common.XmlErrorWatcher; |
| |
| import java.io.*; |
| import java.util.*; |
| import java.net.URL; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.InvocationTargetException; |
| |
| import org.apache.xmlbeans.impl.schema.SchemaTypeCodePrinter; |
| import org.apache.xmlbeans.impl.common.IOUtil; |
| |
| import repackage.Repackager; |
| |
| public class SchemaCodeGenerator |
| { |
| // input directory, output dir filename |
| // todo: output jar |
| public static boolean compileTypeSystem(SchemaTypeSystem saver, File sourcedir, File[] javasrc, Map sourcesToCopyMap, File[] classpath, File classesdir, File outputJar, boolean nojavac, boolean jaxb, XmlErrorWatcher errors, String repackage, boolean verbose, List sourcefiles ) |
| { |
| |
| if (sourcedir == null || classesdir == null) |
| throw new IllegalArgumentException("Source and class gen dir must not be null."); |
| |
| boolean failure = false; |
| |
| saver.saveToDirectory(classesdir); |
| |
| // Save the schema sources to the classes directory |
| if ((sourcesToCopyMap != null) && (sourcesToCopyMap.size() > 0)) |
| { |
| File schemasdir = createDir(classesdir, "schema/src"); |
| |
| for (Iterator iter = sourcesToCopyMap.keySet().iterator(); iter.hasNext();) |
| { |
| String key = (String)iter.next(); |
| |
| try |
| { |
| URL url = new URL(key); |
| String schemalocation = (String)sourcesToCopyMap.get(key); |
| |
| File targetFile = new File(schemasdir, schemalocation); |
| File parentDir = new File(targetFile.getParent()); |
| createDir(parentDir, null); |
| |
| // Copy the file from filepath to schema/src/<schemaFile> |
| InputStream in = url.openStream(); |
| FileOutputStream out = new FileOutputStream(new File(schemasdir, schemalocation)); |
| IOUtil.copyCompletely(in, out); |
| } |
| catch (IOException e) |
| { |
| System.err.println("IO Error " + e); |
| // failure = true; - not cause for failure |
| } |
| } |
| } |
| |
| Repackager repackager = repackage == null ? null : new Repackager( repackage ); |
| |
| try |
| { |
| String filename = SchemaTypeCodePrinter.indexClassForSystem(saver).replace('.', File.separatorChar) + ".java"; |
| File sourcefile = new File(sourcedir, filename); |
| sourcefile.getParentFile().mkdirs(); |
| |
| Writer writer = |
| repackager == null |
| ? (Writer) new FileWriter( sourcefile ) |
| : (Writer) new RepackagingWriter( sourcefile, repackager ); |
| |
| SchemaTypeCodePrinter.printLoader(writer, saver); |
| |
| writer.close(); |
| |
| sourcefiles.add(sourcefile); |
| } |
| catch (IOException e) |
| { |
| System.err.println("IO Error " + e); |
| failure = true; |
| } |
| |
| if (! jaxb) |
| failure &= genTypes(saver, sourcefiles, sourcedir, repackager, verbose); |
| else |
| failure &= jaxbCodeGenerator(saver, sourcefiles, sourcedir, classesdir, errors); |
| |
| if (failure) |
| return false; |
| |
| return true; |
| } |
| |
| private static boolean genTypes(SchemaTypeSystem saver, List sourcefiles, File sourcedir, Repackager repackager, boolean verbose) |
| { |
| boolean failure = false; |
| |
| List types = new ArrayList(); |
| types.addAll(Arrays.asList(saver.globalTypes())); |
| types.addAll(Arrays.asList(saver.documentTypes())); |
| types.addAll(Arrays.asList(saver.attributeTypes())); |
| |
| for (Iterator i = types.iterator(); i.hasNext(); ) |
| { |
| SchemaType type = (SchemaType)i.next(); |
| if (verbose) |
| System.err.println("Compiling type " + type); |
| if (type.isBuiltinType()) |
| continue; |
| if (type.getFullJavaName() == null) |
| continue; |
| |
| String fjn = type.getFullJavaName(); |
| |
| if (fjn.indexOf('$') > 0) |
| { |
| fjn = |
| fjn.substring( 0, fjn.lastIndexOf( '.' ) ) + "." + |
| fjn.substring( fjn.indexOf( '$' ) + 1 ); |
| } |
| |
| String filename = fjn.replace('.', File.separatorChar) + ".java"; |
| |
| Writer writer = null; |
| |
| try |
| { |
| File sourcefile = new File(sourcedir, filename); |
| sourcefile.getParentFile().mkdirs(); |
| if (verbose) |
| System.err.println("created " + sourcefile.getAbsolutePath()); |
| writer = |
| repackager == null |
| ? (Writer) new FileWriter( sourcefile ) |
| : (Writer) new RepackagingWriter( sourcefile, repackager ); |
| |
| |
| SchemaTypeCodePrinter.printType(writer, type); |
| |
| writer.close(); |
| |
| sourcefiles.add(sourcefile); |
| } |
| catch (IOException e) |
| { |
| System.err.println("IO Error " + e); |
| failure = true; |
| } |
| finally { |
| try { if (writer != null) writer.close(); } catch (IOException e) {} |
| } |
| |
| try |
| { |
| // Generate Implementation class |
| filename = type.getFullJavaImplName().replace('.', File.separatorChar) + ".java"; |
| File implFile = new File(sourcedir, filename); |
| if (verbose) |
| System.err.println("created " + implFile.getAbsolutePath()); |
| implFile.getParentFile().mkdirs(); |
| |
| |
| writer = |
| repackager == null |
| ? (Writer) new FileWriter( implFile ) |
| : (Writer) new RepackagingWriter( implFile, repackager ); |
| |
| SchemaTypeCodePrinter.printTypeImpl(writer, type); |
| |
| writer.close(); |
| |
| sourcefiles.add(implFile); |
| } |
| catch (IOException e) |
| { |
| System.err.println("IO Error " + e); |
| failure = true; |
| } |
| finally { |
| try { if (writer != null) writer.close(); } catch (IOException e) {} |
| } |
| } |
| |
| return failure; |
| } |
| |
| private static class JaxbCodeGeneratorHolder |
| { |
| private static final Method _jaxbCodeGeneratorMethod = buildJaxbCodeGeneratorMethod(); |
| |
| private static Method buildJaxbCodeGeneratorMethod() |
| { |
| try |
| { |
| return Class.forName("org.apache.xmlbeans.impl.jaxb.compiler.JaxbCodeGenerator", false, SchemaCodeGenerator.class.getClassLoader()) |
| .getMethod("compile", new Class[] {SchemaTypeSystem.class, List.class, File.class, File.class, XmlErrorWatcher.class }); |
| } |
| catch (Exception e) |
| { |
| IllegalStateException e2 = new IllegalStateException("Cannot load JaxbCodeGenerator: verify that xbean.jar is on the classpath"); |
| e2.initCause(e); |
| throw e2; |
| } |
| } |
| } |
| |
| private static boolean jaxbCodeGenerator(SchemaTypeSystem saver, List sourcefiles, File sourcedir, File classesdir, XmlErrorWatcher errors) |
| { |
| try |
| { |
| return ((Boolean)JaxbCodeGeneratorHolder._jaxbCodeGeneratorMethod.invoke(null, new Object[] { saver, sourcefiles, sourcedir, classesdir, errors })).booleanValue(); |
| } |
| catch (InvocationTargetException e) |
| { |
| IllegalStateException e2 = new IllegalStateException(e.getMessage()); |
| e2.initCause(e); |
| throw e2; |
| } |
| catch (IllegalAccessException e) |
| { |
| IllegalStateException e2 = new IllegalStateException(e.getMessage()); |
| e2.initCause(e); |
| throw e2; |
| } |
| } |
| |
| protected static File createDir(File rootdir, String subdir) |
| { |
| File newdir = (subdir == null) ? rootdir : new File(rootdir, subdir); |
| boolean created = (newdir.exists() && newdir.isDirectory()) || newdir.mkdirs(); |
| assert(created) : "Could not create " + newdir.getAbsolutePath(); |
| return newdir; |
| } |
| |
| protected static File createTempDir() throws IOException |
| { |
| File tmpFile = File.createTempFile("xbean", null); |
| String path = tmpFile.getAbsolutePath(); |
| if (!path.endsWith(".tmp")) |
| throw new IOException("Error: createTempFile did not create a file ending with .tmp"); |
| path = path.substring(0, path.length() - 4); |
| File tmpSrcDir = null; |
| |
| for (int count = 0; count < 100; count++) |
| { |
| String name = path + ".d" + (count == 0 ? "" : Integer.toString(count++)); |
| |
| tmpSrcDir = new File(name); |
| |
| if (!tmpSrcDir.exists()) |
| { |
| boolean created = tmpSrcDir.mkdirs(); |
| assert created : "Could not create " + tmpSrcDir.getAbsolutePath(); |
| break; |
| } |
| } |
| tmpFile.deleteOnExit(); |
| |
| return tmpSrcDir; |
| } |
| |
| protected static void tryHardToDelete(File dir) |
| { |
| tryToDelete(dir); |
| if (dir.exists()) |
| tryToDeleteLater(dir); |
| } |
| |
| private static void tryToDelete(File dir) |
| { |
| if (dir.exists()) |
| { |
| if (dir.isDirectory()) |
| { |
| String[] list = dir.list(); |
| for (int i = 0; i < list.length; i++) |
| tryToDelete(new File(dir, list[i])); |
| } |
| if (!dir.delete()) |
| return; // don't try very hard, because we're just deleting tmp |
| } |
| } |
| |
| private static Set deleteFileQueue = new HashSet(); |
| private static int triesRemaining = 0; |
| |
| private static boolean tryNowThatItsLater() |
| { |
| List files; |
| |
| synchronized (deleteFileQueue) |
| { |
| files = new ArrayList(deleteFileQueue); |
| deleteFileQueue.clear(); |
| } |
| |
| List retry = new ArrayList(); |
| |
| for (Iterator i = files.iterator(); i.hasNext(); ) |
| { |
| File file = (File)i.next(); |
| tryToDelete(file); |
| if (file.exists()) |
| retry.add(file); |
| } |
| |
| synchronized (deleteFileQueue) |
| { |
| if (triesRemaining > 0) |
| triesRemaining -= 1; |
| |
| if (triesRemaining <= 0 || retry.size() == 0) // done? |
| triesRemaining = 0; |
| else |
| deleteFileQueue.addAll(retry); // try again? |
| |
| return (triesRemaining <= 0); |
| } |
| } |
| |
| private static void giveUp() |
| { |
| synchronized (deleteFileQueue) |
| { |
| deleteFileQueue.clear(); |
| triesRemaining = 0; |
| } |
| } |
| |
| private static void tryToDeleteLater(File dir) |
| { |
| synchronized (deleteFileQueue) |
| { |
| deleteFileQueue.add(dir); |
| if (triesRemaining == 0) |
| { |
| new Thread() |
| { |
| public void run() |
| { |
| // repeats tryNow until triesRemaining == 0 |
| try |
| { |
| for (;;) |
| { |
| if (tryNowThatItsLater()) |
| return; // succeeded |
| Thread.sleep(1000 * 3); // wait three seconds |
| } |
| } |
| catch (InterruptedException e) |
| { |
| giveUp(); |
| } |
| } |
| }; |
| } |
| |
| if (triesRemaining < 10) |
| triesRemaining = 10; |
| } |
| } |
| |
| static class RepackagingWriter extends StringWriter |
| { |
| public RepackagingWriter ( File file, Repackager repackager ) |
| { |
| _file = file; |
| _repackager = repackager; |
| } |
| |
| public void close ( ) throws IOException |
| { |
| super.close(); |
| |
| StringBuffer sb = getBuffer(); |
| |
| _repackager.repackage( sb ); |
| |
| FileWriter fw = new FileWriter( _file ); |
| fw.write( sb.toString() ); |
| fw.close(); |
| } |
| |
| private File _file; |
| private Repackager _repackager; |
| } |
| } |