| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ccvs.core.connection; |
| |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.team.internal.ccvs.core.CVSException; |
| import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; |
| import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; |
| import org.eclipse.team.internal.ccvs.core.IServerConnection; |
| import org.eclipse.team.internal.ccvs.core.Policy; |
| |
| /** |
| * A connection to talk to a cvs server. The life cycle of a connection is |
| * as follows: |
| * <ul> |
| * <li> constructor: creates a new connection object that wraps the given |
| * repository location and connection method. |
| * <li> open: opens a connection. |
| * <li> send a request: use write* method or use the request stream directly. |
| * <code>GetRequestStream</code> returns an output stream to directly |
| * talk to the server. |
| * <li> read responses: use read* methods or use the response stream directly. |
| * <code>GetResponseStream</code> returns an input stream to directly |
| * read output from the server. |
| * <li> close: closes the connection. A closed connection can be reopened by |
| * calling open again. |
| * </ul> |
| */ |
| public class Connection { |
| private static final byte NEWLINE= 0xA; |
| |
| private IServerConnection serverConnection; |
| private ICVSRepositoryLocation fCVSRoot; |
| private String fCVSRootDirectory; |
| private boolean fIsEstablished; |
| private InputStream fResponseStream; |
| private byte[] readLineBuffer = new byte[256]; |
| |
| public Connection(ICVSRepositoryLocation cvsroot, IServerConnection serverConnection) { |
| fCVSRoot = cvsroot; |
| this.serverConnection = serverConnection; |
| } |
| |
| private static byte[] append(byte[] buffer, int index, byte b) { |
| if (index >= buffer.length) { |
| byte[] newBuffer= new byte[index * 2]; |
| System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); |
| buffer= newBuffer; |
| } |
| buffer[index]= b; |
| return buffer; |
| } |
| /** |
| * Closes the connection. |
| */ |
| public void close() throws CVSException { |
| if (!isEstablished()) |
| return; |
| try { |
| serverConnection.close(); |
| } catch (IOException ex) { |
| // Generally, errors on close are of no interest. |
| // However, log them if debugging is on |
| if (CVSProviderPlugin.getPlugin().isDebugging()) { |
| CVSProviderPlugin.log(new CVSCommunicationException(Policy.bind("Connection.cannotClose"), ex));//$NON-NLS-1$ |
| } |
| } finally { |
| fResponseStream = null; |
| fIsEstablished = false; |
| } |
| } |
| /** |
| * Flushes the request stream. |
| */ |
| public void flush() throws CVSException { |
| if (!isEstablished()) |
| return; |
| try { |
| getOutputStream().flush(); |
| } catch(IOException e) { |
| throw new CVSCommunicationException(e); |
| } |
| } |
| |
| /** |
| * Returns the <code>OutputStream</code> used to send requests |
| * to the server. |
| */ |
| public OutputStream getOutputStream() throws CVSException { |
| if (!isEstablished()) |
| return null; |
| return serverConnection.getOutputStream(); |
| } |
| /** |
| * Returns the <code>InputStream</code> used to read responses from |
| * the server. |
| */ |
| public InputStream getInputStream() throws CVSException { |
| if (!isEstablished()) |
| return null; |
| if (fResponseStream == null) |
| fResponseStream = serverConnection.getInputStream(); |
| return fResponseStream; |
| } |
| |
| /** |
| * Returns <code>true</code> if the connection is established; |
| * otherwise <code>false</code>. |
| */ |
| public boolean isEstablished() { |
| return fIsEstablished; |
| } |
| |
| /** |
| * Opens the connection. |
| */ |
| public void open(IProgressMonitor monitor) throws CVSException { |
| if (isEstablished()) |
| return; |
| try { |
| serverConnection.open(monitor); |
| } catch (IOException e) { |
| throw new CVSCommunicationException(e); |
| } |
| fIsEstablished= true; |
| } |
| /** |
| * Reads a line from the response stream. |
| */ |
| public String readLine() throws CVSException { |
| if (!isEstablished()) |
| throw new CVSCommunicationException(Policy.bind("Connection.readUnestablishedConnection"));//$NON-NLS-1$ |
| try { |
| InputStream in = getInputStream(); |
| int index = 0; |
| int r; |
| while ((r = in.read()) != -1) { |
| if (r == NEWLINE) break; |
| readLineBuffer = append(readLineBuffer, index++, (byte) r); |
| } |
| String result = new String(readLineBuffer, 0, index); |
| if (Policy.DEBUG_CVS_PROTOCOL) System.out.println(result); |
| return result; |
| } catch (IOException e) { |
| throw new CVSCommunicationException(e); |
| } |
| } |
| |
| static String readLine(InputStream in) throws IOException { |
| byte[] buffer = new byte[256]; |
| int index = 0; |
| int r; |
| while ((r = in.read()) != -1) { |
| if (r == NEWLINE) |
| break; |
| buffer = append(buffer, index++, (byte) r); |
| } |
| String result = new String(buffer, 0, index); |
| if (Policy.DEBUG_CVS_PROTOCOL) |
| System.out.println(result); |
| return result; |
| } |
| |
| //---- Helper to send strings to the server ---------------------------- |
| |
| /** |
| * Sends the given string to the server. |
| */ |
| public void write(String s) throws CVSException { |
| write(s.getBytes(), false); |
| } |
| |
| /** |
| * Sends the given bytes to the server. |
| */ |
| public void write(byte[] b, int off, int len) throws CVSException { |
| write(b, off, len, false); |
| } |
| /** |
| * Sends the given string and a newline to the server. |
| */ |
| public void writeLine(String s) throws CVSException { |
| write(s.getBytes(), true); |
| } |
| /** |
| * Sends the given bytes and a newline to the server. |
| */ |
| public void writeLine(byte[] b, int off, int len) throws CVSException { |
| write(b, off, len, true); |
| } |
| |
| void write (byte[] bytes, boolean newLine) throws CVSException { |
| write(bytes, 0, bytes.length, newLine); |
| } |
| |
| /** |
| * Low level method to write a string to the server. All write* methods are |
| * funneled through this method. |
| */ |
| void write(byte[] b, int off, int len, boolean newline) throws CVSException { |
| if (!isEstablished()) |
| throw new CVSCommunicationException(Policy.bind("Connection.writeUnestablishedConnection"));//$NON-NLS-1$ |
| |
| if (Policy.DEBUG_CVS_PROTOCOL) |
| System.out.print(new String(b, off, len) + (newline ? "\n" : ""));//$NON-NLS-1$ //$NON-NLS-2$ |
| |
| try { |
| OutputStream out= getOutputStream(); |
| out.write(b, off, len); |
| if (newline) |
| out.write(NEWLINE); |
| out.flush(); |
| |
| } catch (IOException e) { |
| throw new CVSCommunicationException(e); |
| } |
| } |
| } |