KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > ecore > resource > impl > URIConverterImpl


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2002-2004 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: URIConverterImpl.java,v 1.6 2005/06/08 06:20:10 nickb Exp $
16  */

17 package org.eclipse.emf.ecore.resource.impl;
18
19
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.OutputStream JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.net.URLConnection JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import org.eclipse.core.resources.IContainer;
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IFolder;
35 import org.eclipse.core.resources.IResource;
36 import org.eclipse.core.resources.IWorkspaceRoot;
37 import org.eclipse.core.runtime.CoreException;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.Path;
40 import org.eclipse.emf.common.archive.ArchiveURLConnection;
41 import org.eclipse.emf.common.util.URI;
42 import org.eclipse.emf.ecore.plugin.EcorePlugin;
43 import org.eclipse.emf.ecore.resource.Resource;
44 import org.eclipse.emf.ecore.resource.URIConverter;
45
46
47 /**
48  * A highly functional and extensible URI converter implementation.
49  * <p>
50  * This implementation provides seamless transparent Eclipse integration
51  * by supporting the <code>platform:/resource</code> mechanism both inside of Eclipse and outside of Eclipse.
52  * Furthermore, although the implementation imports
53  * both {@link org.eclipse.core.runtime} and {@link org.eclipse.core.resources},
54  * and hence requires the Eclipse libraries at development time,
55  * the implementation does <b>not</b> require them at runtime.
56  * Clients of this implementation must be cautious if they wish to maintain this platform neutral behaviour.
57  * </p>
58  */

59 public class URIConverterImpl implements URIConverter
60 {
61   // ECLIPSE-DEPEND-BEGIN
62
/**
63    * An output stream that transfers its contents to an {@link IFile} upon closing.
64    */

65   public static class PlatformResourceOutputStream extends ByteArrayOutputStream JavaDoc
66   {
67     protected IFile file;
68     protected boolean force;
69     protected boolean keepHistory;
70     protected IProgressMonitor progressMonitor;
71     protected boolean previouslyFlushed;
72
73     public PlatformResourceOutputStream(IFile file, boolean force, boolean keepHistory, IProgressMonitor progressMonitor)
74     {
75       this.file = file;
76       this.force = force;
77       this.keepHistory = keepHistory;
78       this.progressMonitor = progressMonitor;
79     }
80
81     protected void createContainer(IContainer container) throws IOException JavaDoc
82     {
83       if (!container.exists())
84       {
85         if (container.getType() == IResource.FOLDER)
86         {
87           createContainer(container.getParent());
88           try
89           {
90             ((IFolder)container).create(force, keepHistory, progressMonitor);
91           }
92           catch (CoreException exception)
93           {
94             throw new ResourceImpl.IOWrappedException(exception);
95           }
96         }
97       }
98     }
99
100     public void close() throws IOException JavaDoc
101     {
102       flush();
103       super.close();
104     }
105
106     public void flush() throws IOException JavaDoc
107     {
108       super.flush();
109
110       if (previouslyFlushed)
111       {
112         if (count == 0)
113         {
114           return;
115         }
116       }
117       else
118       {
119         createContainer(file.getParent());
120       }
121
122       byte[] contents = toByteArray();
123       InputStream JavaDoc inputStream = new ByteArrayInputStream JavaDoc(contents, 0, contents.length);
124   
125       try
126       {
127         if (previouslyFlushed)
128         {
129           file.appendContents(inputStream, force, false, progressMonitor);
130         }
131         else if (!file.exists())
132         {
133           file.create(inputStream, false, null);
134           previouslyFlushed = true;
135         }
136         else
137         {
138           if (!file.isLocal(IResource.DEPTH_ONE) || !file.isSynchronized(IResource.DEPTH_ONE))
139           {
140             file.refreshLocal(IResource.DEPTH_ONE, progressMonitor);
141           }
142           file.setContents(inputStream, force, keepHistory, progressMonitor);
143           previouslyFlushed = true;
144         }
145         reset();
146       }
147       catch (CoreException exception)
148       {
149         throw new Resource.IOWrappedException(exception);
150       }
151     }
152   }
153
154   /**
155    * Isolated Eclipse workbench utilities.
156    */

157   public static class WorkbenchHelper
158   {
159     /**
160      * Creates an output stream for the given {@link IFile} path.
161      * <p>
162      * This implementation uses a {@link URIConverterImpl.PlatformResourceOutputStream}.
163      * </p>
164      * @return an open output stream.
165      * @exception IOException if there is a problem obtaining an open output stream.
166      * @see IWorkspaceRoot#getFile(org.eclipse.core.runtime.IPath)
167      * @see URIConverterImpl.PlatformResourceOutputStream
168      * @see IFile#setContents(InputStream, boolean, boolean, IProgressMonitor)
169      */

170     public static OutputStream JavaDoc createPlatformResourceOutputStream(String JavaDoc platformResourcePath) throws IOException JavaDoc
171     {
172       IFile file = workspaceRoot.getFile(new Path(platformResourcePath));
173       return new PlatformResourceOutputStream(file, false, true, null);
174     }
175
176     /**
177      * Creates an input stream for the given {@link IFile} path.
178      * <p>
179      * This implementation uses {@link IFile#getContents IFile.getContents}.
180      * </p>
181      * @return an open input stream.
182      * @see IWorkspaceRoot#getFile(org.eclipse.core.runtime.IPath)
183      * @see IFile#getContents
184      * @exception IOException if there is a problem obtaining an open input stream.
185      */

186     public static InputStream JavaDoc createPlatformResourceInputStream(String JavaDoc platformResourcePath) throws IOException JavaDoc
187     {
188       IFile file = workspaceRoot.getFile(new Path(platformResourcePath));
189       try
190       {
191         if (!file.isLocal(IResource.DEPTH_ONE) || !file.isSynchronized(IResource.DEPTH_ONE))
192         {
193           file.refreshLocal(IResource.DEPTH_ONE, null);
194         }
195         return file.getContents();
196       }
197       catch (CoreException exception)
198       {
199         throw new Resource.IOWrappedException(exception);
200       }
201     }
202   }
203
204   /**
205    * The cached Eclipse workspace.
206    */

207   protected static IWorkspaceRoot workspaceRoot = EcorePlugin.getWorkspaceRoot();
208
209   // ECLIPSE-DEPEND-END
210

211   /**
212    * A map that remaps URIs.
213    */

214   public interface URIMap extends Map JavaDoc
215   {
216     /**
217      * Returns the remapped URI, or the URI itself.
218      * @param uri the URI to remap.
219      * @return the remapped URI, or the URI itself.
220      */

221     URI getURI(URI uri);
222   }
223
224   /**
225    * The URI map.
226    */

227   protected URIMap uriMap;
228
229   /**
230    * Creates an instance.
231    */

232   public URIConverterImpl()
233   {
234     // This is a hacky way to test stand-alone platform:/resource support in what's really an headless environment.
235
//
236
// org.eclipse.core.resources.IProject [] projects = workspaceRoot.getProjects();
237
// for (int i = 0; i < projects.length; ++i)
238
// {
239
// String rootContainerName = projects[i].getName();
240
// URI rootContainerLocation = URI.createFileURI(projects[i].getLocation().toString() + "/");
241
// platformResourceMap.put(rootContainerName, rootContainerLocation);
242
// }
243
//
244
// workspaceRoot = null;
245
}
246   
247   /**
248    * Returns whether the scheme is one that this implementation should treat as an archive.
249    * This implementation returns <code>true</code> which the schem is <code>"archive"</code>.
250    * @param scheme the scheme to consider.
251    * @return whether the scheme is one that this implementation treats as an archive.
252    */

253   protected boolean isArchiveScheme(String JavaDoc scheme)
254   {
255     return "archive".equals(scheme);
256   }
257
258   /**
259    * Creates an output stream for the URI and returns it.
260    * <p>
261    * This implementation {@link #normalize normalizes} the URI and uses that as the basis for further processing.
262    * It factors out the URI schemes <code>file</code> and <code>platform</code> (with leading <code>resource</code> segment)
263    * for special processing by
264    * {@link #createFileOutputStream createFileOutputStream} and
265    * {@link #createPlatformResourceOutputStream createPlatformResourceOutputStream}, respectively.
266    * The file-based URI is {@link URI#toFileString converted} to a file path, e.g.,
267    *<pre>
268    * file:///C:/directory/file
269    * ->
270    * C:/directory/file
271    *</pre>
272    * and the platform-based URI is converted to a platform path by trimming the leading <code>platform:/resource</code>, e.g.,
273    *<pre>
274    * platform:/resource/project/directory/file
275    * ->
276    * /project/directory/file
277    *</pre>
278    * All other cases are handled as standard URLs by {@link #createURLOutputStream createURLOutputStream}.
279    * </p>
280    * @return an open output stream.
281    * @exception IOException if there is a problem obtaining an open output stream.
282    */

283   public OutputStream JavaDoc createOutputStream(URI uri) throws IOException JavaDoc
284   {
285     URI converted = normalize(uri);
286     if (converted.isFile())
287     {
288       String JavaDoc filePath = converted.toFileString();
289       return createFileOutputStream(filePath);
290     }
291     else
292     {
293       String JavaDoc scheme = converted.scheme();
294       if (isArchiveScheme(scheme))
295       {
296         return createArchiveOutputStream(converted);
297       }
298       else if ("platform".equals(scheme) && converted.segmentCount() > 1 && "resource".equals(converted.segment(0)))
299       {
300         StringBuffer JavaDoc platformResourcePath = new StringBuffer JavaDoc();
301         for (int i = 1, size = converted.segmentCount(); i < size; ++i)
302         {
303           platformResourcePath.append('/');
304           platformResourcePath.append(URI.decode(converted.segment(i)));
305         }
306         return createPlatformResourceOutputStream(platformResourcePath.toString());
307       }
308       else
309       {
310         return createURLOutputStream(converted);
311       }
312     }
313   }
314
315   /**
316    * Creates an output stream for the file path and returns it.
317    * <p>
318    * This implementation allocates a {@link FileOutputStream} and creates subdirectories as necessary.
319    * </p>
320    * @return an open output stream.
321    * @exception IOException if there is a problem obtaining an open output stream.
322    */

323   protected OutputStream JavaDoc createFileOutputStream(String JavaDoc filePath) throws IOException JavaDoc
324   {
325     File JavaDoc file = new File JavaDoc(filePath);
326     String JavaDoc parent = file.getParent();
327     if (parent != null)
328     {
329       new File JavaDoc(parent).mkdirs();
330     }
331     OutputStream JavaDoc outputStream = new FileOutputStream JavaDoc(file);
332     return outputStream;
333   }
334   
335   /**
336    * Creates an output stream for the archive access.
337    * </p>
338    * @return an open output stream.
339    * @exception IOException if there is a problem obtaining an open output stream.
340    */

341   protected OutputStream JavaDoc createArchiveOutputStream(URI archiveURI) throws IOException JavaDoc
342   {
343     return createArchive(archiveURI).getOutputStream();
344   }
345
346   /**
347    * Creates an output stream for the platform resource path and returns it.
348    * <p>
349    * This implementation does one of two things, depending on the runtime environment.
350    * If there is an Eclipse workspace, it delegates to
351    * {@link WorkbenchHelper#createPlatformResourceOutputStream WorkbenchHelper.createPlatformResourceOutputStream},
352    * which gives the expected Eclipse behaviour.
353    * Otherwise, the {@link EcorePlugin#resolvePlatformResourcePath resolved} URI
354    * is delegated to {@link #createOutputStream createOutputStream}
355    * for recursive processing.
356    * @return an open output stream.
357    * @exception IOException if there is a problem obtaining an open output stream or a valid interpretation of the path.
358    * @see EcorePlugin#resolvePlatformResourcePath(String)
359    */

360   protected OutputStream JavaDoc createPlatformResourceOutputStream(String JavaDoc platformResourcePath) throws IOException JavaDoc
361   {
362     // ECLIPSE-DEPEND-BEGIN
363
if (workspaceRoot != null)
364     {
365       return WorkbenchHelper.createPlatformResourceOutputStream(platformResourcePath);
366     }
367     else
368     // ECLIPSE-DEPEND-END
369
{
370       URI resolvedLocation = EcorePlugin.resolvePlatformResourcePath(platformResourcePath);
371       if (resolvedLocation != null)
372       {
373         return createOutputStream(resolvedLocation);
374       }
375
376       throw new IOException JavaDoc("The path '" + platformResourcePath + "' is unmapped");
377     }
378   }
379
380   /**
381    * Creates an output stream for the URI, assuming it's a URL, and returns it.
382    * @return an open output stream.
383    * @exception IOException if there is a problem obtaining an open output stream.
384    */

385   protected OutputStream JavaDoc createURLOutputStream(URI uri) throws IOException JavaDoc
386   {
387     URL JavaDoc url = new URL JavaDoc(uri.toString());
388     URLConnection JavaDoc urlConnection = url.openConnection();
389     urlConnection.setDoOutput(true);
390     return urlConnection.getOutputStream();
391   }
392
393   /**
394    * Creates an input stream for the URI and returns it.
395    * <p>
396    * This implementation {@link #normalize normalizes} the URI and uses that as the basis for further processing.
397    * It factors out the URI schemes <code>file</code> and <code>platform</code> (with leading <code>resource</code> segment)
398    * for special processing by
399    * {@link #createFileInputStream createFileInputStream} and
400    * {@link #createPlatformResourceInputStream createPlatformResourceInputStream}, respectively.
401    * The file-based URI is {@link URI#toFileString converted} to a file path, e.g.,
402    *<pre>
403    * file:///C:/directory/file
404    * ->
405    * C:/directory/file
406    *</pre>
407    * and the platform-based URI is converted to a platform path by trimming the leading <code>platform:/resource</code>, e.g.,
408    *<pre>
409    * platform:/resource/project/directory/file
410    * ->
411    * /project/directory/file
412    *</pre>
413    * All other cases are handled as standard URLs by {@link #createURLInputStream createURLInputStream}.
414    * </p>
415    * @return an open Input stream.
416    * @exception IOException if there is a problem obtaining an open input stream.
417    */

418   public InputStream JavaDoc createInputStream(URI uri) throws IOException JavaDoc
419   {
420     URI converted = normalize(uri);
421     if (converted.isFile())
422     {
423       String JavaDoc filePath = converted.toFileString();
424       return createFileInputStream(filePath);
425     }
426     else
427     {
428       String JavaDoc scheme = converted.scheme();
429       if (isArchiveScheme(scheme))
430       {
431         return createArchiveInputStream(converted);
432       }
433       else if ("platform".equals(scheme) && converted.segmentCount() > 1 && "resource".equals(converted.segment(0)))
434       {
435         
436         StringBuffer JavaDoc platformResourcePath = new StringBuffer JavaDoc();
437         for (int i = 1, size = converted.segmentCount(); i < size; ++i)
438         {
439           platformResourcePath.append('/');
440           platformResourcePath.append(URI.decode(converted.segment(i)));
441         }
442         return createPlatformResourceInputStream(platformResourcePath.toString());
443       }
444       else
445       {
446         return createURLInputStream(converted);
447       }
448     }
449   }
450
451   /**
452    * Creates an input stream for the file path and returns it.
453    * <p>
454    * This implementation allocates a {@link FileInputStream}.
455    * </p>
456    * @return an open input stream.
457    * @exception IOException if there is a problem obtaining an open input stream.
458    */

459   protected InputStream JavaDoc createFileInputStream(String JavaDoc filePath) throws IOException JavaDoc
460   {
461     File JavaDoc file = new File JavaDoc(filePath);
462     InputStream JavaDoc inputStream = new FileInputStream JavaDoc(file);
463     return inputStream;
464   }
465   
466   /**
467    * A specialized class for reading from an archive.
468    */

469   protected class Archive extends ArchiveURLConnection
470   {
471     public Archive(URI uri)
472     {
473       super(uri.toString());
474     }
475     
476     protected boolean emulateArchiveScheme()
477     {
478       return false;
479     }
480     
481     protected boolean useZipFile()
482     {
483       return true;
484     }
485     
486     protected InputStream JavaDoc createInputStream(String JavaDoc nestedURL) throws IOException JavaDoc
487     {
488       return URIConverterImpl.this.createInputStream(URI.createURI(nestedURL));
489     }
490     
491     protected OutputStream JavaDoc createOutputStream(String JavaDoc nestedURL) throws IOException JavaDoc
492     {
493       return URIConverterImpl.this.createOutputStream(URI.createURI(nestedURL));
494     }
495   }
496   
497   protected Archive createArchive(URI uri)
498   {
499     return new Archive(uri);
500   }
501   
502   /**
503    * Creates an input stream for the archive paths and returns it.
504    * It uses {@link ArchiveReader} to implement read access.
505    * </p>
506    * @return an open input stream.
507    * @exception IOException if there is a problem obtaining an open input stream.
508    */

509   protected InputStream JavaDoc createArchiveInputStream(URI archiveURI) throws IOException JavaDoc
510   {
511     return createArchive(archiveURI).getInputStream();
512   }
513
514   /**
515    * Creates an input stream for the platform resource path and returns it.
516    * <p>
517    * This implementation does one of two things, depending on the runtime environment.
518    * If there is an Eclipse workspace, it delegates to
519    * {@link WorkbenchHelper#createPlatformResourceInputStream WorkbenchHelper.createPlatformResourceInputStream},
520    * which gives the expected Eclipse behaviour.
521    * Otherwise, the {@link EcorePlugin#resolvePlatformResourcePath resolved} URI
522    * is delegated to {@link #createInputStream createInputStream}
523    * for recursive processing.
524    * @return an open input stream.
525    * @exception IOException if there is a problem obtaining an open input stream or a valid interpretation of the path.
526    * @see EcorePlugin#resolvePlatformResourcePath(String)
527    */

528   protected InputStream JavaDoc createPlatformResourceInputStream(String JavaDoc platformResourcePath) throws IOException JavaDoc
529   {
530     // ECLIPSE-DEPEND-BEGIN
531
if (workspaceRoot != null)
532     {
533       return WorkbenchHelper.createPlatformResourceInputStream(platformResourcePath);
534     }
535     else
536     // ECLIPSE-DEPEND-END
537
{
538       URI resolvedLocation = EcorePlugin.resolvePlatformResourcePath(platformResourcePath);
539       if (resolvedLocation != null)
540       {
541         return createInputStream(resolvedLocation);
542       }
543
544       throw new IOException JavaDoc("The path '" + platformResourcePath + "' is unmapped");
545     }
546   }
547
548   /**
549    * Creates an input stream for the URI, assuming it's a URL, and returns it.
550    * @return an open input stream.
551    * @exception IOException if there is a problem obtaining an open input stream.
552    */

553   protected InputStream JavaDoc createURLInputStream(URI uri) throws IOException JavaDoc
554   {
555     URL JavaDoc url = new URL JavaDoc(uri.toString());
556     URLConnection JavaDoc urlConnection = url.openConnection();
557     return urlConnection.getInputStream();
558   }
559
560   /**
561    * Returns the normalized form of the URI.
562    * <p>
563    * This implementation does precisely and only the {@link URIConverter#normalize typical} thing.
564    * It calls itself recursively so that mapped chains are followed.
565    * </p>
566    * @param uri the URI to normalize.
567    * @return the normalized form.
568    * @see org.eclipse.emf.ecore.plugin.EcorePlugin#getPlatformResourceMap
569    */

570   public URI normalize(URI uri)
571   {
572     String JavaDoc fragment = uri.fragment();
573     URI result =
574       fragment == null ?
575         getInternalURIMap().getURI(uri) :
576         getInternalURIMap().getURI(uri.trimFragment()).appendFragment(fragment);
577     String JavaDoc scheme = result.scheme();
578     if (scheme == null)
579     {
580       // ECLIPSE-DEPEND-BEGIN
581
if (workspaceRoot != null)
582       {
583         if (result.hasAbsolutePath())
584         {
585           result = URI.createPlatformResourceURI(result.trimFragment().toString());
586           if (fragment != null)
587           {
588             result = result.appendFragment(fragment);
589           }
590         }
591       }
592       else
593       // ECLIPSE-DEPEND-END
594
{
595         if (result.hasAbsolutePath())
596         {
597           result = URI.createURI("file:" + result);
598         }
599         else
600         {
601           result = URI.createFileURI(new File JavaDoc(result.trimFragment().toString()).getAbsolutePath());
602           if (fragment != null)
603           {
604             result = result.appendFragment(fragment);
605           }
606         }
607       }
608     }
609
610     if (result.equals(uri))
611     {
612       return uri;
613     }
614     else
615     {
616       return normalize(result);
617     }
618   }
619
620   /*
621    * Javadoc copied from interface.
622    */

623   public Map JavaDoc getURIMap()
624   {
625     return getInternalURIMap();
626   }
627
628   /**
629    * Returns the internal version of the URI map.
630    * @return the internal version of the URI map.
631    */

632   protected URIMap getInternalURIMap()
633   {
634     if (uriMap == null)
635     {
636       URIMappingRegistryImpl mappingRegistryImpl =
637         new URIMappingRegistryImpl()
638         {
639           protected URI delegatedGetURI(URI uri)
640           {
641             return URIMappingRegistryImpl.INSTANCE.getURI(uri);
642           }
643         };
644
645       uriMap = (URIMap)mappingRegistryImpl.map();
646     }
647
648     return uriMap;
649   }
650 }
651
Popular Tags