OSDN Git Service

snapshot
[android-x86/sdk.git] / eclipse / plugins / com.android.ide.eclipse.adt / src / com / android / ide / eclipse / adt / internal / sdk / DexWrapper.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
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
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
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.
15  */
16
17 package com.android.ide.eclipse.adt.internal.sdk;
18
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.build.Messages;
21
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25
26 import java.io.File;
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;
33 import java.net.URL;
34 import java.net.URLClassLoader;
35
36 /**
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.
40  */
41 public final class DexWrapper {
42     
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$
46     
47     private final static String MAIN_RUN = "run"; //$NON-NLS-1$
48     
49     private Method mRunMethod;
50
51     private Constructor<?> mArgConstructor;
52     private Field mArgOutName;
53     private Field mArgVerbose;
54     private Field mArgJarOutput;
55     private Field mArgFileNames;
56
57     private Field mConsoleOut;
58     private Field mConsoleErr;
59     
60     /**
61      * Loads the dex library from a file path.
62      * 
63      * The loaded library can be used via
64      * {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}.
65      * 
66      * @param osFilepath the location of the dex.jar file.
67      * @return an IStatus indicating the result of the load.
68      */
69     public synchronized IStatus loadDex(String osFilepath) {
70         try {
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));
75             }
76             URL url = f.toURL();
77     
78             URLClassLoader loader = new URLClassLoader(new URL[] { url },
79                     DexWrapper.class.getClassLoader());
80             
81             // get the classes.
82             Class<?> mainClass = loader.loadClass(DEX_MAIN);
83             Class<?> consoleClass = loader.loadClass(DEX_CONSOLE);
84             Class<?> argClass = loader.loadClass(DEX_ARGS);
85             
86             try {
87                 // now get the fields/methods we need
88                 mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
89                 
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$
95                 
96                 mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
97                 mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
98                 
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);
105             }
106
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);
115         }
116     }
117     
118     /**
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
127      */
128     public synchronized int run(String osOutFilePath, String[] osFilenames,
129             boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException {
130         
131         try {
132             // set the stream
133             mConsoleErr.set(null /* obj: static field */, errStream);
134             mConsoleOut.set(null /* obj: static field */, outStream);
135             
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);
142             
143             // call the run method
144             Object res = mRunMethod.invoke(null /* obj: static method */, args);
145             
146             if (res instanceof Integer) {
147                 return ((Integer)res).intValue();
148             }
149         
150             return -1;
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));
160         }
161     }
162     
163     private static IStatus createErrorStatus(String message, Exception e) {
164         AdtPlugin.log(e, message);
165         AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message);
166         
167         return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e);
168     }
169 }