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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 
27 #include "comphelper_module.hxx"
28 
29 #include <com/sun/star/util/XCloseBroadcaster.hpp>
30 #include <com/sun/star/util/XCloseable.hpp>
31 #include <com/sun/star/lang/DisposedException.hpp>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/frame/XDesktop.hpp>
34 #include <com/sun/star/frame/DoubleInitializationException.hpp>
35 #include <com/sun/star/frame/DoubleInitializationException.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 
38 #include "instancelocker.hxx"
39 
40 using namespace ::com::sun::star;
41 
42 
43 // ====================================================================
44 // OInstanceLocker
45 // ====================================================================
46 
47 // --------------------------------------------------------
OInstanceLocker(const uno::Reference<uno::XComponentContext> & xContext)48 OInstanceLocker::OInstanceLocker( const uno::Reference< uno::XComponentContext >& xContext )
49 : m_xContext( xContext )
50 , m_pLockListener( NULL )
51 , m_pListenersContainer( NULL )
52 , m_bDisposed( sal_False )
53 , m_bInitialized( sal_False )
54 {
55 }
56 
57 // --------------------------------------------------------
~OInstanceLocker()58 OInstanceLocker::~OInstanceLocker()
59 {
60 	if ( !m_bDisposed )
61 	{
62 		m_refCount++; // to call dispose
63 		try {
64 			dispose();
65 		}
66 		catch ( uno::RuntimeException& )
67 		{}
68 	}
69 
70 	if ( m_pListenersContainer )
71 	{
72 		delete m_pListenersContainer;
73 		m_pListenersContainer = NULL;
74 	}
75 }
76 
77 // XComponent
78 // --------------------------------------------------------
dispose()79 void SAL_CALL OInstanceLocker::dispose()
80 	throw (uno::RuntimeException)
81 {
82 	::osl::MutexGuard aGuard( m_aMutex );
83 
84 	if ( m_bDisposed )
85 		throw lang::DisposedException();
86 
87    	lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
88 	if ( m_pListenersContainer )
89 		m_pListenersContainer->disposeAndClear( aSource );
90 
91 	if ( m_xLockListener.is() )
92 	{
93 		if ( m_pLockListener )
94 		{
95 			m_pLockListener->Dispose();
96 			m_pLockListener = NULL;
97 		}
98 		m_xLockListener = uno::Reference< uno::XInterface >();
99 	}
100 
101 	m_bDisposed = sal_True;
102 }
103 
104 // --------------------------------------------------------
addEventListener(const uno::Reference<lang::XEventListener> & xListener)105 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
106 	throw (uno::RuntimeException)
107 {
108 	::osl::MutexGuard aGuard( m_aMutex );
109 	if ( m_bDisposed )
110 		throw lang::DisposedException(); // TODO
111 
112 	if ( !m_pListenersContainer )
113 		m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex );
114 
115 	m_pListenersContainer->addInterface( xListener );
116 }
117 
118 // --------------------------------------------------------
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)119 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
120 	throw (uno::RuntimeException)
121 {
122 	::osl::MutexGuard aGuard( m_aMutex );
123 	if ( m_pListenersContainer )
124 		m_pListenersContainer->removeInterface( xListener );
125 }
126 
127 // XInitialization
128 // --------------------------------------------------------
initialize(const uno::Sequence<uno::Any> & aArguments)129 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments )
130 	throw (uno::Exception, uno::RuntimeException)
131 {
132 	::osl::MutexGuard aGuard( m_aMutex );
133 	if ( m_bInitialized )
134 		throw frame::DoubleInitializationException();
135 
136 	if ( m_bDisposed )
137 		throw lang::DisposedException(); // TODO
138 
139 	if ( !m_refCount )
140 		throw uno::RuntimeException(); // the object must be refcounted already!
141 
142 	uno::Reference< uno::XInterface > xInstance;
143 	uno::Reference< embed::XActionsApproval > xApproval;
144 	sal_Int32 nModes = 0;
145 
146 	try
147 	{
148 		sal_Int32 nLen = aArguments.getLength();
149 		if ( nLen < 2 || nLen > 3 )
150 			throw lang::IllegalArgumentException(
151 							::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ),
152 							uno::Reference< uno::XInterface >(),
153 							0 );
154 
155 		if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() )
156 			throw lang::IllegalArgumentException(
157 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ),
158 					uno::Reference< uno::XInterface >(),
159 					0 );
160 
161 		if (
162             !( aArguments[1] >>= nModes ) ||
163             (
164               !( nModes & embed::Actions::PREVENT_CLOSE ) &&
165               !( nModes & embed::Actions::PREVENT_TERMINATION )
166             )
167            )
168         {
169 			throw lang::IllegalArgumentException(
170 					::rtl::OUString(
171 							RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ),
172 					uno::Reference< uno::XInterface >(),
173 					0 );
174         }
175 
176 		if ( nLen == 3 && !( aArguments[2] >>= xApproval ) )
177 			throw lang::IllegalArgumentException(
178 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ),
179 					uno::Reference< uno::XInterface >(),
180 					0 );
181 
182 		m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ),
183 											xInstance,
184 											nModes,
185 											xApproval );
186 		m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( m_pLockListener ) );
187 		m_pLockListener->Init();
188 	}
189 	catch( uno::Exception& )
190 	{
191 		dispose();
192 		throw;
193 	}
194 
195 	m_bInitialized = sal_True;
196 }
197 
198 
199 // XServiceInfo
200 // --------------------------------------------------------
getImplementationName()201 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName(  )
202 	throw (uno::RuntimeException)
203 {
204 	return getImplementationName_static();
205 }
206 
207 // --------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)208 ::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName )
209 	throw (uno::RuntimeException)
210 {
211 	uno::Sequence< ::rtl::OUString > aSeq = getSupportedServiceNames();
212 
213 	for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
214     	if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
215         	return sal_True;
216 
217 	return sal_False;
218 }
219 
220 // --------------------------------------------------------
getSupportedServiceNames()221 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames()
222 	throw (uno::RuntimeException)
223 {
224 	return getSupportedServiceNames_static();
225 }
226 
227 // Static methods
228 // --------------------------------------------------------
getSupportedServiceNames_static()229 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames_static()
230 {
231     const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) );
232     return uno::Sequence< rtl::OUString >( &aServiceName, 1 );
233 }
234 
235 // --------------------------------------------------------
getImplementationName_static()236 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName_static()
237 {
238     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) );
239 }
240 
241 // --------------------------------------------------------
Create(const uno::Reference<uno::XComponentContext> & rxContext)242 uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::Create(
243 								const uno::Reference< uno::XComponentContext >& rxContext )
244 {
245     return static_cast< cppu::OWeakObject * >( new OInstanceLocker( rxContext ) );
246 }
247 
248 
249 
250 // ====================================================================
251 // OLockListener
252 // ====================================================================
253 
254 // --------------------------------------------------------
OLockListener(const uno::WeakReference<lang::XComponent> & xWrapper,const uno::Reference<uno::XInterface> & xInstance,sal_Int32 nMode,const uno::Reference<embed::XActionsApproval> xApproval)255 OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper,
256 					const uno::Reference< uno::XInterface >& xInstance,
257 					sal_Int32 nMode,
258 					const uno::Reference< embed::XActionsApproval > xApproval )
259 : m_xInstance( xInstance )
260 , m_xApproval( xApproval )
261 , m_xWrapper( xWrapper )
262 , m_bDisposed( sal_False )
263 , m_bInitialized( sal_False )
264 , m_nMode( nMode )
265 {
266 }
267 
268 // --------------------------------------------------------
~OLockListener()269 OLockListener::~OLockListener()
270 {
271 }
272 
273 // --------------------------------------------------------
Dispose()274 void OLockListener::Dispose()
275 {
276 	::osl::ResettableMutexGuard aGuard( m_aMutex );
277 
278 	if ( m_bDisposed )
279 		return;
280 
281 	if ( m_nMode & embed::Actions::PREVENT_CLOSE )
282 	{
283 		try
284 		{
285 			uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY );
286 			if ( xCloseBroadcaster.is() )
287 				xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
288 
289 			uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY );
290 			if ( xCloseable.is() )
291 				xCloseable->close( sal_True );
292 		}
293 		catch( uno::Exception& )
294 		{}
295 	}
296 
297 	if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
298 	{
299 		try
300 		{
301 			uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
302 			xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
303 		}
304 		catch( uno::Exception& )
305 		{}
306 	}
307 
308 	m_xInstance = uno::Reference< uno::XInterface >();
309 	m_bDisposed = sal_True;
310 }
311 
312 // XEventListener
313 // --------------------------------------------------------
disposing(const lang::EventObject & aEvent)314 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent )
315 	throw (uno::RuntimeException)
316 {
317 	::osl::ResettableMutexGuard aGuard( m_aMutex );
318 
319 	// object is disposed
320 	if ( aEvent.Source == m_xInstance )
321 	{
322 		// the object does not listen for anything any more
323 		m_nMode = 0;
324 
325 		// dispose the wrapper;
326 		uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
327 		aGuard.clear();
328 		if ( xComponent.is() )
329 		{
330 			try { xComponent->dispose(); }
331 			catch( uno::Exception& ){}
332 		}
333 	}
334 }
335 
336 
337 // XCloseListener
338 // --------------------------------------------------------
queryClosing(const lang::EventObject & aEvent,sal_Bool)339 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool )
340 	throw (util::CloseVetoException, uno::RuntimeException)
341 {
342 	// GetsOwnership parameter is always ignored, the user of the service must close the object always
343 	::osl::ResettableMutexGuard aGuard( m_aMutex );
344 	if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) )
345 	{
346 		try
347 		{
348 			uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
349 
350 			// unlock the mutex here
351 			aGuard.clear();
352 
353 			if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) )
354 				throw util::CloseVetoException();
355 		}
356 		catch( util::CloseVetoException& )
357 		{
358 			// rethrow this exception
359 			throw;
360 		}
361 		catch( uno::Exception& )
362 		{
363 			// no action should be done
364 		}
365 	}
366 }
367 
368 // --------------------------------------------------------
notifyClosing(const lang::EventObject & aEvent)369 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent )
370 	throw (uno::RuntimeException)
371 {
372 	::osl::ResettableMutexGuard aGuard( m_aMutex );
373 
374 	// object is closed, no reason to listen
375 	if ( aEvent.Source == m_xInstance )
376 	{
377 		uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY );
378 		if ( xCloseBroadcaster.is() )
379 		{
380 			xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) );
381 			m_nMode &= ~embed::Actions::PREVENT_CLOSE;
382 			if ( !m_nMode )
383 			{
384 				// dispose the wrapper;
385 				uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
386 				aGuard.clear();
387 				if ( xComponent.is() )
388 				{
389 					try { xComponent->dispose(); }
390 					catch( uno::Exception& ){}
391 				}
392 			}
393 		}
394 	}
395 }
396 
397 
398 // XTerminateListener
399 // --------------------------------------------------------
queryTermination(const lang::EventObject & aEvent)400 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent )
401 	throw (frame::TerminationVetoException, uno::RuntimeException)
402 {
403 	::osl::ResettableMutexGuard aGuard( m_aMutex );
404 	if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) )
405 	{
406 		try
407 		{
408 			uno::Reference< embed::XActionsApproval > xApprove = m_xApproval;
409 
410 			// unlock the mutex here
411 			aGuard.clear();
412 
413 			if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) )
414 				throw frame::TerminationVetoException();
415 		}
416 		catch( frame::TerminationVetoException& )
417 		{
418 			// rethrow this exception
419 			throw;
420 		}
421 		catch( uno::Exception& )
422 		{
423 			// no action should be done
424 		}
425 	}
426 }
427 
428 // --------------------------------------------------------
notifyTermination(const lang::EventObject & aEvent)429 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent )
430 	throw (uno::RuntimeException)
431 {
432 	::osl::ResettableMutexGuard aGuard( m_aMutex );
433 
434 	// object is terminated, no reason to listen
435 	if ( aEvent.Source == m_xInstance )
436 	{
437 		uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY );
438 		if ( xDesktop.is() )
439 		{
440 			try
441 			{
442 				xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
443 				m_nMode &= ~embed::Actions::PREVENT_TERMINATION;
444 				if ( !m_nMode )
445 				{
446 					// dispose the wrapper;
447 					uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
448 					aGuard.clear();
449 					if ( xComponent.is() )
450 					{
451 						try { xComponent->dispose(); }
452 						catch( uno::Exception& ){}
453 					}
454 				}
455 			}
456 			catch( uno::Exception& )
457 			{}
458 		}
459 	}
460 }
461 
462 
463 // XInitialization
464 // --------------------------------------------------------
Init()465 sal_Bool OLockListener::Init()
466 {
467 	::osl::ResettableMutexGuard aGuard( m_aMutex );
468 
469 	if ( m_bDisposed || m_bInitialized )
470 		return sal_False;
471 
472 	try
473 	{
474 		if ( m_nMode & embed::Actions::PREVENT_CLOSE )
475 		{
476 			uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW );
477 			xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) );
478 		}
479 
480 		if ( m_nMode & embed::Actions::PREVENT_TERMINATION )
481 		{
482 			uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW );
483 			xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) );
484 		}
485 	}
486 	catch( uno::Exception& )
487 	{
488 		// dispose the wrapper;
489 		uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY );
490 		aGuard.clear();
491 		if ( xComponent.is() )
492 		{
493 			try { xComponent->dispose(); }
494 			catch( uno::Exception& ){}
495 		}
496 
497 		throw;
498 	}
499 
500 	m_bInitialized = sal_True;
501 
502 	return sal_True;
503 }
504 
createRegistryInfo_OInstanceLocker()505 void createRegistryInfo_OInstanceLocker()
506 {
507     static ::comphelper::module::OAutoRegistration< OInstanceLocker > aAutoRegistration;
508 }
509