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_package.hxx"
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <com/sun/star/embed/XHierarchicalStorageAccess2.hpp>
29 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
30
31 #include "ohierarchyholder.hxx"
32
33 using namespace ::com::sun::star;
34
35 //===============================================
36 // OHierarchyHolder_Impl
37 //===============================================
38
39 //-----------------------------------------------
GetStreamHierarchically(sal_Int32 nStorageMode,OStringList_Impl & aListPath,sal_Int32 nStreamMode,const::comphelper::SequenceAsHashMap & aEncryptionData)40 uno::Reference< embed::XExtendedStorageStream > OHierarchyHolder_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
41 {
42 uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
43
44 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
45 throw io::IOException();
46
47 uno::Reference< embed::XExtendedStorageStream > xResult =
48 m_xChild->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
49 if ( !xResult.is() )
50 throw uno::RuntimeException();
51
52 return xResult;
53 }
54
55 //-----------------------------------------------
RemoveStreamHierarchically(OStringList_Impl & aListPath)56 void OHierarchyHolder_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath )
57 {
58 uno::Reference< embed::XStorage > xOwnStor( m_xWeakOwnStorage.get(), uno::UNO_QUERY_THROW );
59
60 m_xChild->RemoveStreamHierarchically( aListPath );
61 }
62
63 //-----------------------------------------------
64 // static
GetListPathFromString(const::rtl::OUString & aPath)65 OStringList_Impl OHierarchyHolder_Impl::GetListPathFromString( const ::rtl::OUString& aPath )
66 {
67 OStringList_Impl aResult;
68 sal_Int32 nIndex = 0;
69 do
70 {
71 ::rtl::OUString aName = aPath.getToken( 0, '/', nIndex );
72 if ( !aName.getLength() )
73 throw lang::IllegalArgumentException();
74
75 aResult.push_back( aName );
76 }
77 while ( nIndex >= 0 );
78
79 return aResult;
80 }
81
82 //===============================================
83 // OHierarchyElement_Impl
84 //===============================================
85
86 //-----------------------------------------------
GetStreamHierarchically(sal_Int32 nStorageMode,OStringList_Impl & aListPath,sal_Int32 nStreamMode,const::comphelper::SequenceAsHashMap & aEncryptionData)87 uno::Reference< embed::XExtendedStorageStream > OHierarchyElement_Impl::GetStreamHierarchically( sal_Int32 nStorageMode, OStringList_Impl& aListPath, sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData )
88 {
89 ::osl::MutexGuard aGuard( m_aMutex );
90
91 if ( !( nStorageMode & embed::ElementModes::WRITE ) && ( nStreamMode & embed::ElementModes::WRITE ) )
92 throw io::IOException();
93
94 if ( !aListPath.size() )
95 throw uno::RuntimeException();
96
97 ::rtl::OUString aNextName = *(aListPath.begin());
98 aListPath.erase( aListPath.begin() );
99
100 uno::Reference< embed::XExtendedStorageStream > xResult;
101
102 uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
103 : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY );
104 if ( !xOwnStor.is() )
105 throw uno::RuntimeException();
106
107 if ( !aListPath.size() )
108 {
109 if ( !aEncryptionData.size() )
110 {
111 uno::Reference< embed::XHierarchicalStorageAccess > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
112 xResult = xHStorage->openStreamElementByHierarchicalName( aNextName, nStreamMode );
113 }
114 else
115 {
116 uno::Reference< embed::XHierarchicalStorageAccess2 > xHStorage( xOwnStor, uno::UNO_QUERY_THROW );
117 xResult = xHStorage->openEncryptedStreamByHierarchicalName( aNextName, nStreamMode, aEncryptionData.getAsConstNamedValueList() );
118 }
119
120 uno::Reference< embed::XTransactedObject > xTransact( xResult, uno::UNO_QUERY );
121 if ( xTransact.is() )
122 {
123 // the existance of the transacted object means that the stream is opened for writing also
124 // so the whole chain must be commited
125 uno::Reference< embed::XTransactionBroadcaster > xTrBroadcast( xTransact, uno::UNO_QUERY_THROW );
126 xTrBroadcast->addTransactionListener( static_cast< embed::XTransactionListener* >( this ) );
127 }
128 else
129 {
130 uno::Reference< lang::XComponent > xStreamComp( xResult, uno::UNO_QUERY_THROW );
131 xStreamComp->addEventListener( static_cast< lang::XEventListener* >( this ) );
132 }
133
134 m_aOpenStreams.push_back( uno::WeakReference< embed::XExtendedStorageStream >( xResult ) );
135 }
136 else
137 {
138 sal_Bool bNewElement = sal_False;
139 ::rtl::Reference< OHierarchyElement_Impl > aElement;
140 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
141 if ( aIter != m_aChildren.end() )
142 aElement = aIter->second;
143
144 if ( !aElement.is() )
145 {
146 bNewElement = sal_True;
147 uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName, nStorageMode );
148 if ( !xChildStorage.is() )
149 throw uno::RuntimeException();
150
151 aElement = new OHierarchyElement_Impl( NULL, xChildStorage );
152 }
153
154 xResult = aElement->GetStreamHierarchically( nStorageMode, aListPath, nStreamMode, aEncryptionData );
155 if ( !xResult.is() )
156 throw uno::RuntimeException();
157
158 if ( bNewElement )
159 {
160 m_aChildren[aNextName] = aElement;
161 aElement->SetParent( this );
162 }
163 }
164
165 // the subelement was opened successfuly, remember the storage to let it be locked
166 m_xOwnStorage = xOwnStor;
167
168 return xResult;
169 }
170
171 //-----------------------------------------------
RemoveStreamHierarchically(OStringList_Impl & aListPath)172 void OHierarchyElement_Impl::RemoveStreamHierarchically( OStringList_Impl& aListPath )
173 {
174 ::osl::MutexGuard aGuard( m_aMutex );
175
176 if ( !aListPath.size() )
177 throw uno::RuntimeException();
178
179 ::rtl::OUString aNextName = *(aListPath.begin());
180 aListPath.erase( aListPath.begin() );
181
182 uno::Reference< embed::XExtendedStorageStream > xResult;
183
184 uno::Reference< embed::XStorage > xOwnStor = m_xOwnStorage.is() ? m_xOwnStorage
185 : uno::Reference< embed::XStorage >( m_xWeakOwnStorage.get(), uno::UNO_QUERY );
186 if ( !xOwnStor.is() )
187 throw uno::RuntimeException();
188
189 if ( !aListPath.size() )
190 {
191 xOwnStor->removeElement( aNextName );
192 }
193 else
194 {
195 sal_Bool bNewElement = sal_False;
196 ::rtl::Reference< OHierarchyElement_Impl > aElement;
197 OHierarchyElementList_Impl::iterator aIter = m_aChildren.find( aNextName );
198 if ( aIter != m_aChildren.end() )
199 aElement = aIter->second;
200
201 if ( !aElement.is() )
202 {
203 bNewElement = sal_True;
204 uno::Reference< embed::XStorage > xChildStorage = xOwnStor->openStorageElement( aNextName,
205 embed::ElementModes::READWRITE );
206 if ( !xChildStorage.is() )
207 throw uno::RuntimeException();
208
209 aElement = new OHierarchyElement_Impl( NULL, xChildStorage );
210 }
211
212 aElement->RemoveStreamHierarchically( aListPath );
213 }
214
215 uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY );
216 if ( xTransact.is() )
217 xTransact->commit();
218
219 TestForClosing();
220 }
221
222 //-----------------------------------------------
Commit()223 void OHierarchyElement_Impl::Commit()
224 {
225 ::rtl::Reference< OHierarchyElement_Impl > aLocker( this );
226 ::rtl::Reference< OHierarchyElement_Impl > aParent;
227 uno::Reference< embed::XStorage > xOwnStor;
228
229 {
230 ::osl::MutexGuard aGuard( m_aMutex );
231 aParent = m_rParent;
232 xOwnStor = m_xOwnStorage;
233 }
234
235 if ( xOwnStor.is() )
236 {
237 uno::Reference< embed::XTransactedObject > xTransact( xOwnStor, uno::UNO_QUERY_THROW );
238 xTransact->commit();
239 if ( aParent.is() )
240 aParent->Commit();
241 }
242 }
243
244 //-----------------------------------------------
TestForClosing()245 void OHierarchyElement_Impl::TestForClosing()
246 {
247 ::rtl::Reference< OHierarchyElement_Impl > aLocker( this );
248 {
249 ::osl::MutexGuard aGuard( m_aMutex );
250
251 if ( !m_aOpenStreams.size() && !m_aChildren.size() )
252 {
253 if ( m_rParent.is() )
254 {
255 // only the root storage should not be disposed, other storages can be disposed
256 if ( m_xOwnStorage.is() )
257 {
258 try
259 {
260 m_xOwnStorage->dispose();
261 }
262 catch( uno::Exception& )
263 {}
264 }
265
266 m_rParent->RemoveElement( this );
267 }
268
269 m_xOwnStorage = uno::Reference< embed::XStorage >();
270 }
271 }
272 }
273
274 //-----------------------------------------------
disposing(const lang::EventObject & Source)275 void SAL_CALL OHierarchyElement_Impl::disposing( const lang::EventObject& Source )
276 throw ( uno::RuntimeException )
277 {
278 uno::Sequence< embed::XStorage > aStoragesToCommit;
279
280 try
281 {
282 ::osl::ClearableMutexGuard aGuard( m_aMutex );
283 uno::Reference< embed::XExtendedStorageStream > xStream( Source.Source, uno::UNO_QUERY );
284
285 for ( OWeakStorRefList_Impl::iterator pStorageIter = m_aOpenStreams.begin();
286 pStorageIter != m_aOpenStreams.end(); )
287 {
288 OWeakStorRefList_Impl::iterator pTmp = pStorageIter++;
289 if ( !pTmp->get().is() || pTmp->get() == xStream )
290 m_aOpenStreams.erase( pTmp );
291 }
292
293 aGuard.clear();
294
295 TestForClosing();
296 }
297 catch( uno::Exception& )
298 {
299 throw uno::RuntimeException(); // no exception must happen here, usually an exception means disaster
300 }
301 }
302
303 //-----------------------------------------------
RemoveElement(const::rtl::Reference<OHierarchyElement_Impl> & aRef)304 void OHierarchyElement_Impl::RemoveElement( const ::rtl::Reference< OHierarchyElement_Impl >& aRef )
305 {
306 {
307 ::osl::MutexGuard aGuard( m_aMutex );
308 for ( OHierarchyElementList_Impl::iterator aIter = m_aChildren.begin();
309 aIter != m_aChildren.end(); /* increment is done in body */)
310 {
311 OHierarchyElementList_Impl::iterator aTmpIter = aIter;
312 aIter++;
313
314 if ( aTmpIter->second == aRef )
315 m_aChildren.erase( aTmpIter );
316 }
317 }
318
319 TestForClosing();
320 }
321
322 // XTransactionListener
323 //-----------------------------------------------
preCommit(const::com::sun::star::lang::EventObject &)324 void SAL_CALL OHierarchyElement_Impl::preCommit( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
325 throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
326 {
327 }
328
329 //-----------------------------------------------
commited(const::com::sun::star::lang::EventObject &)330 void SAL_CALL OHierarchyElement_Impl::commited( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
331 throw (::com::sun::star::uno::RuntimeException)
332 {
333 try
334 {
335 Commit();
336 }
337 catch( uno::Exception& e )
338 {
339 throw lang::WrappedTargetRuntimeException(
340 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can not commit storage sequence!" ) ),
341 uno::Reference< uno::XInterface >(),
342 uno::makeAny( e ) );
343 }
344 }
345
346 //-----------------------------------------------
preRevert(const::com::sun::star::lang::EventObject &)347 void SAL_CALL OHierarchyElement_Impl::preRevert( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
348 throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
349 {
350 }
351
352 //-----------------------------------------------
reverted(const::com::sun::star::lang::EventObject &)353 void SAL_CALL OHierarchyElement_Impl::reverted( const ::com::sun::star::lang::EventObject& /*aEvent*/ )
354 throw (::com::sun::star::uno::RuntimeException)
355 {
356 }
357
358