/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tools.internal;
import java.io.*;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.*;
import java.util.Arrays;
import org.eclipse.swt.SWT;
public class JNIGeneratorApp {
JNIClass mainClass;
JNIClass[] classes;
ProgressMonitor progress;
String mainClassName, classesDir, outputDir, classpath;
MetaData metaData;
static boolean USE_AST = true;
public JNIGeneratorApp() {
}
public String getClasspath() {
return classpath;
}
public String getClassesDir() {
return classesDir;
}
public JNIClass getMainClass() {
return mainClass;
}
public String getMainClassName() {
return mainClassName;
}
public MetaData getMetaData() {
return metaData;
}
String getMetaDataDir() {
return "./JNI Generation/org/eclipse/swt/tools/internal/";
}
public String getOutputDir() {
return outputDir;
}
public void generateAll() {
String mainClasses = new MetaData(getDefaultMainClass()).getMetaData("swt_main_classes", null);
if (mainClasses != null) {
String[] list = JNIGenerator.split(mainClasses, ",");
for (int i = 0; i < list.length; i += 2) {
String className = list[i].trim();
if (!USE_AST) {
try {
Class.forName(className, false, getClass().getClassLoader());
} catch (Throwable e) {
continue;
}
}
setMainClassName(className);
generate();
}
}
}
void generateSTATS_C(JNIClass[] classes) {
try {
StatsGenerator gen = new StatsGenerator(false);
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = outputDir + gen.getFileName();
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateSTATS_H(JNIClass[] classes) {
try {
StatsGenerator gen = new StatsGenerator(true);
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = outputDir + gen.getFileName();
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateSTRUCTS_H(JNIClass[] classes) {
try {
StructsGenerator gen = new StructsGenerator(true);
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = outputDir + gen.getFileName();
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateSTRUCTS_C(JNIClass[] classes) {
try {
StructsGenerator gen = new StructsGenerator(false);
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = outputDir + gen.getFileName();
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateSWT_C(JNIClass[] classes) {
try {
NativesGenerator gen = new NativesGenerator();
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = outputDir + gen.getFileName();
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateMetaData(JNIClass[] classes) {
try {
MetaDataGenerator gen = new MetaDataGenerator();
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.setProgressMonitor(progress);
ByteArrayOutputStream out = new ByteArrayOutputStream();
gen.setOutput(new PrintStream(out));
String fileName = getMetaDataDir() + gen.getFileName();
if (new File(fileName).exists()) {
gen.setDelimiter(JNIGenerator.getDelimiter(fileName));
gen.generate();
if (!new File(getMetaDataDir()).exists()) {
System.out.println("Warning: Meta data output dir does not exist");
return;
}
if (out.size() > 0) JNIGenerator.output(out.toByteArray(), fileName);
}
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
void generateEmbededMetaData(JNIClass[] classes) {
try {
EmbedMetaData gen = new EmbedMetaData();
gen.setMainClass(mainClass);
gen.setClasses(classes);
gen.setMetaData(metaData);
gen.generate();
} catch (Exception e) {
System.out.println("Problem");
e.printStackTrace(System.out);
}
}
public void generate() {
System.out.println("Generating \"" + getMainClassName() + "\"");
generate(null);
}
public void generate(ProgressMonitor progress) {
if (mainClass == null) return;
if (progress != null) progress.setMessage("Initializing...");
JNIClass[] classes = getClasses();
JNIClass[] natives = getNativesClasses(classes);
JNIClass[] structs = getStructureClasses(classes);
this.progress = progress;
if (progress != null) {
int nativeCount = 0;
for (int i = 0; i < natives.length; i++) {
JNIClass clazz = natives[i];
JNIMethod[] methods = clazz.getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
JNIMethod method = methods[j];
if ((method.getModifiers() & Modifier.NATIVE) == 0) continue;
nativeCount++;
}
}
int total = nativeCount * 4;
total += classes.length;
total += natives.length * (3);
total += structs.length * 2;
progress.setTotal(total);
progress.setMessage("Generating structs.h ...");
}
generateSTRUCTS_H(structs);
if (progress != null) progress.setMessage("Generating structs.c ...");
generateSTRUCTS_C(structs);
if (progress != null) progress.setMessage("Generating natives ...");
generateSWT_C(natives);
if (progress != null) progress.setMessage("Generating stats.h ...");
generateSTATS_H(natives);
if (progress != null) progress.setMessage("Generating stats.c ...");
generateSTATS_C(natives);
if (progress != null) progress.setMessage("Generating meta data ...");
generateMetaData(classes);
// if (progress != null) progress.setMessage("Generating embeded meta data ...");
// generateEmbededMetaData(classes);
if (progress != null) progress.setMessage("Done.");
this.progress = null;
}
String getPackageName(String className) {
int dot = mainClassName.lastIndexOf('.');
if (dot == -1) return "";
return mainClassName.substring(0, dot);
}
String[] getClassNames(String mainClassName) {
String pkgName = getPackageName(mainClassName);
String classpath = getClasspath();
if (classpath == null) classpath = System.getProperty("java.class.path");
String pkgPath = pkgName.replace('.', File.separatorChar);
String pkgZipPath = pkgName.replace('.', '/');
ArrayList<String> classes = new ArrayList<String>();
int start = 0;
int index = 0;
while (index < classpath.length()) {
index = classpath.indexOf(File.pathSeparatorChar, start);
if (index == -1) index = classpath.length();
String path = classpath.substring(start, index);
if (path.toLowerCase().endsWith(".jar")) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(path);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String name = entry.getName();
if (name.startsWith(pkgZipPath) && name.indexOf('/', pkgZipPath.length() + 1) == -1 && name.endsWith(".class")) {
String className = name.substring(pkgZipPath.length() + 1, name.length() - 6);
className.replace('/', '.');
classes.add(className);
}
}
} catch (IOException e) {
} finally {
try {
if (zipFile != null) zipFile.close();
} catch (IOException ex) {}
}
} else {
File file = new File(path + File.separator + pkgPath);
if (file.exists()) {
String[] entries = file.list();
for (int i = 0; i < entries.length; i++) {
String entry = entries[i];
File f = new File(file, entry);
if (!f.isDirectory()) {
if (f.getAbsolutePath().endsWith(".class")) {
String className = entry.substring(0, entry.length() - 6);
classes.add(className);
}
}
}
}
}
start = index + 1;
}
return classes.toArray(new String[classes.size()]);
}
public JNIClass[] getClasses() {
if (classes != null) return classes;
if (mainClassName == null) return new JNIClass[0];
if (USE_AST) return getASTClasses();
String[] classNames = getClassNames(mainClassName);
Arrays.sort(classNames);
String packageName = getPackageName(mainClassName);
JNIClass[] classes = new JNIClass[classNames.length];
for (int i = 0; i < classNames.length; i++) {
String className = classNames[i];
try {
String qualifiedName = packageName + "." + className;
if (qualifiedName.equals(mainClassName)) {
classes[i] = mainClass;
} else {
String root = classesDir != null ? classesDir : new File(outputDir).getParent() + "/";
String sourcePath = root + qualifiedName.replace('.', '/') + ".java";
classes[i] = new ReflectClass(Class.forName(qualifiedName, false, getClass().getClassLoader()), metaData, sourcePath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return classes;
}
JNIClass[] getASTClasses() {
if (classes != null) return classes;
if (mainClassName == null) return new JNIClass[0];
String root = classesDir != null ? classesDir : new File(outputDir).getParent() + "/";
String mainPath = new File(root + mainClassName.replace('.', '/') + ".java").getAbsolutePath();
ArrayList<JNIClass> classes = new ArrayList<JNIClass>();
String packageName = getPackageName(mainClassName);
File dir = new File(root + "/" + packageName.replace('.', '/'));
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
try {
String path = file.getAbsolutePath().replace('\\', '/');
if (path.endsWith(".java")) {
if (mainPath.equals(path)){
classes.add(mainClass);
} else {
classes.add(new ASTClass(path, metaData));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return classes.toArray(new JNIClass[classes.size()]);
}
public JNIClass[] getNativesClasses(JNIClass[] classes) {
if (mainClass == null) return new JNIClass[0];
ArrayList<JNIClass> result = new ArrayList<JNIClass>();
for (int i = 0; i < classes.length; i++) {
JNIClass clazz = classes[i];
JNIMethod[] methods = clazz.getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
JNIMethod method = methods[j];
int mods = method.getModifiers();
if ((mods & Modifier.NATIVE) != 0) {
result.add(clazz);
break;
}
}
}
return result.toArray(new JNIClass[result.size()]);
}
public JNIClass[] getStructureClasses(JNIClass[] classes) {
if (mainClass == null) return new JNIClass[0];
ArrayList<JNIClass> result = new ArrayList<JNIClass>();
outer:
for (int i = 0; i < classes.length; i++) {
JNIClass clazz = classes[i];
JNIMethod[] methods = clazz.getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
JNIMethod method = methods[j];
int mods = method.getModifiers();
if ((mods & Modifier.NATIVE) != 0) continue outer;
}
JNIField[] fields = clazz.getDeclaredFields();
boolean hasPublicFields = false;
for (int j = 0; j < fields.length; j++) {
JNIField field = fields[j];
int mods = field.getModifiers();
if ((mods & Modifier.PUBLIC) != 0 && (mods & Modifier.STATIC) == 0) {
hasPublicFields = true;
break;
}
}
if (!hasPublicFields) continue;
result.add(clazz);
}
return result.toArray(new JNIClass[result.size()]);
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
public void setMainClass(JNIClass mainClass) {
this.mainClass = mainClass;
}
public void setMetaData(MetaData data) {
this.metaData = data;
}
public void setClasses(JNIClass[] classes) {
this.classes = classes;
}
public void setMainClassName(String str) {
mainClassName = str;
metaData = new MetaData(mainClassName);
String mainClasses = getMetaData().getMetaData("swt_main_classes", null);
if (mainClasses != null) {
String[] list = JNIGenerator.split(mainClasses, ",");
for (int i = 0; i < list.length; i += 2) {
if (mainClassName.equals(list[i].trim())) {
setOutputDir(list[i + 1].trim());
}
}
}
if (mainClassName != null) {
try {
String root = classesDir != null ? classesDir : new File(outputDir).getParent() + "/";
String sourcePath = root + mainClassName.replace('.', '/') + ".java";
if (USE_AST) {
mainClass = new ASTClass(sourcePath, metaData);
} else {
mainClass = new ReflectClass(Class.forName(mainClassName, false, getClass().getClassLoader()), metaData, sourcePath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void setMainClassName(String str, String outputDir) {
setMainClassName(str, outputDir, null);
}
public void setMainClassName(String str, String outputDir, String classesDir) {
mainClassName = str;
setClassesDir(classesDir);
setOutputDir(outputDir);
metaData = new MetaData(mainClassName);
try {
String root = classesDir != null ? classesDir : new File(outputDir).getParent() + "/";
String sourcePath = root + mainClassName.replace('.', '/') + ".java";
if (USE_AST) {
mainClass = new ASTClass(sourcePath, metaData);
} else {
mainClass = new ReflectClass(Class.forName(mainClassName, false, getClass().getClassLoader()), metaData, sourcePath);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setClassesDir(String str) {
if (str != null) {
if (!str.endsWith("\\") && !str.endsWith("/") ) {
str += File.separator;
}
str = str.replace('\\', '/');
}
classesDir = str;
}
public void setOutputDir(String str) {
if (str != null) {
if (!str.endsWith("\\") && !str.endsWith("/") ) {
str += File.separator;
}
str = str.replace('\\', '/');
}
outputDir = str;
}
public static String getDefaultMainClass() {
return "org.eclipse.swt.internal." + getDefaultPlatform() + ".OS";
}
public static String getDefaultPlatform() {
return SWT.getPlatform();
}
public static void main(String[] args) {
JNIGeneratorApp gen = new JNIGeneratorApp ();
if (args.length == 1 && (args[0].equals("*") || args[0].equals("all"))) {
gen.generateAll();
return;
}
if (args.length > 0) {
gen.setMainClassName(args[0]);
if (args.length > 1) gen.setOutputDir(args[1]);
if (args.length > 2) gen.setClasspath(args[2]);
} else {
gen.setMainClassName(getDefaultMainClass());
}
gen.generate();
}
}