| /* |
| * Copyright (c) 2007-2012 Eike Stepper (Berlin, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.net4j.internal.util.bundle; |
| |
| import org.eclipse.net4j.internal.util.om.pref.Preferences; |
| import org.eclipse.net4j.util.ReflectUtil; |
| import org.eclipse.net4j.util.io.IOUtil; |
| import org.eclipse.net4j.util.om.OMBundle; |
| import org.eclipse.net4j.util.om.OMPlatform; |
| import org.eclipse.net4j.util.om.log.Logger; |
| import org.eclipse.net4j.util.om.log.OMLogger; |
| import org.eclipse.net4j.util.om.trace.OMTracer; |
| import org.eclipse.net4j.util.om.trace.Tracer; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.text.MessageFormat; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.Properties; |
| import java.util.PropertyResourceBundle; |
| import java.util.ResourceBundle; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public abstract class AbstractBundle implements OMBundle, OMBundle.DebugSupport, OMBundle.TranslationSupport |
| { |
| private static final String CLASS_EXTENSION = ".class"; |
| |
| private AbstractPlatform platform; |
| |
| private String bundleID; |
| |
| private Class<?> accessor; |
| |
| private Object bundleContext; |
| |
| private boolean debugging; |
| |
| private boolean debuggingInitialized; |
| |
| private Map<String, Tracer> tracers = new ConcurrentHashMap<String, Tracer>(0); |
| |
| private OMLogger logger; |
| |
| private Preferences preferences; |
| |
| private ResourceBundle resourceBundle; |
| |
| private ResourceBundle untranslatedResourceBundle; |
| |
| private Map<String, String> strings = new HashMap<String, String>(0); |
| |
| private Map<String, String> untranslatedStrings = new HashMap<String, String>(0); |
| |
| private boolean shouldTranslate = true; |
| |
| public AbstractBundle(AbstractPlatform platform, String bundleID, Class<?> accessor) |
| { |
| this.platform = platform; |
| this.bundleID = bundleID; |
| this.accessor = accessor; |
| } |
| |
| public OMPlatform getPlatform() |
| { |
| return platform; |
| } |
| |
| public String getBundleID() |
| { |
| return bundleID; |
| } |
| |
| public Class<?> getAccessor() |
| { |
| return accessor; |
| } |
| |
| public Object getBundleContext() |
| { |
| return bundleContext; |
| } |
| |
| @Deprecated |
| public void setBundleContext(Object bundleContext) |
| { |
| this.bundleContext = bundleContext; |
| } |
| |
| public DebugSupport getDebugSupport() |
| { |
| return this; |
| } |
| |
| public TranslationSupport getTranslationSupport() |
| { |
| return this; |
| } |
| |
| public boolean isDebugging() |
| { |
| if (!platform.isDebugging()) |
| { |
| return false; |
| } |
| |
| if (!debuggingInitialized) |
| { |
| debugging = getDebugOption("debug", false); //$NON-NLS-1$ |
| debuggingInitialized = true; |
| } |
| |
| return debugging; |
| } |
| |
| public void setDebugging(boolean debugging) |
| { |
| this.debugging = debugging; |
| } |
| |
| public String getDebugOption(String option, String defaultValue) |
| { |
| String value = getDebugOption(option); |
| return value == null ? defaultValue : value; |
| } |
| |
| public boolean getDebugOption(String option, boolean defaultValue) |
| { |
| String value = getDebugOption(option); |
| return value == null ? defaultValue : Boolean.parseBoolean(value); |
| } |
| |
| public void setDebugOption(String option, boolean value) |
| { |
| setDebugOption(option, Boolean.toString(value)); |
| } |
| |
| public int getDebugOption(String option, int defaultValue) |
| { |
| try |
| { |
| String value = getDebugOption(option); |
| return value == null ? defaultValue : Integer.parseInt(value); |
| } |
| catch (NumberFormatException e) |
| { |
| return defaultValue; |
| } |
| } |
| |
| public void setDebugOption(String option, int value) |
| { |
| setDebugOption(option, Integer.toString(value)); |
| } |
| |
| public String getDebugOption(String option) |
| { |
| return platform.getDebugOption(bundleID, option); |
| } |
| |
| public void setDebugOption(String option, String value) |
| { |
| platform.setDebugOption(bundleID, option, value); |
| } |
| |
| public synchronized OMTracer tracer(String name) |
| { |
| OMTracer tracer = tracers.get(name); |
| if (tracer == null) |
| { |
| tracer = createTracer(name); |
| } |
| |
| return tracer; |
| } |
| |
| public synchronized OMLogger logger() |
| { |
| if (logger == null) |
| { |
| logger = createLogger(); |
| } |
| |
| return logger; |
| } |
| |
| public IStatus getStatus(Object obj) |
| { |
| if (obj instanceof CoreException) |
| { |
| CoreException coreException = (CoreException)obj; |
| return coreException.getStatus(); |
| } |
| |
| if (obj instanceof Throwable) |
| { |
| Throwable t = (Throwable)obj; |
| String msg = t.getLocalizedMessage(); |
| if (msg == null || msg.length() == 0) |
| { |
| msg = t.getClass().getName(); |
| } |
| |
| return new Status(IStatus.ERROR, getBundleID(), msg, t); |
| } |
| |
| return new Status(IStatus.INFO, getBundleID(), obj.toString(), null); |
| } |
| |
| public void coreException(Throwable t) throws CoreException |
| { |
| if (t instanceof CoreException) |
| { |
| CoreException ex = (CoreException)t; |
| IStatus status = ex.getStatus(); |
| if (status != null && status.getSeverity() == IStatus.CANCEL) |
| { |
| throw new OperationCanceledException(); |
| } |
| |
| throw ex; |
| } |
| |
| if (t instanceof OperationCanceledException) |
| { |
| throw (OperationCanceledException)t; |
| } |
| |
| if (t instanceof Error) |
| { |
| throw (Error)t; |
| } |
| |
| IStatus status = getStatus(t); |
| throw new CoreException(status); |
| } |
| |
| public File getConfigFile() |
| { |
| return platform.getConfigFile(getConfigFileName()); |
| } |
| |
| public Properties getConfigProperties() |
| { |
| return platform.getConfigProperties(getConfigFileName()); |
| } |
| |
| public synchronized Preferences preferences() |
| { |
| if (preferences == null) |
| { |
| preferences = new Preferences(this); |
| } |
| |
| return preferences; |
| } |
| |
| public InputStream getInputStream(String path) throws IOException |
| { |
| String base = getBaseURL().toString(); |
| if (!base.endsWith("/")) //$NON-NLS-1$ |
| { |
| base += "/"; //$NON-NLS-1$ |
| } |
| |
| if (path.startsWith("/")) //$NON-NLS-1$ |
| { |
| path = path.substring(1); |
| } |
| |
| URL url = new URL(base + path); |
| return url.openStream(); |
| } |
| |
| public boolean shouldTranslate() |
| { |
| return shouldTranslate; |
| } |
| |
| public void setShouldTranslate(boolean shouldTranslate) |
| { |
| this.shouldTranslate = shouldTranslate; |
| } |
| |
| public String getString(String key, boolean translate) |
| { |
| Map<String, String> stringMap = translate ? strings : untranslatedStrings; |
| String result = stringMap.get(key); |
| if (result == null) |
| { |
| ResourceBundle bundle = translate ? resourceBundle : untranslatedResourceBundle; |
| if (bundle == null) |
| { |
| String packageName = ReflectUtil.getPackageName(accessor); |
| if (translate) |
| { |
| try |
| { |
| bundle = resourceBundle = ResourceBundle.getBundle(packageName + ".plugin"); //$NON-NLS-1$ |
| } |
| 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. |
| InputStream inputStream = null; |
| try |
| { |
| inputStream = getInputStream("plugin.properties"); //$NON-NLS-1$ |
| bundle = new PropertyResourceBundle(inputStream); |
| untranslatedResourceBundle = resourceBundle = bundle; |
| inputStream.close(); |
| } |
| catch (IOException ignore) |
| { |
| } |
| finally |
| { |
| IOUtil.closeSilent(inputStream); |
| } |
| |
| if (resourceBundle == null) |
| { |
| throw exception; |
| } |
| } |
| } |
| else |
| { |
| InputStream inputStream = null; |
| |
| try |
| { |
| inputStream = getInputStream("plugin.properties"); //$NON-NLS-1$ |
| bundle = untranslatedResourceBundle = new PropertyResourceBundle(inputStream); |
| inputStream.close(); |
| } |
| catch (IOException ioException) |
| { |
| throw new MissingResourceException("Missing resource: plugin.properties", accessor //$NON-NLS-1$ |
| .getName(), key); |
| } |
| finally |
| { |
| IOUtil.closeSilent(inputStream); |
| } |
| } |
| } |
| |
| result = bundle.getString(key); |
| stringMap.put(key, result); |
| } |
| |
| return result; |
| } |
| |
| public String getString(String key) |
| { |
| return getString(key, shouldTranslate()); |
| } |
| |
| public String getString(String key, Object... args) |
| { |
| return getString(key, shouldTranslate(), args); |
| } |
| |
| public String getString(String key, boolean translate, Object... args) |
| { |
| return MessageFormat.format(getString(key, translate), args); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return bundleID; |
| } |
| |
| public void start() throws Exception |
| { |
| invokeMethod("start"); //$NON-NLS-1$ |
| } |
| |
| public void stop() throws Exception |
| { |
| try |
| { |
| if (preferences != null) |
| { |
| preferences.save(); |
| } |
| } |
| catch (RuntimeException ex) |
| { |
| OM.LOG.error(ex); |
| } |
| |
| invokeMethod("stop"); //$NON-NLS-1$ |
| } |
| |
| protected OMTracer createTracer(String name) |
| { |
| return new Tracer(this, name); |
| } |
| |
| protected OMLogger createLogger() |
| { |
| return new Logger(this); |
| } |
| |
| protected String getConfigFileName() |
| { |
| return bundleID + ".properties"; //$NON-NLS-1$ |
| } |
| |
| protected final Class<?> getClassFromBundle(String path) |
| { |
| if (path.endsWith(CLASS_EXTENSION)) |
| { |
| int start = path.startsWith("/") ? 1 : 0; |
| int end = path.length() - CLASS_EXTENSION.length(); |
| String className = path.substring(start, end).replace('/', '.'); |
| |
| for (;;) |
| { |
| try |
| { |
| ClassLoader classLoader = getAccessor().getClassLoader(); |
| Class<?> c = classLoader.loadClass(className); |
| if (c != null) |
| { |
| return c; |
| } |
| } |
| catch (NoClassDefFoundError ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| catch (ClassNotFoundException ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| |
| int dot = className.indexOf('.'); |
| if (dot == -1) |
| { |
| break; |
| } |
| |
| className = className.substring(dot + 1); |
| } |
| } |
| |
| return null; |
| } |
| |
| private void invokeMethod(String name) throws Exception |
| { |
| try |
| { |
| Method method = accessor.getDeclaredMethod(name, ReflectUtil.NO_PARAMETERS); |
| if (!method.isAccessible()) |
| { |
| method.setAccessible(true); |
| } |
| |
| method.invoke(null, ReflectUtil.NO_ARGUMENTS); |
| } |
| catch (NoSuchMethodException ignore) |
| { |
| } |
| catch (IllegalAccessException ignore) |
| { |
| } |
| catch (InvocationTargetException ex) |
| { |
| Throwable targetException = ex.getTargetException(); |
| if (targetException instanceof Exception) |
| { |
| throw (Exception)targetException; |
| } |
| else if (targetException instanceof Error) |
| { |
| throw (Error)targetException; |
| } |
| else |
| { |
| OM.LOG.error(targetException); |
| } |
| } |
| } |
| } |