LCOV - code coverage report
Current view: top level - dbaccess/source/core/recovery - dbdocrecovery.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 152 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "recovery/dbdocrecovery.hxx"
      21             : #include "sdbcoretools.hxx"
      22             : #include "storagetextstream.hxx"
      23             : #include "subcomponentrecovery.hxx"
      24             : #include "subcomponents.hxx"
      25             : #include "dbastrings.hrc"
      26             : 
      27             : #include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
      28             : #include <com/sun/star/embed/ElementModes.hpp>
      29             : #include <com/sun/star/document/XStorageBasedDocument.hpp>
      30             : #include <com/sun/star/io/XTextOutputStream.hpp>
      31             : #include <com/sun/star/io/TextInputStream.hpp>
      32             : #include <com/sun/star/io/XActiveDataSource.hpp>
      33             : #include <com/sun/star/io/XActiveDataSink.hpp>
      34             : #include <com/sun/star/util/XModifiable.hpp>
      35             : #include <com/sun/star/beans/XPropertySet.hpp>
      36             : 
      37             : #include <comphelper/namedvaluecollection.hxx>
      38             : #include <rtl/ustrbuf.hxx>
      39             : #include <tools/diagnose_ex.h>
      40             : 
      41             : #include <algorithm>
      42             : 
      43             : namespace dbaccess
      44             : {
      45             : 
      46             :     using css::uno::Reference;
      47             :     using css::uno::XInterface;
      48             :     using css::uno::UNO_QUERY;
      49             :     using css::uno::UNO_QUERY_THROW;
      50             :     using css::uno::UNO_SET_THROW;
      51             :     using css::uno::Exception;
      52             :     using css::uno::RuntimeException;
      53             :     using css::uno::Any;
      54             :     using css::uno::makeAny;
      55             :     using css::uno::Sequence;
      56             :     using css::uno::Type;
      57             :     using css::uno::XComponentContext;
      58             :     using css::embed::XStorage;
      59             :     using css::frame::XController;
      60             :     using css::sdb::application::XDatabaseDocumentUI;
      61             :     using css::lang::XComponent;
      62             :     using css::document::XStorageBasedDocument;
      63             :     using css::beans::PropertyValue;
      64             :     using css::io::XStream;
      65             :     using css::io::XTextOutputStream;
      66             :     using css::io::XActiveDataSource;
      67             :     using css::io::TextInputStream;
      68             :     using css::io::XTextInputStream2;
      69             :     using css::io::XActiveDataSink;
      70             :     using css::frame::XModel;
      71             :     using css::util::XModifiable;
      72             :     using css::beans::XPropertySet;
      73             : 
      74             :     namespace ElementModes = css::embed::ElementModes;
      75             : 
      76             :     // helpers
      77             :     namespace
      78             :     {
      79           0 :         static void lcl_getPersistentRepresentation( const MapStringToCompDesc::value_type& i_rComponentDesc, OUStringBuffer& o_rBuffer )
      80             :         {
      81           0 :             o_rBuffer.append( i_rComponentDesc.first );
      82           0 :             o_rBuffer.append( '=' );
      83           0 :             o_rBuffer.append( i_rComponentDesc.second.sName );
      84           0 :             o_rBuffer.append( ',' );
      85           0 :             o_rBuffer.append( sal_Unicode( i_rComponentDesc.second.bForEditing ? '1' : '0' ) );
      86           0 :         }
      87             : 
      88           0 :         static bool lcl_extractCompDesc( const OUString& i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc )
      89             :         {
      90           0 :             const sal_Int32 nEqualSignPos = i_rIniLine.indexOf( '=' );
      91           0 :             if ( nEqualSignPos < 1 )
      92             :             {
      93             :                 OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" );
      94           0 :                 return false;
      95             :             }
      96           0 :             o_rStorName = i_rIniLine.copy( 0, nEqualSignPos );
      97             : 
      98           0 :             const sal_Int32 nCommaPos = i_rIniLine.lastIndexOf( ',' );
      99           0 :             if ( nCommaPos != i_rIniLine.getLength() - 2 )
     100             :             {
     101             :                 OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" );
     102           0 :                 return false;
     103             :             }
     104           0 :             o_rCompDesc.sName = i_rIniLine.copy( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 );
     105           0 :             o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] == '1' );
     106           0 :             return true;
     107             :         }
     108             : 
     109             :         static const char sRecoveryDataSubStorageName[] = "recovery";
     110             : 
     111             :         static const char sObjectMapStreamName[] = "storage-component-map.ini";
     112             : 
     113           0 :         static void lcl_writeObjectMap_throw( const Reference<XComponentContext> & i_rContext, const Reference< XStorage >& i_rStorage,
     114             :             const MapStringToCompDesc& i_mapStorageToCompDesc )
     115             :         {
     116           0 :             if ( i_mapStorageToCompDesc.empty() )
     117             :                 // nothing to do
     118           0 :                 return;
     119             : 
     120           0 :             StorageTextOutputStream aTextOutput( i_rContext, i_rStorage, sObjectMapStreamName );
     121             : 
     122           0 :             aTextOutput.writeLine( "[storages]" );
     123             : 
     124           0 :             for (   MapStringToCompDesc::const_iterator stor = i_mapStorageToCompDesc.begin();
     125           0 :                     stor != i_mapStorageToCompDesc.end();
     126             :                     ++stor
     127             :                 )
     128             :             {
     129           0 :                 OUStringBuffer aLine;
     130           0 :                 lcl_getPersistentRepresentation( *stor, aLine );
     131             : 
     132           0 :                 aTextOutput.writeLine( aLine.makeStringAndClear() );
     133           0 :             }
     134             : 
     135           0 :             aTextOutput.writeLine();
     136             :         }
     137             : 
     138           0 :         static bool lcl_isSectionStart( const OUString& i_rIniLine, OUString& o_rSectionName )
     139             :         {
     140           0 :             const sal_Int32 nLen = i_rIniLine.getLength();
     141           0 :             if ( i_rIniLine.startsWith("[") && i_rIniLine.endsWith("]") )
     142             :             {
     143           0 :                 o_rSectionName = i_rIniLine.copy( 1, nLen -2 );
     144           0 :                 return true;
     145             :             }
     146           0 :             return false;
     147             :         }
     148             : 
     149           0 :         static void lcl_stripTrailingLineFeed( OUString& io_rLine )
     150             :         {
     151           0 :             const sal_Int32 nLen = io_rLine.getLength();
     152           0 :             if ( io_rLine.endsWith("\n") )
     153           0 :                 io_rLine = io_rLine.copy( 0, nLen - 1 );
     154           0 :         }
     155             : 
     156           0 :         static void lcl_readObjectMap_throw( const Reference<XComponentContext> & i_rxContext, const Reference< XStorage >& i_rStorage,
     157             :             MapStringToCompDesc& o_mapStorageToObjectName )
     158             :         {
     159           0 :             ENSURE_OR_THROW( i_rStorage.is(), "invalid storage" );
     160           0 :             if ( !i_rStorage->hasByName( sObjectMapStreamName ) )
     161             :             {   // nothing to do, though suspicious
     162             :                 OSL_FAIL( "lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" );
     163           0 :                 return;
     164             :             }
     165             : 
     166           0 :             Reference< XStream > xIniStream( i_rStorage->openStreamElement(
     167           0 :                 sObjectMapStreamName, ElementModes::READ ), UNO_SET_THROW );
     168             : 
     169           0 :             Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext );
     170           0 :             xTextInput->setEncoding( "UTF-8" );
     171           0 :             xTextInput->setInputStream( xIniStream->getInputStream() );
     172             : 
     173           0 :             OUString sCurrentSection;
     174           0 :             bool bCurrentSectionIsKnownToBeUnsupported = true;
     175           0 :             while ( !xTextInput->isEOF() )
     176             :             {
     177           0 :                 OUString sLine = xTextInput->readLine();
     178           0 :                 lcl_stripTrailingLineFeed( sLine );
     179             : 
     180           0 :                 if ( sLine.isEmpty() )
     181           0 :                     continue;
     182             : 
     183           0 :                 if ( lcl_isSectionStart( sLine, sCurrentSection ) )
     184             :                 {
     185           0 :                     bCurrentSectionIsKnownToBeUnsupported = false;
     186           0 :                     continue;
     187             :                 }
     188             : 
     189           0 :                 if ( bCurrentSectionIsKnownToBeUnsupported )
     190           0 :                     continue;
     191             : 
     192             :                 // the only section we support so far is "storages"
     193           0 :                 if ( sCurrentSection != "storages" )
     194             :                 {
     195           0 :                     bCurrentSectionIsKnownToBeUnsupported = true;
     196           0 :                     continue;
     197             :                 }
     198             : 
     199           0 :                 OUString sStorageName;
     200           0 :                 SubComponentDescriptor aCompDesc;
     201           0 :                 if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) )
     202           0 :                     continue;
     203           0 :                 o_mapStorageToObjectName[ sStorageName ] = aCompDesc;
     204           0 :             }
     205             :         }
     206             : 
     207           0 :         static void lcl_markModified( const Reference< XComponent >& i_rSubComponent )
     208             :         {
     209           0 :             const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY );
     210           0 :             if ( !xModify.is() )
     211             :             {
     212             :                 OSL_FAIL( "lcl_markModified: unhandled case!" );
     213           0 :                 return;
     214             :             }
     215             : 
     216           0 :             xModify->setModified( sal_True );
     217             :         }
     218             :     }
     219             : 
     220             :     // DatabaseDocumentRecovery_Data
     221           0 :     struct DBACCESS_DLLPRIVATE DatabaseDocumentRecovery_Data
     222             :     {
     223             :         const Reference<XComponentContext> aContext;
     224             : 
     225           0 :         DatabaseDocumentRecovery_Data( const Reference<XComponentContext> & i_rContext )
     226           0 :             :aContext( i_rContext )
     227             :         {
     228           0 :         }
     229             :     };
     230             : 
     231             :     // DatabaseDocumentRecovery
     232           0 :     DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference<XComponentContext> & i_rContext )
     233           0 :         :m_pData( new DatabaseDocumentRecovery_Data( i_rContext ) )
     234             :     {
     235           0 :     }
     236             : 
     237           0 :     DatabaseDocumentRecovery::~DatabaseDocumentRecovery()
     238             :     {
     239           0 :     }
     240             : 
     241           0 :     void DatabaseDocumentRecovery::saveModifiedSubComponents( const Reference< XStorage >& i_rTargetStorage,
     242             :         const ::std::vector< Reference< XController > >& i_rControllers )
     243             :     {
     244           0 :         ENSURE_OR_THROW( i_rTargetStorage.is(), "invalid document storage" );
     245             : 
     246             :         // create a sub storage for recovery data
     247           0 :         if ( i_rTargetStorage->hasByName( sRecoveryDataSubStorageName ) )
     248           0 :             i_rTargetStorage->removeElement( sRecoveryDataSubStorageName );
     249           0 :         Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READWRITE );
     250             : 
     251             :         // store recovery data for open sub components of the given controller(s)
     252           0 :         if ( !i_rControllers.empty() )
     253             :         {
     254           0 :             ENSURE_OR_THROW( i_rControllers.size() == 1, "can't handle more than one controller" );
     255             :             // At the moment, there can be only one view to a database document. If we ever allow for more than this,
     256             :             // then we need a concept for sub documents opened from different controllers (i.e. two document views,
     257             :             // and the user opens the very same form in both views). And depending on this, we need a concept for
     258             :             // how those are saved to the recovery file.
     259             : 
     260           0 :             MapCompTypeToCompDescs aMapCompDescs;
     261             : 
     262           0 :             for (   ::std::vector< Reference< XController > >::const_iterator ctrl = i_rControllers.begin();
     263           0 :                     ctrl != i_rControllers.end();
     264             :                     ++ctrl
     265             :                 )
     266             :             {
     267           0 :                 Reference< XDatabaseDocumentUI > xDatabaseUI( *ctrl, UNO_QUERY_THROW );
     268           0 :                 Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
     269             : 
     270           0 :                 const Reference< XComponent >* component = aComponents.getConstArray();
     271           0 :                 const Reference< XComponent >* componentEnd = aComponents.getConstArray() + aComponents.getLength();
     272           0 :                 for ( ; component != componentEnd; ++component )
     273             :                 {
     274           0 :                     SubComponentRecovery aComponentRecovery( m_pData->aContext, xDatabaseUI, *component );
     275           0 :                     aComponentRecovery.saveToRecoveryStorage( xRecoveryStorage, aMapCompDescs );
     276           0 :                 }
     277           0 :             }
     278             : 
     279           0 :             for (   MapCompTypeToCompDescs::const_iterator map = aMapCompDescs.begin();
     280           0 :                     map != aMapCompDescs.end();
     281             :                     ++map
     282             :                 )
     283             :             {
     284           0 :                 Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     285           0 :                     SubComponentRecovery::getComponentsStorageName( map->first ), ElementModes::WRITE | ElementModes::NOCREATE ) );
     286           0 :                 lcl_writeObjectMap_throw( m_pData->aContext, xComponentsStor, map->second );
     287           0 :                 tools::stor::commitStorageIfWriteable( xComponentsStor );
     288           0 :             }
     289             :         }
     290             : 
     291             :         // commit the recovery storage
     292           0 :         tools::stor::commitStorageIfWriteable( xRecoveryStorage );
     293           0 :     }
     294             : 
     295           0 :     void DatabaseDocumentRecovery::recoverSubDocuments( const Reference< XStorage >& i_rDocumentStorage,
     296             :         const Reference< XController >& i_rTargetController )
     297             :     {
     298           0 :         ENSURE_OR_THROW( i_rDocumentStorage.is(), "illegal document storage" );
     299           0 :         Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW );
     300             : 
     301           0 :         if ( !i_rDocumentStorage->hasByName( sRecoveryDataSubStorageName ) )
     302             :             // that's allowed
     303           0 :             return;
     304             : 
     305             :         // the "recovery" sub storage
     306           0 :         Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READ );
     307             : 
     308             :         // read the map from sub storages to object names
     309           0 :         MapCompTypeToCompDescs aMapCompDescs;
     310           0 :         SubComponentType aKnownTypes[] = { TABLE, QUERY, FORM, REPORT, RELATION_DESIGN };
     311           0 :         for ( size_t i = 0; i < sizeof( aKnownTypes ) / sizeof( aKnownTypes[0] ); ++i )
     312             :         {
     313           0 :             if ( !xRecoveryStorage->hasByName( SubComponentRecovery::getComponentsStorageName( aKnownTypes[i] ) ) )
     314           0 :                 continue;
     315             : 
     316           0 :             Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     317           0 :                 SubComponentRecovery::getComponentsStorageName( aKnownTypes[i] ), ElementModes::READ ) );
     318           0 :             lcl_readObjectMap_throw( m_pData->aContext, xComponentsStor, aMapCompDescs[ aKnownTypes[i] ] );
     319           0 :             xComponentsStor->dispose();
     320           0 :         }
     321             : 
     322             :         // recover all sub components as indicated by the map
     323           0 :         for (   MapCompTypeToCompDescs::const_iterator map = aMapCompDescs.begin();
     324           0 :                 map != aMapCompDescs.end();
     325             :                 ++map
     326             :             )
     327             :         {
     328           0 :             const SubComponentType eComponentType = map->first;
     329             : 
     330             :             // the storage for all components of the current type
     331           0 :             Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     332           0 :                 SubComponentRecovery::getComponentsStorageName( eComponentType ), ElementModes::READ ), UNO_QUERY_THROW );
     333             : 
     334             :             // loop through all components of this type
     335           0 :             for (   MapStringToCompDesc::const_iterator stor = map->second.begin();
     336           0 :                     stor != map->second.end();
     337             :                     ++stor
     338             :                 )
     339             :             {
     340           0 :                 const OUString sComponentName( stor->second.sName );
     341           0 :                 if ( !xComponentsStor->hasByName( stor->first ) )
     342             :                 {
     343             :                     SAL_WARN( "dbaccess",
     344             :                               "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" <<
     345             :                               stor->first <<
     346             :                               "' not found in '" <<
     347             :                               SubComponentRecovery::getComponentsStorageName( eComponentType ) <<
     348             :                               "', but required per map file!" );
     349           0 :                     continue;
     350             :                 }
     351             : 
     352             :                 // the controller needs to have a connection to be able to open sub components
     353           0 :                 if ( !xDocumentUI->isConnected() )
     354           0 :                     xDocumentUI->connect();
     355             : 
     356             :                 // recover the single component
     357           0 :                 Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( stor->first, ElementModes::READ ) );
     358           0 :                 SubComponentRecovery aComponentRecovery( m_pData->aContext, xDocumentUI, eComponentType );
     359           0 :                 Reference< XComponent > xSubComponent( aComponentRecovery.recoverFromStorage( xCompStor, sComponentName, stor->second.bForEditing ) );
     360             : 
     361             :                 // at the moment, we only store, during session save, sub components which are modified. So, set this
     362             :                 // recovered sub component to "modified", too.
     363           0 :                 lcl_markModified( xSubComponent );
     364           0 :             }
     365             : 
     366           0 :             xComponentsStor->dispose();
     367           0 :         }
     368             : 
     369           0 :         xRecoveryStorage->dispose();
     370             : 
     371             :         // now that we successfully recovered, removed the "recovery" sub storage
     372             :         try
     373             :         {
     374           0 :             i_rDocumentStorage->removeElement( sRecoveryDataSubStorageName );
     375             :         }
     376           0 :         catch( const Exception& )
     377             :         {
     378             :             DBG_UNHANDLED_EXCEPTION();
     379           0 :         }
     380             :     }
     381             : 
     382             : } // namespace dbaccess
     383             : 
     384             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11