001    /**
002     * <copyright> 
003     *
004     * Copyright (c) 2002-2007 IBM Corporation and others.
005     * All rights reserved.   This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors: 
011     *   IBM - Initial API and implementation
012     *
013     * </copyright>
014     *
015     * $Id: CommonPlugin.java,v 1.14 2009/10/20 09:50:21 emerks Exp $
016     */
017    package org.eclipse.emf.common;
018    
019    
020    import java.io.IOException;
021    import java.lang.reflect.Method;
022    import java.net.URL;
023    import java.text.Collator;
024    import java.util.Comparator;
025    import java.util.Locale;
026    
027    import org.eclipse.core.runtime.FileLocator;
028    import org.eclipse.core.runtime.Platform;
029    import org.eclipse.emf.common.util.ResourceLocator;
030    import org.eclipse.emf.common.util.URI;
031    import org.osgi.framework.Bundle;
032    
033    
034    /**
035     * The <b>Plugin</b> for the model EMF.Common library.
036     * EMF must run 
037     * within an Eclipse workbench,
038     * within a headless Eclipse workspace,
039     * or just stand-alone as part of some other application.
040     * To support this, all resource access should be directed to the resource locator,
041     * which can redirect the service as appropriate to the runtime.
042     * During stand-alone invocation no plugin initialization takes place.
043     * In this case, common.resources.jar must be on the CLASSPATH.
044     * @see #INSTANCE
045     */
046    public final class CommonPlugin extends EMFPlugin 
047    {
048      /**
049       * The singleton instance of the plugin.
050       */
051      public static final CommonPlugin INSTANCE = new CommonPlugin();
052    
053      /**
054       * The one instance of this class.
055       */
056      private static Implementation plugin;
057    
058      /**
059       * Creates the singleton instance.
060       */
061      private CommonPlugin()
062      {
063        super(new ResourceLocator[] {});
064      }
065    
066      @Override
067      public ResourceLocator getPluginResourceLocator()
068      {
069        return plugin;
070      }
071    
072      /**
073       * Returns the singleton instance of the Eclipse plugin.
074       * @return the singleton instance.
075       */
076      public static Implementation getPlugin()
077      {
078        return plugin;
079      }
080    
081      /**
082       * Use the platform, if available, to convert to a local URI.
083       */
084      public static URI asLocalURI(URI uri)
085      {
086        return plugin == null ? uri : Implementation.asLocalURI(uri);
087      }
088    
089      /**
090       * Use the platform, if available, to resolve the URI.
091       */
092      public static URI resolve(URI uri)
093      {
094        return plugin == null ? uri : Implementation.resolve(uri);
095      }
096    
097      /**
098       * Use the platform, if available, to load the named class using the right class loader.
099       */
100      public static Class<?> loadClass(String pluginID, String className) throws ClassNotFoundException
101      {
102        return plugin == null ? Class.forName(className) : Implementation.loadClass(pluginID, className);
103      }
104    
105      private static final Method COLLATOR_GET_INSTANCE_METHOD;
106      static
107      {
108        Method collatorGetInstanceMethod = null;
109        try
110        {
111          Class<?> collatorClass = loadClass("com.ibm.icu", "com.ibm.icu.text.Collator");
112          collatorGetInstanceMethod = collatorClass.getMethod("getInstance", Locale.class);
113        }
114        catch (Throwable throwable)
115        {
116          // Assume the class is not available.
117        }
118        COLLATOR_GET_INSTANCE_METHOD = collatorGetInstanceMethod;
119      }
120    
121      /**
122       * Returns a string comparator appropriate for collating strings for the {@link Locale#getDefault() current locale}.
123       * @return a string comparator appropriate for collating strings for the {@link Locale#getDefault() current locale}.
124       */
125      public Comparator<String> getComparator()
126      {
127        return getComparator(Locale.getDefault());
128      }
129    
130      /**
131       * Returns a string comparator appropriate for collating strings for the give locale.
132       * This will use ICU, when available that plugins is available, or {@link Collator} otherwise.
133       * @param locale the locale for which a comparator is needed.
134       * @return a string comparator appropriate for collating strings for the give locale.
135       */
136      @SuppressWarnings("unchecked")
137      public Comparator<String> getComparator(Locale locale)
138      {
139        if (COLLATOR_GET_INSTANCE_METHOD != null)
140        {
141          try
142          {
143            return (Comparator<String>)COLLATOR_GET_INSTANCE_METHOD.invoke(null, locale);
144          }
145          catch (Throwable eception)
146          {
147            // Just return the default.
148          }
149        }
150        return (Comparator<String>)(Comparator<?>)Collator.getInstance(locale);
151      }
152    
153      /**
154       * The actual implementation of the Eclipse <b>Plugin</b>.
155       */
156      public static class Implementation extends EclipsePlugin 
157      {
158        /**
159         * Creates an instance.
160         */
161        public Implementation()
162        {
163          super();
164    
165          // Remember the static instance.
166          //
167          plugin = this;
168        }
169    
170        /**
171         * Use the platform to convert to a local URI.
172         */
173        protected static URI asLocalURI(URI uri)
174        {
175          try
176          {
177            String fragment = uri.fragment();
178            URL url = FileLocator.toFileURL(new URL(uri.trimFragment().toString()));
179            return fix(url, fragment);
180          }
181          catch (IOException exception)
182          {
183            // Ignore the exception and return the original URI.
184          }
185          return uri;
186        }
187    
188        /**
189         * Use the platform to convert to a local URI.
190         */
191        protected static URI resolve(URI uri)
192        {
193          String fragment = uri.fragment();
194          URI uriWithoutFragment = uri.trimFragment();
195          String uriWithoutFragmentToString = uriWithoutFragment.toString();
196          
197          URL url = null;
198          try
199          {
200            url = FileLocator.resolve(new URL(uriWithoutFragmentToString));
201          }
202          catch (IOException exception1)
203          {
204            // Platform.resolve() doesn't work if the project is encoded.
205            //
206            try
207            {
208              uriWithoutFragmentToString = URI.decode(uriWithoutFragmentToString);
209              url = FileLocator.resolve(new URL(uriWithoutFragmentToString));
210            }
211            catch (IOException exception2)
212            {
213              // Continue with the unresolved URI.
214            }
215          }
216          if (url != null)
217          {
218            try
219            {
220              return fix(url, fragment);
221            }
222            catch (IOException exception)
223            {
224              // Return the original URI.
225            }
226          }
227          
228          return uri;
229        }
230    
231        protected static URI fix(URL url, String fragment) throws IOException
232        {
233          // Only file-scheme URIs will be re-encoded. If a URI was decoded in the workaround
234          // above, and Platform.resolve() didn't return a file-scheme URI, then this will return
235          // an decoded URI.
236          //
237          URI result = 
238            "file".equalsIgnoreCase(url.getProtocol()) ?
239              URI.createFileURI(URI.decode(url.getFile())) :
240              URI.createURI(url.toString());
241          if (fragment != null)
242          {
243            result = result.appendFragment(fragment);
244          }
245          return result;
246        }
247        
248        /**
249         * Use the platform to load the named class using the right class loader.
250         */
251        public static Class<?> loadClass(String pluginID, String className) throws ClassNotFoundException
252        {
253          Bundle bundle = Platform.getBundle(pluginID);
254          if (bundle == null)
255          {
256            throw new ClassNotFoundException(className + " cannot be loaded because because bundle " + pluginID + " cannot be resolved");
257          }
258          else
259          {
260            return bundle.loadClass(className);
261          }
262        }
263      }
264    }