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_dbaccess.hxx"
30 
31 #include "dbmm_module.hxx"
32 #include "dbmm_global.hrc"
33 #include "migrationerror.hxx"
34 #include "migrationlog.hxx"
35 
36 /** === begin UNO includes === **/
37 /** === end UNO includes === **/
38 
39 #include <comphelper/anytostring.hxx>
40 #include <comphelper/string.hxx>
41 #include <tools/string.hxx>
42 #include <rtl/ustrbuf.hxx>
43 
44 #include <vector>
45 #include <map>
46 #include <list>
47 
48 //........................................................................
49 namespace dbmm
50 {
51 //........................................................................
52 
53 	/** === begin UNO using === **/
54 	/** === end UNO using === **/
55 
56 	//====================================================================
57 	//= LibraryEntry
58 	//====================================================================
59     struct LibraryEntry
60     {
61         ScriptType      eType;
62         ::rtl::OUString sOldName;
63         ::rtl::OUString sNewName;
64 
65         LibraryEntry()
66             :eType( eBasic )
67             ,sOldName()
68             ,sNewName()
69         {
70         }
71 
72         LibraryEntry( const ScriptType& _eType, const ::rtl::OUString& _rOldName, const ::rtl::OUString& _rNewName )
73             :eType( _eType )
74             ,sOldName( _rOldName )
75             ,sNewName( _rNewName )
76         {
77         }
78     };
79 
80 	//====================================================================
81 	//= DocumentEntry
82 	//====================================================================
83     struct DocumentEntry
84     {
85         SubDocumentType                 eType;
86         ::rtl::OUString                 sName;
87         ::std::vector< LibraryEntry >   aMovedLibraries;
88 
89         DocumentEntry()
90             :eType( eForm )
91             ,sName()
92             ,aMovedLibraries()
93         {
94         }
95 
96         DocumentEntry( const SubDocumentType _eType, const ::rtl::OUString& _rName )
97             :eType( _eType )
98             ,sName( _rName )
99         {
100         }
101     };
102 
103 	//====================================================================
104 	//= DocumentLogs
105 	//====================================================================
106     typedef ::std::map< DocumentID, DocumentEntry > DocumentLogs;
107 
108 	//====================================================================
109 	//= ErrorLog
110 	//====================================================================
111     typedef ::std::list< MigrationError >   ErrorLog;
112 
113 	//====================================================================
114 	//= MigrationLog_Data
115 	//====================================================================
116     struct MigrationLog_Data
117     {
118         ::rtl::OUString sBackupLocation;
119         DocumentLogs    aDocumentLogs;
120         ErrorLog        aFailures;
121         ErrorLog        aWarnings;
122     };
123 
124 	//====================================================================
125 	//= MigrationLog
126 	//====================================================================
127 	//--------------------------------------------------------------------
128     MigrationLog::MigrationLog()
129         :m_pData( new MigrationLog_Data )
130     {
131     }
132 
133 	//--------------------------------------------------------------------
134     MigrationLog::~MigrationLog()
135     {
136     }
137 
138 	//--------------------------------------------------------------------
139     void MigrationLog::logFailure( const MigrationError& _rError )
140     {
141         m_pData->aFailures.push_back( _rError );
142     }
143 
144 	//--------------------------------------------------------------------
145     void MigrationLog::logRecoverable( const MigrationError& _rError )
146     {
147         m_pData->aWarnings.push_back( _rError );
148     }
149 
150 	//--------------------------------------------------------------------
151     bool MigrationLog::hadFailure() const
152     {
153         return !m_pData->aFailures.empty();
154     }
155 
156 	//--------------------------------------------------------------------
157     void MigrationLog::backedUpDocument( const ::rtl::OUString& _rNewDocumentLocation )
158     {
159         m_pData->sBackupLocation = _rNewDocumentLocation;
160     }
161 
162 	//--------------------------------------------------------------------
163     DocumentID MigrationLog::startedDocument( const SubDocumentType _eType, const ::rtl::OUString& _rName )
164     {
165 #if OSL_DEBUG_LEVEL > 0
166         bool bAlreadyKnown = false;
167         for (   DocumentLogs::const_iterator doc = m_pData->aDocumentLogs.begin();
168                 doc != m_pData->aDocumentLogs.end() && !bAlreadyKnown;
169                 ++doc
170             )
171         {
172             bAlreadyKnown = ( doc->second.eType == _eType ) && ( doc->second.sName == _rName );
173         }
174         OSL_ENSURE( !bAlreadyKnown, "MigrationLog::startedDocument: document is already known!" );
175 #endif
176 
177         DocumentID nID = (DocumentID)( m_pData->aDocumentLogs.size() + 1 );
178         while ( m_pData->aDocumentLogs.find( nID ) != m_pData->aDocumentLogs.end() )
179             ++nID;
180 
181         m_pData->aDocumentLogs[ nID ] = DocumentEntry( _eType, _rName );
182 
183         return nID;
184     }
185 
186 	//--------------------------------------------------------------------
187     void MigrationLog::movedLibrary( const DocumentID _nDocID, const ScriptType _eScriptType,
188             const ::rtl::OUString& _rOriginalLibName, const ::rtl::OUString& _rNewLibName )
189     {
190         OSL_ENSURE( m_pData->aDocumentLogs.find( _nDocID ) != m_pData->aDocumentLogs.end(),
191             "MigrationLog::movedLibrary: document is not known!" );
192 
193         DocumentEntry& rDocEntry = m_pData->aDocumentLogs[ _nDocID ];
194         rDocEntry.aMovedLibraries.push_back( LibraryEntry( _eScriptType, _rOriginalLibName, _rNewLibName ) );
195     }
196 
197 	//--------------------------------------------------------------------
198     void MigrationLog::finishedDocument( const DocumentID _nDocID )
199     {
200         OSL_ENSURE( m_pData->aDocumentLogs.find( _nDocID ) != m_pData->aDocumentLogs.end(),
201             "MigrationLog::finishedDocument: document is not known!" );
202 
203         DocumentEntry& rDocEntry = m_pData->aDocumentLogs[ _nDocID ];
204         (void)rDocEntry;
205         // nothing to do here
206     }
207 
208 	//--------------------------------------------------------------------
209     const ::rtl::OUString& MigrationLog::getNewLibraryName( DocumentID _nDocID, ScriptType _eScriptType,
210         const ::rtl::OUString& _rOriginalLibName ) const
211     {
212         static ::rtl::OUString s_sEmptyString;
213 
214         DocumentLogs::const_iterator docPos = m_pData->aDocumentLogs.find( _nDocID );
215         if ( docPos == m_pData->aDocumentLogs.end() )
216         {
217             OSL_ENSURE( false, "MigrationLog::getNewLibraryName: document is not known!" );
218             return s_sEmptyString;
219         }
220 
221         const DocumentEntry& rDocEntry( docPos->second );
222         for (   ::std::vector< LibraryEntry >::const_iterator lib = rDocEntry.aMovedLibraries.begin();
223                 lib != rDocEntry.aMovedLibraries.end();
224                 ++lib
225             )
226         {
227             if  (   ( _eScriptType == lib->eType )
228                 &&  ( _rOriginalLibName == lib->sOldName )
229                 )
230                 return lib->sNewName;
231         }
232 
233         OSL_ENSURE( false, "MigrationLog::getNewLibraryName: doc is known, but library isn't!" );
234         return s_sEmptyString;
235     }
236 
237 	//--------------------------------------------------------------------
238     namespace
239     {
240 	    //----------------------------------------------------------------
241         static void lcl_appendErrorDescription( ::rtl::OUStringBuffer& _inout_rBuffer, const MigrationError& _rError )
242         {
243             const sal_Char* pAsciiErrorDescription( NULL );
244             ::std::vector< const sal_Char* > aAsciiParameterNames;
245             switch ( _rError.eType )
246             {
247             case ERR_OPENING_SUB_DOCUMENT_FAILED:
248                 pAsciiErrorDescription = "opening '#doc#' failed";
249                 aAsciiParameterNames.push_back( "#doc#" );
250                 break;
251 
252             case ERR_CLOSING_SUB_DOCUMENT_FAILED:
253                 pAsciiErrorDescription = "closing '#doc#' failed";
254                 aAsciiParameterNames.push_back( "#doc#" );
255                 break;
256 
257             case ERR_STORAGE_COMMIT_FAILED:
258                 pAsciiErrorDescription = "committing the changes for document '#doc#' failed";
259                 aAsciiParameterNames.push_back( "#doc#" );
260                 break;
261 
262             case ERR_STORING_DATABASEDOC_FAILED:
263                 pAsciiErrorDescription = "storing the database document failed";
264                 break;
265 
266             case ERR_COLLECTING_DOCUMENTS_FAILED:
267                 pAsciiErrorDescription = "collecting the forms/reports of the database document failed";
268                 break;
269 
270             case ERR_UNEXPECTED_LIBSTORAGE_ELEMENT:
271                 pAsciiErrorDescription = "unexpected #lib# storage element in document '#doc#', named '#element#'";
272                 aAsciiParameterNames.push_back( "#doc#" );
273                 aAsciiParameterNames.push_back( "#libstore#" );
274                 aAsciiParameterNames.push_back( "#element#" );
275                 break;
276 
277             case ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED:
278                 pAsciiErrorDescription = "creating the database document's storage for #scripttype# scripts failed";
279                 aAsciiParameterNames.push_back( "#scripttype#" );
280                 break;
281 
282             case ERR_COMMITTING_SCRIPT_STORAGES_FAILED:
283                 pAsciiErrorDescription = "saving the #scripttype# scripts for document '#doc#' failed";
284                 aAsciiParameterNames.push_back( "#scripttype#" );
285                 aAsciiParameterNames.push_back( "#doc#" );
286                 break;
287 
288             case ERR_GENERAL_SCRIPT_MIGRATION_FAILURE:
289                 pAsciiErrorDescription = "general error while migrating #scripttype# scripts of document '#doc#'";
290                 aAsciiParameterNames.push_back( "#scripttype#" );
291                 aAsciiParameterNames.push_back( "#doc#" );
292                 break;
293 
294             case ERR_GENERAL_MACRO_MIGRATION_FAILURE:
295                 pAsciiErrorDescription = "general error during macro migration of document '#doc#'";
296                 aAsciiParameterNames.push_back( "#doc#" );
297                 break;
298 
299             case ERR_UNKNOWN_SCRIPT_TYPE:
300                 pAsciiErrorDescription = "unknown script type: #type#";
301                 aAsciiParameterNames.push_back( "#type#" );
302                 break;
303 
304             case ERR_UNKNOWN_SCRIPT_LANGUAGE:
305                 pAsciiErrorDescription = "unknown script language: #lang#";
306                 aAsciiParameterNames.push_back( "#lang#" );
307                 break;
308 
309             case ERR_UNKNOWN_SCRIPT_NAME_FORMAT:
310                 pAsciiErrorDescription = "unknown script name format: #script#";
311                 aAsciiParameterNames.push_back( "#script#" );
312                 break;
313 
314             case ERR_SCRIPT_TRANSLATION_FAILURE:
315                 pAsciiErrorDescription = "analyzing/translating the script URL failed; script type: #type#; script: #code#";
316                 aAsciiParameterNames.push_back( "#type#" );
317                 aAsciiParameterNames.push_back( "#code#" );
318                 break;
319 
320             case ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT:
321                 pAsciiErrorDescription = "invalid script descriptor format";
322                 break;
323 
324             case ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED:
325                 pAsciiErrorDescription = "adjusting events for document '#doc#' failed";
326                 aAsciiParameterNames.push_back( "#doc#" );
327                 break;
328 
329             case ERR_ADJUSTING_DIALOG_EVENTS_FAILED:
330                 pAsciiErrorDescription = "adjusting events for dialog #lib#.#dlg# in document '#doc#' failed";
331                 aAsciiParameterNames.push_back( "#doc#" );
332                 aAsciiParameterNames.push_back( "#lib#" );
333                 aAsciiParameterNames.push_back( "#dlg#" );
334                 break;
335 
336             case ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED:
337                 pAsciiErrorDescription = "adjusting form component events for '#doc#' failed";
338                 aAsciiParameterNames.push_back( "#doc#" );
339                 break;
340 
341             case ERR_BIND_SCRIPT_STORAGE_FAILED:
342                 pAsciiErrorDescription = "binding to the script storage failed for document '#doc#'";
343                 aAsciiParameterNames.push_back( "#doc#" );
344                 break;
345 
346             case ERR_REMOVE_SCRIPTS_STORAGE_FAILED:
347                 pAsciiErrorDescription = "removing a scripts storage failed for document '#doc#'";
348                 aAsciiParameterNames.push_back( "#doc#" );
349                 break;
350 
351             case ERR_DOCUMENT_BACKUP_FAILED:
352                 pAsciiErrorDescription = "backing up the document to #location# failed";
353                 aAsciiParameterNames.push_back( "#location#" );
354                 break;
355 
356             case ERR_UNKNOWN_SCRIPT_FOLDER:
357                 pAsciiErrorDescription = "unknown script folder '#name#' in document '#doc#'";
358                 aAsciiParameterNames.push_back( "#doc#" );
359                 aAsciiParameterNames.push_back( "#name#" );
360                 break;
361 
362             case ERR_EXAMINING_SCRIPTS_FOLDER_FAILED:
363                 pAsciiErrorDescription = "examining the 'Scripts' folder failed for document '#doc#'";
364                 aAsciiParameterNames.push_back( "#doc#" );
365                 break;
366 
367             case ERR_PASSWORD_VERIFICATION_FAILED:
368                 pAsciiErrorDescription = "password verification failed for document '#doc#', #libtype# library '#name#'";
369                 aAsciiParameterNames.push_back( "#doc#" );
370                 aAsciiParameterNames.push_back( "#libtype#" );
371                 aAsciiParameterNames.push_back( "#name#" );
372                 break;
373 
374             case ERR_NEW_STYLE_REPORT:
375                 pAsciiErrorDescription = "#doc# could not be processed, since you don't have the Oracle Report Builder (TM) extension installed.";
376                 aAsciiParameterNames.push_back( "#doc#" );
377                 break;
378 
379                 // do *not* add a default case here: Without a default, some compilers will warn you when
380                 // you miss a newly-introduced enum value here
381             }
382             OSL_ENSURE( pAsciiErrorDescription, "lcl_appendErrorDescription: no error message!" );
383             if ( pAsciiErrorDescription )
384             {
385                 ::rtl::OUString sSubstituted( ::rtl::OUString::createFromAscii( pAsciiErrorDescription ) );
386                 OSL_ENSURE( aAsciiParameterNames.size() == _rError.aErrorDetails.size(),
387                     "lcl_appendErrorDescription: unexpected number of error message parameters!" );
388 
389                 for ( size_t i=0; i < ::std::min( aAsciiParameterNames.size(), _rError.aErrorDetails.size() ); ++i )
390                 {
391                     ::comphelper::string::searchAndReplaceAsciiI( sSubstituted, aAsciiParameterNames[i],
392                         _rError.aErrorDetails[i] );
393                 }
394 
395                 _inout_rBuffer.append( sSubstituted );
396             }
397         }
398 
399         //----------------------------------------------------------------
400         void lcl_describeErrors( ::rtl::OUStringBuffer& _rBuffer, const ErrorLog& _rErrors, const sal_uInt16 _nHeadingResId )
401         {
402             _rBuffer.appendAscii( "=== " );
403             _rBuffer.append     ( String( MacroMigrationResId( _nHeadingResId ) ) );
404             _rBuffer.appendAscii( " ===\n" );
405 
406             String sException( MacroMigrationResId( STR_EXCEPTION ) );
407 
408             for (   ErrorLog::const_iterator error = _rErrors.begin();
409                     error != _rErrors.end();
410                     ++error
411                 )
412             {
413                 _rBuffer.append( sal_Unicode( '-' ) );
414                 _rBuffer.append( sal_Unicode( ' ' ) );
415                 lcl_appendErrorDescription( _rBuffer, *error );
416                 _rBuffer.append( sal_Unicode( '\n' ) );
417 
418                 if ( !error->aCaughtException.hasValue() )
419                     continue;
420 
421                 _rBuffer.append( sException );
422                 _rBuffer.append( ::comphelper::anyToString( error->aCaughtException ) );
423                 _rBuffer.append( sal_Unicode( '\n' ) );
424                 _rBuffer.append( sal_Unicode( '\n' ) );
425             }
426         }
427     }
428 
429 	//--------------------------------------------------------------------
430     bool MigrationLog::movedAnyLibrary( const DocumentID _nDocID )
431     {
432         DocumentLogs::const_iterator docPos = m_pData->aDocumentLogs.find( _nDocID );
433         if ( docPos == m_pData->aDocumentLogs.end() )
434         {
435             OSL_ENSURE( false, "MigrationLog::movedAnyLibrary: document is not known!" );
436             return false;
437         }
438         return !docPos->second.aMovedLibraries.empty();
439     }
440 
441 	//--------------------------------------------------------------------
442     ::rtl::OUString MigrationLog::getCompleteLog() const
443     {
444         ::rtl::OUStringBuffer aBuffer;
445 
446         if ( m_pData->sBackupLocation.getLength() )
447         {
448             String sBackedUp( MacroMigrationResId( STR_SAVED_COPY_TO ) );
449             sBackedUp.SearchAndReplaceAllAscii( "$location$", m_pData->sBackupLocation );
450 
451             aBuffer.appendAscii( "=== " );
452             aBuffer.append     ( String( MacroMigrationResId( STR_DATABASE_DOCUMENT ) ) );
453             aBuffer.appendAscii( " ===\n" );
454             aBuffer.append     ( sBackedUp );
455             aBuffer.appendAscii( "\n\n" );
456         }
457 
458         if ( !m_pData->aFailures.empty() )
459         {
460             lcl_describeErrors( aBuffer, m_pData->aFailures
461                 , STR_ERRORS );
462         }
463         else
464         {
465             String sMovedLibTemplate( MacroMigrationResId( STR_MOVED_LIBRARY ) );
466 
467             for (   DocumentLogs::const_iterator doc = m_pData->aDocumentLogs.begin();
468                     doc != m_pData->aDocumentLogs.end();
469                     ++doc
470                 )
471             {
472                 const DocumentEntry& rDoc( doc->second );
473 
474                 if ( rDoc.aMovedLibraries.empty() )
475                     continue;
476 
477                 String sDocTitle( MacroMigrationResId( rDoc.eType == eForm ? STR_FORM : STR_REPORT ) );
478                 sDocTitle.SearchAndReplaceAllAscii( "$name$", rDoc.sName );
479 
480                 aBuffer.appendAscii( "=== " );
481                 aBuffer.append     ( sDocTitle );
482                 aBuffer.appendAscii( " ===\n" );
483 
484                 for (   ::std::vector< LibraryEntry >::const_iterator lib = rDoc.aMovedLibraries.begin();
485                         lib != rDoc.aMovedLibraries.end();
486                         ++lib
487                     )
488                 {
489                     String sMovedLib( sMovedLibTemplate );
490                     sMovedLib.SearchAndReplaceAllAscii( "$type$", getScriptTypeDisplayName( lib->eType ) );
491                     sMovedLib.SearchAndReplaceAllAscii( "$old$", lib->sOldName );
492                     sMovedLib.SearchAndReplaceAllAscii( "$new$", lib->sNewName );
493 
494                     aBuffer.append( sMovedLib );
495                     aBuffer.append( sal_Unicode( '\n' ) );
496                 }
497 
498                 aBuffer.append( sal_Unicode( '\n' ) );
499             }
500         }
501 
502         if ( !m_pData->aWarnings.empty() )
503         {
504             lcl_describeErrors( aBuffer, m_pData->aWarnings, STR_WARNINGS );
505         }
506 
507         return aBuffer.makeStringAndClear();
508     }
509 
510 //........................................................................
511 } // namespace dbmm
512 //........................................................................
513