/**
* Copyright (c) 2002-2007 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
*/
package org.eclipse.emf.ecore.resource.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.archive.ArchiveURLConnection;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
/**
* A highly functional and extensible URI converter implementation.
* <p>
* This implementation provides seamless transparent Eclipse integration
* by supporting the <code>platform:/resource</code> mechanism both inside of Eclipse and outside of Eclipse.
* Furthermore, although the implementation imports
* both {@link org.eclipse.core.runtime} and {@link org.eclipse.core.resources},
* and hence requires the Eclipse libraries at development time,
* the implementation does <b>not</b> require them at runtime.
* Clients of this implementation must be cautious if they wish to maintain this platform neutral behaviour.
* </p>
* @deprecated since 2.4; use {@link ExtensibleURIConverterImpl} instead.
*/
@Deprecated
public class URIConverterImpl extends ExtensibleURIConverterImpl
{
/**
* An output stream that transfers its contents to an {@link IFile} upon closing.
* @deprecated @since 2.4; use {@link PlatformResourceURIHandlerImpl.PlatformResourceOutputStream} directly.
*/
@Deprecated
public static class PlatformResourceOutputStream extends PlatformResourceURIHandlerImpl.PlatformResourceOutputStream
{
/**
* @deprecated since 2.4; use {@link PlatformResourceURIHandlerImpl.PlatformResourceOutputStream#PlatformResourceOutputStream(IFile, boolean, boolean, IProgressMonitor)} instead.
*/
@Deprecated
public PlatformResourceOutputStream(IFile file, boolean force, boolean keepHistory, IProgressMonitor progressMonitor)
{
super(file, force, keepHistory, progressMonitor);
}
}
/**
* Isolated Eclipse workbench utilities.
* @deprecated since 2.4; use {@link PlatformResourceURIHandlerImpl.WorkbenchHelper} directly.
*/
@Deprecated
public static class WorkbenchHelper extends PlatformResourceURIHandlerImpl.WorkbenchHelper
{
/**
* Creates an output stream for the given {@link IFile} path.
* <p>
* This implementation uses a {@link PlatformResourceURIHandlerImpl.PlatformResourceOutputStream}.
* </p>
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
* @see IWorkspaceRoot#getFile(org.eclipse.core.runtime.IPath)
* @see PlatformResourceURIHandlerImpl.PlatformResourceOutputStream
* @see IFile#setContents(InputStream, boolean, boolean, IProgressMonitor)
* @deprecated since 2.4; use {@link PlatformResourceURIHandlerImpl.WorkbenchHelper#createPlatformResourceOutputStream(String, Map)} directly.
*/
@Deprecated
public static OutputStream createPlatformResourceOutputStream(String platformResourcePath) throws IOException
{
return PlatformResourceURIHandlerImpl.WorkbenchHelper.createPlatformResourceOutputStream(platformResourcePath, null);
}
/**
* Creates an input stream for the given {@link IFile} path.
* <p>
* This implementation uses {@link IFile#getContents() IFile.getContents}.
* </p>
* @return an open input stream.
* @see IWorkspaceRoot#getFile(org.eclipse.core.runtime.IPath)
* @see IFile#getContents()
* @exception IOException if there is a problem obtaining an open input stream.
* @deprecated since 2.4; use {@link PlatformResourceURIHandlerImpl.WorkbenchHelper#createPlatformResourceInputStream(String, Map)} directly.
*/
@Deprecated
public static InputStream createPlatformResourceInputStream(String platformResourcePath) throws IOException
{
return PlatformResourceURIHandlerImpl.WorkbenchHelper.createPlatformResourceInputStream(platformResourcePath, null);
}
}
/**
* The cached Eclipse workspace.
* @deprecated
*/
@Deprecated
protected static IWorkspaceRoot workspaceRoot = EcorePlugin.getWorkspaceRoot();
private static Map<String, Boolean> efsScheme;
private static final Method EFS_GET_FILE_SYSTEM_METHOD;
private static final Method EFS_GET_STORE_METHOD;
private static final Method FILE_STORE_OPEN_INPUT_STREAM_METHOD;
private static final Method FILE_STORE_OPEN_OUTPUT_STREAM_METHOD;
static
{
Method efsGetStoreMethod = null;
Method efsGetFileSystemMethod = null;
Method fileStoreOpenInputStreamMethod = null;
Method fileStoreOpenOutputStreamMethod = null;
try
{
Class <?> efsClass = CommonPlugin.loadClass("org.eclipse.core.filesystem", "org.eclipse.core.filesystem.EFS");
efsGetStoreMethod = efsClass.getMethod("getStore", java.net.URI.class);
efsGetFileSystemMethod = efsClass.getMethod("getFileSystem", String.class);
Class <?> fileStoreClass = efsGetStoreMethod.getReturnType();
fileStoreOpenInputStreamMethod = fileStoreClass.getMethod("openInputStream", Integer.TYPE, IProgressMonitor.class);
fileStoreOpenOutputStreamMethod = fileStoreClass.getMethod("openOutputStream", Integer.TYPE, IProgressMonitor.class);
}
catch (Throwable exeption)
{
// Ignore any exceptions and assume the class isn't available.
}
EFS_GET_STORE_METHOD = efsGetStoreMethod;
EFS_GET_FILE_SYSTEM_METHOD = efsGetFileSystemMethod;
FILE_STORE_OPEN_INPUT_STREAM_METHOD = fileStoreOpenInputStreamMethod;
FILE_STORE_OPEN_OUTPUT_STREAM_METHOD = fileStoreOpenOutputStreamMethod;
}
/**
* A map that remaps URIs.
* @deprecated since 2.4 use {@link ExtensibleURIConverterImpl.URIMap} instead.
*/
@Deprecated
public interface URIMap extends ExtensibleURIConverterImpl.URIMap
{
// No methods added.
}
/**
* Creates an instance.
* @deprecated since 2.4;
* use new {@link ExtensibleURIConverterImpl#ExtensibleURIConverterImpl() ExtensibleURIConverterImpl()} instead.
*/
@Deprecated
public URIConverterImpl()
{
super();
}
/**
* Returns whether the scheme is one that this implementation should treat as an archive.
* This implementation returns <code>true</code> when the scheme is <code>"archive"</code>.
* @param scheme the scheme to consider.
* @return whether the scheme is one that this implementation treats as an archive.
*/
protected boolean isArchiveScheme(String scheme)
{
return "archive".equals(scheme);
}
/**
* Returns whether the scheme is one that this implementation should treat as a supported Eclipse File System scheme.
* This implementation uses Java reflection to check whether there is an Eclipse File System available and if so whether it supports this scheme.
* @param scheme the scheme to consider.
* @return whether the scheme is one that this implementation treats as an Eclipse File System scheme.
*/
protected boolean isEFSScheme(String scheme)
{
if (EFS_GET_FILE_SYSTEM_METHOD == null)
{
return false;
}
else
{
Boolean result = efsScheme == null ? null : efsScheme.get(scheme);
if (result == null)
{
try
{
result = EFS_GET_FILE_SYSTEM_METHOD.invoke(null, scheme) != null;
}
catch (Throwable exception)
{
result = Boolean.FALSE;
}
Map<String, Boolean> map = new HashMap<String, Boolean>();
if (efsScheme != null)
{
map.putAll(efsScheme);
}
map.put(scheme, result);
efsScheme = map;
}
return result == Boolean.TRUE;
}
}
/**
* Creates an output stream for the URI and returns it.
* <p>
* This implementation {@link #normalize(URI) normalizes} the URI and uses that as the basis for further processing.
* A {@link URI#isFile() file-based} URI is {@link URI#toFileString converted} to a file path, e.g.,
*<pre>
* file:///C:/directory/file
* ->
* C:/directory/file
*</pre>
* and is delegated to {@link #createFileOutputStream createFileOutputStream}.
* An {@link #isArchiveScheme(String) archive-based} URI is delegated to {@link #createArchiveOutputStream createArchiveOutputStream}.
* A {@link URI#isPlatformResource() platform-based} URI is {@link URI#toPlatformString(boolean) converted} to a platform path
* by trimming the leading <code>platform:/resource</code>, e.g.,
*<pre>
* platform:/resource/project/directory/file
* ->
* /project/directory/file
*</pre>
* and is delegated to {@link #createPlatformResourceOutputStream createPlatformResourceOutputStream}.
* An {@link #isEFSScheme(String) EFS-based} URI is delegated to {@link #createEFSInputStream(URI) createEFSOutputStream}.
* And all other cases are handled as standard URLs by {@link #createURLOutputStream createURLOutputStream}.
* </p>
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
*/
@Override
public OutputStream createOutputStream(URI uri) throws IOException
{
URI converted = normalize(uri);
if (converted.isFile())
{
String filePath = converted.toFileString();
return createFileOutputStream(filePath);
}
else
{
String scheme = converted.scheme();
if (isArchiveScheme(scheme))
{
return createArchiveOutputStream(converted);
}
else if (converted.isPlatformResource())
{
return createPlatformResourceOutputStream(converted.toPlatformString(true));
}
else if (isEFSScheme(scheme))
{
return createEFSOutputStream(converted);
}
else
{
return createURLOutputStream(converted);
}
}
}
@Override
public OutputStream createOutputStream(URI uri, Map<?, ?> options) throws IOException
{
return createOutputStream(uri);
}
/**
* Creates an output stream for the file path and returns it.
* <p>
* This implementation allocates a {@link FileOutputStream} and creates subdirectories as necessary.
* </p>
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
*/
protected OutputStream createFileOutputStream(String filePath) throws IOException
{
File file = new File(filePath);
String parent = file.getParent();
if (parent != null)
{
new File(parent).mkdirs();
}
OutputStream outputStream = new FileOutputStream(file);
return outputStream;
}
/**
* Creates an output stream for the archive access.
* </p>
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
*/
protected OutputStream createArchiveOutputStream(URI archiveURI) throws IOException
{
return createArchive(archiveURI).getOutputStream();
}
/**
* Creates an output stream for the platform resource path and returns it.
* <p>
* This implementation does one of two things, depending on the runtime environment.
* If there is an Eclipse workspace, it delegates to
* {@link WorkbenchHelper#createPlatformResourceOutputStream WorkbenchHelper.createPlatformResourceOutputStream},
* which gives the expected Eclipse behaviour.
* Otherwise, the {@link EcorePlugin#resolvePlatformResourcePath resolved} URI
* is delegated to {@link #createOutputStream(URI, Map) createOutputStream}
* for recursive processing.
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream or a valid interpretation of the path.
* @see EcorePlugin#resolvePlatformResourcePath(String)
*/
protected OutputStream createPlatformResourceOutputStream(String platformResourcePath) throws IOException
{
// ECLIPSE-DEPEND-BEGIN
if (workspaceRoot != null)
{
return WorkbenchHelper.createPlatformResourceOutputStream(platformResourcePath);
}
else
// ECLIPSE-DEPEND-END
{
URI resolvedLocation = EcorePlugin.resolvePlatformResourcePath(platformResourcePath);
if (resolvedLocation != null)
{
return createOutputStream(resolvedLocation);
}
throw new IOException("The path '" + platformResourcePath + "' is unmapped");
}
}
/**
* Creates an output stream for the URI, assuming it's a URI recognized by the Eclipse File System, and returns it.
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
*/
protected OutputStream createEFSOutputStream(URI uri) throws IOException
{
if (EFS_GET_STORE_METHOD != null)
{
try
{
Object store = EFS_GET_STORE_METHOD.invoke(null, new java.net.URI(uri.toString()));
if (store != null)
{
return (OutputStream)FILE_STORE_OPEN_OUTPUT_STREAM_METHOD.invoke(store, 0, null);
}
}
catch (Exception exception)
{
throw new Resource.IOWrappedException(exception);
}
}
throw new IOException("EFS unavailable");
}
/**
* Creates an output stream for the URI, assuming it's a URL, and returns it.
* @return an open output stream.
* @exception IOException if there is a problem obtaining an open output stream.
*/
protected OutputStream createURLOutputStream(URI uri) throws IOException
{
try
{
URL url = new URL(uri.toString());
URLConnection urlConnection = url.openConnection();
urlConnection.setDoOutput(true);
return urlConnection.getOutputStream();
}
catch (RuntimeException exception)
{
throw new Resource.IOWrappedException(exception);
}
}
/**
* Creates an input stream for the URI and returns it.
* <p>
* This implementation {@link #normalize(URI) normalizes} the URI and uses that as the basis for further processing.
* A {@link URI#isFile() file-based} URI is {@link URI#toFileString converted} to a file path, e.g.,
*<pre>
* file:///C:/directory/file
* ->
* C:/directory/file
*</pre>
* and is delegated to {@link #createFileInputStream createFileInputStream}.
* An {@link #isArchiveScheme(String) archive-based} URI is delegated to {@link #createArchiveInputStream createArchiveInputStream}.
* A {@link URI#isPlatformResource() platform-based} URI is {@link URI#toPlatformString(boolean) converted} to a platform path
* by trimming the leading <code>platform:/resource</code>, e.g.,
*<pre>
* platform:/resource/project/directory/file
* ->
* /project/directory/file
*</pre>
* and is delegated to {@link #createPlatformResourceInputStream createPlatformResourceInputStream}.
* An {@link #isEFSScheme(String) EFS-based} URI is delegated to {@link #createEFSInputStream(URI) createEFSInputStream}.
* And all other cases are handled as standard URLs by {@link #createURLInputStream createURLInputStream}.
* </p>
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream.
*/
@Override
public InputStream createInputStream(URI uri) throws IOException
{
URI converted = normalize(uri);
if (converted.isFile())
{
String filePath = converted.toFileString();
return createFileInputStream(filePath);
}
else
{
String scheme = converted.scheme();
if (isArchiveScheme(scheme))
{
return createArchiveInputStream(converted);
}
else if (converted.isPlatformResource())
{
return createPlatformResourceInputStream(converted.toPlatformString(true));
}
else if (isEFSScheme(scheme))
{
return createEFSInputStream(converted);
}
else
{
return createURLInputStream(converted);
}
}
}
@Override
public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException
{
return createInputStream(uri);
}
/**
* Creates an input stream for the file path and returns it.
* <p>
* This implementation allocates a {@link FileInputStream}.
* </p>
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream.
*/
protected InputStream createFileInputStream(String filePath) throws IOException
{
File file = new File(filePath);
InputStream inputStream = new FileInputStream(file);
return inputStream;
}
/**
* A specialized class for reading from an archive.
*/
protected class Archive extends ArchiveURLConnection
{
public Archive(URI uri)
{
super(uri.toString());
}
@Override
protected boolean emulateArchiveScheme()
{
return false;
}
@Override
protected boolean useZipFile()
{
return true;
}
@Override
protected InputStream createInputStream(String nestedURL) throws IOException
{
return URIConverterImpl.this.createInputStream(URI.createURI(nestedURL));
}
@Override
protected OutputStream createOutputStream(String nestedURL) throws IOException
{
return URIConverterImpl.this.createOutputStream(URI.createURI(nestedURL));
}
}
protected Archive createArchive(URI uri)
{
return new Archive(uri);
}
/**
* Creates an input stream for the archive paths and returns it.
* It uses {@link Archive} to implement read access.
* </p>
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream.
*/
protected InputStream createArchiveInputStream(URI archiveURI) throws IOException
{
return createArchive(archiveURI).getInputStream();
}
/**
* Creates an input stream for the platform resource path and returns it.
* <p>
* This implementation does one of two things, depending on the runtime environment.
* If there is an Eclipse workspace, it delegates to
* {@link WorkbenchHelper#createPlatformResourceInputStream WorkbenchHelper.createPlatformResourceInputStream},
* which gives the expected Eclipse behaviour.
* Otherwise, the {@link EcorePlugin#resolvePlatformResourcePath resolved} URI
* is delegated to {@link #createInputStream(URI, Map) createInputStream}
* for recursive processing.
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream or a valid interpretation of the path.
* @see EcorePlugin#resolvePlatformResourcePath(String)
*/
protected InputStream createPlatformResourceInputStream(String platformResourcePath) throws IOException
{
// ECLIPSE-DEPEND-BEGIN
if (workspaceRoot != null)
{
return WorkbenchHelper.createPlatformResourceInputStream(platformResourcePath);
}
else
// ECLIPSE-DEPEND-END
{
URI resolvedLocation = EcorePlugin.resolvePlatformResourcePath(platformResourcePath);
if (resolvedLocation != null)
{
return createInputStream(resolvedLocation);
}
throw new IOException("The path '" + platformResourcePath + "' is unmapped");
}
}
/**
* Creates an input stream for the URI, assuming it's a URI recognized by the Eclipse File System, and returns it.
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream.
*/
protected InputStream createEFSInputStream(URI uri) throws IOException
{
if (EFS_GET_STORE_METHOD != null)
{
try
{
Object store = EFS_GET_STORE_METHOD.invoke(null, new java.net.URI(uri.toString()));
if (store != null)
{
return (InputStream)FILE_STORE_OPEN_INPUT_STREAM_METHOD.invoke(store, 0, null);
}
}
catch (Exception exception)
{
throw new Resource.IOWrappedException(exception);
}
}
throw new IOException("EFS unavailable");
}
/**
* Creates an input stream for the URI, assuming it's a URL, and returns it.
* @return an open input stream.
* @exception IOException if there is a problem obtaining an open input stream.
*/
protected InputStream createURLInputStream(URI uri) throws IOException
{
try
{
URL url = new URL(uri.toString());
URLConnection urlConnection = url.openConnection();
return urlConnection.getInputStream();
}
catch (RuntimeException exception)
{
throw new Resource.IOWrappedException(exception);
}
}
/**
* Returns the internal version of the URI map.
* @return the internal version of the URI map.
* @deprecated since 2.4; there should be no need to call this method directly so use {@link #getURIMap()} instead.
*/
@Override
@Deprecated
protected URIMap getInternalURIMap()
{
return (URIMap)super.getInternalURIMap();
}
}