001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.content;
028:
029: import javax.microedition.content.ActionNameMap;
030: import javax.microedition.content.ContentHandlerException;
031:
032: import com.sun.midp.midletsuite.MIDletSuiteStorage;
033: import com.sun.midp.midletsuite.MIDletSuiteImpl;
034: import com.sun.midp.midlet.MIDletSuite;
035:
036: import com.sun.midp.security.SecurityToken;
037:
038: import com.sun.midp.log.Logging;
039:
040: /**
041: * Standalone Registry Storage manager.
042: * All protected methods, which are all static, redirect their work
043: * to alone instance allowed for given Java runtime (for MIDP
044: * it is Isolate).
045: * Teh standalone instance initializes resources in the private
046: * constructor and then releases its in the native finalizer.
047: */
048: class RegistryStore {
049:
050: /**
051: * Content Handler fields indexes.
052: * <BR>Used with functions: @link findHandler(), @link getValues() and
053: * @link getArrayField().
054: * <BR> They should match according enums in jsr211_registry.h
055: */
056: static final int FIELD_ID = 0;
057: /** Handler ID */
058: static final int FIELD_TYPES = 1;
059: /** Types supported by a handler */
060: static final int FIELD_SUFFIXES = 2;
061: /** Suffixes supported */
062: /** by a handler */
063: static final int FIELD_ACTIONS = 3;
064: /** Actions supported */
065: /** by a handler */
066: static final int FIELD_LOCALES = 4;
067: /** Locales supported */
068: /** by a handler */
069: static final int FIELD_ACTION_MAP = 5;
070: /** Handler action map */
071: static final int FIELD_ACCESSES = 6;
072: /** Access list */
073: static final int FIELD_COUNT = 7;
074: /** Total number of fields */
075:
076: /**
077: * Search flags for @link getHandler() method.
078: */
079: static final int SEARCH_EXACT = 0;
080: /** Search by exact match with ID */
081: static final int SEARCH_PREFIX = 1;
082: /** Search by prefix of given value */
083:
084: /**
085: * Handler flags constants.
086: * <BR> They should match according enums in jsr211_registry.h
087: */
088: static final private int FLAG_ERROR = -1; /* Indicates error during */
089: /* native call */
090:
091: /**
092: * Result codes for launch0() native method.
093: * These values should correspond to enum type jsr211_launch_result
094: * in the 'jsr211_registry.h'.
095: */
096: /** OK, handler started */
097: static final private int LAUNCH_OK = 0;
098: /** OK, handler started or is ready to start, invoking app should exit. */
099: static final private int LAUNCH_OK_SHOULD_EXIT = 1;
100: /** ERROR, not supported */
101: static final private int LAUNCH_ERR_NOTSUPPORTED = -1;
102: /** ERROR, no requested handler */
103: static final private int LAUNCH_ERR_NO_HANDLER = -2;
104: /** ERROR, no invocation queued for requested handler */
105: static final private int LAUNCH_ERR_NO_INVOCATION = -3;
106: /** common error */
107: static final private int LAUNCH_ERROR = -4;
108:
109: /** This class has a different security domain than the MIDlet suite */
110: private static SecurityToken classSecurityToken;
111:
112: /**
113: * Registers given content handler.
114: * @param contentHandler content handler being registered.
115: * @return true if success, false - otherwise.
116: */
117: static boolean register(ContentHandlerImpl contentHandler) {
118: return store.register0(contentHandler);
119: }
120:
121: /**
122: * Unregisters content handler specified by its ID.
123: * @param handlerId ID of unregistered handler.
124: * @return true if success, false - otherwise.
125: */
126: static boolean unregister(String handlerId) {
127: return store.unregister0(handlerId);
128: }
129:
130: /**
131: * Tests ID value for registering handler accordingly with JSR claim:
132: * <BR><CITE>Each content handler is uniquely identified by an ID. ...
133: * <BR> The ID MUST NOT be equal to any other registered handler ID.
134: * <BR> Every other ID MUST NOT be a prefix of this ID.
135: * <BR> The ID MUST NOT be a prefix of any other registered ID. </CITE>
136: * @param testID tested value
137: *
138: * @return conflicted handlers array.
139: */
140: static ContentHandlerImpl[] findConflicted(String testID) {
141: return findHandler(null, FIELD_ID, testID);
142: }
143:
144: /**
145: * Searchs coontent handlers by searchable fields values. As specified in
146: * JSR 211 API:
147: * <BR><CITE> Only content handlers that this application is allowed to
148: * access will be included. </CITE> (in result).
149: * @param callerId ID value to check access
150: * @param searchBy indicator of searchable field. Allowed:
151: * @link FIELD_TYPES, @link FIELD_SUFFIXES, @link FIELD_ACTIONS
152: * values. The special case for the testId implementation:
153: * @link FIELD_ID specified.
154: * @param value Searched value
155: * @return found handlers array.
156: */
157: static ContentHandlerImpl[] findHandler(String callerId,
158: int searchBy, String value) {
159: /* Check value for null */
160: value.length();
161: String res = store.findHandler0(callerId, searchBy, value);
162: return deserializeCHArray(res);
163: }
164:
165: /**
166: * The special finder for exploring handlers registered by the given suite.
167: * @param suiteId explored suite Id
168: *
169: * @return found handlers array.
170: */
171: static ContentHandlerImpl[] forSuite(int suiteId) {
172: String res = store.forSuite0(suiteId);
173: return deserializeCHArray(res);
174: }
175:
176: /**
177: * Returns all stored in the Registry values for specified field.
178: * @param callerId ID value to check access
179: * @param searchBy index of searchable field. Allowed:
180: * @link FIELD_TYPES, @link FIELD_SUFFIXES, @link FIELD_ACTIONS,
181: * @link FIELD_ID values.
182: * @return found values array.
183: */
184: static String[] getValues(String callerId, int searchBy) {
185: String res = store.getValues0(callerId, searchBy);
186: return deserializeStrArray(res);
187: }
188:
189: /**
190: * Returns array field
191: * @param handlerId ID for access check
192: * @param fieldId index of field. Allowed:
193: * @link FIELD_TYPES, @link FIELD_SUFFIXES, @link FIELD_ACTIONS
194: * @link FIELD_LOCALES, @link FIELD_ACTION_MAP, @link FIELD_ACCESSES
195: * valiues.
196: * @return array of values
197: */
198: static String[] getArrayField(String handlerId, int fieldId) {
199: String res = store.loadFieldValues0(handlerId, fieldId);
200: return deserializeStrArray(res);
201: }
202:
203: /**
204: * Creates and loads handler's data.
205: * @param handlerId ID of content handler to be loaded.
206: * @param searchMode ID matching mode. Used <ul>
207: * <li> @link SEARCH_EXACT
208: * <li> @link SEARCH_PREFIX </ul>
209: *
210: * @return loaded ContentHandlerImpl object or
211: * <code>null</code> if given handler ID is not found in Registry database.
212: */
213: static ContentHandlerImpl getHandler(String callerId, String id,
214: int searchMode) {
215: if (id.length() == 0) {
216: return null;
217: }
218:
219: return deserializeCH(store
220: .getHandler0(callerId, id, searchMode));
221: }
222:
223: /**
224: * The special finder for acquiring handler by its suite and class name.
225: * @param suiteId explored suite Id
226: * @param classname requested class name.
227: *
228: * @return found handler or <code>null</code> if none found.
229: */
230: static ContentHandlerImpl getHandler(int suiteId, String classname) {
231: ContentHandlerImpl[] arr = forSuite(suiteId);
232: ContentHandlerImpl handler = null;
233:
234: if (classname.length() == 0)
235: throw new IllegalArgumentException(
236: "classname can't be emty");
237:
238: if (arr != null) {
239: for (int i = 0; i < arr.length; i++) {
240: if (classname.equals(arr[i].classname)) {
241: handler = arr[i];
242: break;
243: }
244: }
245: }
246:
247: return handler;
248: }
249:
250: /**
251: * Starts native content handler.
252: * @param handler Content handler to be executed.
253: * @return true if invoking app should exit.
254: * @exception ContentHandlerException if no such handler ID in the Registry
255: * or native handlers execution is not supported.
256: */
257: static boolean launch(ContentHandlerImpl handler)
258: throws ContentHandlerException {
259: int result = store.launch0(handler.getID());
260: if (result < 0) {
261: throw new ContentHandlerException(
262: "Unable to launch platform handler",
263: ContentHandlerException.NO_REGISTERED_HANDLER);
264: }
265:
266: return (result == LAUNCH_OK_SHOULD_EXIT);
267: }
268:
269: /**
270: * Returns content handler suitable for URL.
271: * @param callerId ID of calling application.
272: * @param URL content URL.
273: * @param action requested action.
274: * @return found handler if any or null.
275: */
276: static ContentHandlerImpl getByURL(String callerId, String url,
277: String action) {
278: return deserializeCH(store.getByURL0(callerId, url, action));
279: }
280:
281: /**
282: * Transforms serialized form to array of Strings.
283: * <BR>Serialization format is the same as ContentHandlerImpl
284: * used.
285: * @param str String in serialized form to transform to array of Strings.
286: * @return array of Strings. If input String is NULL 0-length array
287: * returned. ... And we believe that input string is not misformed.
288: */
289: private static String[] deserializeStrArray(String str) {
290: int n; // array length
291: String[] arr; // result array
292:
293: n = (str == null || str.length() == 0) ? 0 : (int) str
294: .charAt(0);
295:
296: arr = new String[n];
297: if (n > 0) {
298: int len; // String len
299: int pos; // current position
300:
301: pos = 1;
302: for (int i = 0; i < n; i++) {
303: len = (int) str.charAt(pos++);
304: arr[i] = str.substring(pos, pos + len);
305: pos += len;
306: }
307: }
308:
309: return arr;
310: }
311:
312: /**
313: * Restores ContentHandler main fields (ID, suite_ID, class_name and flag)
314: * from serialized form to ContentHandlerImpl object.
315: * @param str ContentHandler main data in serialized form.
316: * @return restored ContentHandlerImpl object or null
317: */
318: private static ContentHandlerImpl deserializeCH(String str) {
319: ContentHandlerImpl ch = null;
320:
321: while (str != null && str.length() > 0) {
322: String id;
323: String class_name;
324: int beg = 0, end;
325:
326: end = str.indexOf('\n', beg);
327: if (end == -1) {
328: break; // no 1-st delimiter
329: }
330: id = str.substring(beg, end);
331: if (id.length() == 0) {
332: break; // ID is significant field
333: }
334: beg = end + 1;
335:
336: end = str.indexOf('\n', beg);
337: if (end == -1 || str.length() != end + 4) {
338: break; // no 2-nd delimiter or wrong length of the string
339: }
340: class_name = str.substring(beg, end++);
341:
342: ch = new ContentHandlerImpl();
343: ch.ID = id;
344: ch.classname = class_name;
345: ch.storageId = str.charAt(end++);
346: ch.storageId <<= 16;
347: ch.storageId |= str.charAt(end++);
348: ch.registrationMethod = str.charAt(end);
349:
350: break;
351: }
352: return ch;
353: }
354:
355: /**
356: * Restores ContentHandlerImpl array from serialized form.
357: * @param str ContentHandlerImpl array in serialized form.
358: * @return restored ContentHandlerImpl array
359: */
360: private static ContentHandlerImpl[] deserializeCHArray(String str) {
361: String[] strs;
362: ContentHandlerImpl[] arr;
363:
364: strs = deserializeStrArray(str);
365: arr = new ContentHandlerImpl[strs.length];
366: for (int i = 0; i < strs.length; i++) {
367: arr[i] = deserializeCH(strs[i]);
368: }
369:
370: return arr;
371: }
372:
373: /**
374: * Sets the security token used for priveleged operations.
375: * The token may only be set once.
376: * @param token a Security token
377: */
378: static void setSecurityToken(SecurityToken token) {
379: if (classSecurityToken != null) {
380: throw new SecurityException();
381: }
382: classSecurityToken = token;
383: }
384:
385: /** Singleton instance. Worker for the class static methods. */
386: private static RegistryStore store = new RegistryStore();
387:
388: /**
389: * Private constructor for the singleton storage class.
390: * If ClassNotFoundException is thrown during ActionNameMap
391: * loading the constructor throws RuntimeException
392: */
393: private RegistryStore() {
394: try {
395: Class.forName("javax.microedition.content.ActionNameMap");
396: } catch (ClassNotFoundException cnfe) {
397: throw new RuntimeException(cnfe.getMessage());
398: }
399: if (!init()) {
400: throw new RuntimeException(
401: "RegistryStore initialization failed");
402: }
403: }
404:
405: /**
406: * Native implementation of <code>findHandler</code>.
407: * @param callerId ID value to check access
408: * @param searchBy index of searchable field.
409: * @param value searched value
410: * @return found handlers array in serialized form.
411: */
412: private native String findHandler0(String callerId, int searchBy,
413: String value);
414:
415: /**
416: * Native implementation of <code>findBySuite</code>.
417: * @param suiteId explored suite Id
418: * @return handlers registered for the given suite in serialized form.
419: */
420: private native String forSuite0(int suiteId);
421:
422: /**
423: * Native implementation of <code>getValues</code>.
424: * @param callerId ID value to check access
425: * @param searchBy index of searchable field.
426: * @return found values in serialized form.
427: */
428: private native String getValues0(String callerId, int searchBy);
429:
430: /**
431: * Loads content handler data.
432: * @param callerId ID value to check access.
433: * @param id Id of required content handler.
434: * @param mode flag defined search mode aplied for the operation.
435: * @return serialized content handler or null.
436: */
437: private native String getHandler0(String callerId, String id,
438: int mode);
439:
440: /**
441: * Loads values for array fields.
442: * @param handlerId ID of content handler ID.
443: * @param fieldId fieldId to be loaded.
444: * @return loaded field values in serialized form.
445: */
446: private native String loadFieldValues0(String handlerId, int fieldId);
447:
448: /**
449: * Returns content handler suitable for URL.
450: * @param callerId ID of calling application.
451: * @param URL content URL.
452: * @param action requested action.
453: * @return ID of found handler if any or null.
454: */
455: private native String getByURL0(String callerId, String url,
456: String action);
457:
458: /**
459: * Starts native content handler.
460: * @param handlerId ID of the handler to be executed
461: * @return result status:
462: * <ul>
463: * <li> LAUNCH_OK or LAUNCH_OK_SHOULD_EXIT if content handler
464: * started successfully
465: * <li> other code from the LAUNCH_ERR_* constants set
466: * according to error codition
467: * </ul>
468: */
469: private native int launch0(String handlerId);
470:
471: /**
472: * Initialize persistence storage.
473: * @return <code>true</code> or
474: * <BR><code>false</code> if initialization fails.
475: */
476: private native boolean init();
477:
478: /**
479: * Cleanup native resources.
480: */
481: private native void finalize();
482:
483: /**
484: * Registers given content handler.
485: * @param contentHandler content handler being registered.
486: * @return true if success, false - otherwise.
487: */
488: private native boolean register0(ContentHandlerImpl contentHandler);
489:
490: /**
491: * Unregisters content handler specified by its ID.
492: * @param handlerId ID of unregistered handler.
493: * @return true if success, false - otherwise.
494: */
495: private native boolean unregister0(String handlerId);
496:
497: }
|