/** * <copyright> * * Copyright (c) 2002, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM - Initial API and implementation * * </copyright> * * $Id: DelegatingResourceLocator.java,v 1.3 2008/04/22 13:35:46 emerks Exp $ */ package net.enilink.komma.common.util; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import net.enilink.komma.common.CommonPlugin; import net.enilink.komma.core.URI; import net.enilink.komma.core.URIs; /** * An abstract resource locator implementation comprising a * {@link #getPrimaryResourceLocator() primary locator} and a series * {@link #getDelegateResourceLocators() delegate locators}. */ public abstract class DelegatingResourceLocator implements IResourceLocator { /** * The cached base URL. */ protected URL baseURL; /** * The resource bundle containing untranslated strings. */ protected ResourceBundle untranslatedResourceBundle; /** * The resource bundle containing translated strings. */ protected ResourceBundle resourceBundle; /** * A cache of the translated strings. */ protected Map<String, String> strings = new HashMap<String, String>(); /** * A cache of the untranslated strings. */ protected Map<String, String> untranslatedStrings = new HashMap<String, String>(); /** * A cache of the image descriptions. */ protected Map<String, Object> images = new HashMap<String, Object>(); /** * Whether to translate strings by default. */ protected boolean shouldTranslate = true; /** * Creates an instance. */ public DelegatingResourceLocator() { super(); } /** * Returns the primary resource locator. * * @return the primary resource locator. */ protected abstract IResourceLocator getPrimaryResourceLocator(); /** * Returns the delegate resource locators. * * @return the delegate resource locators. */ protected abstract IResourceLocator[] getDelegateResourceLocators(); private static final URI DOT = URIs.createURI("."); /* * Javadoc copied from interface. */ public URL getBaseURL() { if (baseURL == null) { if (getPrimaryResourceLocator() == null) { try { // Determine the base URL by looking for the // plugin.properties file in the standard way. // Class<? extends DelegatingResourceLocator> theClass = getClass(); URL pluginPropertiesURL = theClass .getResource("plugin.properties"); if (pluginPropertiesURL == null) { // If that fails, determine the URL for the class // itself. // The URL will be of one of the following forms, // so there are a few good places to consider looking // for the plugin.properties. // // For a plugin.xml with runtime="common.jar": // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/common.jar!/org/eclipse/common/CommonPlugin.class // // For a plugin.xml with runtime="runtime/common.jar": // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/runtime/common.jar!/org/eclipse/common/CommonPlugin.class // // For a plugin.xml with runtime="." where the plugin is // jarred: // jar:file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common.jar!/org/eclipse/common/CommonPlugin.class // // For a plugin.xml with runtime="." where the plugin is // not jarred. // file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/org/eclipse/emf/common/CommonPlugin.class // // Running in PDE with bin on classpath: // file:/D:/sandbox/unpackage1-3.1M7/eclipse/plugins/org.eclipse.emf.common/bin/org/eclipse/emf/common/CommonPlugin.class // String className = theClass.getName(); int index = className.lastIndexOf("."); URL classURL = theClass .getResource((index == -1 ? className : className.substring(index + 1)) + ".class"); URI uri = URIs.createURI(classURL.toString()); // Trim off the segments corresponding to the package // nesting. // int count = 1; for (int i = 0; (i = className.indexOf('.', i)) != -1; ++i) { ++count; } uri = uri.trimSegments(count); // For an archive URI, check for the plugin.properties // in the archive. // if (URIs.isArchiveScheme(uri.scheme())) { try { // If we can open an input stream, then the // plugin.properties is there, and we have a // good base URL. // InputStream inputStream = new URL(uri .appendSegment("plugin.properties") .toString()).openStream(); inputStream.close(); baseURL = new URL(uri.toString()); } catch (IOException exception) { // If the plugin.properties isn't within the // root of the archive, // create a new URI for the folder location of // the archive, // so we can look in the folder that contains // it. // uri = URIs.createURI(uri.authority()) .trimSegments(1); } } // If we didn't find the plugin.properties in the usual // place nor in the archive... // if (baseURL == null) { // Trim off the "bin" or "runtime" segment. // String lastSegment = uri.lastSegment(); if ("bin".equals(lastSegment) || "runtime".equals(lastSegment)) { uri = uri.trimSegments(1); } uri = uri.appendSegment("plugin.properties"); try { // If we can open an input stream, then the // plugin.properties is in the folder, and we // have a good base URL. // InputStream inputStream = new URL( uri.toString()).openStream(); inputStream.close(); baseURL = new URL(DOT.resolve(uri).toString()); } catch (IOException exception) { // Continue with the established base URL. } } // If we still don't have a good base URL, complain // about it. // if (baseURL == null) { String resourceName = index == -1 ? "plugin.properties" : className.substring(0, index + 1) .replace('.', '/') + "plugin.properties"; throw new MissingResourceException( "Missing properties: " + resourceName, theClass.getName(), "plugin.properties"); } } else { baseURL = new URL(DOT.resolve( URIs.createURI(pluginPropertiesURL.toString())) .toString()); } } catch (IOException exception) { throw new WrappedException(exception); } } else { baseURL = getPrimaryResourceLocator().getBaseURL(); } } return baseURL; } /* * Javadoc copied from interface. */ public Object getImage(String key) { Object result = images.get(key); if (result == null) { IResourceLocator pluginResourceLocator = getPrimaryResourceLocator(); if (pluginResourceLocator == null) { try { result = doGetImage(key); } catch (MalformedURLException exception) { throw new WrappedException(exception); } catch (IOException exception) { result = delegatedGetImage(key); } } else { try { result = pluginResourceLocator.getImage(key); } catch (MissingResourceException exception) { result = delegatedGetImage(key); } } images.put(key, result); } return result; } /** * Does the work of fetching the image associated with the key. It ensures * that the image exists. * * @param key * the key of the image to fetch. * @exception IOException * if an image doesn't exist. * @return the description of the image associated with the key. */ protected Object doGetImage(String key) throws IOException { URL url = new URL(getBaseURL() + "icons/" + key + extensionFor(key)); InputStream inputStream = url.openStream(); inputStream.close(); return url; } /** * Computes the file extension to be used with the key to specify an image * resource. * * @param key * the key for the imagine. * @return the file extension to be used with the key to specify an image * resource. */ protected static String extensionFor(String key) { String result = ".gif"; int index = key.lastIndexOf('.'); if (index != -1) { String extension = key.substring(index + 1); if ("png".equalsIgnoreCase(extension) || "gif".equalsIgnoreCase(extension) || "bmp".equalsIgnoreCase(extension) || "ico".equalsIgnoreCase(extension) || "jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension) || "tif".equalsIgnoreCase(extension) || "tiff".equalsIgnoreCase(extension)) { result = ""; } } return result; } /** * Does the work of fetching the image associated with the key, when the * image resource is not available locally. * * @param key * the key of the image to fetch. * @exception MissingResourceException * if the image resource doesn't exist anywhere. * @see #getDelegateResourceLocators() */ protected Object delegatedGetImage(String key) throws MissingResourceException { IResourceLocator[] delegateResourceLocators = getDelegateResourceLocators(); for (int i = 0; i < delegateResourceLocators.length; ++i) { try { return delegateResourceLocators[i].getImage(key); } catch (MissingResourceException exception) { // Ignore the exception since we will throw one when all else // fails. } } throw new MissingResourceException(CommonPlugin.INSTANCE.getString( "_UI_ImageResourceNotFound_exception", new Object[] { key }), getClass().getName(), key); } /** * Indicates whether strings should be translated by default. * * @return <code>true</code> if strings should be translated by default; * <code>false</code> otherwise. */ public boolean shouldTranslate() { return shouldTranslate; } /** * Sets whether strings should be translated by default. * * @param shouldTranslate * whether strings should be translated by default. */ public void setShouldTranslate(boolean shouldTranslate) { this.shouldTranslate = shouldTranslate; } /* * Javadoc copied from interface. */ public String getString(String key) { return getString(key, shouldTranslate()); } /* * Javadoc copied from interface. */ public String getString(String key, boolean translate) { Map<String, String> stringMap = translate ? strings : untranslatedStrings; String result = stringMap.get(key); if (result == null) { try { IResourceLocator pluginResourceLocator = getPrimaryResourceLocator(); if (pluginResourceLocator == null) { result = doGetString(key, translate); } else { result = pluginResourceLocator.getString(key, translate); } } catch (MissingResourceException exception) { result = delegatedGetString(key, translate); } stringMap.put(key, result); } return result; } /** * Does the work of fetching the string associated with the key. It ensures * that the string exists. * * @param key * the key of the string to fetch. * @exception MissingResourceException * if a string doesn't exist. * @return the string associated with the key. */ protected String doGetString(String key, boolean translate) throws MissingResourceException { ResourceBundle bundle = translate ? resourceBundle : untranslatedResourceBundle; if (bundle == null) { String packageName = getClass().getName(); int index = packageName.lastIndexOf("."); if (index != -1) { packageName = packageName.substring(0, index); } if (translate) { try { bundle = resourceBundle = ResourceBundle .getBundle(packageName + ".plugin"); } catch (MissingResourceException exception) { // If the bundle can't be found the normal way, try to find // it as the base URL. // If that also doesn't work, rethrow the original // exception. // try { InputStream inputStream = new URL(getBaseURL() .toString() + "plugin.properties").openStream(); bundle = untranslatedResourceBundle = resourceBundle = new PropertyResourceBundle( inputStream); inputStream.close(); } catch (IOException ioException) { // We'll rethrow the original exception, not this one. } if (bundle == null) { throw exception; } } } else { String resourceName = getBaseURL().toString() + "plugin.properties"; try { InputStream inputStream = new URL(resourceName) .openStream(); bundle = untranslatedResourceBundle = new PropertyResourceBundle( inputStream); inputStream.close(); } catch (IOException ioException) { throw new MissingResourceException("Missing properties: " + resourceName, getClass().getName(), "plugin.properties"); } } } return bundle.getString(key); } /** * Does the work of fetching the string associated with the key, when the * string resource is not available locally. * * @param key * the key of the string to fetch. * @exception MissingResourceException * if the string resource doesn't exist anywhere. * @see #getDelegateResourceLocators() */ protected String delegatedGetString(String key, boolean translate) { IResourceLocator[] delegateResourceLocators = getDelegateResourceLocators(); for (int i = 0; i < delegateResourceLocators.length; ++i) { try { return delegateResourceLocators[i].getString(key, translate); } catch (MissingResourceException exception) { // Ignore this since we will throw an exception when all else // fails. } } throw new MissingResourceException(MessageFormat.format( "The string resource ''{0}'' could not be located", new Object[] { key }), getClass().getName(), key); } /* * Javadoc copied from interface. */ public String getString(String key, Object... substitutions) { return getString(key, substitutions, shouldTranslate()); } /* * Javadoc copied from interface. */ public String getString(String key, Object[] substitutions, boolean translate) { return MessageFormat.format(getString(key, translate), substitutions); } }