Coverage Report

Created: 2026-07-10 11:04

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