blob: d26374abaf1a0bd3f2f880885610778d9bdc97b5 [file] [log] [blame]
/* 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;
}
}