1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package com.sun.star.comp.connections;
29 
30 
31 import com.sun.star.comp.loader.FactoryHelper;
32 
33 import com.sun.star.connection.XConnection;
34 
35 import com.sun.star.lang.XMultiServiceFactory;
36 import com.sun.star.lang.XSingleServiceFactory;
37 
38 import com.sun.star.registry.XRegistryKey;
39 
40 /**
41  * The PipedConnection is a component that implements the
42  * <code>XConnection</code> Interface.
43  * It is useful for <code>Thread</code> communication
44  * in one Process.
45  * <p>
46  * @version 	$Revision: 1.3 $ $ $Date: 2008-04-11 11:09:30 $
47  * @author 	    Kay Ramme
48  * @see         com.sun.star.connections.XConnection
49  * @see         com.sun.star.loader.JavaLoader
50  * @since       UDK1.0
51  */
52 public class PipedConnection implements XConnection {
53 	/**
54 	 * When set to true, enables various debugging output.
55 	 */
56 	public static final boolean DEBUG = false;
57 
58 	/**
59 	 * The name of the service, the <code>JavaLoader</code> acceses this through reflection.
60 	 */
61     static private final String __serviceName = "com.sun.star.connection.PipedConnection";
62 
63 	/**
64 	 * Gives a factory for creating the service.
65 	 * This method is called by the <code>JavaLoader</code>
66 	 * <p>
67 	 * @return  returns a <code>XSingleServiceFactory</code> for creating the component
68 	 * @param   implName     the name of the implementation for which a service is desired
69 	 * @param   multiFactory the service manager to be uses if needed
70 	 * @param   regKey       the registryKey
71 	 * @see                  com.sun.star.comp.loader.JavaLoader
72 	 */
73 	public static XSingleServiceFactory __getServiceFactory(String implName,
74 														  XMultiServiceFactory multiFactory,
75 														  XRegistryKey regKey)
76 	{
77 		XSingleServiceFactory xSingleServiceFactory = null;
78 
79 	    if (implName.equals(PipedConnection.class.getName()) )
80 	        xSingleServiceFactory = FactoryHelper.getServiceFactory(PipedConnection.class,
81 																	__serviceName,
82 																	multiFactory,
83 																	regKey);
84 
85 	    return xSingleServiceFactory;
86 	}
87 
88 	/**
89 	 * The amount of time in milliseconds, to wait to
90 	 * see check the buffers.
91 	 */
92 	protected static final int __waitTime = 10000;
93 
94 	protected byte			   _buffer[] = new byte[4096];
95 	protected int			   _in,
96 							   _out;
97 	protected boolean		   _closed;
98 	protected PipedConnection  _otherSide;
99 
100 	/**
101 	 * Constructs a new <code>PipedConnection</code>, sees if there
102 	 * is an other side, which it should be connected to.
103 	 * <p>
104 	 * @param    args   Another side could be in index 0.
105 	 */
106 	public PipedConnection(Object args[]) throws com.sun.star.uno.RuntimeException {
107 		if (DEBUG) System.err.println("##### " + getClass().getName() + " - instantiated");
108 
109 		_otherSide = (args.length == 1) ? (PipedConnection)args[0] : null;
110 		if(_otherSide != null) {
111 			if(_otherSide == this)
112 				throw new RuntimeException("can not connect to myself");
113 
114 			_otherSide._otherSide = this;
115 		}
116 	}
117 
118 	/**
119 	 * This is a private method, used to cummunicate
120 	 * internal in the pipe.
121 	 */
122 	private synchronized void receive(byte aData[]) throws com.sun.star.io.IOException {
123 		int bytesWritten = 0;
124 
125 		if(DEBUG) System.err.println("##### PipedConnection.receive - bytes:" + aData.length + " at:" + _out);
126 
127 		while(bytesWritten < aData.length) {
128 			// wait until it is not full anymore
129 			while(_out == (_in - 1) || (_in == 0 && _out == _buffer.length - 1)) {
130 				try {
131 					notify(); // the buffer is full, signal it
132 
133 					wait(__waitTime);
134 				}
135 				catch(InterruptedException interruptedException) {
136 					throw new com.sun.star.io.IOException(interruptedException.toString());
137 				}
138 			}
139 
140 			if(_closed) throw new com.sun.star.io.IOException("connection has been closed");
141 
142 			int bytes  ;
143 
144 			if(_out < _in) {
145 				bytes = Math.min(aData.length - bytesWritten, _in - _out - 1);
146 
147 				System.arraycopy(aData, bytesWritten, _buffer, _out, bytes);
148 			}
149 			else {
150 				if(_in > 0){
151 					bytes = Math.min(aData.length - bytesWritten, _buffer.length - _out);
152 				}
153 				else {
154 					bytes = Math.min(aData.length - bytesWritten, _buffer.length - _out - 1);
155 				}
156 
157 				System.arraycopy(aData, bytesWritten, _buffer, _out, bytes);
158 			}
159 
160 			bytesWritten += bytes;
161 			_out += bytes;
162 			if(_out >= _buffer.length)
163 				_out = 0;
164 		}
165 	}
166 
167 	/**
168 	 * Read the required number of bytes.
169 	 * <p>
170 	 * @return   the number of bytes read
171 	 * @param    aReadBytes   the outparameter, where the bytes have to be placed
172 	 * @param    nBytesToRead the number of bytes to read
173      * @see       com.sun.star.connections.XConnection#read
174 	 */
175     public synchronized int read(/*OUT*/byte[][] aReadBytes, int nBytesToRead) throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
176 		aReadBytes[0] = new byte[nBytesToRead];
177 
178 		if(DEBUG) System.err.println("##### PipedConnection.read - bytes:" + nBytesToRead + " at:" + _in);
179 
180 		// loop while not all bytes read or when closed but there is still data
181 		while(nBytesToRead > 0 && (_in != _out || !_closed)) {
182 			while(_in == _out && !_closed) {
183 				try {
184 					notify(); // the buffer is empty, signal it
185 
186 					wait(__waitTime); // we wait for data or for the pipe to be closed
187 				}
188 				catch(InterruptedException interruptedException) {
189 					throw new com.sun.star.io.IOException(interruptedException.toString());
190 				}
191 			}
192 
193 			if(_in < _out) {
194 				int bytes = Math.min(nBytesToRead, _out - _in);
195 
196 				System.arraycopy(_buffer, _in, aReadBytes[0], aReadBytes[0].length - nBytesToRead, bytes);
197 
198 				nBytesToRead -= bytes;
199 				_in += bytes;
200 			}
201 			else if(_in > _out) {
202 				int bytes = Math.min(nBytesToRead, _buffer.length - _in);
203 
204 				System.arraycopy(_buffer, _in, aReadBytes[0], aReadBytes[0].length - nBytesToRead, bytes);
205 
206 				nBytesToRead -= bytes;
207 				_in += bytes;
208 				if(_in >= _buffer.length)
209 					_in = 0;
210 			}
211 		}
212 
213 		if(nBytesToRead > 0) { // not all bytes read
214 			byte tmp[] = new byte[aReadBytes[0].length - nBytesToRead];
215 			System.arraycopy(aReadBytes[0], 0, tmp, 0, tmp.length);
216 
217 			aReadBytes[0] = tmp;
218 		}
219 
220 		return aReadBytes[0].length;
221 	}
222 
223 	/**
224 	 * Write bytes.
225 	 * <p>
226 	 * @param    aData the bytes to write
227      * @see       com.sun.star.connections.XConnection#write
228 	 */
229     public void write(byte aData[]) throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
230 		_otherSide.receive(aData);
231 	}
232 
233 	/**
234 	 * Flushes the buffer, notifies if necessary the other side that new data has arrived.
235 	 * <p>
236      * @see       com.sun.star.connections.XConnection#flush
237 	 */
238     public void flush() throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
239 		synchronized(_otherSide) {
240 			_otherSide.notify();
241 		}
242 	}
243 
244 	/**
245 	 * Closes the pipe.
246 	 * <p>
247      * @see       com.sun.star.connections.XConnection#closed
248 	 */
249     public synchronized void close() throws com.sun.star.io.IOException, com.sun.star.uno.RuntimeException {
250 		if(!_closed) {
251 			_closed = true;
252 
253 			_otherSide.close();
254 
255 			notify();
256 		}
257 	}
258 
259 	/**
260 	 * Gives a description of this pipe.
261 	 * <p>
262 	 * @return  the description
263      * @see       com.sun.star.connections.XConnection#getDescription
264 	 */
265     public String getDescription() throws com.sun.star.uno.RuntimeException {
266 		return getClass().getName();
267 	}
268 
269 }
270 
271