2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.eclipse.org/org/documents/epl-v10.php
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.ide.eclipse.adt.internal.sdk;
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.build.Messages;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
27 import java.io.PrintStream;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.Field;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.net.MalformedURLException;
34 import java.net.URLClassLoader;
37 * Wrapper to access dex.jar through reflection.
38 * <p/>Since there is no proper api to call the method in the dex library, this wrapper is going
39 * to access it through reflection.
41 public final class DexWrapper {
43 private final static String DEX_MAIN = "com.android.dx.command.dexer.Main"; //$NON-NLS-1$
44 private final static String DEX_CONSOLE = "com.android.dx.command.DxConsole"; //$NON-NLS-1$
45 private final static String DEX_ARGS = "com.android.dx.command.dexer.Main$Arguments"; //$NON-NLS-1$
47 private final static String MAIN_RUN = "run"; //$NON-NLS-1$
49 private Method mRunMethod;
51 private Constructor<?> mArgConstructor;
52 private Field mArgOutName;
53 private Field mArgVerbose;
54 private Field mArgJarOutput;
55 private Field mArgFileNames;
57 private Field mConsoleOut;
58 private Field mConsoleErr;
61 * Loads the dex library from a file path.
63 * The loaded library can be used via
64 * {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}.
66 * @param osFilepath the location of the dex.jar file.
67 * @return an IStatus indicating the result of the load.
69 public synchronized IStatus loadDex(String osFilepath) {
71 File f = new File(osFilepath);
72 if (f.isFile() == false) {
73 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format(
74 Messages.DexWrapper_s_does_not_exists, osFilepath));
78 URLClassLoader loader = new URLClassLoader(new URL[] { url },
79 DexWrapper.class.getClassLoader());
82 Class<?> mainClass = loader.loadClass(DEX_MAIN);
83 Class<?> consoleClass = loader.loadClass(DEX_CONSOLE);
84 Class<?> argClass = loader.loadClass(DEX_ARGS);
87 // now get the fields/methods we need
88 mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
90 mArgConstructor = argClass.getConstructor();
91 mArgOutName = argClass.getField("outName"); //$NON-NLS-1$
92 mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$
93 mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$
94 mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$
96 mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
97 mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
99 } catch (SecurityException e) {
100 return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e);
101 } catch (NoSuchMethodException e) {
102 return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e);
103 } catch (NoSuchFieldException e) {
104 return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e);
107 return Status.OK_STATUS;
108 } catch (MalformedURLException e) {
109 // really this should not happen.
110 return createErrorStatus(
111 String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
112 } catch (ClassNotFoundException e) {
113 return createErrorStatus(
114 String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
119 * Runs the dex command.
120 * @param osOutFilePath the OS path to the outputfile (classes.dex
121 * @param osFilenames list of input source files (.class and .jar files)
122 * @param verbose verbose mode.
123 * @param outStream the stdout console
124 * @param errStream the stderr console
125 * @return the integer return code of com.android.dx.command.dexer.Main.run()
126 * @throws CoreException
128 public synchronized int run(String osOutFilePath, String[] osFilenames,
129 boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException {
133 mConsoleErr.set(null /* obj: static field */, errStream);
134 mConsoleOut.set(null /* obj: static field */, outStream);
136 // create the Arguments object.
137 Object args = mArgConstructor.newInstance();
138 mArgOutName.set(args, osOutFilePath);
139 mArgFileNames.set(args, osFilenames);
140 mArgJarOutput.set(args, false);
141 mArgVerbose.set(args, verbose);
143 // call the run method
144 Object res = mRunMethod.invoke(null /* obj: static method */, args);
146 if (res instanceof Integer) {
147 return ((Integer)res).intValue();
151 } catch (IllegalAccessException e) {
152 throw new CoreException(createErrorStatus(
153 String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e));
154 } catch (InstantiationException e) {
155 throw new CoreException(createErrorStatus(
156 String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e));
157 } catch (InvocationTargetException e) {
158 throw new CoreException(createErrorStatus(
159 String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e));
163 private static IStatus createErrorStatus(String message, Exception e) {
164 AdtPlugin.log(e, message);
165 AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message);
167 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e);