View Javadoc

1   /**
2    *  MicroEmulator
3    *  Copyright (C) 2006-2007 Bartek Teodorczyk <barteo@barteo.net>
4    *  Copyright (C) 2006-2007 Vlad Skarzhevskyy
5    *
6    *  It is licensed under the following two licenses as alternatives:
7    *    1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
8    *    2. Apache License (the "AL") Version 2.0
9    *
10   *  You may not use this file except in compliance with at least one of
11   *  the above two licenses.
12   *
13   *  You may obtain a copy of the LGPL at
14   *      http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
15   *
16   *  You may obtain a copy of the AL at
17   *      http://www.apache.org/licenses/LICENSE-2.0
18   *
19   *  Unless required by applicable law or agreed to in writing, software
20   *  distributed under the License is distributed on an "AS IS" BASIS,
21   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22   *  See the LGPL or the AL for the specific language governing permissions and
23   *  limitations.
24   *
25   *  @version $Id: AppletProducer.java 1977 2009-03-17 18:34:54Z barteo $
26   */
27  
28  package org.microemu.app.util;
29  
30  import java.io.ByteArrayInputStream;
31  import java.io.File;
32  import java.io.FileOutputStream;
33  import java.io.FileWriter;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.net.URL;
37  import java.util.ArrayList;
38  import java.util.Enumeration;
39  import java.util.Iterator;
40  import java.util.List;
41  import java.util.jar.JarEntry;
42  import java.util.jar.JarFile;
43  import java.util.jar.JarInputStream;
44  import java.util.jar.JarOutputStream;
45  import java.util.jar.Manifest;
46  
47  import org.microemu.DisplayComponent;
48  import org.microemu.EmulatorContext;
49  import org.microemu.MIDletBridge;
50  import org.microemu.app.classloader.ClassPreprocessor;
51  import org.microemu.app.classloader.ExtensionsClassLoader;
52  import org.microemu.app.classloader.InstrumentationConfig;
53  import org.microemu.app.ui.Message;
54  import org.microemu.app.ui.noui.NoUiDisplayComponent;
55  import org.microemu.device.DeviceDisplay;
56  import org.microemu.device.FontManager;
57  import org.microemu.device.InputMethod;
58  import org.microemu.device.impl.DeviceDisplayImpl;
59  import org.microemu.device.impl.DeviceImpl;
60  import org.microemu.device.j2se.J2SEDevice;
61  import org.microemu.device.j2se.J2SEDeviceDisplay;
62  import org.microemu.device.j2se.J2SEFontManager;
63  import org.microemu.device.j2se.J2SEInputMethod;
64  import org.microemu.log.Logger;
65  
66  public class AppletProducer {
67  	
68  	public static void createHtml(File htmlOutputFile, DeviceImpl device, String className, File midletOutputFile,
69  			File appletPackageOutputFile, File deviceOutputFile) throws IOException {
70  		int width;
71  		int height;
72  		if (((DeviceDisplayImpl) device.getDeviceDisplay()).isResizable()) {
73  			width = device.getDeviceDisplay().getFullWidth();
74  			height = device.getDeviceDisplay().getFullHeight();
75  		} else {
76  			width = device.getNormalImage().getWidth();
77  			height = device.getNormalImage().getHeight();
78  		}
79  		
80  		FileWriter writer = null;
81  		try {
82  			writer = new FileWriter(htmlOutputFile);
83  			writer.write("");
84  			writer.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n\n");
85  			writer.write("<html>\n");
86  			writer.write("\t<head>\n");
87  			writer.write("\t\t<title>MicroEmulator</title>\n");
88  			writer.write("\t</head>\n");
89  			writer.write("\t<body>\n");
90  			writer.write("\t\t<applet code=\"org.microemu.applet.Main\"\n");
91  			writer.write("\t\t\t\twidth=\"" + width + "\" height=\"" + height + "\"\n");
92  			writer.write("\t\t\t\tarchive=\"" + appletPackageOutputFile.getName() + ",");
93  			if (deviceOutputFile != null) {
94  				writer.write(deviceOutputFile.getName() + ",");
95  			}
96  			writer.write(midletOutputFile.getName() + "\">\n");
97  			writer.write("\t\t\t<param name=\"midlet\" value=\"" + className + "\">\n");
98  			if (device.getDescriptorLocation() != null) {
99  				writer.write("\t\t\t<param name=\"device\" value=\"" + device.getDescriptorLocation() + "\">\n");
100 			}
101 			writer.write("\t\t</applet>\n");
102 			writer.write("\t</body>\n");
103 			writer.write("</html>\n");
104 		} finally {
105 			IOUtils.closeQuietly(writer);
106 		}
107 	}
108 
109 	public static void createMidlet(URL midletInputUrl, File midletOutputFile) throws IOException {
110 		JarInputStream jis = null;
111 		JarInputStream ijis = null;
112 		JarOutputStream jos = null;
113 		InstrumentationConfig config = new InstrumentationConfig();
114 		config.setEnhanceThreadCreation(true);
115 		try {
116 			jis = new JarInputStream(midletInputUrl.openStream());
117 			Manifest manifest = jis.getManifest();
118 			if (manifest == null) {
119 				jos = new JarOutputStream(new FileOutputStream(midletOutputFile));
120 			} else {
121 				jos = new JarOutputStream(new FileOutputStream(midletOutputFile), manifest);
122 			}
123 		
124 			byte[] inputBuffer = new byte[1024];
125 			JarEntry jarEntry;
126 			while ((jarEntry = jis.getNextJarEntry()) != null) {
127 				if (jarEntry.isDirectory() == false) {
128 					String name = jarEntry.getName();
129 					int size = 0;
130 					int read;
131 					int length = inputBuffer.length;
132 					while ((read = jis.read(inputBuffer, size, length)) > 0) {
133 						size += read;
134 						
135 						length = 1024;
136 						if (size + length > inputBuffer.length) {
137 							byte[] newInputBuffer = new byte[size + length];
138 							System.arraycopy(inputBuffer, 0, newInputBuffer, 0, inputBuffer.length);
139 							inputBuffer = newInputBuffer;
140 						}
141 					}
142 					
143 					byte[] outputBuffer = inputBuffer;
144 					int outputSize = size;
145 					if (name.endsWith(".class")) {					
146 				        outputBuffer = ClassPreprocessor.instrument(new ByteArrayInputStream(inputBuffer, 0, size), config);
147 				        outputSize = outputBuffer.length;
148 					}
149 					jos.putNextEntry(new JarEntry(name));
150 					jos.write(outputBuffer, 0, outputSize);
151 				}
152 			}
153 			
154 			URL url = AppletProducer.class.getResource("/microemu-injected.jar");
155 			if (url != null) {
156 				ijis = new JarInputStream(url.openStream());
157 				while ((jarEntry = ijis.getNextJarEntry()) != null) {
158 					if (jarEntry.getName().equals("org/microemu/Injected.class")) {
159 						jos.putNextEntry(new JarEntry(jarEntry.getName()));
160 						int read;
161 						while ((read = ijis.read(inputBuffer)) > 0) {
162 							jos.write(inputBuffer, 0, read);
163 						}
164 					}
165 				}
166 			} else {
167 				Logger.error("Cannot find microemu-injected.jar resource in classpath");
168 			}
169 		} finally {
170 			IOUtils.closeQuietly(jis);
171 			IOUtils.closeQuietly(ijis);
172 			IOUtils.closeQuietly(jos);
173 		}
174 	}
175 		
176 	
177 	public static void main(String args[]) {
178 		String midletClass = null;;
179 		File appletInputFile = null;
180 		File deviceInputFile = null;
181 		File midletInputFile = null;
182 		File htmlOutputFile = null;
183 		File appletOutputFile = null;
184 		File deviceOutputFile = null;
185 		File midletOutputFile = null;
186 		
187 		List params = new ArrayList();
188 		for (int i = 0; i < args.length; i++) {
189 			params.add(args[i]);
190 		}
191 		
192 		Iterator argsIterator = params.iterator();
193 		while (argsIterator.hasNext()) {
194 			String arg = (String) argsIterator.next();
195 			argsIterator.remove();
196 
197 			if ((arg.equals("--help")) || (arg.equals("-help"))) {
198 				System.out.println(usage());
199 				System.exit(0);
200 			} else if (arg.equals("--midletClass")) {
201 				midletClass = (String) argsIterator.next();
202 				argsIterator.remove();
203 			} else if (arg.equals("--appletInput")) {
204 				appletInputFile = new File((String) argsIterator.next());
205 				argsIterator.remove();
206 			} else if (arg.equals("--deviceInput")) {
207 				deviceInputFile = new File((String) argsIterator.next());
208 				argsIterator.remove();
209 			} else if (arg.equals("--midletInput")) {
210 				midletInputFile = new File((String) argsIterator.next());
211 				argsIterator.remove();
212 			} else if (arg.equals("--htmlOutput")) {
213 				htmlOutputFile = new File((String) argsIterator.next());
214 				argsIterator.remove();
215 			} else if (arg.equals("--appletOutput")) {
216 				appletOutputFile = new File((String) argsIterator.next());
217 				argsIterator.remove();
218 			} else if (arg.equals("--deviceOutput")) {
219 				deviceOutputFile = new File((String) argsIterator.next());
220 				argsIterator.remove();
221 			} else if (arg.equals("--midletOutput")) {
222 				midletOutputFile = new File((String) argsIterator.next());
223 				argsIterator.remove();
224 			}
225 		}		
226 
227 		if (midletClass == null
228 				|| appletInputFile == null 
229 				|| deviceInputFile == null
230 				|| midletInputFile == null
231 				|| htmlOutputFile == null
232 				|| appletOutputFile == null
233 				|| deviceOutputFile == null
234 				|| midletOutputFile == null) {
235 			System.out.println(usage());
236 			System.exit(0);
237 		}
238 		
239 		try {
240 			DeviceImpl device = null;
241 			String descriptorLocation = null;
242 			JarFile jar = new JarFile(deviceInputFile);
243 			for (Enumeration en = jar.entries(); en.hasMoreElements();) {
244 				String entry = ((JarEntry) en.nextElement()).getName();
245 				if ((entry.toLowerCase().endsWith(".xml") || entry.toLowerCase().endsWith("device.txt"))
246 						&& !entry.toLowerCase().startsWith("meta-inf")) {
247 					descriptorLocation = entry;
248 					break;
249 				}
250 			}
251 			if (descriptorLocation != null) {
252 				EmulatorContext context = new EmulatorContext() {
253 					private DisplayComponent displayComponent = new NoUiDisplayComponent();
254 
255 					private InputMethod inputMethod = new J2SEInputMethod();
256 
257 					private DeviceDisplay deviceDisplay = new J2SEDeviceDisplay(this);
258 
259 					private FontManager fontManager = new J2SEFontManager();
260 
261 					public DisplayComponent getDisplayComponent() {
262 						return displayComponent;
263 					}
264 
265 					public InputMethod getDeviceInputMethod() {
266 						return inputMethod;
267 					}
268 
269 					public DeviceDisplay getDeviceDisplay() {
270 						return deviceDisplay;
271 					}
272 
273 					public FontManager getDeviceFontManager() {
274 						return fontManager;
275 					}
276 
277 					public InputStream getResourceAsStream(String name) {
278 						return MIDletBridge.getCurrentMIDlet().getClass().getResourceAsStream(name);
279 					}
280 					
281 					public boolean platformRequest(final String URL) {
282 						new Thread(new Runnable() {
283 							public void run() {
284 								Message.info("MIDlet requests that the device handle the following URL: " + URL);
285 							}
286 						}).start();
287 
288 						return false;
289 					}
290 				};
291 
292 				URL[] urls = new URL[1];
293 				urls[0] = deviceInputFile.toURI().toURL();
294 				ClassLoader classLoader = new ExtensionsClassLoader(urls, urls.getClass().getClassLoader());
295 				device = DeviceImpl.create(context, classLoader, descriptorLocation, J2SEDevice.class);
296 			}
297 			
298 			if (device == null) {
299 				System.out.println("Error parsing device package: " + descriptorLocation);
300 				System.exit(0);
301 			}
302 			
303 			createHtml(htmlOutputFile, device, midletClass, midletOutputFile, appletOutputFile, deviceOutputFile);
304 			createMidlet(midletInputFile.toURI().toURL(), midletOutputFile);
305 			IOUtils.copyFile(appletInputFile, appletOutputFile);
306 			IOUtils.copyFile(deviceInputFile, deviceOutputFile);
307 		} catch (IOException ex) {
308 			ex.printStackTrace();
309 		}
310 		
311 		System.exit(0);
312 	}
313 	
314 	
315 	private static String usage() {
316 		return "--midletClass {midlet class name} \n" +
317 			   "--appletInput {emulator applet jar input file} \n" +
318 			   "--deviceInput {device jar input file} \n" +
319 			   "--midletInput {midlet jar input file} \n" +
320 			   "--htmlOutput {html output file} \n" +
321 			   "--appletOutput {emulator applet jar output file} \n" +
322 			   "--deviceOutput {device jar output file} \n" +
323 			   "--midletOutput {midlet jar output file}";
324 	}
325 	
326 }