package com.francetelecom.rd.stubs.engine;
/*
* #%L
* Matos
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2008 - 2014 Orange SA
* %%
* 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.
* #L%
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Properties;
import java.util.Set;
/**
* Main entry point for the stub generator. The options are:
* <ul>
* -jars for the paths to the jar to translate. The classpath must be specified
* with the classic separator char.
* <li>-d for the path to the directory where the java code is produced.
* </ul>
*
* @author Pierre Cregut
*/
public class Main {
final static String OTHER_PREFIX = "aNnOtPrEfIxOrAnGe";
final static String PREFIX = "oLaBsTuBs";
final private static String PREFIX_DB = "oXaXsTxBs";
final static String ANNOTATION_PACKAGE = "com.francetelecom.rd.stubs.annotation";
final static int MODE_EMPTY_STUB = 1;
final static int MODE_STAT = 2;
final static int MODE_GEN_STUB = 3;
final static int MODE_XML = 4;
final static int MODE_VERSION = 5;
final static int MODE_WITNESS = 6;
final static int WIDTH = 600, HEIGHT = 600;
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String[] jars = new String[0];
String[] annotJars = null;
String outDir = "out";
String outFile = null;
String dbName = null;
String versionName = null;
String sideFile = null;
String configName = null;
int mode = MODE_EMPTY_STUB;
String sdkPath = null;
VersionDatabase database;
for (int i = 0; i < args.length; i++) {
String arg = args[i].trim();
if (arg.equals("-a")) {
annotJars = args[++i].split(File.pathSeparator);
} else if (arg.equals("-d")) {
outDir = args[++i];
} else if (arg.equals("-db")) {
dbName = args[++i];
} else if (arg.equals("-jars")) {
String[] newJars = args[++i].split(File.pathSeparator);
int length = jars.length;
if (length == 0)
jars = newJars;
else {
jars = Arrays.copyOf(jars, length + newJars.length);
System.arraycopy(newJars, 0, jars, length, newJars.length);
}
} else if (arg.equals("-r")) {
mode = MODE_GEN_STUB;
configName = args[++i];
} else if (arg.equals("-s")) {
mode = MODE_STAT;
configName = args[++i];
} else if (arg.equals("-v")) {
mode = MODE_VERSION;
versionName = args[++i];
} else if (arg.equals("-w")) {
sideFile = args[++i];
} else if (arg.equals("-x")) {
mode = MODE_XML;
outFile = args[++i];
} else if (arg.equals("-W")) {
mode = MODE_WITNESS;
} else if (arg.equals("-SDK")) {
sdkPath = args[++i];
} else {
System.err.println("I do not know what to do with " + arg);
}
}
if (sdkPath != null) {
System.exit(buildDatabase(sdkPath, dbName));
}
Hierarchy hierarchy = new Hierarchy();
RelocatingClassLoader loader = new RelocatingClassLoader(jars, PREFIX);
AlternativeImplementation altImplem = null;
Properties properties = null;
ReflexUtil rf = null;
if (configName != null) {
InputStream is = new FileInputStream(configName);
properties = new Properties();
properties.loadFromXML(is);
is.close();
}
if (annotJars != null) {
RelocatingClassLoader annotLoader = new RelocatingClassLoader(annotJars, OTHER_PREFIX);
annotLoader.setSilent();
annotLoader.initLookup();
rf = new ReflexUtil(PREFIX, OTHER_PREFIX, ANNOTATION_PACKAGE);
altImplem = new AlternativeImplementation(annotLoader, OTHER_PREFIX, PREFIX);
} else {
rf = new ReflexUtil(mode == MODE_VERSION ? PREFIX_DB : PREFIX, null, ANNOTATION_PACKAGE);
}
populate(hierarchy, loader);
hierarchy.count();
switch (mode) {
case MODE_STAT:
if (dbName == null) {
System.err.println("Missing database argument for stats!");
System.exit(-1);
}
database = new VersionDatabase(dbName, rf);
JClassView.viewStat(hierarchy, rf, properties, database);
break;
case MODE_EMPTY_STUB:
AlternativeAnnotations altAnnot = new AlternativeReplacedAnnotations(altImplem);
doDump(hierarchy, new ClassDumper(outDir, rf, altAnnot));
break;
case MODE_GEN_STUB:
AnnotatingClassDumper acd = new AnnotatingClassDumper(outDir, rf, properties,
hierarchy);
if (dbName != null) {
database = new VersionDatabase(dbName, rf);
acd.setVersionDatabase(database);
}
doDump(hierarchy, acd);
break;
case MODE_XML:
RuleGenerator.generate(outFile, sideFile, rf, hierarchy);
break;
case MODE_WITNESS:
WitnessIssuesDumper.dumpWitnessIssues(rf, hierarchy);
break;
case MODE_VERSION:
doRegister(hierarchy, rf, dbName, versionName);
break;
default:
System.out.println("Problem with mode");
}
}
private static void populate(Hierarchy hierarchy, RelocatingClassLoader loader) throws IOException {
Set<String> everyone = loader.initLookup();
for (String name : everyone) {
try {
Class<?> clazz = loader.loadClass(name);
hierarchy.register(clazz);
} catch (Throwable e) {
System.err.println("============== CANNOT HANDLE " + name + " =============");
e.printStackTrace();
}
}
}
private static int buildDatabase(String sdkPath, String dbName) {
ReflexUtil rf = new ReflexUtil(PREFIX, null, ANNOTATION_PACKAGE);
try {
if (dbName == null) {
System.err.println("Needs a database with option -SDK");
return 1;
}
File platformDir = new File(sdkPath, "platforms");
if (!platformDir.exists()) {
System.err.println("Cannot find the relevant dirs in SDK");
return 1;
}
for (File dirfile : platformDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File arg0, String arg1) {
return arg1.startsWith("android-");
}
})) {
Hierarchy h = new Hierarchy();
String jar = new File(dirfile, "android.jar").getAbsolutePath();
RelocatingClassLoader rcl = new RelocatingClassLoader(new String[] {
jar
}, PREFIX);
populate(h, rcl);
String suffix = dirfile.getName().substring(8);
if (suffix.equals("Honeycomb")) continue;
if (suffix.equals("2.1")) suffix="7";
String versionName = "v" + suffix;
doRegister(h, rf, dbName, versionName);
}
return 0;
} catch (IOException e) {
e.printStackTrace();
return 1;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return 1;
}
}
private static void doRegister(Hierarchy hierarchy, ReflexUtil rf, String dbName,
String versionName) {
try {
VersionDatabase db = new VersionDatabase(dbName, rf);
db.open_transaction();
db.setVersion(versionName);
int count = 0;
for (Class<?> clazz : hierarchy.getContents()) {
if (clazz.getName().contains("$"))
continue;
System.out.println(count++ + " - " + clazz);
db.registerClass(clazz);
}
db.close_transaction();
db.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void doDump(Hierarchy hierarchy, ClassDumper dumper) {
int count = 0;
for (Class<?> clazz : hierarchy.getContents()) {
dumper.register(clazz);
}
dumper.dumpRegistered();
for (Class<?> clazz : hierarchy.getContents()) {
try {
dumper.dumpClass(clazz);
} catch (Throwable e) {
System.err.println("============== CANNOT DUMP " + clazz + " =============");
e.printStackTrace();
count++;
}
}
System.err.println("Errors = " + count + "/" + dumper.count);
}
}