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