001: /*
002: * $RCSfile: RegistryFileParser.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:19 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.io.BufferedReader;
015: import java.io.BufferedWriter;
016: import java.io.FileInputStream;
017: import java.io.IOException;
018: import java.io.InputStream;
019: import java.io.InputStreamReader;
020: import java.io.OutputStream;
021: import java.io.OutputStreamWriter;
022: import java.io.Reader;
023: import java.io.StreamTokenizer;
024: import java.net.URL;
025: import java.text.MessageFormat;
026: import java.util.Hashtable;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Locale;
030: import java.util.Vector;
031: import javax.media.jai.util.CaselessStringKey;
032:
033: /**
034: * A class to parse the JAI registry file.
035: *
036: * @since JAI 1.1
037: */
038: class RegistryFileParser {
039:
040: /**
041: * Load the <code>OperationRegistry</code> with the descriptors,
042: * factories and their preferences from the input stream.
043: */
044: static void loadOperationRegistry(OperationRegistry or,
045: ClassLoader cl, InputStream is) throws IOException {
046:
047: (new RegistryFileParser(or, cl, is)).parseFile();
048: }
049:
050: /**
051: * Load the <code>OperationRegistry</code> with the descriptors,
052: * factories and their preferences from the <code>URL</code>.
053: */
054: static void loadOperationRegistry(OperationRegistry or,
055: ClassLoader cl, URL url) throws IOException {
056:
057: (new RegistryFileParser(or, cl, url)).parseFile();
058: }
059:
060: private URL url;
061: private InputStream is;
062: private ClassLoader classLoader;
063:
064: // The OperationRegistry being read in.
065: private OperationRegistry or;
066: private StreamTokenizer st;
067:
068: // The current token - the one last returned by StreamTokenizer
069: private int token;
070:
071: // The current line number being parsed in the registry file.
072: private int lineno;
073:
074: // Table used to map local-factory names to factory instances
075: // on a per mode basis.
076: private Hashtable localNamesTable;
077:
078: /**
079: * Create a JAI registry file parser from an <code>URL</code>
080: */
081: private RegistryFileParser(OperationRegistry or, ClassLoader cl,
082: URL url) throws IOException {
083:
084: this (or, cl, url.openStream());
085: this .url = url;
086: }
087:
088: /**
089: * Create a JAI registry file parser from the <code>InputStream</code>
090: */
091: private RegistryFileParser(OperationRegistry or, ClassLoader cl,
092: InputStream is) throws IOException {
093:
094: if (or == null)
095: or = JAI.getDefaultInstance().getOperationRegistry();
096:
097: this .is = is;
098: this .url = null;
099: this .or = or;
100: this .classLoader = cl;
101:
102: // Set up streamtokenizer
103: BufferedReader reader = new BufferedReader(
104: new InputStreamReader(is));
105:
106: st = new StreamTokenizer(reader);
107:
108: st.commentChar('#');
109: st.eolIsSignificant(true);
110: st.slashSlashComments(true);
111: st.slashStarComments(true);
112:
113: token = st.ttype;
114: lineno = -1;
115:
116: // Initialize a table to map local names to factories.
117:
118: localNamesTable = new Hashtable();
119:
120: String modeNames[] = RegistryMode.getModeNames();
121:
122: for (int i = 0; i < modeNames.length; i++)
123: localNamesTable.put(new CaselessStringKey(modeNames[i]),
124: new Hashtable());
125: }
126:
127: /**
128: * Skip all the empty tokens generated due to empty lines
129: * and comments.
130: */
131: private int skipEmptyTokens() throws IOException {
132:
133: while (st.sval == null) {
134: if (token == StreamTokenizer.TT_EOF)
135: return token;
136:
137: token = st.nextToken();
138: }
139:
140: return token;
141: }
142:
143: /**
144: * Get an array of <code>String</code>s of words in the
145: * next line after skipping over empty and comment lines.
146: */
147: private String[] getNextLine() throws IOException {
148:
149: if (skipEmptyTokens() == StreamTokenizer.TT_EOF)
150: return null;
151:
152: Vector v = new Vector();
153:
154: lineno = st.lineno();
155:
156: while ((token != StreamTokenizer.TT_EOL)
157: && (token != StreamTokenizer.TT_EOF)) {
158:
159: if (st.sval != null)
160: v.addElement(st.sval);
161:
162: token = st.nextToken();
163: }
164:
165: if (v.size() == 0)
166: return null;
167:
168: return (String[]) v.toArray(new String[0]);
169: }
170:
171: // Aliases for backward compatibility
172: private static String[][] aliases = { { "odesc", "descriptor" },
173: { "rif", "rendered" }, { "crif", "renderable" },
174: { "cif", "collection" }, };
175:
176: /**
177: * Map old keywords to the new keywords
178: */
179: private String mapName(String key) {
180: for (int i = 0; i < aliases.length; i++)
181: if (key.equalsIgnoreCase(aliases[i][0]))
182: return aliases[i][1];
183:
184: return key;
185: }
186:
187: /**
188: * Create an instance given the class name.
189: */
190: private Object getInstance(String className) {
191:
192: try {
193: Class descriptorClass = null;
194: String errorMsg = null;
195:
196: // Since the classes listed in the registryFile can
197: // reside anywhere (core, ext, classpath or the specified
198: // classloader) we have to try every place.
199:
200: // First try the specified classloader
201: if (classLoader != null) {
202: try {
203: descriptorClass = Class.forName(className, true,
204: classLoader);
205: } catch (Exception e) {
206: errorMsg = e.getMessage();
207: }
208: }
209:
210: // Next try the callee classloader
211: if (descriptorClass == null) {
212: try {
213: descriptorClass = Class.forName(className);
214: } catch (Exception e) {
215: errorMsg = e.getMessage();
216: }
217: }
218:
219: // Then try the System classloader (because the specified
220: // classloader might be null and the callee classloader
221: // might be an ancestor of the SystemClassLoader
222: if (descriptorClass == null) {
223: try {
224: descriptorClass = Class.forName(className, true,
225: ClassLoader.getSystemClassLoader());
226: } catch (Exception e) {
227: errorMsg = e.getMessage();
228: }
229: }
230:
231: if (descriptorClass == null) {
232: registryFileError(errorMsg);
233: return null;
234: }
235:
236: return descriptorClass.newInstance();
237:
238: } catch (Exception e) {
239: registryFileError(e.getMessage());
240: e.printStackTrace();
241: }
242:
243: return null;
244: }
245:
246: /**
247: * Parse the entire registry file and load internal structures
248: * with the info.
249: */
250: boolean parseFile() throws IOException {
251:
252: // If the file has already been parsed do nothing.
253: if (token == StreamTokenizer.TT_EOF)
254: return true;
255:
256: String[] keys;
257:
258: token = st.nextToken();
259:
260: while (token != StreamTokenizer.TT_EOF) {
261:
262: if ((keys = getNextLine()) == null)
263: break;
264:
265: RegistryMode mode;
266:
267: String key = mapName(keys[0]);
268:
269: // This indicates a new registry mode to be added.
270: if (key.equalsIgnoreCase("registryMode")) {
271:
272: mode = (RegistryMode) getInstance(keys[1]);
273:
274: if (mode != null) {
275: if (RegistryMode.addMode(mode) == false)
276: registryFileError(JaiI18N
277: .getString("RegistryFileParser10"));
278: }
279:
280: // Old format operation-descriptor line OR
281: // the new generic RegistryElementDescriptor line
282: } else if (key.equalsIgnoreCase("descriptor")) {
283:
284: registerDescriptor(keys);
285:
286: // If it is a registry mode name, then register the
287: // factory object.
288: } else if ((mode = RegistryMode.getMode(key)) != null) {
289:
290: registerFactory(mode, keys);
291:
292: // If the line starts with a "pref" there are two options
293: } else if (key.equalsIgnoreCase("pref")) {
294:
295: key = mapName(keys[1]);
296:
297: // If what follows is the keyword "product" then
298: // it is assumed to be setting product preferences
299: // for the "rendered" mode (old file format)
300: if (key.equalsIgnoreCase("product")) {
301:
302: setProductPreference(RegistryMode
303: .getMode("rendered"), keys);
304:
305: // If it is followed by a modeName then it is
306: // for setting preferences between factory object.
307: } else if ((mode = RegistryMode.getMode(key)) != null) {
308:
309: setFactoryPreference(mode, keys);
310:
311: } else {
312: registryFileError(JaiI18N
313: .getString("RegistryFileParser4"));
314: }
315:
316: // For setting product preferences
317: } else if (key.equalsIgnoreCase("productPref")) {
318:
319: key = mapName(keys[1]);
320:
321: // If it is followed by a modeName then it is
322: // for setting preferences between products
323: if ((mode = RegistryMode.getMode(key)) != null) {
324:
325: setProductPreference(mode, keys);
326:
327: } else {
328: registryFileError(JaiI18N
329: .getString("RegistryFileParser5"));
330: }
331: } else {
332: registryFileError(JaiI18N
333: .getString("RegistryFileParser6"));
334: }
335: }
336:
337: // If this was read in from an URL, we created the InputStream
338: // and so we should close it.
339: if (url != null)
340: is.close();
341:
342: return true;
343: }
344:
345: /**
346: * Register a descriptor with operation registry.
347: */
348: private void registerDescriptor(String[] keys) {
349:
350: if (keys.length >= 2) {
351:
352: RegistryElementDescriptor red = (RegistryElementDescriptor) getInstance(keys[1]);
353:
354: if (red != null) {
355: try {
356: or.registerDescriptor(red);
357: } catch (Exception e) {
358: registryFileError(e.getMessage());
359: }
360: }
361:
362: } else {
363: registryFileError(JaiI18N.getString("RegistryFileParser1"));
364: }
365: }
366:
367: /**
368: * Register a factory instance against a registry mode
369: * under given product and local-name.
370: */
371: private void registerFactory(RegistryMode mode, String[] keys) {
372:
373: Object factory;
374:
375: if (mode.arePreferencesSupported()) {
376:
377: if (keys.length >= 5) {
378:
379: if ((factory = getInstance(keys[1])) != null) {
380: try {
381: or.registerFactory(mode.getName(), keys[3],
382: keys[2], factory);
383:
384: mapLocalNameToObject(mode.getName(), keys[4],
385: factory);
386:
387: } catch (Exception e) {
388: registryFileError(e.getMessage());
389: }
390: }
391:
392: } else {
393: registryFileError(JaiI18N
394: .getString("RegistryFileParser2"));
395: }
396:
397: } else {
398: if (keys.length >= 3) {
399:
400: if ((factory = getInstance(keys[1])) != null) {
401: try {
402: or.registerFactory(mode.getName(), keys[2],
403: null, factory);
404:
405: } catch (Exception e) {
406: registryFileError(e.getMessage());
407: }
408: }
409:
410: } else {
411: registryFileError(JaiI18N
412: .getString("RegistryFileParser3"));
413: }
414: }
415: }
416:
417: /**
418: * Register a factory instance against a registry mode
419: * under given product and local-name.
420: */
421: private void setProductPreference(RegistryMode mode, String[] keys) {
422:
423: String modeName = mode.getName();
424:
425: if (mode.arePreferencesSupported()) {
426:
427: if (keys.length >= 5) {
428:
429: try {
430: or.setProductPreference(modeName, keys[2], keys[3],
431: keys[4]);
432:
433: } catch (Exception e) {
434: registryFileError(e.getMessage());
435: }
436:
437: } else {
438: registryFileError(JaiI18N
439: .getString("RegistryFileParser5"));
440: }
441:
442: } else {
443: registryFileError(JaiI18N.getString("RegistryFileParser9"));
444: }
445: }
446:
447: /**
448: * Register a factory instance against a registry mode
449: * under given product and local-name.
450: */
451: private void setFactoryPreference(RegistryMode mode, String[] keys) {
452:
453: String modeName = mode.getName();
454: Object factory;
455:
456: if (mode.arePreferencesSupported()) {
457:
458: if (keys.length >= 6) {
459:
460: Object preferred = getObjectFromLocalName(modeName,
461: keys[4]);
462: Object other = getObjectFromLocalName(modeName, keys[5]);
463:
464: if ((preferred != null) && (other != null)) {
465:
466: try {
467: or.setFactoryPreference(modeName, keys[2],
468: keys[3], preferred, other);
469:
470: } catch (Exception e) {
471: registryFileError(e.getMessage());
472: }
473: }
474:
475: } else {
476: registryFileError(JaiI18N
477: .getString("RegistryFileParser4"));
478: }
479:
480: } else {
481: registryFileError(JaiI18N.getString("RegistryFileParser7"));
482: }
483: }
484:
485: /**
486: * Map local names to factory instances, so that they can
487: * be used to directly set preferences later.
488: */
489: private void mapLocalNameToObject(String modeName,
490: String localName, Object factory) {
491:
492: Hashtable modeTable = (Hashtable) localNamesTable
493: .get(new CaselessStringKey(modeName));
494:
495: modeTable.put(new CaselessStringKey(localName), factory);
496: }
497:
498: /**
499: * Get object registered under the local name for under the mode.
500: */
501: private Object getObjectFromLocalName(String modeName,
502: String localName) {
503:
504: Hashtable modeTable = (Hashtable) localNamesTable
505: .get(new CaselessStringKey(modeName));
506:
507: Object obj = modeTable.get(new CaselessStringKey(localName));
508:
509: if (obj == null)
510: registryFileError(localName + ": "
511: + JaiI18N.getString("RegistryFileParser8"));
512:
513: return obj;
514: }
515:
516: private boolean headerLinePrinted = false;
517:
518: /**
519: * Print the line number and then print the passed in message.
520: */
521: private void registryFileError(String msg) {
522:
523: if (!headerLinePrinted) {
524:
525: if (url != null) {
526: errorMsg(JaiI18N.getString("RegistryFileParser11"),
527: new Object[] { url.getPath() });
528: }
529:
530: headerLinePrinted = true;
531: }
532:
533: errorMsg(JaiI18N.getString("RegistryFileParser0"),
534: new Object[] { new Integer(lineno) });
535:
536: if (msg != null)
537: errorMsg(msg, null);
538: }
539:
540: /**
541: * Creates a <code>MessageFormat</code> object and set the
542: * <code>Locale</code> to default and formats the message
543: */
544: private void errorMsg(String key, Object[] args) {
545: MessageFormat mf = new MessageFormat(key);
546: mf.setLocale(Locale.getDefault());
547:
548: if (System.err != null)
549: System.err.println(mf.format(args));
550: }
551:
552: /**
553: * Write the OperationRegistry out to the output stream.
554: */
555: static void writeOperationRegistry(OperationRegistry or,
556: OutputStream os) throws IOException {
557:
558: writeOperationRegistry(or, new BufferedWriter(
559: new OutputStreamWriter(os)));
560: }
561:
562: /**
563: * Write the OperationRegistry out to the output stream.
564: */
565: static void writeOperationRegistry(OperationRegistry or,
566: BufferedWriter bw) throws IOException {
567:
568: // First cycle through all the descriptor classes
569: Iterator dcit = RegistryMode.getDescriptorClasses().iterator();
570:
571: String tab = " ";
572:
573: while (dcit.hasNext()) {
574:
575: Class descriptorClass = (Class) dcit.next();
576:
577: List descriptors = or.getDescriptors(descriptorClass);
578:
579: // First write all the descriptors corresponding
580: // to this descriptorClass
581: bw.write("#");
582: bw.newLine();
583: bw.write("# Descriptors corresponding to class : "
584: + descriptorClass.getName());
585: bw.newLine();
586: bw.write("#");
587: bw.newLine();
588:
589: if ((descriptors == null) || (descriptors.size() <= 0)) {
590: bw.write("# <EMPTY>");
591: bw.newLine();
592: } else {
593:
594: Iterator it = descriptors.iterator();
595:
596: while (it.hasNext()) {
597: bw.write("descriptor" + tab);
598: bw.write(it.next().getClass().getName());
599: bw.newLine();
600: }
601: }
602: bw.newLine();
603:
604: // Now cycle through all registry modes associated
605: // with this descriptorClass and write out the
606: // factories and their preferences
607:
608: String modeNames[] = RegistryMode
609: .getModeNames(descriptorClass);
610:
611: boolean empty;
612: int i, j, k, l;
613:
614: for (i = 0; i < modeNames.length; i++) {
615: bw.write("#");
616: bw.newLine();
617: bw.write("# Factories registered under mode : "
618: + modeNames[i]);
619: bw.newLine();
620: bw.write("#");
621: bw.newLine();
622:
623: RegistryMode mode = RegistryMode.getMode(modeNames[i]);
624:
625: boolean prefs = mode.arePreferencesSupported();
626:
627: String[] descriptorNames = or
628: .getDescriptorNames(modeNames[i]);
629:
630: // Over all descriptor names for this mode.
631: for (j = 0, empty = true; j < descriptorNames.length; j++) {
632:
633: if (prefs) {
634: Vector productVector = or
635: .getOrderedProductList(modeNames[i],
636: descriptorNames[j]);
637:
638: if (productVector == null)
639: continue;
640:
641: String[] productNames = (String[]) productVector
642: .toArray(new String[0]);
643:
644: // Over all products under which there are
645: // factories registered under this descriptor name
646: for (k = 0; k < productNames.length; k++) {
647:
648: List factoryList = or
649: .getOrderedFactoryList(
650: modeNames[i],
651: descriptorNames[j],
652: productNames[k]);
653:
654: Iterator fit = factoryList.iterator();
655:
656: while (fit.hasNext()) {
657: Object instance = fit.next();
658:
659: if (instance == null)
660: continue;
661:
662: bw.write(modeNames[i] + tab);
663: bw.write(instance.getClass().getName()
664: + tab);
665: bw.write(productNames[k] + tab);
666: bw.write(descriptorNames[j] + tab);
667: bw.write(or.getLocalName(modeNames[i],
668: instance));
669: bw.newLine();
670:
671: empty = false;
672: }
673: }
674: } else {
675: Iterator fit = or.getFactoryIterator(
676: modeNames[i], descriptorNames[j]);
677:
678: while (fit.hasNext()) {
679: Object instance = fit.next();
680:
681: if (instance == null)
682: continue;
683:
684: bw.write(modeNames[i] + tab);
685: bw.write(instance.getClass().getName()
686: + tab);
687: bw.write(descriptorNames[j]);
688: bw.newLine();
689:
690: empty = false;
691: }
692: }
693: }
694:
695: if (empty) {
696: bw.write("# <EMPTY>");
697: bw.newLine();
698: }
699: bw.newLine();
700:
701: // If the mode does not support preferences
702: // then just continue
703: if (!prefs) {
704: bw.write("#");
705: bw.newLine();
706: bw.write("# Preferences not supported for mode : "
707: + modeNames[i]);
708: bw.newLine();
709: bw.write("#");
710: bw.newLine();
711: bw.newLine();
712: continue;
713: }
714:
715: // Next, write the product preferences for this mode
716: bw.write("#");
717: bw.newLine();
718: bw.write("# Product preferences for mode : "
719: + modeNames[i]);
720: bw.newLine();
721: bw.write("#");
722: bw.newLine();
723:
724: for (j = 0, empty = true; j < descriptorNames.length; j++) {
725:
726: String[][] productPrefs = or.getProductPreferences(
727: modeNames[i], descriptorNames[j]);
728: if (productPrefs == null)
729: continue;
730:
731: for (k = 0; k < productPrefs.length; k++) {
732: bw.write("productPref" + tab);
733: bw.write(modeNames[i] + tab);
734: bw.write(descriptorNames[j] + tab);
735: bw.write(productPrefs[k][0] + tab);
736: bw.write(productPrefs[k][1]);
737: bw.newLine();
738:
739: empty = false;
740: }
741: }
742:
743: if (empty) {
744: bw.write("# <EMPTY>");
745: bw.newLine();
746: }
747: bw.newLine();
748:
749: // Next, write the factory preferences for this mode
750: bw.write("#");
751: bw.newLine();
752: bw.write("# Factory preferences for mode : "
753: + modeNames[i]);
754: bw.newLine();
755: bw.write("#");
756: bw.newLine();
757:
758: // Over all descriptor names for this mode.
759: for (j = 0, empty = true; j < descriptorNames.length; j++) {
760:
761: if (prefs) {
762: Vector productVector = or
763: .getOrderedProductList(modeNames[i],
764: descriptorNames[j]);
765:
766: if (productVector == null)
767: continue;
768:
769: String[] productNames = (String[]) productVector
770: .toArray(new String[0]);
771:
772: // Over all products under which there are
773: // factories registered under this descriptor name
774: for (k = 0; k < productNames.length; k++) {
775:
776: Object fprefs[][] = or
777: .getFactoryPreferences(
778: modeNames[i],
779: descriptorNames[j],
780: productNames[k]);
781:
782: if (fprefs == null)
783: continue;
784:
785: for (l = 0; l < fprefs.length; l++) {
786: bw.write("pref" + tab);
787: bw.write(modeNames[i] + tab);
788: bw.write(descriptorNames[j] + tab);
789: bw.write(productNames[k] + tab);
790: bw.write(or.getLocalName(modeNames[i],
791: fprefs[l][0])
792: + tab);
793: bw.write(or.getLocalName(modeNames[i],
794: fprefs[l][1]));
795: bw.newLine();
796:
797: empty = false;
798: }
799: }
800: }
801: }
802:
803: if (empty) {
804: bw.write("# <EMPTY>");
805: bw.newLine();
806: }
807: bw.newLine();
808: }
809: }
810:
811: bw.flush();
812: }
813: }
|