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