001: /*
002: * $Header: /cvs/j3dfly/J3dFly/src/org/jdesktop/j3dfly/utils/loadercontrol/LoaderControl.java,v 1.1 2005/04/20 21:05:06 paulby Exp $
003: *
004: * Sun Public License Notice
005: *
006: * The contents of this file are subject to the Sun Public License Version
007: * 1.0 (the "License"). You may not use this file except in compliance with
008: * the License. A copy of the License is available at http://www.sun.com/
009: *
010: * The Original Code is Java 3D(tm) Fly Through.
011: * The Initial Developer of the Original Code is Paul Byrne.
012: * Portions created by Paul Byrne are Copyright (C) 2002.
013: * All Rights Reserved.
014: *
015: * Contributor(s): Paul Byrne.
016: *
017: **/
018: package org.jdesktop.j3dfly.utils.loadercontrol;
019:
020: import java.io.File;
021: import java.lang.reflect.Field;
022: import java.util.ArrayList;
023: import java.util.Iterator;
024: import javax.swing.JMenu;
025: import javax.swing.JMenuItem;
026: import javax.swing.filechooser.FileFilter;
027: import javax.swing.JFileChooser;
028: import javax.swing.filechooser.FileFilter;
029: import java.net.URL;
030:
031: import com.sun.j3d.loaders.Scene;
032: import com.sun.j3d.loaders.Loader;
033:
034: import org.jdesktop.j3dfly.utils.gui.ErrorHandler;
035: import org.jdesktop.j3dfly.utils.gui.ErrorManager;
036:
037: import org.jdesktop.j3dfly.utils.loadercontrol.UnsupportedFormatException;
038:
039: /**
040: * Provides a single interface for using all the Java3D loaders.
041: *
042: * @author Paul Byrne
043: * @version $Id: LoaderControl.java,v 1.1 2005/04/20 21:05:06 paulby Exp $
044: *
045: */
046: public class LoaderControl extends Object {
047:
048: private ArrayList fileFilters = null;
049: private LoaderSelectionDialog selectionDialog = null;
050: private LoaderControlListener menuLoaderListener = null;
051:
052: private java.net.URLClassLoader classLoader;
053:
054: private ArrayList loaderList = new ArrayList();
055:
056: /** Creates new LoaderControl
057: * The LoaderControl will create it's own URLClassLoader from which
058: * to load the loaders
059: */
060: public LoaderControl() {
061: loadConfig();
062: checkInstalled();
063:
064: //write();
065: }
066:
067: private void loadConfig() {
068: File file;
069: ArrayList urls = new ArrayList();
070: String prop = System.getProperty("J3dFly.Loaders");
071: if (prop == null)
072: file = new java.io.File("loaders.xml");
073: else
074: file = new java.io.File(prop);
075:
076: java.beans.XMLDecoder decoder = null;
077: try {
078: java.io.InputStream in = new java.io.BufferedInputStream(
079: new java.io.FileInputStream(file));
080: decoder = new java.beans.XMLDecoder(in);
081: LoaderConfig config;
082: while (true) {
083: config = (LoaderConfig) decoder.readObject();
084: if (config != null) {
085: loaderList.add(config);
086: try {
087: if (config.getClasspathURL() != null) {
088: URL url = new URL(config.getClasspathURL());
089: if (url.getPath().startsWith("..")
090: && url.getProtocol()
091: .equalsIgnoreCase("file")) {
092: String path = file
093: .getAbsolutePath()
094: .substring(
095: 0,
096: file
097: .getAbsolutePath()
098: .lastIndexOf(
099: file.separatorChar));
100: config.setClasspathURL("file:" + path
101: + "/" + url.getPath());
102: url = new URL("file:" + path + "/"
103: + url.getPath());
104: }
105: try {
106: url.openStream();
107: } catch (java.io.IOException e) {
108: // URL is invalid or file is missing
109: url = null;
110: }
111:
112: if (url != null)
113: urls.add(url);
114: }
115: } catch (java.net.MalformedURLException e) {
116: System.err.println("Bad URL in loaders file "
117: + config.getClasspathURL());
118: }
119: }
120: }
121: } catch (java.io.IOException e) {
122: ErrorManager.getDefault().notify(e,
123: ErrorHandler.INFORMATIONAL,
124: "Error loading Loader details " + file.getName());
125: } catch (ArrayIndexOutOfBoundsException ex) {
126: // It's horrible, but ArrayIndexOutOfBounds indicates the
127: // end of the stream
128: decoder.close();
129: }
130:
131: classLoader = new java.net.URLClassLoader((URL[]) urls
132: .toArray(new URL[urls.size()]));
133:
134: }
135:
136: /**
137: * Returns the ClassLoader used to load all the loaders
138: */
139: public java.net.URLClassLoader getClassLoader() {
140: return classLoader;
141: }
142:
143: private void write() {
144: try {
145: java.beans.XMLEncoder enc = new java.beans.XMLEncoder(
146: new java.io.BufferedOutputStream(
147: new java.io.FileOutputStream("loaders.xml")));
148: for (int i = 0; i < loaderList.size(); i++) {
149: enc.writeObject(loaderList.get(i));
150: }
151:
152: enc.close();
153: } catch (Exception e) {
154: e.printStackTrace();
155: }
156: }
157:
158: /**
159: * Return the dialog which allows users to configure loaders
160: */
161: public LoaderSelectionDialog getSelectionDialog(
162: java.awt.Frame parent, boolean modal) {
163: if (selectionDialog == null) {
164: selectionDialog = new LoaderSelectionDialog(parent, modal);
165: boolean enabled;
166: LoaderConfig loader;
167: for (int i = 0; i < loaderList.size(); i++) {
168: loader = (LoaderConfig) loaderList.get(i);
169: selectionDialog.addLoader(loader.getName(), loader
170: .getFileExtension(), loader.getFlags(), loader
171: .isEnabled(), loader.isInstalled(), loader
172: .getClasspathURL());
173: }
174: }
175: return selectionDialog;
176: }
177:
178: /**
179: * Show the selection dialog which allows the user to choose
180: * which loaders to use
181: */
182: public void showSelectionDialog(java.awt.Frame parent) {
183: selectionDialog = getSelectionDialog(parent, true);
184:
185: if (selectionDialog.showDialog()) {
186: selectionDialog.getEnabledLoaders(loaderList);
187:
188: if (fileFilters != null) {
189: // Remove all the file filters fileFilter will be update when setFileFilters is called
190: fileFilters.clear();
191: }
192:
193: }
194: }
195:
196: /**
197: * Populate </code>menu</code> with MenuItems representing all the
198: * available loaders
199: *
200: * This class handles all ActionEvents on the menu, when an item is
201: * loaded the loaderListener will be called
202: */
203: /*
204: public void setupMenu( JMenu menu, LoaderControlListener loaderListener ) {
205: menuLoaderListener = loaderListener;
206: for(int i=0; i<loaders.length; i++) {
207: JMenuItem item = new JMenuItem( loaders[i][0] );
208: item.addActionListener( this );
209: item.setActionCommand( Integer.toString(i) );
210:
211: item.setEnabled( installed[i] );
212:
213: menu.add( item );
214: }
215: }
216: **/
217:
218: /**
219: * Check which loaders are installed in the Classpath and
220: * setup the enabledList
221: */
222: private void checkInstalled() {
223: LoaderConfig loader;
224: for (int i = 0; i < loaderList.size(); i++) {
225: loader = (LoaderConfig) loaderList.get(i);
226: try { // Disable menu item if class not available
227: Class cl = classLoader.loadClass(loader.getClassName());
228: } catch (ClassNotFoundException e) {
229: //System.out.println( "Not Installed "+loaders[i][2] );
230: loader.setInstalled(false);
231: loader.setEnabled(false);
232: } catch (NoClassDefFoundError e) {
233: //System.out.println( "Not Installed "+loaders[i][2] );
234: loader.setInstalled(false);
235: loader.setEnabled(false);
236: }
237: }
238: }
239:
240: /**
241: * Sets the file filters in the JFileChooser to the various geometry
242: * file formats available in the classpath of the app.
243: *
244: * Previous file filters are cleared from the chooser.
245: *
246: * This method should be called whenever the fileChooser is
247: * displayed because the FileFilter may change depending on
248: * user updates made in showSelectionDialog().
249: */
250: public void setFileFilter(javax.swing.JFileChooser fileChooser) {
251: if (fileFilters == null) {
252: fileFilters = new ArrayList();
253: }
254:
255: if (fileFilters.size() == 0) {
256:
257: ExampleFileFilter allFilter = new ExampleFileFilter();
258: allFilter.setDescription("All Geometry Files");
259: allFilter.setExtensionListInDescription(false);
260: LoaderConfig loader;
261: for (int i = 0; i < loaderList.size(); i++) {
262: loader = (LoaderConfig) loaderList.get(i);
263: if (loader.isInstalled() && loader.isEnabled()) {
264: allFilter.addExtension(loader.getFileExtension());
265: fileFilters.add(new ExampleFileFilter(loader
266: .getFileExtension(), loader.getName()));
267: }
268: }
269:
270: fileFilters.add(allFilter);
271: }
272:
273: fileChooser.resetChoosableFileFilters();
274:
275: Iterator it = fileFilters.iterator();
276: while (it.hasNext())
277: fileChooser.addChoosableFileFilter((FileFilter) it.next());
278:
279: // Set the current filter to the allFilter
280: fileChooser.setFileFilter((FileFilter) fileFilters
281: .get(fileFilters.size() - 1));
282:
283: }
284:
285: /**
286: * Return the Class Name for the specified loader
287: */
288: public String getLoaderClassName(int loaderID) {
289: return ((LoaderConfig) loaderList.get(loaderID)).getClassName();
290: }
291:
292: /**
293: * Return the loader for the given loaderID
294: */
295: private Loader getLoader(int loaderID) {
296: Loader actualLoader = null;
297: LoaderConfig loader = (LoaderConfig) loaderList.get(loaderID);
298:
299: try {
300: Class loaderClass = classLoader.loadClass(loader
301: .getClassName());
302: actualLoader = (Loader) loaderClass.newInstance();
303: int loaderFlags = 0;
304: if (loader.getFlags() != null) {
305: String tokens = loader.getFlags();
306: int nextWord = tokens.indexOf(' ', 0);
307: int startWord = 0;
308: String str;
309: if (tokens.length() != 0) {
310: do {
311: if (nextWord == -1)
312: nextWord = tokens.length();
313: str = tokens.substring(startWord, nextWord);
314: Field field = loaderClass.getField(str);
315: loaderFlags |= field.getInt(actualLoader);
316: startWord = nextWord + 1;
317: nextWord = tokens.indexOf(' ', startWord);
318: } while (startWord != 0
319: && startWord < tokens.length());
320: }
321: }
322: actualLoader.setFlags(0);
323: actualLoader.setFlags(loaderFlags);
324: } catch (ClassNotFoundException e) {
325: ErrorManager.getDefault().notify(e, ErrorHandler.EXCEPTION);
326: } catch (IllegalAccessException ex) {
327: ErrorManager.getDefault()
328: .notify(ex, ErrorHandler.EXCEPTION);
329: } catch (InstantiationException exc) {
330: ErrorManager.getDefault().notify(exc,
331: ErrorHandler.EXCEPTION);
332: } catch (NoSuchFieldException exce) {
333: ErrorManager.getDefault().notify(exce,
334: ErrorHandler.EXCEPTION);
335: }
336:
337: return actualLoader;
338: }
339:
340: /**
341: * Load the file and don't return until the load is complete
342: * @param file The file to load
343: * @param listener The listener to call when the load is complete
344: * @param workMonitor A progress monitor for the load, can be null
345: */
346: public void loadFileAndWait(File file,
347: LoaderControlListener listener,
348: org.jdesktop.j3dfly.utils.gui.WorkMonitor workMonitor)
349: throws UnsupportedFormatException {
350: actualLoadFile(file, listener, workMonitor).waitForCompletion();
351: }
352:
353: /**
354: * Load the specified file, listener is notified when load is complete
355: * Loading takes place in a seperate thread, this method will return
356: * without waiting for the load to complete.
357: *
358: * @param file The file to load
359: * @param listener The listener to call when the load is complete
360: * @param workMonitor A progress monitor for the load, can be null
361: *
362: */
363: public void loadFile(File file, LoaderControlListener listener,
364: org.jdesktop.j3dfly.utils.gui.WorkMonitor workMonitor)
365: throws UnsupportedFormatException {
366: actualLoadFile(file, listener, workMonitor);
367: }
368:
369: private SceneLoader actualLoadFile(File file,
370: LoaderControlListener listener,
371: org.jdesktop.j3dfly.utils.gui.WorkMonitor workMonitor)
372: throws UnsupportedFormatException {
373: String filename = file.getName();
374: String extension;
375: int loaderID = -1;
376: try {
377: extension = filename.substring(
378: filename.lastIndexOf('.') + 1, filename.length());
379: } catch (Exception e) {
380: throw new UnsupportedFormatException(
381: "Unknown file extension " + filename);
382: }
383:
384: LoaderConfig loader = null;
385: for (int i = 0; i < loaderList.size() && loaderID == -1; i++) {
386: loader = (LoaderConfig) loaderList.get(i);
387: if (loader.getFileExtension()
388: .compareToIgnoreCase(extension) == 0
389: && loader.isEnabled())
390: loaderID = i;
391: }
392:
393: if (loaderID == -1) {
394: UnsupportedFormatException ex = new UnsupportedFormatException(
395: "Unsupported file extension " + extension);
396: // No need to report this to the ErrorManager
397: //ErrorManager.getDefault().notify( ex, ErrorHandler.EXCEPTION );
398: throw ex;
399: }
400:
401: int loaderMethod;
402: if (loader.getLoadInterface().equalsIgnoreCase("Reader"))
403: loaderMethod = SceneLoader.USE_READER;
404: else if (loader.getLoadInterface().equalsIgnoreCase("Filename"))
405: loaderMethod = SceneLoader.USE_FILENAME;
406: else if (loader.getLoadInterface().equalsIgnoreCase("URL"))
407: loaderMethod = SceneLoader.USE_URL;
408: else if (loader.getLoadInterface().equalsIgnoreCase(
409: "Nonstandard"))
410: loaderMethod = SceneLoader.USE_NONSTANDARD;
411: else {
412: System.out
413: .println("WARNING - LoaderControl has invalid LoaderMethod for "
414: + loader.getClassName());
415: loaderMethod = SceneLoader.USE_READER;
416: }
417:
418: Loader actualLoader = getLoader(loaderID);
419: SceneLoader sceneLoader = new SceneLoader(actualLoader,
420: listener, file, loaderID, loaderMethod, workMonitor);
421: return sceneLoader;
422: }
423:
424: public String getLoaderFileExtension(int loaderID) {
425: return ((LoaderConfig) loaderList.get(loaderID))
426: .getFileExtension();
427: }
428:
429: public String[] getEnabledFileExtensions() {
430: if (selectionDialog != null) {
431: selectionDialog.getEnabledLoaders(loaderList);
432: }
433:
434: ArrayList ext = new ArrayList();
435: LoaderConfig loader;
436: for (int i = 0, x = 0; i < loaderList.size(); i++) {
437: loader = (LoaderConfig) loaderList.get(i);
438: if (loader.isInstalled() && loader.isEnabled()) {
439: ext.add(loader.getFileExtension());
440: }
441: }
442:
443: return (String[]) ext.toArray(new String[ext.size()]);
444: }
445:
446: public static class LoaderConfig implements java.io.Serializable {
447:
448: /** Holds value of property name. */
449: private String name;
450:
451: /** Holds value of property fileExtension. */
452: private String fileExtension;
453:
454: /** Holds value of property className. */
455: private String className;
456:
457: /** The flags for the loader, eg LOAD_ALL */
458: private String flags;
459:
460: /** IS this loader enabled ? */
461: private boolean enabled;
462:
463: /** Specifies which interface to use with the loader
464: * this must be either Filename or Reader.
465: *
466: * A special interface Nonstandard is used for the NCSA loaders
467: */
468: private String loadInterface = "Filename";
469:
470: /** Is this loader installed */
471: private boolean installed = true;
472:
473: /** Holds value of property classpathURL. */
474: private String classpathURL;
475:
476: public LoaderConfig() {
477: }
478:
479: /** Getter for property name.
480: * @return Value of property name.
481: */
482: public String getName() {
483: return name;
484: }
485:
486: /** Setter for property name.
487: * @param name New value of property name.
488: */
489: public void setName(String name) {
490: this .name = name;
491: }
492:
493: /** Getter for property fileExtension.
494: * @return Value of property fileExtension.
495: */
496: public String getFileExtension() {
497: return fileExtension;
498: }
499:
500: /** Setter for property fileExtension.
501: * @param fileExtension New value of property fileExtension.
502: */
503: public void setFileExtension(String fileExtension) {
504: this .fileExtension = fileExtension;
505: }
506:
507: /** Getter for property className.
508: * @return Value of property className.
509: */
510: public String getClassName() {
511: return className;
512: }
513:
514: /** Setter for property className.
515: * @param className New value of property className.
516: */
517: public void setClassName(String className) {
518: this .className = className;
519: }
520:
521: /** Getter for property flags.
522: * @return Value of property flags.
523: */
524: public String getFlags() {
525: return flags;
526: }
527:
528: /** Setter for property flags.
529: * @param flags New value of property flags.
530: */
531: public void setFlags(String flags) {
532: this .flags = flags;
533: }
534:
535: /** Getter for property enabled.
536: * @return Value of property enabled.
537: */
538: public boolean isEnabled() {
539: return enabled;
540: }
541:
542: /** Setter for property enabled.
543: * @param enabled New value of property enabled.
544: */
545: public void setEnabled(boolean enabled) {
546: this .enabled = enabled;
547: }
548:
549: /** Getter for property loadInterface.
550: * @return Value of property loadInterface.
551: */
552: public String getLoadInterface() {
553: return loadInterface;
554: }
555:
556: /** Setter for property loadInterface.
557: * @param loadInterface New value of property loadInterface.
558: */
559: public void setLoadInterface(String loadInterface) {
560: this .loadInterface = loadInterface;
561: }
562:
563: /** Getter for property installed.
564: * @return Value of property installed.
565: */
566: public boolean isInstalled() {
567: return installed;
568: }
569:
570: /** Setter for property installed.
571: * @param installed New value of property installed.
572: */
573: public void setInstalled(boolean installed) {
574: this .installed = installed;
575: }
576:
577: /** Getter for property Classpath URL.
578: * @return Value of property classPath.
579: */
580: public String getClasspathURL() {
581: return this .classpathURL;
582: }
583:
584: /** Setter for property the Jar containing the loader.
585: * @param classPath New value of property classPath.
586: */
587: public void setClasspathURL(String classpathURL) {
588: this.classpathURL = classpathURL;
589: }
590:
591: }
592:
593: }
|