001: /*
002: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024:
025: package com.sun.jumpimpl.module.download;
026:
027: import com.sun.jump.common.JUMPApplication;
028: import com.sun.jump.module.download.*;
029: import com.sun.jump.common.JUMPAppModel;
030:
031: import java.io.InputStream;
032: import java.io.InputStreamReader;
033: import java.io.LineNumberReader;
034: import java.io.OutputStream;
035: import java.io.FileReader;
036: import java.io.FileWriter;
037: import java.io.PrintWriter;
038: import java.io.File;
039: import java.net.HttpURLConnection;
040: import java.net.MalformedURLException;
041: import java.net.URL;
042: import java.net.URLConnection;
043: import java.net.URLEncoder;
044: import java.util.Hashtable;
045: import java.util.Iterator;
046: import java.util.Map;
047: import java.util.Properties;
048: import java.util.Vector;
049:
050: public class MIDPOTADownloadModule implements JUMPDownloadModule {
051:
052: // From the JUMPModule interface.
053: public void load(Map config) {
054: }
055:
056: public void unload() {
057: }
058:
059: public static Hashtable statusOTA2MIDP = new Hashtable();
060: static String jadMime = "text/vnd.sun.j2me.app-descriptor";
061:
062: public JUMPDownloader createDownloader(
063: JUMPDownloadDescriptor descriptor)
064: throws JUMPDownloadException {
065:
066: return new DownloaderImpl(descriptor);
067: }
068:
069: private String encode(String url) {
070: // Change spaces to %20
071: String encodedURL = "";
072: for (int i = 0; i < url.length(); i++) {
073: char c = url.charAt(i);
074: if (c == ' ') {
075: encodedURL += "%20";
076: } else {
077: encodedURL += c;
078: }
079: }
080: return encodedURL;
081: }
082:
083: public JUMPDownloadDescriptor createDescriptor(String url)
084: throws JUMPDownloadException {
085:
086: MIDPDownloadDescriptor d = new MIDPDownloadDescriptor(
087: getSchema(), url);
088:
089: try {
090:
091: URL jadURL = new URL(encode(url));
092:
093: URLConnection conn = jadURL.openConnection();
094: if (jadURL.getProtocol().equals("http")
095: && ((HttpURLConnection) conn).getResponseCode() != HttpURLConnection.HTTP_OK) {
096: throw new JUMPDownloadException(
097: "Bad Http response code: "
098: + ((HttpURLConnection) conn)
099: .getResponseCode());
100: }
101:
102: String mimeType = conn.getContentType();
103:
104: if (DownloadModuleFactoryImpl.verbose) {
105: System.err.println("debug : jad mimetype is "
106: + mimeType);
107: }
108:
109: if (!jadURL.getProtocol().equals("file")
110: && (mimeType == null || !mimeType
111: .equalsIgnoreCase(jadMime))) {
112: throw new JUMPDownloadException(
113: "Content type for the JAD URL" + " is not "
114: + jadMime + "\n" + url);
115: }
116:
117: /**
118: * First, write out the .jad as a temp file.
119: * The installer may use the stored jad data to perform
120: * additional content verificiation.
121: */
122:
123: InputStream in = conn.getInputStream();
124: LineNumberReader pr = new LineNumberReader(
125: new InputStreamReader(in));
126:
127: File jadFile = File.createTempFile("midlet", ".jad");
128: PrintWriter outputStream = new PrintWriter(new FileWriter(
129: jadFile));
130:
131: String l;
132: while ((l = pr.readLine()) != null) {
133: outputStream.println(l);
134: }
135:
136: pr.close();
137: outputStream.close();
138:
139: // Now, let's read back the data.
140: pr = new LineNumberReader(new FileReader(jadFile));
141:
142: Hashtable missed = new Hashtable();
143:
144: while (true) {
145:
146: String prop = pr.readLine();
147: if (prop == null || prop.equals("")) {
148: break;
149: }
150:
151: int idx = prop.indexOf(':');
152:
153: if (idx <= 1) {
154: throw new JUMPDownloadException(
155: "Jad file format error, line:\n" + prop);
156: }
157:
158: String name = prop.substring(0, idx).trim()
159: .toLowerCase();
160: String value = prop.substring(idx + 1).trim();
161:
162: if ("midlet-jar-size".equals(name)) {
163: d.setSize(Integer.parseInt(value));
164: } else if ("midlet-jar-url".equals(name)) {
165: d.setObjectURI(value);
166: } else if ("midlet-version".equals(name)) {
167: d.setVersion(value);
168: } else if ("midlet-install-notify".equals(name)) {
169: d.setInstallNotifyURI(value);
170: } else if ("midlet-name".equals(name)) {
171: d.setName(value);
172: } else if ("midlet-description".equals(name)) {
173: d.setDescription(value);
174: } else if ("midlet-vendor".equals(name)) {
175: d.setVendor(value);
176: } else {
177: missed.put(name, value);
178: }
179: }
180:
181: // Done with parsing. Close the jad file.
182: pr.close();
183:
184: int no = 1;
185:
186: Vector applications = new Vector();
187:
188: while (true) {
189:
190: String key;
191: String val = (String) missed.get(key = "midlet-" + no);
192: if (val == null) {
193: break;
194: }
195:
196: int idx1 = val.indexOf(',');
197: int idx2 = val.lastIndexOf(',');
198: if ((idx1 < 0) || (idx1 == idx2)) {
199: throw new JUMPDownloadException(
200: "Invalid midlet reference " + val);
201: }
202:
203: String classname = val.substring(0, idx1);
204: String iconpath = val.substring(idx1 + 1, idx2);
205: String title = val.substring(idx2 + 1);
206:
207: // Set the properties for the application
208: Properties props = new Properties();
209: props.setProperty("MIDLETApplication_initialClass",
210: classname);
211: props.setProperty(JUMPApplication.TITLE_KEY, title);
212: props.setProperty(JUMPApplication.ICONPATH_KEY,
213: iconpath);
214: props.setProperty(JUMPApplication.APPMODEL_KEY,
215: JUMPAppModel.MIDLET.getName());
216: props.setProperty("JUMPApplication_localJadUrl",
217: jadFile.getCanonicalPath());
218:
219: applications.add(props);
220:
221: d.setType(JUMPDownloadDescriptor.TYPE_APPLICATION);
222: missed.remove(key);
223:
224: }
225:
226: Object appsArray[] = applications.toArray();
227: Properties apps[] = new Properties[appsArray.length];
228: for (int i = 0; i < appsArray.length; i++) {
229: apps[i] = (Properties) appsArray[i];
230: }
231: d.setApplications(apps);
232:
233: d.checkOut();
234: } catch (SyntaxException e) {
235: throw new JUMPDownloadException(
236: "ERROR: Descriptor is invalid");
237: } catch (JUMPDownloadException e) {
238: throw e;
239: } catch (Throwable e) {
240: throw new JUMPDownloadException("ERROR: I/O trouble:\n"
241: + e.toString());
242: }
243: return d;
244: }
245:
246: public boolean sendNotify(String notifyURL, String statusCode,
247: String statusMsg) {
248:
249: try {
250: if ((notifyURL == null) || "".equals(notifyURL)) {
251: return false;
252: }
253:
254: statusCode = (String) statusOTA2MIDP.get(statusCode);
255:
256: if ((statusCode == null) || "".equals(statusCode)) {
257: return false;
258: }
259:
260: if (DownloadModuleFactoryImpl.verbose) {
261: System.out.println("InstallNotifyURL: " + notifyURL);
262: }
263:
264: URL url = new URL(notifyURL);
265:
266: // Open a connection to the install-notiy URL
267: HttpURLConnection huc = (HttpURLConnection) url
268: .openConnection();
269:
270: // This operation sends a POST request
271: huc.setDoOutput(true);
272:
273: if (DownloadModuleFactoryImpl.verbose) {
274: System.out.println("StatusCode=" + statusCode);
275: System.out.println("StatusMsg=" + statusMsg);
276: }
277:
278: // Write the status code and message to the URL
279: OutputStream os = huc.getOutputStream();
280: String content = statusCode + " " + statusMsg;
281: byte[] buf = content.getBytes();
282: os.write(buf);
283: os.flush();
284: os.close();
285:
286: if (huc.getResponseCode() != HttpURLConnection.HTTP_OK) {
287: throw new JUMPDownloadException(
288: "Bad Http response code: "
289: + huc.getResponseCode());
290: } else {
291: if (DownloadModuleFactoryImpl.verbose) {
292: System.out.println("RESPONSE code: "
293: + huc.getResponseCode() + " "
294: + huc.getResponseMessage());
295: }
296: }
297:
298: huc.disconnect();
299:
300: } catch (Exception e) {
301: e.printStackTrace();
302: return false;
303: }
304:
305: return true;
306: }
307:
308: static {
309: statusOTA2MIDP.put(DownloaderImpl.ST_SUCCESS,
310: DownloaderImpl.ST_SUCCESS);
311: statusOTA2MIDP.put(DownloaderImpl.ST_INSUFFICIENTMEMORY,
312: DownloaderImpl.ST_INSUFFICIENTMEMORY);
313: statusOTA2MIDP.put(DownloaderImpl.ST_USERCANCELLED,
314: DownloaderImpl.ST_USERCANCELLED);
315: statusOTA2MIDP.put(DownloaderImpl.ST_LOSSOFSERVICE,
316: DownloaderImpl.ST_LOSSOFSERVICE);
317: statusOTA2MIDP.put(DownloaderImpl.ST_SIZEMISMATCH,
318: DownloaderImpl.ST_SIZEMISMATCH);
319: statusOTA2MIDP.put(DownloaderImpl.ST_ATTRIBUTEMISMATCH,
320: DownloaderImpl.ST_ATTRIBUTEMISMATCH);
321: statusOTA2MIDP.put(DownloaderImpl.ST_INVALIDDESCRIPTOR,
322: DownloaderImpl.ST_INVALIDDESCRIPTOR);
323: statusOTA2MIDP.put(DownloaderImpl.ST_INVALIDDDVERSION,
324: DownloaderImpl.ST_INVALIDDESCRIPTOR);
325: statusOTA2MIDP.put(DownloaderImpl.ST_DEVICEABORTED,
326: DownloaderImpl.ST_USERCANCELLED);
327: statusOTA2MIDP.put(DownloaderImpl.ST_NONACCEPTABLECONTENT,
328: DownloaderImpl.ST_INVALIDDESCRIPTOR);
329: statusOTA2MIDP.put(DownloaderImpl.ST_LOADERERROR,
330: DownloaderImpl.ST_INSUFFICIENTMEMORY);
331: }
332:
333: public String getSchema() {
334: return "midp";
335: }
336: }
|