LCOV - code coverage report
Current view: top level - dbaccess/source/core/recovery - dbdocrecovery.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 0 161 0.0 %
Date: 2014-11-03 Functions: 0 16 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           0 :         static const OUString& lcl_getRecoveryDataSubStorageName()
     110             :         {
     111           0 :             static const OUString s_sRecDataStorName( "recovery" );
     112           0 :             return s_sRecDataStorName;
     113             :         }
     114             : 
     115           0 :         static const OUString& lcl_getObjectMapStreamName()
     116             :         {
     117           0 :             static const OUString s_sObjectMapStreamName( "storage-component-map.ini" );
     118           0 :             return s_sObjectMapStreamName;
     119             :         }
     120             : 
     121           0 :         static const OUString& lcl_getMapStreamEncodingName()
     122             :         {
     123           0 :             static const OUString s_sMapStreamEncodingName( "UTF-8" );
     124           0 :             return s_sMapStreamEncodingName;
     125             :         }
     126             : 
     127           0 :         static void lcl_writeObjectMap_throw( const Reference<XComponentContext> & i_rContext, const Reference< XStorage >& i_rStorage,
     128             :             const MapStringToCompDesc& i_mapStorageToCompDesc )
     129             :         {
     130           0 :             if ( i_mapStorageToCompDesc.empty() )
     131             :                 // nothing to do
     132           0 :                 return;
     133             : 
     134           0 :             StorageTextOutputStream aTextOutput( i_rContext, i_rStorage, lcl_getObjectMapStreamName() );
     135             : 
     136           0 :             aTextOutput.writeLine( "[storages]" );
     137             : 
     138           0 :             for (   MapStringToCompDesc::const_iterator stor = i_mapStorageToCompDesc.begin();
     139           0 :                     stor != i_mapStorageToCompDesc.end();
     140             :                     ++stor
     141             :                 )
     142             :             {
     143           0 :                 OUStringBuffer aLine;
     144           0 :                 lcl_getPersistentRepresentation( *stor, aLine );
     145             : 
     146           0 :                 aTextOutput.writeLine( aLine.makeStringAndClear() );
     147           0 :             }
     148             : 
     149           0 :             aTextOutput.writeLine();
     150             :         }
     151             : 
     152           0 :         static bool lcl_isSectionStart( const OUString& i_rIniLine, OUString& o_rSectionName )
     153             :         {
     154           0 :             const sal_Int32 nLen = i_rIniLine.getLength();
     155           0 :             if ( i_rIniLine.startsWith("[") && i_rIniLine.endsWith("]") )
     156             :             {
     157           0 :                 o_rSectionName = i_rIniLine.copy( 1, nLen -2 );
     158           0 :                 return true;
     159             :             }
     160           0 :             return false;
     161             :         }
     162             : 
     163           0 :         static void lcl_stripTrailingLineFeed( OUString& io_rLine )
     164             :         {
     165           0 :             const sal_Int32 nLen = io_rLine.getLength();
     166           0 :             if ( io_rLine.endsWith("\n") )
     167           0 :                 io_rLine = io_rLine.copy( 0, nLen - 1 );
     168           0 :         }
     169             : 
     170           0 :         static void lcl_readObjectMap_throw( const Reference<XComponentContext> & i_rxContext, const Reference< XStorage >& i_rStorage,
     171             :             MapStringToCompDesc& o_mapStorageToObjectName )
     172             :         {
     173           0 :             ENSURE_OR_THROW( i_rStorage.is(), "invalid storage" );
     174           0 :             if ( !i_rStorage->hasByName( lcl_getObjectMapStreamName() ) )
     175             :             {   // nothing to do, though suspicious
     176             :                 OSL_FAIL( "lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" );
     177           0 :                 return;
     178             :             }
     179             : 
     180           0 :             Reference< XStream > xIniStream( i_rStorage->openStreamElement(
     181           0 :                 lcl_getObjectMapStreamName(), ElementModes::READ ), UNO_SET_THROW );
     182             : 
     183           0 :             Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext );
     184           0 :             xTextInput->setEncoding( lcl_getMapStreamEncodingName() );
     185           0 :             xTextInput->setInputStream( xIniStream->getInputStream() );
     186             : 
     187           0 :             OUString sCurrentSection;
     188           0 :             bool bCurrentSectionIsKnownToBeUnsupported = true;
     189           0 :             while ( !xTextInput->isEOF() )
     190             :             {
     191           0 :                 OUString sLine = xTextInput->readLine();
     192           0 :                 lcl_stripTrailingLineFeed( sLine );
     193             : 
     194           0 :                 if ( sLine.isEmpty() )
     195           0 :                     continue;
     196             : 
     197           0 :                 if ( lcl_isSectionStart( sLine, sCurrentSection ) )
     198             :                 {
     199           0 :                     bCurrentSectionIsKnownToBeUnsupported = false;
     200           0 :                     continue;
     201             :                 }
     202             : 
     203           0 :                 if ( bCurrentSectionIsKnownToBeUnsupported )
     204           0 :                     continue;
     205             : 
     206             :                 // the only section we support so far is "storages"
     207           0 :                 if ( sCurrentSection != "storages" )
     208             :                 {
     209           0 :                     bCurrentSectionIsKnownToBeUnsupported = true;
     210           0 :                     continue;
     211             :                 }
     212             : 
     213           0 :                 OUString sStorageName;
     214           0 :                 SubComponentDescriptor aCompDesc;
     215           0 :                 if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) )
     216           0 :                     continue;
     217           0 :                 o_mapStorageToObjectName[ sStorageName ] = aCompDesc;
     218           0 :             }
     219             :         }
     220             : 
     221           0 :         static void lcl_markModified( const Reference< XComponent >& i_rSubComponent )
     222             :         {
     223           0 :             const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY );
     224           0 :             if ( !xModify.is() )
     225             :             {
     226             :                 OSL_FAIL( "lcl_markModified: unhandled case!" );
     227           0 :                 return;
     228             :             }
     229             : 
     230           0 :             xModify->setModified( sal_True );
     231             :         }
     232             :     }
     233             : 
     234             :     // DatabaseDocumentRecovery_Data
     235           0 :     struct DBACCESS_DLLPRIVATE DatabaseDocumentRecovery_Data
     236             :     {
     237             :         const Reference<XComponentContext> aContext;
     238             : 
     239           0 :         DatabaseDocumentRecovery_Data( const Reference<XComponentContext> & i_rContext )
     240           0 :             :aContext( i_rContext )
     241             :         {
     242           0 :         }
     243             :     };
     244             : 
     245             :     // DatabaseDocumentRecovery
     246           0 :     DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference<XComponentContext> & i_rContext )
     247           0 :         :m_pData( new DatabaseDocumentRecovery_Data( i_rContext ) )
     248             :     {
     249           0 :     }
     250             : 
     251           0 :     DatabaseDocumentRecovery::~DatabaseDocumentRecovery()
     252             :     {
     253           0 :     }
     254             : 
     255           0 :     void DatabaseDocumentRecovery::saveModifiedSubComponents( const Reference< XStorage >& i_rTargetStorage,
     256             :         const ::std::vector< Reference< XController > >& i_rControllers )
     257             :     {
     258           0 :         ENSURE_OR_THROW( i_rTargetStorage.is(), "invalid document storage" );
     259             : 
     260             :         // create a sub storage for recovery data
     261           0 :         if ( i_rTargetStorage->hasByName( lcl_getRecoveryDataSubStorageName() ) )
     262           0 :             i_rTargetStorage->removeElement( lcl_getRecoveryDataSubStorageName() );
     263           0 :         Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( lcl_getRecoveryDataSubStorageName(), ElementModes::READWRITE );
     264             : 
     265             :         // store recovery data for open sub components of the given controller(s)
     266           0 :         if ( !i_rControllers.empty() )
     267             :         {
     268           0 :             ENSURE_OR_THROW( i_rControllers.size() == 1, "can't handle more than one controller" );
     269             :             // At the moment, there can be only one view to a database document. If we ever allow for more than this,
     270             :             // then we need a concept for sub documents opened from different controllers (i.e. two document views,
     271             :             // and the user opens the very same form in both views). And depending on this, we need a concept for
     272             :             // how those are saved to the recovery file.
     273             : 
     274           0 :             MapCompTypeToCompDescs aMapCompDescs;
     275             : 
     276           0 :             for (   ::std::vector< Reference< XController > >::const_iterator ctrl = i_rControllers.begin();
     277           0 :                     ctrl != i_rControllers.end();
     278             :                     ++ctrl
     279             :                 )
     280             :             {
     281           0 :                 Reference< XDatabaseDocumentUI > xDatabaseUI( *ctrl, UNO_QUERY_THROW );
     282           0 :                 Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
     283             : 
     284           0 :                 const Reference< XComponent >* component = aComponents.getConstArray();
     285           0 :                 const Reference< XComponent >* componentEnd = aComponents.getConstArray() + aComponents.getLength();
     286           0 :                 for ( ; component != componentEnd; ++component )
     287             :                 {
     288           0 :                     SubComponentRecovery aComponentRecovery( m_pData->aContext, xDatabaseUI, *component );
     289           0 :                     aComponentRecovery.saveToRecoveryStorage( xRecoveryStorage, aMapCompDescs );
     290           0 :                 }
     291           0 :             }
     292             : 
     293           0 :             for (   MapCompTypeToCompDescs::const_iterator map = aMapCompDescs.begin();
     294           0 :                     map != aMapCompDescs.end();
     295             :                     ++map
     296             :                 )
     297             :             {
     298           0 :                 Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     299           0 :                     SubComponentRecovery::getComponentsStorageName( map->first ), ElementModes::WRITE | ElementModes::NOCREATE ) );
     300           0 :                 lcl_writeObjectMap_throw( m_pData->aContext, xComponentsStor, map->second );
     301           0 :                 tools::stor::commitStorageIfWriteable( xComponentsStor );
     302           0 :             }
     303             :         }
     304             : 
     305             :         // commit the recovery storage
     306           0 :         tools::stor::commitStorageIfWriteable( xRecoveryStorage );
     307           0 :     }
     308             : 
     309           0 :     void DatabaseDocumentRecovery::recoverSubDocuments( const Reference< XStorage >& i_rDocumentStorage,
     310             :         const Reference< XController >& i_rTargetController )
     311             :     {
     312           0 :         ENSURE_OR_THROW( i_rDocumentStorage.is(), "illegal document storage" );
     313           0 :         Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW );
     314             : 
     315           0 :         if ( !i_rDocumentStorage->hasByName( lcl_getRecoveryDataSubStorageName() ) )
     316             :             // that's allowed
     317           0 :             return;
     318             : 
     319             :         // the "recovery" sub storage
     320           0 :         Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( lcl_getRecoveryDataSubStorageName(), ElementModes::READ );
     321             : 
     322             :         // read the map from sub storages to object names
     323           0 :         MapCompTypeToCompDescs aMapCompDescs;
     324           0 :         SubComponentType aKnownTypes[] = { TABLE, QUERY, FORM, REPORT, RELATION_DESIGN };
     325           0 :         for ( size_t i = 0; i < sizeof( aKnownTypes ) / sizeof( aKnownTypes[0] ); ++i )
     326             :         {
     327           0 :             if ( !xRecoveryStorage->hasByName( SubComponentRecovery::getComponentsStorageName( aKnownTypes[i] ) ) )
     328           0 :                 continue;
     329             : 
     330           0 :             Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     331           0 :                 SubComponentRecovery::getComponentsStorageName( aKnownTypes[i] ), ElementModes::READ ) );
     332           0 :             lcl_readObjectMap_throw( m_pData->aContext, xComponentsStor, aMapCompDescs[ aKnownTypes[i] ] );
     333           0 :             xComponentsStor->dispose();
     334           0 :         }
     335             : 
     336             :         // recover all sub components as indicated by the map
     337           0 :         for (   MapCompTypeToCompDescs::const_iterator map = aMapCompDescs.begin();
     338           0 :                 map != aMapCompDescs.end();
     339             :                 ++map
     340             :             )
     341             :         {
     342           0 :             const SubComponentType eComponentType = map->first;
     343             : 
     344             :             // the storage for all components of the current type
     345           0 :             Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
     346           0 :                 SubComponentRecovery::getComponentsStorageName( eComponentType ), ElementModes::READ ), UNO_QUERY_THROW );
     347             : 
     348             :             // loop thru all components of this type
     349           0 :             for (   MapStringToCompDesc::const_iterator stor = map->second.begin();
     350           0 :                     stor != map->second.end();
     351             :                     ++stor
     352             :                 )
     353             :             {
     354           0 :                 const OUString sComponentName( stor->second.sName );
     355           0 :                 if ( !xComponentsStor->hasByName( stor->first ) )
     356             :                 {
     357             :                     SAL_WARN( "dbaccess",
     358             :                               "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" <<
     359             :                               stor->first <<
     360             :                               "' not found in '" <<
     361             :                               SubComponentRecovery::getComponentsStorageName( eComponentType ) <<
     362             :                               "', but required per map file!" );
     363           0 :                     continue;
     364             :                 }
     365             : 
     366             :                 // the controller needs to have a connection to be able to open sub components
     367           0 :                 if ( !xDocumentUI->isConnected() )
     368           0 :                     xDocumentUI->connect();
     369             : 
     370             :                 // recover the single component
     371           0 :                 Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( stor->first, ElementModes::READ ) );
     372           0 :                 SubComponentRecovery aComponentRecovery( m_pData->aContext, xDocumentUI, eComponentType );
     373           0 :                 Reference< XComponent > xSubComponent( aComponentRecovery.recoverFromStorage( xCompStor, sComponentName, stor->second.bForEditing ) );
     374             : 
     375             :                 // at the moment, we only store, during session save, sub components which are modified. So, set this
     376             :                 // recovered sub component to "modified", too.
     377           0 :                 lcl_markModified( xSubComponent );
     378           0 :             }
     379             : 
     380           0 :             xComponentsStor->dispose();
     381           0 :         }
     382             : 
     383           0 :         xRecoveryStorage->dispose();
     384             : 
     385             :         // now that we successfully recovered, removed the "recovery" sub storage
     386             :         try
     387             :         {
     388           0 :             i_rDocumentStorage->removeElement( lcl_getRecoveryDataSubStorageName() );
     389             :         }
     390           0 :         catch( const Exception& )
     391             :         {
     392             :             DBG_UNHANDLED_EXCEPTION();
     393           0 :         }
     394             :     }
     395             : 
     396             : } // namespace dbaccess
     397             : 
     398             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10