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