001: /*
002: * $RCSfile: FactoryCache.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:08 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.lang.reflect.InvocationTargetException;
015: import java.lang.reflect.Method;
016: import java.util.ArrayList;
017: import java.util.Enumeration;
018: import java.util.Hashtable;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Vector;
022: import javax.media.jai.util.CaselessStringKey;
023:
024: /**
025: * A class to manage the various instances of a descriptor factory.
026: * This also manages preferences between factory instances for
027: * a specified descriptor/product.
028: *
029: * @since JAI 1.1
030: */
031: class FactoryCache {
032:
033: /** * The registry mode name. */
034: final String modeName;
035:
036: /**
037: * Cache the RegistryMode since it is bound to get used
038: * many, many times.
039: */
040: final RegistryMode mode;
041:
042: /** The Class corresponding to the factory. */
043: final Class factoryClass;
044:
045: /**
046: * The name of the method in this factory used to
047: * do a "create"
048: */
049: final Method factoryMethod;
050:
051: /**
052: * does the factory support preferences both among products
053: * and among multiple instances of the factory within the
054: * same product ?
055: */
056: final boolean arePreferencesSupported;
057:
058: /**
059: * A Hashtable of all the instances, hashed by a filename that
060: * uniquely identifies each registered factory.
061: */
062: private Hashtable instances;
063:
064: /**
065: * A Hashtable of all the unique factory filenames, hashed by
066: * the factory they represent.
067: */
068: private Hashtable instancesByName;
069:
070: /** A count to give a number to each registered factory. */
071: private int count = 0;
072:
073: /**
074: * A Hashtable of a Hashtable of all the factory preferences, hashed
075: * by the descriptor name first and then the product name that the
076: * factory belongs to. Each element of the per product Hashtable is
077: * a Vector which contains a list of pairwise factory preferences
078: * stored as Vectors.
079: */
080: private Hashtable prefs;
081:
082: /**
083: * Constructor. Create a FactoryCache to hold factory objects
084: * for a specific mode.
085: *
086: * @param modeName the registry mode name.
087: */
088: FactoryCache(String modeName) {
089:
090: this .modeName = modeName;
091:
092: mode = RegistryMode.getMode(modeName);
093: factoryClass = mode.getFactoryClass();
094: factoryMethod = mode.getFactoryMethod();
095: arePreferencesSupported = mode.arePreferencesSupported();
096:
097: instances = new Hashtable();
098:
099: if (arePreferencesSupported) {
100: instancesByName = new Hashtable();
101: prefs = new Hashtable();
102: }
103: }
104:
105: /**
106: * Invoke the create method of the given factory instance
107: *
108: * @param factoryInstance an instance of this factory
109: * @param parameterValues the parameterValues to be passed in to the
110: * the create method.
111: *
112: * @return the object created by the create method
113: *
114: * @throws IllegalArgumentException thrown by Method.invoke
115: * @throws InvocationTargetException thrown by Method.invoke
116: * @throws IllegalAccessException thrown by Method.invoke
117: */
118: Object invoke(Object factoryInstance, Object[] parameterValues)
119: throws InvocationTargetException, IllegalAccessException {
120:
121: return factoryMethod.invoke(factoryInstance, parameterValues);
122: }
123:
124: /**
125: * Add a factory instance to this factory. If the factory has
126: * NO preferences add it to a table hashed by just the operation name.
127: * Otherwise add it to two tables, one hashed by a unique filename
128: * (modeName + count) and the other hashed by the factory interface
129: * name.
130: *
131: * @param descriptorName operation that this factory instance implements
132: * @param productName product to which this factory instance belongs
133: * @param factoryInstance the factory instance
134: */
135: void addFactory(String descriptorName, String productName,
136: Object factoryInstance) {
137:
138: checkInstance(factoryInstance);
139:
140: if (arePreferencesSupported) {
141:
142: if (productName == null)
143: throw new IllegalArgumentException(JaiI18N
144: .getString("Generic0"));
145:
146: // Update structures to reflect the addition of
147: // this factory instance.
148: Vector v = new Vector();
149:
150: v.add(factoryInstance.getClass().getName());
151: v.add(productName);
152: v.add(descriptorName);
153:
154: CaselessStringKey fileName = new CaselessStringKey(modeName
155: + count);
156:
157: instancesByName.put(factoryInstance, fileName);
158: instances.put(fileName, v);
159: count++;
160:
161: } else
162: instances.put(new CaselessStringKey(descriptorName),
163: factoryInstance);
164: }
165:
166: /**
167: * Remove a facory instance associated with the specified operation
168: *
169: * @param descriptorName operation that this factory instance implements
170: * @param productName product to which this factory instance belongs
171: * @param factoryInstance the factory instance
172: *
173: */
174: void removeFactory(String descriptorName, String productName,
175: Object factoryInstance) {
176:
177: checkInstance(factoryInstance);
178: checkRegistered(descriptorName, productName, factoryInstance);
179:
180: if (arePreferencesSupported) {
181:
182: // Update structures to reflect the removal of
183: // this factoryInstance.
184: CaselessStringKey fileName = (CaselessStringKey) instancesByName
185: .get(factoryInstance);
186:
187: instancesByName.remove(factoryInstance);
188: instances.remove(fileName);
189: count--;
190: } else {
191: instances.remove(new CaselessStringKey(descriptorName));
192: }
193: }
194:
195: /**
196: * Sets a preference between two factory instances for the given
197: * operation and product.
198: *
199: * @param descriptorName operation that this factory instance implements
200: * @param productName product to which this factory instance belongs
201: * @param preferredOp the preferred factory instance
202: * @param otherOp the not-so preferred/other factory instance
203: */
204: void setPreference(String descriptorName, String productName,
205: Object preferredOp, Object otherOp) {
206:
207: if (!arePreferencesSupported) {
208: throw new IllegalArgumentException(JaiI18N.formatMsg(
209: "FactoryCache1", new Object[] { modeName }));
210: }
211:
212: if ((preferredOp == null) || (otherOp == null)) {
213: throw new IllegalArgumentException(JaiI18N
214: .getString("Generic0"));
215: }
216:
217: checkRegistered(descriptorName, productName, preferredOp);
218: checkRegistered(descriptorName, productName, otherOp);
219:
220: if (preferredOp == otherOp)
221: return;
222:
223: checkInstance(preferredOp);
224: checkInstance(otherOp);
225:
226: CaselessStringKey dn = new CaselessStringKey(descriptorName);
227: CaselessStringKey pn = new CaselessStringKey(productName);
228:
229: Hashtable dht = (Hashtable) prefs.get(dn);
230:
231: if (dht == null) {
232: prefs.put(dn, dht = new Hashtable());
233: }
234:
235: Vector pv = (Vector) dht.get(pn);
236:
237: if (pv == null) {
238: dht.put(pn, pv = new Vector());
239: }
240:
241: pv.addElement(new Object[] { preferredOp, otherOp });
242: }
243:
244: /**
245: * Unets a preference between two factory instances for the given
246: * operation and product.
247: *
248: * @param descriptorName operation that this factory instance implements
249: * @param productName product to which this factory instance belongs
250: * @param preferredOp the preferred factory instance
251: * @param otherOp the not-so preferred/other factory instance
252: */
253: void unsetPreference(String descriptorName, String productName,
254: Object preferredOp, Object otherOp) {
255:
256: if (!arePreferencesSupported) {
257: throw new IllegalArgumentException(JaiI18N.formatMsg(
258: "FactoryCache1", new Object[] { modeName }));
259: }
260:
261: if ((preferredOp == null) || (otherOp == null)) {
262: throw new IllegalArgumentException(JaiI18N
263: .getString("Generic0"));
264: }
265:
266: checkRegistered(descriptorName, productName, preferredOp);
267: checkRegistered(descriptorName, productName, otherOp);
268:
269: if (preferredOp == otherOp)
270: return;
271:
272: checkInstance(preferredOp);
273: checkInstance(otherOp);
274:
275: // Update structures to reflect removal of this pref.
276: Hashtable dht = (Hashtable) prefs.get(new CaselessStringKey(
277: descriptorName));
278:
279: boolean found = false;
280:
281: if (dht != null) {
282:
283: Vector pv = (Vector) dht.get(new CaselessStringKey(
284: productName));
285:
286: if (pv != null) {
287: Iterator it = pv.iterator();
288:
289: while (it.hasNext()) {
290: Object[] objs = (Object[]) it.next();
291:
292: if ((objs[0] == preferredOp)
293: && (objs[1] == otherOp)) {
294:
295: it.remove();
296: found = true;
297: }
298: }
299:
300: }
301: }
302:
303: if (!found)
304: throw new IllegalArgumentException(JaiI18N.formatMsg(
305: "FactoryCache2", new Object[] {
306: preferredOp.getClass().getName(),
307: otherOp.getClass().getName(), modeName,
308: descriptorName, productName }));
309: }
310:
311: /**
312: * Gets an iterator over all preferences set between factory
313: * instances for a given descriptor and product.
314: *
315: * @param descriptorName operation that this factory instance implements
316: * @param productName product to which this factory instance belongs
317: */
318: Object[][] getPreferences(String descriptorName, String productName) {
319:
320: if (!arePreferencesSupported) {
321: throw new IllegalArgumentException(JaiI18N.formatMsg(
322: "FactoryCache1", new Object[] { modeName }));
323: }
324:
325: if ((descriptorName == null) || (productName == null))
326: throw new IllegalArgumentException(JaiI18N
327: .getString("Generic0"));
328:
329: // Update structures to reflect removal of this pref.
330: Hashtable dht = (Hashtable) prefs.get(new CaselessStringKey(
331: descriptorName));
332:
333: if (dht != null) {
334:
335: Vector pv = (Vector) dht.get(new CaselessStringKey(
336: productName));
337:
338: if (pv != null) {
339: return (Object[][]) pv.toArray(new Object[0][]);
340: }
341: }
342:
343: return null;
344: }
345:
346: /**
347: * Removes all preferences set between factory
348: * instances for a given descriptor and product.
349: *
350: * @param descriptorName operation that this factory instance implements
351: * @param productName product to which this factory instance belongs
352: */
353: void clearPreferences(String descriptorName, String productName) {
354:
355: if (!arePreferencesSupported) {
356: throw new IllegalArgumentException(JaiI18N.formatMsg(
357: "FactoryCache1", new Object[] { modeName }));
358: }
359:
360: // Update structures to reflect removal of this pref.
361: Hashtable dht = (Hashtable) prefs.get(new CaselessStringKey(
362: descriptorName));
363:
364: if (dht != null)
365: dht.remove(new CaselessStringKey(productName));
366: }
367:
368: /**
369: * Get a list of factory objects registered under the descriptor
370: * and the product (in no particular order).
371: */
372: List getFactoryList(String descriptorName, String productName) {
373:
374: if (arePreferencesSupported) {
375:
376: ArrayList list = new ArrayList();
377:
378: Enumeration keys = instancesByName.keys();
379:
380: while (keys.hasMoreElements()) {
381: Object instance = keys.nextElement();
382: CaselessStringKey fileName = (CaselessStringKey) instancesByName
383: .get(instance);
384:
385: Vector v = (Vector) instances.get(fileName);
386:
387: String dn = (String) v.get(2);
388: String pn = (String) v.get(1);
389:
390: if (descriptorName.equalsIgnoreCase(dn)
391: && productName.equalsIgnoreCase(pn))
392: list.add(instance);
393: }
394:
395: return list;
396:
397: } else {
398: Object obj = instances.get(new CaselessStringKey(
399: descriptorName));
400:
401: ArrayList list = new ArrayList(1);
402:
403: list.add(obj);
404: return list;
405: }
406: }
407:
408: /**
409: * Get the local name of a factoryInstance
410: */
411: String getLocalName(Object factoryInstance) {
412: CaselessStringKey fileName = (CaselessStringKey) instancesByName
413: .get(factoryInstance);
414:
415: if (fileName != null)
416: return fileName.getName();
417:
418: return null;
419: }
420:
421: /**
422: * Check to see if the factoryInstance is valid object
423: * of this registry mode.
424: */
425: private boolean checkInstance(Object factoryInstance) {
426:
427: if (!factoryClass.isInstance(factoryInstance))
428: throw new IllegalArgumentException(JaiI18N.formatMsg(
429: "FactoryCache0", new Object[] {
430: factoryInstance.getClass().getName(),
431: modeName, factoryClass.getName() }));
432:
433: return true;
434: }
435:
436: /**
437: * Check to see if <code>factoryInstance</code> is registered against
438: * the specified <code>descriptorName</code> and <code>productName</code>.
439: */
440: private void checkRegistered(String descriptorName,
441: String productName, Object factoryInstance) {
442:
443: if (arePreferencesSupported) {
444:
445: if (productName == null)
446: throw new IllegalArgumentException("productName : "
447: + JaiI18N.getString("Generic0"));
448:
449: CaselessStringKey fileName = (CaselessStringKey) instancesByName
450: .get(factoryInstance);
451:
452: if (fileName != null) {
453:
454: Vector v = (Vector) instances.get(fileName);
455:
456: String pn = (String) v.get(1);
457: String dn = (String) v.get(2);
458:
459: if ((dn != null) && dn.equalsIgnoreCase(descriptorName)
460: && (pn != null)
461: && pn.equalsIgnoreCase(productName)) {
462: return;
463: }
464: }
465:
466: throw new IllegalArgumentException(JaiI18N.formatMsg(
467: "FactoryCache3", new Object[] {
468: factoryInstance.getClass().getName(),
469: descriptorName, productName }));
470: } else {
471:
472: CaselessStringKey key = new CaselessStringKey(
473: descriptorName);
474:
475: if (factoryInstance != instances.get(key)) {
476: throw new IllegalArgumentException(JaiI18N.formatMsg(
477: "FactoryCache4", new Object[] {
478: factoryInstance.getClass().getName(),
479: descriptorName }));
480: }
481: }
482: }
483: }
|