001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.theme;
042:
043: import java.beans.Beans;
044: import java.io.IOException;
045: import java.io.InputStream;
046: import java.net.URL;
047: import java.net.URLClassLoader;
048: import java.net.URLConnection;
049: import java.text.MessageFormat;
050: import java.util.ArrayList;
051: import java.util.Enumeration;
052: import java.util.HashMap;
053: import java.util.HashSet;
054: import java.util.Iterator;
055: import java.util.Locale;
056: import java.util.Map;
057: import java.util.MissingResourceException;
058: import java.util.ResourceBundle;
059: import java.util.Set;
060: import java.util.Vector;
061: import java.util.jar.Attributes;
062: import java.util.jar.Manifest;
063:
064: import javax.servlet.ServletContext; //import javax.portlet.PortletContext;
065:
066: import javax.faces.FactoryFinder;
067: import javax.faces.application.Application;
068: import javax.faces.application.ApplicationFactory;
069: import javax.faces.context.ExternalContext;
070: import javax.faces.context.FacesContext;
071:
072: import com.sun.rave.web.ui.util.ClassLoaderFinder;
073:
074: /**
075: * <p>Factory class responsible for setting up the Sun Web Component
076: * application's ThemeManager.</p>
077: */
078: public class ThemeFactory {
079:
080: /**
081: * The init parameter name used to set the default theme name.
082: */
083: public final static String DEFAULT_THEME = "com.sun.rave.web.ui.DEFAULT_THEME"; //NOI18N
084:
085: /**
086: * The init parameter name used to override the default
087: * message bundle location.
088: */
089: public final static String MESSAGES_PARAM = "com.sun.rave.web.ui.MESSAGES"; //NOI18N
090:
091: // Private variables
092: private static String messageOverride = null;
093:
094: // Private message variables
095: private final static String WARNING_LOAD = "WARNING: the Sun Web Components could not load any themes.";
096: private final static String WARNING_BADFILE = "WARNING: the Sun Web Components detected a corrupted theme configuration file:\n\t";
097:
098: // Private attribute names
099: public final static String MANIFEST = "META-INF/MANIFEST.MF"; //NOI18N
100: public final static String FILENAME = "manifest-file"; //NOI18N
101: public final static String COMPONENTS_SECTION = "com/sun/rave/web/ui/"; //NOI18N
102: public final static String THEME_SECTION = "com/sun/rave/web/ui/theme/"; //NOI18N
103: public final static String THEME_VERSION_REQUIRED = "X-SJWUIC-Theme-Version-Required"; //NOI18N
104: public final static String THEME_VERSION = "X-SJWUIC-Theme-Version"; //NOI18N
105: public final static String NAME = "X-SJWUIC-Theme-Name"; //NOI18N
106: public final static String PREFIX = "X-SJWUIC-Theme-Prefix"; //NOI18N
107: public final static String DEFAULT = "X-SJWUIC-Theme-Default"; //NOI18N
108: public final static String STYLESHEETS = "X-SJWUIC-Theme-Stylesheets"; //NOI18N
109: public final static String JSFILES = "X-SJWUIC-Theme-JavaScript"; //NOI18N
110: public final static String CLASSMAPPER = "X-SJWUIC-Theme-ClassMapper"; //NOI18N
111: public final static String IMAGES = "X-SJWUIC-Theme-Images"; //NOI18N
112: public final static String MESSAGES = "X-SJWUIC-Theme-Messages"; //NOI18N
113:
114: private static final boolean DEBUG = false;
115:
116: private ThemeFactory(String messageOverride) {
117: this .messageOverride = messageOverride;
118: }
119:
120: /**
121: * This method initializes the ThemeManager for the Sun Web
122: * Component's application. It is invoked by the ThemeServlet's
123: * init method. To initialize the ThemeManager and the Themes
124: * during web application startup, declare the load-on-startup
125: * property of the ThemeServlet in the web application
126: * deployment descriptor.
127: * @param context the ServletContext in which the application
128: * @param locales a Set of locales supported by the application
129: * If this parameter is null, the supported locales will be
130: * retrieved from the JSF runtime.
131: * is running
132: */
133: public static ThemeManager initializeThemeManager(
134: ServletContext context, Set locales) {
135:
136: // We don't need to synchronize this method. It must only be
137: // invoked during the ThemeServlet's init method.
138:
139: if (DEBUG)
140: log("initializeThemeManager(ServletContext)");
141: if (context.getAttribute(ThemeManager.THEME_MANAGER) != null) {
142: if (DEBUG)
143: log("ThemeManager already initialized");
144: return null;
145: }
146:
147: // Set the default theme if specified in the DD
148: String defaultThemeName = processInitParameter(context
149: .getInitParameter(DEFAULT_THEME));
150: String messageOverride = processInitParameter(context
151: .getInitParameter(MESSAGES_PARAM));
152:
153: ThemeFactory themeFactory = new ThemeFactory(messageOverride);
154: ThemeManager manager = null;
155: if (locales == null) {
156: manager = themeFactory.createThemeManager(defaultThemeName);
157: } else {
158: manager = themeFactory.createThemeManager(defaultThemeName,
159: locales, null);
160: }
161: if (manager == null) {
162: return null;
163: }
164: context.setAttribute(ThemeManager.THEME_MANAGER, manager);
165: return manager;
166: }
167:
168: /**
169: * This method initializes the ThemeManager for the Sun Web
170: * Component's application. It is invoked by the XXX's
171: * init method. To initialize the ThemeManager and the Themes
172: * during portlet application startup, declare the load-on-startup
173: * property of the XXX in the portlet application configuration
174: * file.
175: * @param context the PortletContext in which the application
176: * is running
177: */
178: // protected static void initializeThemeManager(PortletContext context) {
179: //
180: // // We don't need to synchronize this method. It must only be
181: // // invoked during during the initialization of a
182: // // PortletContext
183: //
184: // if(DEBUG) log("initializeThemeManager(PortletContext)");
185: // if(context.getAttribute(ThemeManager.THEME_MANAGER) != null) {
186: // if(DEBUG) log("ThemeManager already initialized");
187: // }
188: //
189: // // Set the default theme if specified in the DD
190: // String defaultThemeName =
191: // processInitParameter(context.getInitParameter(DEFAULT_THEME));
192: // String messageOverride =
193: // processInitParameter(context.getInitParameter(MESSAGES_PARAM));
194: //
195: // ThemeFactory themeFactory = new ThemeFactory(messageOverride);
196: // ThemeManager manager =
197: // themeFactory.createThemeManager(defaultThemeName);
198: // context.setAttribute(ThemeManager.THEME_MANAGER, manager);
199: // }
200: /**
201: * Initializes a ThemeManager based on an External Context.
202: * This method is invoked by ThemeUtilities.getTheme() if
203: * the ThemeManager has not been initialized during the
204: * context initialization phase.
205: * @param context The ExternalContext used to access Session and Context attributes
206: * @return The ThemeManager constructed
207: */
208: public static ThemeManager initializeThemeManager(
209: ExternalContext context) {
210:
211: if (DEBUG)
212: log("initializeThemeManager(ExternalContext)");
213: // This method must be synchronized, since this is a fallback
214: // approach to be used if we failed to initialize the
215: // ThemeManager during startup. There could be several
216: // simultaneous requests to the container
217:
218: // Also, I probably need to move the ThemeUtilities into this
219: // package or I'm stuck with a public method :(
220:
221: // Set the default theme if specified in the DD
222: String defaultThemeName = processInitParameter(context
223: .getInitParameter(DEFAULT_THEME));
224: String messageOverride = processInitParameter(context
225: .getInitParameter(MESSAGES_PARAM));
226:
227: ThemeFactory themeFactory = new ThemeFactory(messageOverride);
228: ThemeManager manager = themeFactory
229: .createThemeManager(defaultThemeName);
230: context.getApplicationMap().put(ThemeManager.THEME_MANAGER,
231: manager);
232: return manager;
233: }
234:
235: /**
236: * <p>Create ThemeInstances for each theme name and supported locale.
237: * Each ThemeInstance must be packaged in a Jar. The Jar must
238: * contain, in META-INF, a properties file called
239: * <code>swc_theme.properties</code> which must contain the following
240: * properties:
241: * </p>
242: * <ul>
243: * <li><code>name</code>: the name of the theme</li>
244: * <li><code>prefix</code>: the prefix used to retrieve the resource
245: * file. This should be the same as the URL mapping used by the ThemeServlet
246: * to serve the Theme resources.</li>
247: * <li><code>propertyfile</code>: the name of the propertyfile that
248: * describes the theme resources (see ThemeFactory)</li>
249: * </ul>
250: * and may contain the following optional parameter:
251: *< ul>
252: * <li><code>default</code>: set this to true if the theme
253: * specified should be the default theme (the last theme processed
254: * wins).</li>
255: * </ul>
256: */
257: private ThemeManager createThemeManager(String defaultThemeName) {
258:
259: Application app = getApplication();
260: if (app == null) {
261: // JSF not intialized - try later
262: //if(DEBUG) context.log("JSF is not initialized yet");
263: return null;
264: }
265:
266: return createThemeManager(defaultThemeName, getLocales(app),
267: app.getDefaultLocale());
268: }
269:
270: /**
271: * <p>Create ThemeInstances for each theme name and supported locale.
272: * Each ThemeInstance must be packaged in a Jar. The Jar must
273: * contain, in META-INF, a properties file called
274: * <code>swc_theme.properties</code> which must contain the following
275: * properties:
276: * </p>
277: * <ul>
278: * <li><code>name</code>: the name of the theme</li>
279: * <li><code>prefix</code>: the prefix used to retrieve the resource
280: * file. This should be the same as the URL mapping used by the ThemeServlet
281: * to serve the Theme resources.</li>
282: * <li><code>propertyfile</code>: the name of the propertyfile that
283: * describes the theme resources (see ThemeFactory)</li>
284: * </ul>
285: * and may contain the following optional parameter:
286: *< ul>
287: * <li><code>default</code>: set this to true if the theme
288: * specified should be the default theme (the last theme processed
289: * wins).</li>
290: * </ul>
291: */
292: private ThemeManager createThemeManager(String defaultThemeName,
293: Set localeSet, Locale defaultLocale) {
294:
295: if (DEBUG)
296: log("createThemeManager");
297:
298: String requiredThemeVersion = getRequiredThemeVersion();
299:
300: ThemeManager manager = new ThemeManager();
301: manager.setDefaultLocale(defaultLocale);
302:
303: Iterator themeAttributesIterator = getThemeAttributes();
304:
305: if (!themeAttributesIterator.hasNext()) {
306: throw new ThemeConfigurationException(WARNING_LOAD);
307: }
308:
309: Attributes themeAttributes = null;
310: Iterator locales = null;
311: Locale locale = null;
312: Theme theme = null;
313: String defaultName = defaultThemeName;
314:
315: while (themeAttributesIterator.hasNext()) {
316:
317: themeAttributes = (Attributes) (themeAttributesIterator
318: .next());
319:
320: if (DEBUG) {
321: String propFile = themeAttributes.getValue(FILENAME);
322: log("Configuring theme from file " + propFile);
323: }
324: String name = readAttribute(themeAttributes, NAME);
325: String version = readAttribute(themeAttributes,
326: THEME_VERSION);
327:
328: if (DEBUG) {
329: log("Required theme version " + //NOI18N
330: String.valueOf(requiredThemeVersion));
331: log("Actual theme version " + version); //NOI18N
332: log(String.valueOf(requiredThemeVersion
333: .compareTo(version)));
334: }
335:
336: if (requiredThemeVersion != null
337: && requiredThemeVersion.compareTo(version) > 0) {
338:
339: throwVersionException(name, version,
340: requiredThemeVersion);
341: }
342:
343: Map map = new HashMap();
344: locales = localeSet.iterator();
345: while (locales.hasNext()) {
346: locale = (Locale) (locales.next());
347: // createTheme throws a ThemeConfigurationException if
348: // it fails, in which case we abort
349: map.put(locale, createTheme(themeAttributes, locale));
350: }
351:
352: manager.addThemeMap(name, map);
353: if (defaultName == null) {
354: String isDefault = themeAttributes.getValue(DEFAULT);
355: if (isDefault != null && isDefault.equals("true")) {
356: defaultName = name;
357: }
358: }
359: }
360:
361: manager.setDefaultThemeName(defaultThemeName);
362: return manager;
363: }
364:
365: public Iterator getThemeAttributes() {
366:
367: if (DEBUG)
368: log("getThemeAttributes()");
369:
370: Enumeration manifests = getManifests();
371:
372: if (!manifests.hasMoreElements()) {
373: String msg = "No Themes in the classpath!";
374: throw new ThemeConfigurationException(msg);
375: }
376:
377: URL url = null;
378: URLConnection conn = null;
379: InputStream in = null;
380: Manifest manifest = null;
381: Attributes themeAttributes = null;
382: ArrayList themeProps = new ArrayList();
383:
384: while (manifests.hasMoreElements()) {
385:
386: url = (URL) (manifests.nextElement());
387:
388: try {
389: if (DEBUG)
390: log("\tExamine " + url.toString());
391: conn = url.openConnection();
392: in = conn.getInputStream();
393: manifest = new Manifest(in);
394: themeAttributes = manifest.getAttributes(THEME_SECTION);
395: if (themeAttributes != null) {
396: if (DEBUG)
397: log("\tFound a theme section");
398: themeAttributes.putValue(FILENAME, url.toString());
399: themeProps.add(themeAttributes);
400: }
401: } catch (IOException ioex) {
402: // do nothing
403: } finally {
404: try {
405: in.close();
406: } catch (Throwable t) {
407: }
408: }
409: }
410: return themeProps.iterator();
411: }
412:
413: private Theme createTheme(Attributes themeAttributes, Locale locale)
414: throws ThemeConfigurationException {
415:
416: if (DEBUG) {
417: log("\tcreateTheme()");
418: log("\tlocale is " + locale.toString());
419: Iterator i = themeAttributes.keySet().iterator();
420: log("\tAttributes are:");
421: while (i.hasNext()) {
422: log("\t\t" + i.next().toString());
423: }
424: }
425:
426: Theme theme = new Theme(locale);
427: ResourceBundle bundle = null;
428:
429: // Configure the prefix
430: if (DEBUG)
431: log("\tSetting the prefix");
432:
433: String prefix = readAttribute(themeAttributes, PREFIX); //NOI18N
434:
435: if (!prefix.startsWith("/")) { //NOI18N
436: prefix = "/".concat(prefix); //NOI18N
437: }
438: theme.setPrefix(prefix);
439: if (DEBUG)
440: log("\tSet prefix to " + prefix);
441:
442: // Configure the messages
443: if (DEBUG)
444: log("\tConfiguring the messages");
445: bundle = createResourceBundle(themeAttributes, MESSAGES, locale);
446:
447: if (messageOverride != null) {
448: if (DEBUG)
449: log("Found message override");
450:
451: try {
452: ResourceBundle override = ResourceBundle.getBundle(
453: messageOverride, locale);
454: theme.configureMessages(bundle, override);
455: } catch (MissingResourceException mre) {
456: StringBuffer errorMessage = new StringBuffer(
457: "The message resource file ");
458: errorMessage.append(messageOverride);
459: errorMessage.append(" specified by context parameter ");
460: errorMessage.append(MESSAGES_PARAM);
461: errorMessage.append(" does not exist.");
462: throw new ThemeConfigurationException(errorMessage
463: .toString());
464: }
465: } else {
466: theme.configureMessages(bundle, null);
467: }
468:
469: // Configure the images
470: if (DEBUG)
471: log("\tConfiguring the images");
472: bundle = createResourceBundle(themeAttributes, IMAGES, locale);
473: theme.configureImages(bundle);
474:
475: // Configure the javascript files
476: bundle = createResourceBundle(themeAttributes, JSFILES, locale);
477: String jsFiles = readAttribute(themeAttributes, JSFILES);
478: theme.configureJSFiles(bundle);
479:
480: // Configure the style sheets
481: bundle = createResourceBundle(themeAttributes, STYLESHEETS,
482: locale);
483: theme.configureStylesheets(bundle);
484:
485: // Configure the classmapper
486: String classMapper = themeAttributes.getValue(CLASSMAPPER);
487: if (classMapper != null && classMapper.length() > 0) {
488: bundle = createResourceBundle(themeAttributes, CLASSMAPPER,
489: locale);
490: theme.configureClassMapper(bundle);
491: }
492: return theme;
493: }
494:
495: private ResourceBundle createResourceBundle(
496: Attributes themeAttributes, String propName, Locale locale) {
497: if (DEBUG)
498: log("createResourceBundle()");
499:
500: String bundleName = readAttribute(themeAttributes, propName);
501: try {
502: if (DEBUG)
503: log("Resource file is " + bundleName);
504: ClassLoader loader = ClassLoaderFinder
505: .getCurrentLoader(ThemeFactory.class);
506: return ResourceBundle.getBundle(bundleName, locale, loader);
507: } catch (MissingResourceException mre) {
508: StringBuffer msgBuffer = new StringBuffer(300);
509: msgBuffer
510: .append("Invalid theme configuration file for theme ");
511: msgBuffer.append(themeAttributes.getValue(NAME));
512: msgBuffer
513: .append(".\nThemeFactory could not locate resource bundle at ");
514: msgBuffer.append(bundleName);
515: msgBuffer.append(".");
516: throw new ThemeConfigurationException(msgBuffer.toString());
517: }
518: }
519:
520: private String readAttribute(Attributes themeAttributes,
521: String propName) {
522: String name = themeAttributes.getValue(propName);
523:
524: if (name == null || name.length() == 0) {
525:
526: String propFile = themeAttributes.getValue(FILENAME);
527:
528: StringBuffer msgBuffer = new StringBuffer(300);
529: msgBuffer.append("ThemeConfiguration file "); //NOI18N
530: if (propFile != null) {
531: msgBuffer.append(propFile);
532: msgBuffer.append(" "); //NOI18N
533: }
534: msgBuffer.append("does not contain required property \""); //NOI18N
535: msgBuffer.append(propName);
536: msgBuffer.append("\".");
537: throw new ThemeConfigurationException(msgBuffer.toString());
538: }
539: return name;
540: }
541:
542: private void throwVersionException(String name, String version,
543: String requiredThemeVersion) {
544:
545: StringBuffer msgBuffer = new StringBuffer(300); //NOI18N
546: msgBuffer.append("\n\nTheme \"");
547: msgBuffer.append(name);
548: msgBuffer
549: .append("\" is not up to date with the component library.\n");
550: msgBuffer.append("Its version is ");
551: msgBuffer.append(version);
552: msgBuffer.append(". Version ");
553: msgBuffer.append(requiredThemeVersion);
554: msgBuffer.append(" or higher required.\n");
555: throw new ThemeConfigurationException(msgBuffer.toString());
556: }
557:
558: private static Application getApplication() {
559: ApplicationFactory factory = (ApplicationFactory) FactoryFinder
560: .getFactory(FactoryFinder.APPLICATION_FACTORY);
561: if (factory == null) {
562: return null;
563: }
564: return factory.getApplication();
565: }
566:
567: private static Set getLocales(Application application) {
568:
569: if (DEBUG)
570: log("getLocales()");
571:
572: HashSet localeSet = new HashSet();
573:
574: Locale locale = application.getDefaultLocale();
575: // According to the JSF spec, getDefaultLocale never returns
576: // null, but in the Creator simulated environment it does,
577: // so we add belt and braces.
578: if (locale != null) {
579: if (DEBUG)
580: log("\tDefault locale is " + locale.toString());
581: localeSet.add(locale);
582: } else if (DEBUG)
583: log("\tNo default locale!");
584:
585: Iterator localeIterator = application.getSupportedLocales();
586: // Again, this should not be null, but we need to account for
587: // Creator...
588: if (localeIterator != null) {
589: while (localeIterator.hasNext()) {
590: Object localeObject = localeIterator.next();
591: if (DEBUG) {
592: log("\tAdding locale " + localeObject.toString());
593: }
594: localeSet.add(localeObject);
595: }
596: } else if (DEBUG)
597: log("\tNo supported locales!");
598:
599: // If things went wrong (= we're in Creator), add the default
600: // locale now
601: if (localeSet.isEmpty()) {
602: if (DEBUG) {
603: log("\tAdding default locale which is " + //NOI18N
604: Locale.getDefault().toString());
605: }
606: localeSet.add(Locale.getDefault());
607: }
608: return localeSet;
609: }
610:
611: private String missingResourceBundleMessage(
612: Attributes themeAttributes, String bundleName) {
613:
614: String propFile = themeAttributes.getValue(FILENAME);
615: StringBuffer msgBuffer = new StringBuffer(
616: "Invalid theme configuration file for theme ");
617: msgBuffer.append(themeAttributes.getValue(NAME));
618:
619: if (propFile != null) {
620: msgBuffer.append(" configured by property file ");
621: msgBuffer.append(propFile);
622: msgBuffer.append(".");
623: }
624: msgBuffer
625: .append("ThemeFactory could not locate resource bundle at ");
626: msgBuffer.append(bundleName);
627: msgBuffer.append(".");
628: return msgBuffer.toString();
629: }
630:
631: private static String processInitParameter(Object object) {
632:
633: if (object == null) {
634: return null;
635: }
636: String string = object.toString();
637: // Unfortunately, the Creator simulated environment returns an
638: // empty string instead of null when the init parameter does
639: // not exist
640: if (string.length() == 0) {
641: return null;
642: }
643: return string;
644: }
645:
646: private String getRequiredThemeVersion() {
647:
648: if (DEBUG)
649: log("getRequiredThemeVersion()");
650:
651: Enumeration manifests = getManifests();
652:
653: if (!manifests.hasMoreElements()) {
654: if (DEBUG)
655: log("\tNo manifests in the classpath!");
656: return null;
657: }
658:
659: URL url = null;
660: InputStream in = null;
661: Manifest manifest = null;
662: String themeVersion = null;
663:
664: while (themeVersion == null && manifests.hasMoreElements()) {
665:
666: url = (URL) (manifests.nextElement());
667: if (url.toString().indexOf("webui") == -1) {
668: continue;
669: }
670:
671: if (DEBUG)
672: log("\tNow processing " + url.toString());
673:
674: try {
675: in = url.openConnection().getInputStream();
676: manifest = new Manifest(in);
677: Attributes attr = manifest
678: .getAttributes(COMPONENTS_SECTION);
679: if (attr != null) {
680: themeVersion = attr
681: .getValue(THEME_VERSION_REQUIRED);
682: if (DEBUG)
683: log("\tFound attribute " + themeVersion);
684: }
685: } catch (IOException ioex) {
686: ioex.printStackTrace();
687: // do nothing
688: } finally {
689: try {
690: in.close();
691: } catch (Throwable t) {
692: }
693: }
694: }
695: return themeVersion;
696: }
697:
698: private Enumeration getManifests() {
699:
700: Enumeration manifests = null;
701: ClassLoader loader = ClassLoaderFinder
702: .getCurrentLoader(ThemeFactory.class);
703:
704: // Temporary workaround for a Creator issue; direct questions on this
705: // to tor.norbye@sun.com
706: if (Beans.isDesignTime() && loader instanceof URLClassLoader) {
707: // This is a temporary hack to limit our manifest search for themes
708: // to the URLs in the ClassLoader, if it's a URLClassLoader.
709: // This is necessary to get theme switching to work when there
710: // are multiple simultaneous open projects in Creator.
711: Vector v = new Vector();
712: URL[] urls = ((URLClassLoader) loader).getURLs();
713: for (int i = 0; i < urls.length; i++) {
714: URL url = urls[i];
715: try {
716: URL manifest = new URL(url, MANIFEST);
717: // See if the manifest file exists
718: InputStream is = manifest.openStream();
719: v.addElement(manifest);
720: is.close();
721: } catch (IOException ioe) {
722: // No such manifest, so don't add one to the vector
723: }
724: }
725: return v.elements();
726: }
727:
728: try {
729: manifests = loader.getResources(MANIFEST);
730: } catch (IOException ioex) {
731: if (DEBUG) {
732: log("\tIOException using the Context ClassLoader");
733: }
734: }
735: if (!manifests.hasMoreElements()) {
736: try {
737: manifests = loader.getResources(MANIFEST);
738: } catch (IOException ioex) {
739: if (DEBUG) {
740: log("\tIOException using ThemeFactory's ClassLoader");
741: }
742: }
743: }
744: return manifests;
745: }
746:
747: private static void log(String s) {
748: System.out.println("ThemeFactory::" + s);
749: }
750: }
|