/** * Copyright (c) 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.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.CommonPlugin; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.URIConverter; public class EFSURIHandlerImpl extends URIHandlerImpl { 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; private static final Method FILE_STORE_DELETE_METHOD; private static final Method FILE_STORE_FETCH_INFO_METHOD; private static final Method FILE_STORE_PUT_INFO_METHOD; private static final Method FILE_INFO_EXISTS_METHOD; private static final Method FILE_INFO_GET_LENGTH_METHOD; private static final Method FILE_INFO_IS_DIRECOTRY_METHOD; private static final Method FILE_INFO_GET_ATTRIBUTE_METHOD; private static final Method FILE_INFO_SET_ATTRIBUTE_METHOD; private static final Method FILE_INFO_GET_LAST_MODIFIED; private static final Method FILE_INFO_SET_LAST_MODIFIED; static { Method efsGetStoreMethod = null; Method efsGetFileSystemMethod = null; Method fileStoreOpenInputStreamMethod = null; Method fileStoreOpenOutputStreamMethod = null; Method fileStoreDeleteMethod = null; Method fileStoreFetchInfoMethod = null; Method fileStorePutInfoMethod = null; Method fileInfoExistsMethod = null; Method fileInfoIsDirectoryMethod = null; Method fileInfoGetLengthMethod = null; Method fileInfoGetAttributeMethod = null; Method fileInfoSetAttributeMethod = null; Method fileInfoGetLastModifiedMethod = null; Method fileInfoSetLastModifiedMethod = 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); fileStoreDeleteMethod = fileStoreClass.getMethod("delete", Integer.TYPE, IProgressMonitor.class); fileStoreFetchInfoMethod = fileStoreClass.getMethod("fetchInfo"); Class <?> fileInfoClass = fileStoreFetchInfoMethod.getReturnType(); fileStorePutInfoMethod = fileStoreClass.getMethod("putInfo", fileInfoClass, Integer.TYPE, IProgressMonitor.class); fileInfoExistsMethod = fileInfoClass.getMethod("exists"); fileInfoIsDirectoryMethod = fileInfoClass.getMethod("isDirectory"); fileInfoGetLengthMethod = fileInfoClass.getMethod("getLength"); fileInfoGetAttributeMethod = fileInfoClass.getMethod("getAttribute", Integer.TYPE); fileInfoSetAttributeMethod = fileInfoClass.getMethod("setAttribute", Integer.TYPE, Boolean.TYPE); fileInfoGetLastModifiedMethod = fileInfoClass.getMethod("getLastModified"); fileInfoSetLastModifiedMethod = fileInfoClass.getMethod("setLastModified", Long.TYPE); } 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; FILE_STORE_DELETE_METHOD = fileStoreDeleteMethod; FILE_STORE_FETCH_INFO_METHOD = fileStoreFetchInfoMethod; FILE_STORE_PUT_INFO_METHOD = fileStorePutInfoMethod; FILE_INFO_EXISTS_METHOD = fileInfoExistsMethod; FILE_INFO_IS_DIRECOTRY_METHOD = fileInfoIsDirectoryMethod; FILE_INFO_GET_ATTRIBUTE_METHOD = fileInfoGetAttributeMethod; FILE_INFO_SET_ATTRIBUTE_METHOD = fileInfoSetAttributeMethod; FILE_INFO_GET_LENGTH_METHOD = fileInfoGetLengthMethod; FILE_INFO_GET_LAST_MODIFIED = fileInfoGetLastModifiedMethod; FILE_INFO_SET_LAST_MODIFIED = fileInfoSetLastModifiedMethod; } /** * Creates an instance. */ public EFSURIHandlerImpl() { super(); } /** * Returns whether the URI 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 uri the URI to consider. * @return whether the URI is one that this implementation treats as an Eclipse File System scheme. */ @Override public boolean canHandle(URI uri) { String scheme = uri.scheme(); if (scheme == null || 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; } } protected Object getStore(URI uri, Map<?, ?> options) throws IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, URISyntaxException { if (EFS_GET_STORE_METHOD != null) { Object store = EFS_GET_STORE_METHOD.invoke(null, new java.net.URI(uri.toString())); if (store != null) { return store; } } throw new IOException("EFS unavailable"); } protected Object getInfo(URI uri, Object store, Map<?, ?> options) throws IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, URISyntaxException { return FILE_STORE_FETCH_INFO_METHOD.invoke(store); } protected Object getInfo(URI uri, Map<?, ?> options) throws IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, URISyntaxException { return getInfo(uri, getStore(uri, options), options); } protected void setInfo(URI uri, Object store, Object info, int set, Map<?, ?> options) throws IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, URISyntaxException { FILE_STORE_PUT_INFO_METHOD.invoke(store, info, set, null); } /** * 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. */ @Override public OutputStream createOutputStream(final URI uri, final Map<?, ?> options) throws IOException { try { OutputStream result = (OutputStream)FILE_STORE_OPEN_OUTPUT_STREAM_METHOD.invoke(getStore(uri, options), 0, null); final Map<Object, Object> response = getResponse(options); if (response != null) { result = new BufferedOutputStream(result) { @Override public void close() throws IOException { try { super.close(); } finally { response.put(URIConverter.RESPONSE_TIME_STAMP_PROPERTY, getAttributes(uri, options).get(URIConverter.ATTRIBUTE_TIME_STAMP)); } } }; } return result; } catch (IllegalArgumentException exception) { throw new Resource.IOWrappedException(exception); } catch (IllegalAccessException exception) { throw new Resource.IOWrappedException(exception); } catch (InvocationTargetException exception) { throw new Resource.IOWrappedException(exception.getCause()); } catch (URISyntaxException exception) { throw new Resource.IOWrappedException(exception); } } /** * 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. */ @Override public InputStream createInputStream(URI uri, Map<?, ?> options) throws IOException { try { InputStream result = (InputStream)FILE_STORE_OPEN_INPUT_STREAM_METHOD.invoke(getStore(uri, options), 0, null); final Map<Object, Object> response = getResponse(options); if (response != null) { response.put(URIConverter.RESPONSE_TIME_STAMP_PROPERTY, getAttributes(uri, options).get(URIConverter.ATTRIBUTE_TIME_STAMP)); } return result; } catch (IllegalArgumentException exception) { throw new Resource.IOWrappedException(exception); } catch (IllegalAccessException exception) { throw new Resource.IOWrappedException(exception); } catch (InvocationTargetException exception) { throw new Resource.IOWrappedException(exception.getCause()); } catch (URISyntaxException exception) { throw new Resource.IOWrappedException(exception); } } @Override public void delete(URI uri, Map<?, ?> options) throws IOException { try { FILE_STORE_DELETE_METHOD.invoke(getStore(uri, options), 0, null); } catch (IllegalArgumentException exception) { throw new Resource.IOWrappedException(exception); } catch (IllegalAccessException exception) { throw new Resource.IOWrappedException(exception); } catch (InvocationTargetException exception) { throw new Resource.IOWrappedException(exception.getCause()); } catch (URISyntaxException exception) { throw new Resource.IOWrappedException(exception); } } @Override public boolean exists(URI uri, Map<?, ?> options) { try { return Boolean.TRUE.equals(FILE_INFO_EXISTS_METHOD.invoke(getInfo(uri, options))); } catch (Exception exception) { return false; } } private static final Integer ATTRIBUTE_READ_ONLY = 1 << 1; private static final Integer ATTRIBUTE_EXECUTABLE = 1 << 2; private static final Integer ATTRIBUTE_ARCHIVE = 1 << 3; private static final Integer ATTRIBUTE_HIDDEN = 1 << 4; private static final int SET_ATTRIBUTES = 1 << 10; private static final int SET_LAST_MODIFIED = 1 << 11; @Override public Map<String, ?> getAttributes(URI uri, Map<?, ?> options) { Map<String, Object> result = new HashMap<String, Object>(); Set<String> requestedAttributes = getRequestedAttributes(options); Object info; try { info = getInfo(uri, options); } catch (Exception exception) { return result; } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_TIME_STAMP)) { try { Object timeStamp = FILE_INFO_GET_LAST_MODIFIED.invoke(info); result.put(URIConverter.ATTRIBUTE_TIME_STAMP, timeStamp); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_READ_ONLY)) { try { Object isReadOnly = FILE_INFO_GET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_READ_ONLY); result.put(URIConverter.ATTRIBUTE_READ_ONLY, isReadOnly); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_ARCHIVE)) { try { Object isArchive = FILE_INFO_GET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_ARCHIVE); result.put(URIConverter.ATTRIBUTE_ARCHIVE, isArchive); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_EXECUTABLE)) { try { Object isExecutable = FILE_INFO_GET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_EXECUTABLE); result.put(URIConverter.ATTRIBUTE_EXECUTABLE, isExecutable); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_HIDDEN)) { try { Object isHidden = FILE_INFO_GET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_HIDDEN); result.put(URIConverter.ATTRIBUTE_HIDDEN, isHidden); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_DIRECTORY)) { try { Object isDirectory = FILE_INFO_IS_DIRECOTRY_METHOD.invoke(info); result.put(URIConverter.ATTRIBUTE_DIRECTORY, isDirectory); } catch (Exception exception) { // Ignore. } } if (requestedAttributes == null || requestedAttributes.contains(URIConverter.ATTRIBUTE_LENGTH)) { try { Object length = FILE_INFO_GET_LENGTH_METHOD.invoke(info); result.put(URIConverter.ATTRIBUTE_LENGTH, length); } catch (Exception exception) { // Ignore. } } return result; } @Override public void setAttributes(URI uri, Map<String, ?> attributes, Map<?, ?> options) throws IOException { int set = 0; Object store; Object info; try { store = getStore(uri, options); info = getInfo(uri, store, options); } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } Object timeStamp = attributes.get(URIConverter.ATTRIBUTE_TIME_STAMP); if (timeStamp != null) { try { FILE_INFO_SET_LAST_MODIFIED.invoke(info, timeStamp); set = SET_LAST_MODIFIED; } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } Object isReadOnly = attributes.get(URIConverter.ATTRIBUTE_READ_ONLY); if (isReadOnly != null) { try { FILE_INFO_SET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_READ_ONLY, isReadOnly); set |= SET_ATTRIBUTES; } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } Object isArchive = attributes.get(URIConverter.ATTRIBUTE_ARCHIVE); if (isArchive != null) { try { FILE_INFO_SET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_ARCHIVE, isArchive); set |= SET_ATTRIBUTES; } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } Object isExecutable = attributes.get(URIConverter.ATTRIBUTE_ARCHIVE); if (isExecutable != null) { try { FILE_INFO_SET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_EXECUTABLE, isExecutable); set |= SET_ATTRIBUTES; } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } Object isHidden = attributes.get(URIConverter.ATTRIBUTE_HIDDEN); if (isHidden != null) { try { FILE_INFO_SET_ATTRIBUTE_METHOD.invoke(info, ATTRIBUTE_HIDDEN, isHidden); set |= SET_ATTRIBUTES; } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } if (set != 0) { try { setInfo(uri, store, info, set, options); } catch (Exception exception) { throw new Resource.IOWrappedException(exception); } } } }