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 
31 #include "connectivity/sqlerror.hxx"
32 
33 /** === begin UNO includes === **/
34 #include <com/sun/star/sdbc/SQLException.hpp>
35 /** === end UNO includes === **/
36 
37 #include <comphelper/officeresourcebundle.hxx>
38 #include <cppuhelper/exc_hlp.hxx>
39 #include <rtl/ustrbuf.hxx>
40 
41 #include <string.h>
42 
43 //........................................................................
44 namespace connectivity
45 {
46 //........................................................................
47 
48 	/** === begin UNO using === **/
49 	using ::com::sun::star::uno::Reference;
50 	using ::com::sun::star::uno::UNO_QUERY;
51 	using ::com::sun::star::uno::UNO_QUERY_THROW;
52 	using ::com::sun::star::uno::Exception;
53 	using ::com::sun::star::uno::RuntimeException;
54 	using ::com::sun::star::uno::Any;
55 	using ::com::sun::star::uno::makeAny;
56     using ::com::sun::star::uno::XInterface;
57     using ::com::sun::star::sdbc::SQLException;
58     using ::com::sun::star::uno::Type;
59 	/** === end UNO using === **/
60 
61     //using SQLError::ParamValue; // GCC (unxlngi6) does not like this
62     namespace
63     {
64         typedef SQLError::ParamValue ParamValue;
65     }
66 
67 	//====================================================================
68 	//= SQLError_Impl - declaration
69 	//====================================================================
70     class SQLError_Impl
71     {
72     public:
73         SQLError_Impl( const ::comphelper::ComponentContext& _rContext );
74         ~SQLError_Impl();
75 
76         // versions of the public SQLError methods which are just delegated to this impl-class
77         static const ::rtl::OUString& getMessagePrefix();
78         ::rtl::OUString     getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
79         ::rtl::OUString     getSQLState( const ErrorCondition _eCondition );
80         static ErrorCode    getErrorCode( const ErrorCondition _eCondition );
81         void                raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
82         void                raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
83         void                raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
84         SQLException        getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
85 
86     private:
87         /// returns the basic error message associated with the given error condition, without any parameter replacements
88         ::rtl::OUString
89                 impl_getErrorMessage( const ErrorCondition& _eCondition );
90 
91         /// returns the SQLState associated with the given error condition
92         ::rtl::OUString
93                 impl_getSQLState( const ErrorCondition& _eCondition );
94 
95         /// returns an SQLException describing the given error condition
96         SQLException
97                 impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
98                     const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 );
99 
100         /// initializes our resource bundle
101         bool    impl_initResources();
102 
103     private:
104         ::osl::Mutex                                            m_aMutex;
105         ::comphelper::ComponentContext                          m_aContext;
106         ::std::auto_ptr< ::comphelper::OfficeResourceBundle >   m_pResources;
107         bool                                                    m_bAttemptedInit;
108     };
109 
110 	//====================================================================
111 	//= SQLError_Impl - implementation
112 	//====================================================================
113 	//--------------------------------------------------------------------
114     SQLError_Impl::SQLError_Impl( const ::comphelper::ComponentContext& _rContext )
115         :m_aContext( _rContext )
116         ,m_pResources( )
117         ,m_bAttemptedInit( false )
118     {
119     }
120 
121 	//--------------------------------------------------------------------
122     SQLError_Impl::~SQLError_Impl()
123     {
124     }
125 
126 	//--------------------------------------------------------------------
127     const ::rtl::OUString& SQLError_Impl::getMessagePrefix()
128     {
129         static ::rtl::OUString s_sMessagePrefix( RTL_CONSTASCII_USTRINGPARAM( "[OOoBase]" ) );
130         return s_sMessagePrefix;
131     }
132 
133 	//--------------------------------------------------------------------
134     namespace
135     {
136 	    //................................................................
137         /** substitutes a given placeholder in the given message with the given value
138         */
139         void    lcl_substitutePlaceholder( ::rtl::OUString& _rMessage, const sal_Char* _pPlaceholder, ParamValue _rParamValue )
140         {
141             size_t nPlaceholderLen( strlen( _pPlaceholder ) );
142             sal_Int32 nIndex = _rMessage.indexOfAsciiL( _pPlaceholder, nPlaceholderLen );
143 
144             bool bHasPlaceholder = ( nIndex != -1 );
145             bool bWantsPlaceholder = _rParamValue.is();
146             OSL_ENSURE( bHasPlaceholder == bWantsPlaceholder, "lcl_substitutePlaceholder: placeholder where none is expected, or no placeholder where one is needed!" );
147 
148             if ( bHasPlaceholder && bWantsPlaceholder )
149                 _rMessage = _rMessage.replaceAt( nIndex, nPlaceholderLen, *_rParamValue );
150         }
151 
152         //................................................................
153         sal_Int32   lcl_getResourceID( const ErrorCondition _eCondition, bool _bSQLState )
154         {
155             return  256
156                 +   2 * ::sal::static_int_cast< sal_Int32, ErrorCondition >( _eCondition )
157                 +   ( _bSQLState ? 1 : 0 );
158         }
159     }
160 
161 	//--------------------------------------------------------------------
162     ::rtl::OUString SQLError_Impl::getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
163     {
164         ::rtl::OUString sErrorMessage( impl_getErrorMessage( _eCondition ) );
165 
166         lcl_substitutePlaceholder( sErrorMessage, "$1$", _rParamValue1 );
167         lcl_substitutePlaceholder( sErrorMessage, "$2$", _rParamValue2 );
168         lcl_substitutePlaceholder( sErrorMessage, "$3$", _rParamValue3 );
169 
170         return sErrorMessage;
171     }
172 
173 	//--------------------------------------------------------------------
174     ::rtl::OUString SQLError_Impl::getSQLState( const ErrorCondition _eCondition )
175     {
176         return impl_getSQLState( _eCondition );
177     }
178 
179 	//--------------------------------------------------------------------
180     ErrorCode SQLError_Impl::getErrorCode( const ErrorCondition _eCondition )
181     {
182         return 0 - ::sal::static_int_cast< ErrorCode, ErrorCondition >( _eCondition );
183     }
184 
185 	//--------------------------------------------------------------------
186     void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
187     {
188         raiseTypedException(
189             _eCondition,
190             _rxContext,
191             ::cppu::UnoType< SQLException >::get(),
192             _rParamValue1,
193             _rParamValue2,
194             _rParamValue3
195         );
196     }
197 
198 	//--------------------------------------------------------------------
199     void SQLError_Impl::raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
200     {
201         raiseTypedException(
202             _eCondition,
203             NULL,
204             ::cppu::UnoType< SQLException >::get(),
205             _rParamValue1,
206             _rParamValue2,
207             _rParamValue3
208         );
209     }
210 
211 	//--------------------------------------------------------------------
212     void SQLError_Impl::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
213         const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
214     {
215         if ( !::cppu::UnoType< SQLException >::get().isAssignableFrom( _rExceptionType ) )
216             throw ::std::bad_cast();
217 
218         // default-construct an exception of the desired type
219         Any aException( NULL, _rExceptionType );
220 
221         // fill it
222         SQLException* pException = static_cast< SQLException* >( aException.pData );
223         *pException = impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
224 
225         // throw it
226         ::cppu::throwException( aException );
227     }
228 
229 	//--------------------------------------------------------------------
230     SQLException SQLError_Impl::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
231         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
232     {
233         return impl_buildSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
234     }
235 
236 	//--------------------------------------------------------------------
237     SQLException SQLError_Impl::impl_buildSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
238         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 )
239     {
240         return SQLException(
241             getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 ),
242             _rxContext,
243             getSQLState( _eCondition ),
244             getErrorCode( _eCondition ),
245             Any()
246         );
247     }
248 
249 	//--------------------------------------------------------------------
250     ::rtl::OUString SQLError_Impl::impl_getErrorMessage( const ErrorCondition& _eCondition )
251     {
252         ::rtl::OUStringBuffer aMessage;
253 
254         if ( impl_initResources() )
255         {
256             ::rtl::OUString sResMessage( m_pResources->loadString( lcl_getResourceID( _eCondition, false ) ) );
257             OSL_ENSURE( sResMessage.getLength(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" );
258             aMessage.append( getMessagePrefix() ).appendAscii( " " ).append( sResMessage );
259         }
260 
261         return aMessage.makeStringAndClear();
262     }
263 
264 	//--------------------------------------------------------------------
265     ::rtl::OUString SQLError_Impl::impl_getSQLState( const ErrorCondition& _eCondition )
266     {
267         ::rtl::OUString sState;
268 
269         if ( impl_initResources() )
270         {
271             sal_Int32 nResourceId( lcl_getResourceID( _eCondition, true ) );
272             if ( m_pResources->hasString( nResourceId ) )
273                 sState = m_pResources->loadString( nResourceId );
274         }
275 
276         if ( !sState.getLength() )
277             sState = ::rtl::OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "S1000" ) );
278 
279         return sState;
280     }
281 
282 	//--------------------------------------------------------------------
283     bool SQLError_Impl::impl_initResources()
284     {
285         if ( m_pResources.get() )
286             return true;
287         if ( m_bAttemptedInit )
288             return false;
289 
290         ::osl::MutexGuard aGuard( m_aMutex );
291         m_bAttemptedInit = true;
292 
293         m_pResources.reset( new ::comphelper::OfficeResourceBundle( m_aContext.getUNOContext(), "sdberr" ) );
294         return m_pResources.get() != NULL;
295     }
296 
297 	//====================================================================
298 	//= SQLError
299 	//====================================================================
300 	//--------------------------------------------------------------------
301     SQLError::SQLError( const ::comphelper::ComponentContext& _rContext )
302         :m_pImpl( new SQLError_Impl( _rContext ) )
303     {
304     }
305 
306 	//--------------------------------------------------------------------
307     SQLError::~SQLError()
308     {
309     }
310 
311 	//--------------------------------------------------------------------
312     const ::rtl::OUString& SQLError::getMessagePrefix()
313     {
314         return SQLError_Impl::getMessagePrefix();
315     }
316 
317 	//--------------------------------------------------------------------
318     ::rtl::OUString SQLError::getErrorMessage( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
319     {
320         return m_pImpl->getErrorMessage( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 );
321     }
322 
323 	//--------------------------------------------------------------------
324     ::rtl::OUString SQLError::getSQLState( const ErrorCondition _eCondition ) const
325     {
326         return m_pImpl->getSQLState( _eCondition );
327     }
328 
329 	//--------------------------------------------------------------------
330     ErrorCode SQLError::getErrorCode( const ErrorCondition _eCondition )
331     {
332         return SQLError_Impl::getErrorCode( _eCondition );
333     }
334 
335 	//--------------------------------------------------------------------
336     void SQLError::raiseException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
337     {
338         m_pImpl->raiseException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
339     }
340 
341 	//--------------------------------------------------------------------
342     void SQLError::raiseException( const ErrorCondition _eCondition, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
343     {
344         m_pImpl->raiseException( _eCondition, _rParamValue1, _rParamValue2, _rParamValue3 );
345     }
346 
347 	//--------------------------------------------------------------------
348     void SQLError::raiseTypedException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
349         const Type& _rExceptionType, const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
350     {
351         m_pImpl->raiseTypedException( _eCondition, _rxContext, _rExceptionType, _rParamValue1, _rParamValue2, _rParamValue3 );
352     }
353 
354 	//--------------------------------------------------------------------
355     SQLException SQLError::getSQLException( const ErrorCondition _eCondition, const Reference< XInterface >& _rxContext,
356         const ParamValue& _rParamValue1, const ParamValue& _rParamValue2, const ParamValue& _rParamValue3 ) const
357     {
358         return m_pImpl->getSQLException( _eCondition, _rxContext, _rParamValue1, _rParamValue2, _rParamValue3 );
359     }
360 
361 //........................................................................
362 } // namespace connectivity
363 //........................................................................
364