diff options
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/url/TcfURLConnection.java')
-rw-r--r-- | target_explorer/plugins/org.eclipse.tcf.te.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/url/TcfURLConnection.java | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/url/TcfURLConnection.java b/target_explorer/plugins/org.eclipse.tcf.te.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/url/TcfURLConnection.java new file mode 100644 index 000000000..3d1e53126 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/url/TcfURLConnection.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2011, 2014 Wind River Systems, Inc. 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: + * William Chen (Wind River)- [345387]Open the remote files with a proper editor + *******************************************************************************/ +package org.eclipse.tcf.te.tcf.filesystem.core.internal.url; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tcf.protocol.IChannel; +import org.eclipse.tcf.protocol.IPeer; +import org.eclipse.tcf.protocol.IToken; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.services.IFileSystem; +import org.eclipse.tcf.services.IFileSystem.DoneClose; +import org.eclipse.tcf.services.IFileSystem.DoneOpen; +import org.eclipse.tcf.services.IFileSystem.FileSystemException; +import org.eclipse.tcf.services.IFileSystem.IFileHandle; +import org.eclipse.tcf.te.tcf.core.Tcf; +import org.eclipse.tcf.te.tcf.filesystem.core.internal.exceptions.TCFChannelException; +import org.eclipse.tcf.te.tcf.filesystem.core.internal.operations.Operation; +import org.eclipse.tcf.te.tcf.filesystem.core.nls.Messages; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode; +import org.eclipse.tcf.te.tcf.locator.interfaces.services.IPeerModelLookupService; +import org.eclipse.tcf.te.tcf.locator.model.ModelManager; + +/** + * The URL connection returned by TCF stream service used to handle "tcf" + * stream protocol. + */ +public class TcfURLConnection extends URLConnection { + // Default connecting timeout. + private static final int DEFAULT_CONNECT_TIMEOUT = 5000; + // Default file opening timeout. + private static final int DEFAULT_OPEN_TIMEOUT = 5000; + // Default file reading timeout. + private static final int DEFAULT_READ_TIMEOUT = 5000; + // Default file closing timeout. + private static final int DEFAULT_CLOSE_TIMEOUT = 5000; + // The schema name of the stream protocol. + public static final String PROTOCOL_SCHEMA = "tcf"; //$NON-NLS-1$ + + // The input stream of this connection. + private TcfInputStream inputStream; + // The output stream of this connection. + private TcfOutputStream outputStream; + + // The TCF agent peer of the connection. + private IPeer peer; + // The path to the resource on the remote file system. + String path; + // The timeout for opening a file. + private int openTimeout; + // The timeout for closing a file. + private int closeTimeout; + + // The TCF channel used to open and read the resource. + IChannel channel; + // The file's handle + IFileHandle handle; + // The file service + IFileSystem service; + + /** + * Create a TCF URL Connection using the specified url. The format of this + * URL should be: tcf:/<TCF_AGENT_ID>/remote/path/to/the/resource... The + * stream protocol schema is designed in this way in order to retrieve the + * agent peer ID without knowing the structure of a TCF peer id. + * + * @see TcfURLStreamHandlerService#parseURL(URL, String, int, int) + * @param url + * The URL of the resource. + */ + public TcfURLConnection(final URL url) { + super(url); + // The peerId is stored as the host name in URL. See TcfURLStreamHandlerService#parseURL for details. + String peerId = url.getHost(); + Assert.isNotNull(peerId); + peer = findPeer(peerId); + if(peer == null) { + throw new IllegalArgumentException(NLS.bind(Messages.TcfURLConnection_NoPeerFound, peerId)); + } + path = url.getPath(); + // Set default timeout. + setConnectTimeout(DEFAULT_CONNECT_TIMEOUT); + setOpenTimeout(DEFAULT_OPEN_TIMEOUT); + setReadTimeout(DEFAULT_READ_TIMEOUT); + setCloseTimeout(DEFAULT_CLOSE_TIMEOUT); + } + + /** + * Find the TCF peer with the specified ID. + * + * @param peerId The target peer's ID. + * @return The peer with this ID or null if not found. + */ + private IPeer findPeer(final String peerId) { + Assert.isNotNull(peerId); + + final AtomicReference<IPeer> peer = new AtomicReference<IPeer>(); + + Runnable runnable = new Runnable() { + + @Override + public void run() { + IPeer p = Protocol.getLocator().getPeers().get(peerId); + if (p == null) { + IPeerNode peerNode = ModelManager.getPeerModel().getService(IPeerModelLookupService.class).lkupPeerModelById(peerId); + if (peerNode != null) p = peerNode.getPeer(); + } + peer.set(p); + } + }; + + if (Protocol.isDispatchThread()) runnable.run(); + else Protocol.invokeAndWait(runnable); + + return peer.get(); + } + + /** + * Get the timeout for closing a file. + * + * @return the timeout in milliseconds. + */ + public long getCloseTimeout() { + return closeTimeout; + } + + /** + * Set the timeout for closing a file. + * + * @param closeTimeout + * the timeout in milliseconds. + */ + public void setCloseTimeout(int closeTimeout) { + this.closeTimeout = closeTimeout; + } + + /** + * Get the timeout for opening a file. + * + * @return the timeout in milliseconds. + */ + public long getOpenTimeout() { + return openTimeout; + } + + /** + * Set the timeout for opening a file. + * + * @param openTimeout + * the timeout in milliseconds. + */ + public void setOpenTimeout(int openTimeout) { + this.openTimeout = openTimeout; + } + + /** + * Open a file on the remote file system for read/write and store the file handle. + * + * @throws IOException Opening file fails. + */ + private void openFile() throws IOException { + if(peer == null) + throw new IOException(Messages.TcfURLConnection_NoSuchTcfAgent); + try { + // Open the channel + channel = Operation.openChannel(peer); + } catch (TCFChannelException e) { + throw new IOException(e.getMessage()); + } + if (channel != null) { + service = Operation.getBlockingFileSystem(channel); + if (service != null) { + final FileSystemException[] errors = new FileSystemException[1]; + // Open the file. + int open_flag = 0; + if (doInput) + open_flag |= IFileSystem.TCF_O_READ; + if (doOutput) + open_flag |= IFileSystem.TCF_O_WRITE | IFileSystem.TCF_O_CREAT | IFileSystem.TCF_O_TRUNC; + service.open(path, open_flag, null, new DoneOpen() { + @Override + public void doneOpen(IToken token, FileSystemException error, IFileHandle hdl) { + errors[0] = error; + handle = hdl; + } + }); + if (errors[0] != null) { + IOException exception = new IOException(errors[0].toString()); + exception.initCause(errors[0]); + throw exception; + } + if (handle == null) { + throw new IOException(Messages.TcfURLConnection_NoFileHandleReturned); + } + } else { + throw new IOException(Messages.Operation_NoFileSystemError); + } + } + } + + /* + * (non-Javadoc) + * + * @see java.net.URLConnection#connect() + */ + @Override + public void connect() throws IOException { + if (!connected) { + openFile(); + if (doInput) { + inputStream = new TcfInputStream(this); + } + if (doOutput) { + outputStream = new TcfOutputStream(this); + } + connected = true; + } + } + + /* + * (non-Javadoc) + * + * @see java.net.URLConnection#getInputStream() + */ + @Override + public InputStream getInputStream() throws IOException { + if (!connected) + connect(); + return inputStream; + } + + /* + * (non-Javadoc) + * @see java.net.URLConnection#getOutputStream() + */ + @Override + public OutputStream getOutputStream() throws IOException { + if (!connected) + connect(); + return outputStream; + } + + /** + * Close the stream, release its file handler and close + * the TCF channel used if possible. + * + * @param stream The stream either the input stream or the output stream. + * @throws IOException If closing file handle times out. + */ + public synchronized void closeStream(Closeable stream) throws IOException { + boolean shouldClose = shouldCloseFileHandle(stream); + if (shouldClose) { + service.close(handle, new DoneClose() { + @Override + public void doneClose(IToken token, FileSystemException error) { + Tcf.getChannelManager().closeChannel(channel); + } + }); + } + } + + /** + * Decide if the file handle and the TCF channel should be closed if + * the specified stream is closed. If the stream is the last stream + * that depends on the file handle and the TCF channel, then it should + * be closed. + * + * @param stream The stream to be closed. + * @return true if the file handle and the TCF channel should be closed. + */ + private boolean shouldCloseFileHandle(Closeable stream) { + boolean shouldClose = false; + if (stream == inputStream) { + if (doOutput) { + if (outputStream.closed) { + shouldClose = true; + } + } else { + shouldClose = true; + } + } else if (stream == outputStream) { + if (doInput) { + if (inputStream.closed) + shouldClose = true; + } else { + shouldClose = true; + } + } + return shouldClose; + } +} |