Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <stdio.h>
22 :
23 : #include <osl/diagnose.h>
24 :
25 : #include <com/sun/star/io/XActiveDataSource.hpp>
26 : #include <com/sun/star/io/XActiveDataSink.hpp>
27 : #include <com/sun/star/io/XActiveDataControl.hpp>
28 : #include <com/sun/star/io/XConnectable.hpp>
29 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
30 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 : #include <com/sun/star/lang/XServiceInfo.hpp>
32 : #include <com/sun/star/registry/XRegistryKey.hpp>
33 :
34 : #include <uno/dispatcher.h>
35 : #include <uno/mapping.hxx>
36 : #include <cppuhelper/implbase5.hxx>
37 : #include <cppuhelper/factory.hxx>
38 : #include <cppuhelper/interfacecontainer.hxx>
39 : #include <osl/mutex.hxx>
40 : #include <osl/thread.h>
41 :
42 :
43 : using namespace osl;
44 : using namespace std;
45 : using namespace cppu;
46 : using namespace com::sun::star::uno;
47 : using namespace com::sun::star::lang;
48 : using namespace com::sun::star::registry;
49 : using namespace com::sun::star::io;
50 :
51 : using ::rtl::OUString;
52 : using ::rtl::OUStringToOString;
53 : using ::rtl::OString;
54 :
55 : #include "factreg.hxx"
56 :
57 : namespace io_stm {
58 :
59 : class Pump : public WeakImplHelper5<
60 : XActiveDataSource, XActiveDataSink, XActiveDataControl, XConnectable, XServiceInfo >
61 : {
62 : Mutex m_aMutex;
63 : oslThread m_aThread;
64 :
65 : Reference< XConnectable > m_xPred;
66 : Reference< XConnectable > m_xSucc;
67 : Reference< XInputStream > m_xInput;
68 : Reference< XOutputStream > m_xOutput;
69 : OInterfaceContainerHelper m_cnt;
70 : sal_Bool m_closeFired;
71 :
72 : void run();
73 : static void static_run( void* pObject );
74 :
75 : void close();
76 : void fireClose();
77 : void fireStarted();
78 : void fireTerminated();
79 : void fireError( const Any &a );
80 :
81 : public:
82 : Pump();
83 : virtual ~Pump();
84 :
85 : // XActiveDataSource
86 : virtual void SAL_CALL setOutputStream( const Reference< ::com::sun::star::io::XOutputStream >& xOutput ) throw();
87 : virtual Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream() throw();
88 :
89 : // XActiveDataSink
90 : virtual void SAL_CALL setInputStream( const Reference< ::com::sun::star::io::XInputStream >& xStream ) throw();
91 : virtual Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream() throw();
92 :
93 : // XActiveDataControl
94 : virtual void SAL_CALL addListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
95 : virtual void SAL_CALL removeListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
96 : virtual void SAL_CALL start() throw( RuntimeException );
97 : virtual void SAL_CALL terminate() throw();
98 :
99 : // XConnectable
100 : virtual void SAL_CALL setPredecessor( const Reference< ::com::sun::star::io::XConnectable >& xPred ) throw();
101 : virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getPredecessor() throw();
102 : virtual void SAL_CALL setSuccessor( const Reference< ::com::sun::star::io::XConnectable >& xSucc ) throw();
103 : virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getSuccessor() throw();
104 :
105 : public: // XServiceInfo
106 : virtual OUString SAL_CALL getImplementationName() throw( );
107 : virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw( );
108 : virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw( );
109 : };
110 :
111 0 : Pump::Pump() : m_aThread( 0 ),
112 : m_cnt( m_aMutex ),
113 0 : m_closeFired( sal_False )
114 : {
115 0 : g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
116 0 : }
117 :
118 0 : Pump::~Pump()
119 : {
120 : // exit gracefully
121 0 : if( m_aThread )
122 : {
123 0 : osl_joinWithThread( m_aThread );
124 0 : osl_destroyThread( m_aThread );
125 : }
126 0 : g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
127 0 : }
128 :
129 0 : void Pump::fireError( const Any & exception )
130 : {
131 0 : OInterfaceIteratorHelper iter( m_cnt );
132 0 : while( iter.hasMoreElements() )
133 : {
134 : try
135 : {
136 0 : static_cast< XStreamListener * > ( iter.next() )->error( exception );
137 : }
138 0 : catch ( const RuntimeException &e )
139 : {
140 0 : OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
141 0 : OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
142 : }
143 0 : }
144 0 : }
145 :
146 0 : void Pump::fireClose()
147 : {
148 0 : sal_Bool bFire = sal_False;
149 : {
150 0 : MutexGuard guard( m_aMutex );
151 0 : if( ! m_closeFired )
152 : {
153 0 : m_closeFired = sal_True;
154 0 : bFire = sal_True;
155 0 : }
156 : }
157 :
158 0 : if( bFire )
159 : {
160 0 : OInterfaceIteratorHelper iter( m_cnt );
161 0 : while( iter.hasMoreElements() )
162 : {
163 : try
164 : {
165 0 : static_cast< XStreamListener * > ( iter.next() )->closed( );
166 : }
167 0 : catch ( const RuntimeException &e )
168 : {
169 0 : OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
170 0 : OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
171 : }
172 0 : }
173 : }
174 0 : }
175 :
176 0 : void Pump::fireStarted()
177 : {
178 0 : OInterfaceIteratorHelper iter( m_cnt );
179 0 : while( iter.hasMoreElements() )
180 : {
181 : try
182 : {
183 0 : static_cast< XStreamListener * > ( iter.next() )->started( );
184 : }
185 0 : catch ( const RuntimeException &e )
186 : {
187 0 : OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
188 0 : OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
189 : }
190 0 : }
191 0 : }
192 :
193 0 : void Pump::fireTerminated()
194 : {
195 0 : OInterfaceIteratorHelper iter( m_cnt );
196 0 : while( iter.hasMoreElements() )
197 : {
198 : try
199 : {
200 0 : static_cast< XStreamListener * > ( iter.next() )->terminated();
201 : }
202 0 : catch ( const RuntimeException &e )
203 : {
204 0 : OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
205 0 : OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
206 : }
207 0 : }
208 0 : }
209 :
210 :
211 :
212 0 : void Pump::close()
213 : {
214 : // close streams and release references
215 0 : Reference< XInputStream > rInput;
216 0 : Reference< XOutputStream > rOutput;
217 : {
218 0 : MutexGuard guard( m_aMutex );
219 0 : rInput = m_xInput;
220 0 : m_xInput.clear();
221 :
222 0 : rOutput = m_xOutput;
223 0 : m_xOutput.clear();
224 0 : m_xSucc.clear();
225 0 : m_xPred.clear();
226 : }
227 0 : if( rInput.is() )
228 : {
229 : try
230 : {
231 0 : rInput->closeInput();
232 : }
233 0 : catch( Exception & )
234 : {
235 : // go down calm
236 : }
237 : }
238 0 : if( rOutput.is() )
239 : {
240 : try
241 : {
242 0 : rOutput->closeOutput();
243 : }
244 0 : catch( Exception & )
245 : {
246 : // go down calm
247 : }
248 0 : }
249 0 : }
250 :
251 0 : void Pump::static_run( void* pObject )
252 : {
253 0 : ((Pump*)pObject)->run();
254 0 : ((Pump*)pObject)->release();
255 0 : }
256 :
257 0 : void Pump::run()
258 : {
259 : try
260 : {
261 0 : fireStarted();
262 : try
263 : {
264 0 : Reference< XInputStream > rInput;
265 0 : Reference< XOutputStream > rOutput;
266 : {
267 0 : Guard< Mutex > aGuard( m_aMutex );
268 0 : rInput = m_xInput;
269 0 : rOutput = m_xOutput;
270 : }
271 :
272 0 : if( ! rInput.is() )
273 : {
274 : NotConnectedException exception(
275 0 : OUString("no input stream set") , Reference<XInterface>((OWeakObject*)this) );
276 0 : throw exception;
277 : }
278 0 : Sequence< sal_Int8 > aData;
279 0 : while( rInput->readSomeBytes( aData, 65536 ) )
280 : {
281 0 : if( ! rOutput.is() )
282 : {
283 : NotConnectedException exception(
284 0 : OUString("no output stream set") , Reference<XInterface>( (OWeakObject*)this) );
285 0 : throw exception;
286 : }
287 0 : rOutput->writeBytes( aData );
288 0 : osl_yieldThread();
289 0 : }
290 : }
291 0 : catch ( const IOException & e )
292 : {
293 0 : fireError( makeAny( e ) );
294 : }
295 0 : catch ( const RuntimeException & e )
296 : {
297 0 : fireError( makeAny( e ) );
298 : }
299 0 : catch ( const Exception & e )
300 : {
301 0 : fireError( makeAny( e ) );
302 : }
303 :
304 0 : close();
305 0 : fireClose();
306 : }
307 0 : catch ( const com::sun::star::uno::Exception &e )
308 : {
309 : // we are the last on the stack.
310 : // this is to avoid crashing the program, when e.g. a bridge crashes
311 0 : OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
312 0 : OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception", sMessage.getStr() );
313 : }
314 0 : }
315 :
316 : // ------------------------------------------------------------
317 :
318 : /*
319 : * XConnectable
320 : */
321 :
322 0 : void Pump::setPredecessor( const Reference< XConnectable >& xPred ) throw()
323 : {
324 0 : Guard< Mutex > aGuard( m_aMutex );
325 0 : m_xPred = xPred;
326 0 : }
327 :
328 : // ------------------------------------------------------------
329 :
330 0 : Reference< XConnectable > Pump::getPredecessor() throw()
331 : {
332 0 : Guard< Mutex > aGuard( m_aMutex );
333 0 : return m_xPred;
334 : }
335 :
336 : // ------------------------------------------------------------
337 :
338 0 : void Pump::setSuccessor( const Reference< XConnectable >& xSucc ) throw()
339 : {
340 0 : Guard< Mutex > aGuard( m_aMutex );
341 0 : m_xSucc = xSucc;
342 0 : }
343 :
344 : // ------------------------------------------------------------
345 :
346 0 : Reference< XConnectable > Pump::getSuccessor() throw()
347 : {
348 0 : Guard< Mutex > aGuard( m_aMutex );
349 0 : return m_xSucc;
350 : }
351 :
352 : // -----------------------------------------------------------------
353 :
354 : /*
355 : * XActiveDataControl
356 : */
357 :
358 0 : void Pump::addListener( const Reference< XStreamListener >& xListener ) throw()
359 : {
360 0 : m_cnt.addInterface( xListener );
361 0 : }
362 :
363 : // ------------------------------------------------------------
364 :
365 0 : void Pump::removeListener( const Reference< XStreamListener >& xListener ) throw()
366 : {
367 0 : m_cnt.removeInterface( xListener );
368 0 : }
369 :
370 : // ------------------------------------------------------------
371 :
372 0 : void Pump::start() throw( RuntimeException )
373 : {
374 0 : Guard< Mutex > aGuard( m_aMutex );
375 0 : m_aThread = osl_createSuspendedThread((oslWorkerFunction)Pump::static_run,this);
376 0 : if( m_aThread )
377 : {
378 : // will be released by OPump::static_run
379 0 : acquire();
380 0 : osl_resumeThread( m_aThread );
381 : }
382 : else
383 : {
384 : throw RuntimeException(
385 : OUString("Pump::start Couldn't create worker thread"),
386 0 : *this);
387 0 : }
388 0 : }
389 :
390 : // ------------------------------------------------------------
391 :
392 0 : void Pump::terminate() throw()
393 : {
394 0 : close();
395 :
396 : // wait for the worker to die
397 0 : if( m_aThread )
398 0 : osl_joinWithThread( m_aThread );
399 :
400 0 : fireTerminated();
401 0 : fireClose();
402 0 : }
403 :
404 : // ------------------------------------------------------------
405 :
406 : /*
407 : * XActiveDataSink
408 : */
409 :
410 0 : void Pump::setInputStream( const Reference< XInputStream >& xStream ) throw()
411 : {
412 0 : Guard< Mutex > aGuard( m_aMutex );
413 0 : m_xInput = xStream;
414 0 : Reference< XConnectable > xConnect( xStream, UNO_QUERY );
415 0 : if( xConnect.is() )
416 0 : xConnect->setSuccessor( this );
417 : // data transfer starts in XActiveDataControl::start
418 0 : }
419 :
420 : // ------------------------------------------------------------
421 :
422 0 : Reference< XInputStream > Pump::getInputStream() throw()
423 : {
424 0 : Guard< Mutex > aGuard( m_aMutex );
425 0 : return m_xInput;
426 : }
427 :
428 : // ------------------------------------------------------------
429 :
430 : /*
431 : * XActiveDataSource
432 : */
433 :
434 0 : void Pump::setOutputStream( const Reference< XOutputStream >& xOut ) throw()
435 : {
436 0 : Guard< Mutex > aGuard( m_aMutex );
437 0 : m_xOutput = xOut;
438 0 : Reference< XConnectable > xConnect( xOut, UNO_QUERY );
439 0 : if( xConnect.is() )
440 0 : xConnect->setPredecessor( this );
441 : // data transfer starts in XActiveDataControl::start
442 0 : }
443 :
444 : // ------------------------------------------------------------
445 :
446 0 : Reference< XOutputStream > Pump::getOutputStream() throw()
447 : {
448 0 : Guard< Mutex > aGuard( m_aMutex );
449 0 : return m_xOutput;
450 : }
451 :
452 :
453 : // XServiceInfo
454 0 : OUString Pump::getImplementationName() throw( )
455 : {
456 0 : return OPumpImpl_getImplementationName();
457 : }
458 :
459 : // XServiceInfo
460 0 : sal_Bool Pump::supportsService(const OUString& ServiceName) throw( )
461 : {
462 0 : Sequence< OUString > aSNL = getSupportedServiceNames();
463 0 : const OUString * pArray = aSNL.getConstArray();
464 :
465 0 : for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
466 0 : if( pArray[i] == ServiceName )
467 0 : return sal_True;
468 :
469 0 : return sal_False;
470 : }
471 :
472 : // XServiceInfo
473 0 : Sequence< OUString > Pump::getSupportedServiceNames(void) throw( )
474 : {
475 0 : return OPumpImpl_getSupportedServiceNames();
476 : }
477 :
478 :
479 0 : Reference< XInterface > SAL_CALL OPumpImpl_CreateInstance(
480 : SAL_UNUSED_PARAMETER const Reference< XComponentContext > & )
481 : throw (Exception)
482 : {
483 0 : return Reference< XInterface >( *new Pump );
484 : }
485 :
486 0 : OUString OPumpImpl_getImplementationName()
487 : {
488 0 : return OUString("com.sun.star.comp.io.Pump");
489 : }
490 :
491 0 : Sequence<OUString> OPumpImpl_getSupportedServiceNames(void)
492 : {
493 0 : OUString s("com.sun.star.io.Pump");
494 0 : Sequence< OUString > seq( &s , 1 );
495 0 : return seq;
496 : }
497 :
498 : }
499 :
500 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|