001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.serverscript.demo;
033:
034: // local
035: import example.serverscript.connector.Interface;
036: import example.serverscript.connector.Interface_Stub;
037:
038: // standard
039: import java.io.ByteArrayInputStream;
040: import java.io.UnsupportedEncodingException;
041:
042: // jax-rpc
043: import java.rmi.RemoteException;
044:
045: import java.util.Hashtable;
046: import java.util.Stack;
047:
048: import javax.microedition.lcdui.Alert;
049: import javax.microedition.lcdui.AlertType;
050: import javax.microedition.lcdui.Command;
051: import javax.microedition.lcdui.CommandListener;
052: import javax.microedition.lcdui.Display;
053: import javax.microedition.lcdui.Displayable;
054: import javax.microedition.lcdui.List;
055: import javax.microedition.lcdui.Screen;
056: import javax.microedition.lcdui.TextBox;
057: import javax.microedition.lcdui.TextField;
058:
059: // micro edition
060: import javax.microedition.midlet.MIDlet;
061:
062: import javax.xml.parsers.ParserConfigurationException;
063: import javax.xml.parsers.SAXParser;
064: import javax.xml.parsers.SAXParserFactory;
065:
066: // xml
067: import org.xml.sax.Attributes;
068: import org.xml.sax.SAXException;
069: import org.xml.sax.helpers.DefaultHandler;
070:
071: /**
072: * JSR 172 demo.
073: * Almost all screens displayed by the demo comes from server in xml format.
074: * It's up to server, what the demo will do.
075: */
076: public class Demo extends MIDlet implements Runnable, CommandListener {
077: /**
078: * Exception with this string is thrown in parser when no need to continue
079: * parsing as Exit screen received.
080: */
081: private static final String EXIT_STRING = "Exiting..";
082:
083: /** Service connector jax-rpc stub for connecting to server. */
084: private Interface_Stub service;
085:
086: /** SAX XML parser handler class. */
087: private ParserHandler parser;
088:
089: /** Operation in progress flag. Disables command listener when true. */
090: private boolean busy = false;
091:
092: /** Current active screen. */
093: private Screen screen;
094:
095: /** This midlet's display object. */
096: private Display display;
097:
098: /** Table of commands names. */
099: private Hashtable commandTypes;
100:
101: /** Table of alert types names. */
102: private Hashtable alertTypes;
103:
104: /** Table of constraints names. */
105: private Hashtable constraints;
106:
107: /** Info parameter in request to server. */
108: private String requestInfo;
109:
110: /** Command parameter in request to server. */
111: private String requestCommand;
112:
113: /** Instance of XML parser engine. */
114: private SAXParser saxParser;
115:
116: /** Initialize midlet data, service, parsers */
117: public void startApp() {
118: service = new Interface_Stub();
119: service._setProperty(Interface_Stub.SESSION_MAINTAIN_PROPERTY,
120: new Boolean(true));
121: parser = new ParserHandler();
122: display = Display.getDisplay(this );
123:
124: // init command types
125: commandTypes = new Hashtable(8);
126: commandTypes.put("back", new Integer(Command.BACK));
127: commandTypes.put("cancel", new Integer(Command.CANCEL));
128: commandTypes.put("exit", new Integer(Command.EXIT));
129: commandTypes.put("help", new Integer(Command.HELP));
130: commandTypes.put("item", new Integer(Command.ITEM));
131: commandTypes.put("ok", new Integer(Command.OK));
132: commandTypes.put("screen", new Integer(Command.SCREEN));
133: commandTypes.put("stop", new Integer(Command.STOP));
134:
135: alertTypes = new Hashtable(5);
136: alertTypes.put("alarm", AlertType.ALARM);
137: alertTypes.put("confirmation", AlertType.CONFIRMATION);
138: alertTypes.put("error", AlertType.ERROR);
139: alertTypes.put("info", AlertType.INFO);
140: alertTypes.put("warning", AlertType.WARNING);
141:
142: constraints = new Hashtable(6);
143: constraints.put("any", new Integer(TextField.ANY));
144: constraints.put("emailaddr", new Integer(TextField.EMAILADDR));
145: constraints.put("numeric", new Integer(TextField.NUMERIC));
146: constraints.put("password", new Integer(TextField.PASSWORD));
147: constraints.put("phonenumber", new Integer(
148: TextField.PHONENUMBER));
149: constraints.put("url", new Integer(TextField.URL));
150:
151: try {
152: SAXParserFactory factory = SAXParserFactory.newInstance();
153: saxParser = factory.newSAXParser();
154: } catch (Exception e) {
155: error("Error initializing JSR172 features.");
156:
157: return;
158: }
159:
160: retrieveScreen(null, null);
161: }
162:
163: /** Pause the midlet. */
164: public void pauseApp() {
165: }
166:
167: /**
168: * Destroy midlet.
169: * @param unconditional Unconditional flag.
170: */
171: public void destroyApp(boolean unconditional) {
172: }
173:
174: /** Initiate thread retrieving next screen from server. */
175: private void retrieveScreen(String info, String command) {
176: System.out.println("retrieve screen: info = " + info
177: + ", command = " + command);
178: busy = true;
179: requestCommand = command;
180: requestInfo = info;
181: new Thread(this ).start();
182: }
183:
184: /** Retrieving and parsing thread. */
185: public void run() {
186: try {
187: String str = service.request(requestInfo, requestCommand);
188: System.out.println("screen = (((" + str + ")))");
189: parser.reset();
190: saxParser.parse(new ByteArrayInputStream(str
191: .getBytes("UTF-8")), parser);
192:
193: if (screen == null) {
194: error("Server error or incompatibility.\n");
195: } else {
196: screen.setCommandListener(this );
197: display.setCurrent(screen);
198: }
199:
200: busy = false;
201: } catch (Exception e) {
202: if (!EXIT_STRING.equals(e.getMessage())) {
203: e.printStackTrace();
204: error("Connection problems.\n"
205: + "Check your internet/proxy settings.");
206: }
207: }
208: }
209:
210: /** Display error screen. */
211: public void error(String msg) {
212: // error initializing xml parser
213: Alert connectionError = new Alert("Error", msg, null,
214: AlertType.ERROR);
215: connectionError.setTimeout(Alert.FOREVER);
216: connectionError.setCommandListener(this );
217: display.setCurrent(connectionError);
218: busy = false;
219: screen = null;
220: }
221:
222: /** Handle users commands. */
223: public void commandAction(Command c, Displayable d) {
224: if (busy) {
225: return;
226: }
227:
228: String info = null;
229:
230: if (screen == null) {
231: destroyApp(false);
232: notifyDestroyed();
233:
234: return;
235: }
236:
237: if (screen instanceof List) {
238: List list = (List) screen;
239: info = list.getString(list.getSelectedIndex());
240: } else if (screen instanceof TextBox) {
241: info = ((TextBox) screen).getString();
242: }
243:
244: retrieveScreen(info, c.getLabel());
245: }
246:
247: /**
248: * Parser handler class to parse screen information received from server.
249: */
250: class ParserHandler extends DefaultHandler {
251: /** Stack of document elements. */
252: Stack stack;
253:
254: /** Current document element. */
255: Object current;
256:
257: /** Reset parser. */
258: public void reset() {
259: stack = new Stack();
260: screen = null;
261: }
262:
263: /** Decode element and create corresponding objects. */
264: public void startElement(String uri, String localName,
265: String qName, Attributes attributes)
266: throws SAXException {
267: if ("Exit".equals(qName)) {
268: screen = null;
269: destroyApp(false);
270: notifyDestroyed();
271: throw new SAXException(EXIT_STRING);
272: } else if ("Alert".equals(qName)) {
273: // get type, default INFO
274: AlertType type = AlertType.INFO;
275: String typeStr = attributes.getValue("type");
276:
277: if (typeStr != null) {
278: type = (AlertType) alertTypes.get(typeStr);
279: }
280:
281: // create alert
282: Alert alert = new Alert(attributes.getValue("title"),
283: null, null, type);
284:
285: // get timeout,default FOREVER
286: int timeout = Alert.FOREVER;
287: String timeoutStr = attributes.getValue("timeout");
288:
289: if (timeoutStr != null) {
290: timeout = Integer.parseInt(timeoutStr);
291: }
292:
293: alert.setTimeout(Alert.FOREVER);
294: current = screen = alert;
295: } else if ("List".equals(qName)) {
296: List list = new List(attributes.getValue("title"),
297: List.IMPLICIT);
298: current = screen = list;
299: } else if ("TextBox".equals(qName)) {
300: // get constraints, default ANY
301: int constr = TextField.ANY;
302: String constrStr = attributes.getValue("constraints");
303:
304: if (constrStr != null) {
305: constr = ((Integer) constraints.get(constrStr))
306: .intValue();
307: }
308:
309: // get size, default 20
310: int size = 20;
311: String sizeStr = attributes.getValue("size");
312:
313: if (sizeStr != null) {
314: size = Integer.parseInt(sizeStr);
315: }
316:
317: TextBox box = new TextBox(attributes.getValue("title"),
318: null, size, constr);
319: current = screen = box;
320: } else if ("Item".equals(qName)) {
321: current = "Item";
322: } else if ("Command".equals(qName)) {
323: // get type, default OK
324: int type = Command.OK;
325: String typeStr = attributes.getValue("type");
326:
327: if (typeStr != null) {
328: type = ((Integer) commandTypes.get(typeStr))
329: .intValue();
330: }
331:
332: //get priority, default 1
333: int priority = 1;
334: String priorityStr = attributes.getValue("priority");
335:
336: if (priorityStr != null) {
337: priority = Integer.parseInt(priorityStr);
338: }
339:
340: // create and add button
341: Command command = new Command(attributes
342: .getValue("title"), type, priority);
343: screen.addCommand(command);
344:
345: if ("true".equals(attributes.getValue("select"))
346: && screen instanceof List) {
347: ((List) screen).setSelectCommand(command);
348: }
349:
350: current = command;
351: } else {
352: current = new Object();
353: }
354:
355: stack.push(current);
356: }
357:
358: /** Handles document character data. */
359: public void characters(char[] ch, int start, int length) {
360: Object current = stack.peek();
361:
362: if (current instanceof Alert) {
363: ((Alert) stack.peek()).setString(new String(ch, start,
364: length));
365: } else if ("Item".equals(current)) {
366: if (screen instanceof List) {
367: ((List) screen).append(
368: new String(ch, start, length), null);
369: }
370: } else if (current instanceof TextBox) {
371: ((TextBox) stack.peek()).setString(new String(ch,
372: start, length));
373: }
374: }
375:
376: /** Handles closing tags. */
377: public void endElement(String uri, String localName,
378: String qName) {
379: stack.pop();
380: }
381: }
382: }
|