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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 #include <connectivity/conncleanup.hxx>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/lang/XComponent.hpp>
33 #include <osl/diagnose.h>
34 
35 //.........................................................................
36 namespace dbtools
37 {
38 //.........................................................................
39 
40 	using namespace ::com::sun::star::uno;
41 	using namespace ::com::sun::star::beans;
42 	using namespace ::com::sun::star::sdbc;
43 	using namespace ::com::sun::star::lang;
44 
45 	//=====================================================================
46 	static const ::rtl::OUString& getActiveConnectionPropertyName()
47 	{
48 		static const ::rtl::OUString s_sActiveConnectionPropertyName = ::rtl::OUString::createFromAscii("ActiveConnection");
49 		return s_sActiveConnectionPropertyName;
50 	}
51 
52 	//=====================================================================
53 	//= OAutoConnectionDisposer
54 	//=====================================================================
55 	//---------------------------------------------------------------------
56 	OAutoConnectionDisposer::OAutoConnectionDisposer(const Reference< XRowSet >& _rxRowSet, const Reference< XConnection >& _rxConnection)
57 		:m_xRowSet( _rxRowSet )
58 		,m_bRSListening( sal_False )
59 		,m_bPropertyListening( sal_False )
60 	{
61 		Reference< XPropertySet > xProps(_rxRowSet, UNO_QUERY);
62 		OSL_ENSURE(xProps.is(), "OAutoConnectionDisposer::OAutoConnectionDisposer: invalid rowset (no XPropertySet)!");
63 
64 		if (!xProps.is())
65 			return;
66 
67 		try
68 		{
69 			xProps->setPropertyValue( getActiveConnectionPropertyName(), makeAny( _rxConnection ) );
70 			m_xOriginalConnection = _rxConnection;
71 			startPropertyListening( xProps );
72 		}
73 		catch( const Exception& )
74 		{
75 			OSL_ENSURE( sal_False, "OAutoConnectionDisposer::OAutoConnectionDisposer: caught an exception!" );
76 		}
77 	}
78 
79 	//---------------------------------------------------------------------
80 	void OAutoConnectionDisposer::startPropertyListening( const Reference< XPropertySet >& _rxRowSet )
81 	{
82 		try
83 		{
84 			_rxRowSet->addPropertyChangeListener( getActiveConnectionPropertyName(), this );
85 			m_bPropertyListening = sal_True;
86 		}
87 		catch( const Exception& )
88 		{
89 			OSL_ENSURE( sal_False, "OAutoConnectionDisposer::startPropertyListening: caught an exception!" );
90 		}
91 	}
92 
93 	//---------------------------------------------------------------------
94 	void OAutoConnectionDisposer::stopPropertyListening( const Reference< XPropertySet >& _rxEventSource )
95 	{
96 		// prevent deletion of ourself while we're herein
97 		Reference< XInterface > xKeepAlive(static_cast< XWeak* >(this));
98 
99 		try
100 		{	// remove ourself as property change listener
101 			OSL_ENSURE( _rxEventSource.is(), "OAutoConnectionDisposer::stopPropertyListening: invalid event source (no XPropertySet)!" );
102 			if ( _rxEventSource.is() )
103 			{
104 				_rxEventSource->removePropertyChangeListener( getActiveConnectionPropertyName(), this );
105 				m_bPropertyListening = sal_False;
106 			}
107 		}
108 		catch( const Exception& )
109 		{
110 			OSL_ENSURE( sal_False, "OAutoConnectionDisposer::stopPropertyListening: caught an exception!" );
111 		}
112 	}
113 
114 	//---------------------------------------------------------------------
115 	void OAutoConnectionDisposer::startRowSetListening()
116 	{
117 		OSL_ENSURE( !m_bRSListening, "OAutoConnectionDisposer::startRowSetListening: already listening!" );
118 		try
119 		{
120 			if ( !m_bRSListening )
121 				m_xRowSet->addRowSetListener( this );
122 		}
123 		catch( const Exception& )
124 		{
125 			OSL_ENSURE( sal_False, "OAutoConnectionDisposer::startRowSetListening: caught an exception!" );
126 		}
127 		m_bRSListening = sal_True;
128 	}
129 
130 	//---------------------------------------------------------------------
131 	void OAutoConnectionDisposer::stopRowSetListening()
132 	{
133 		OSL_ENSURE( m_bRSListening, "OAutoConnectionDisposer::stopRowSetListening: not listening!" );
134 		try
135 		{
136 			m_xRowSet->removeRowSetListener( this );
137 		}
138 		catch( const Exception& )
139 		{
140 			OSL_ENSURE( sal_False, "OAutoConnectionDisposer::stopRowSetListening: caught an exception!" );
141 		}
142 		m_bRSListening = sal_False;
143 	}
144 
145 	//---------------------------------------------------------------------
146 	void SAL_CALL OAutoConnectionDisposer::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException)
147 	{
148 		if ( _rEvent.PropertyName.equals( getActiveConnectionPropertyName() ) )
149 		{	// somebody set a new ActiveConnection
150 
151 			Reference< XConnection > xNewConnection;
152 			_rEvent.NewValue >>= xNewConnection;
153 
154 			if ( isRowSetListening() )
155 			{
156 				// we're listening at the row set, this means that the row set does not have our
157 				// m_xOriginalConnection as active connection anymore
158 				// So there are two possibilities
159 				// a. somebody sets a new connection which is not our original one
160 				// b. somebody sets a new connection, which is exactly the original one
161 				// a. we're not interested in a, but in b: In this case, we simply need to move to the state
162 				// we had originally: listen for property changes, do not listen for row set changes, and
163 				// do not dispose the connection until the row set does not need it anymore
164 				if ( xNewConnection.get() == m_xOriginalConnection.get() )
165 				{
166 					stopRowSetListening();
167 				}
168 			}
169 			else
170 			{
171 				// start listening at the row set. We're allowed to dispose the old connection as soon
172 				// as the RowSet changed
173 
174 				// Unfortunately, the our database form implementations sometimes fire the change of their
175 				// ActiveConnection twice. This is a error in forms/source/component/DatabaseForm.cxx, but
176 				// changing this would require incompatible changes we can't do for a while.
177 				// So for the moment, we have to live with it here.
178 				//
179 				// The only scenario where this doubled notification causes problems is when the connection
180 				// of the form is reset to the one we're responsible for (m_xOriginalConnection), so we
181 				// check this here.
182 				//
183 				// Yes, this is a HACK :(
184 				//
185 				// 94407 - 08.11.2001 - fs@openoffice.org
186 				if ( xNewConnection.get() != m_xOriginalConnection.get() )
187 				{
188 #if OSL_DEBUG_LEVEL > 0
189 					Reference< XConnection > xOldConnection;
190 					_rEvent.OldValue >>= xOldConnection;
191 					OSL_ENSURE( xOldConnection.get() == m_xOriginalConnection.get(), "OAutoConnectionDisposer::propertyChange: unexpected (original) property value!" );
192 #endif
193 					startRowSetListening();
194 				}
195 			}
196 		}
197 	}
198 
199 	//---------------------------------------------------------------------
200 	void SAL_CALL OAutoConnectionDisposer::disposing( const EventObject& _rSource ) throw (RuntimeException)
201 	{
202 		// the rowset is beeing disposed, and nobody has set a new ActiveConnection in the meantime
203 		if ( isRowSetListening() )
204 			stopRowSetListening();
205 
206 		clearConnection();
207 
208 		if ( isPropertyListening() )
209 			stopPropertyListening( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ) );
210 	}
211 	//---------------------------------------------------------------------
212 	void OAutoConnectionDisposer::clearConnection()
213 	{
214 		try
215 		{
216 			// dispose the old connection
217 			Reference< XComponent > xComp(m_xOriginalConnection, UNO_QUERY);
218 			if (xComp.is())
219 				xComp->dispose();
220 			m_xOriginalConnection.clear();
221 		}
222 		catch(Exception&)
223 		{
224 			OSL_ENSURE(sal_False, "OAutoConnectionDisposer::clearConnection: caught an exception!");
225 		}
226 	}
227 	//---------------------------------------------------------------------
228 	void SAL_CALL OAutoConnectionDisposer::cursorMoved( const ::com::sun::star::lang::EventObject& /*event*/ ) throw (::com::sun::star::uno::RuntimeException)
229 	{
230 	}
231 	//---------------------------------------------------------------------
232 	void SAL_CALL OAutoConnectionDisposer::rowChanged( const ::com::sun::star::lang::EventObject& /*event*/ ) throw (::com::sun::star::uno::RuntimeException)
233 	{
234 	}
235 	//---------------------------------------------------------------------
236 	void SAL_CALL OAutoConnectionDisposer::rowSetChanged( const ::com::sun::star::lang::EventObject& /*event*/ ) throw (::com::sun::star::uno::RuntimeException)
237 	{
238 		stopRowSetListening();
239 		clearConnection();
240 
241 	}
242 	//---------------------------------------------------------------------
243 
244 //.........................................................................
245 }	// namespace dbtools
246 //.........................................................................
247 
248