LibreOffice Module ucb (master)  1
webdavdatasupplier.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <memory>
24 #include <utility>
25 
26 #include <com/sun/star/ucb/OpenMode.hpp>
29 #include "webdavdatasupplier.hxx"
30 #include "webdavcontent.hxx"
31 #include "ContentProperties.hxx"
32 #include "DAVProperties.hxx"
33 #include "SerfUri.hxx"
34 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
35 #include <com/sun/star/ucb/ResultSetException.hpp>
36 #include <tools/diagnose_ex.h>
37 
38 using namespace com::sun::star;
39 using namespace http_dav_ucp;
40 
41 namespace http_dav_ucp
42 {
43 
44 
45 // struct ResultListEntry.
46 
47 namespace {
48 
49 struct ResultListEntry
50 {
51  OUString aId;
52  uno::Reference< ucb::XContentIdentifier > xId;
53  uno::Reference< ucb::XContent > xContent;
54  uno::Reference< sdbc::XRow > xRow;
55  std::unique_ptr<ContentProperties> pData;
56 
57  explicit ResultListEntry( std::unique_ptr<ContentProperties> && pEntry ) : pData( std::move(pEntry) ) {}
58 };
59 
60 }
61 
62 // ResultList.
63 
64 
65 typedef std::vector< ResultListEntry* > ResultList;
66 
67 
68 // struct DataSupplier_Impl.
69 
70 
72 {
73  osl::Mutex m_aMutex;
74  ResultList m_aResults;
76  uno::Reference< uno::XComponentContext > m_xContext;
77  sal_Int32 m_nOpenMode;
80 
82  const uno::Reference< uno::XComponentContext >& rxContext,
83  const rtl::Reference< Content >& rContent,
84  sal_Int32 nOpenMode )
85  : m_xContent( rContent ), m_xContext( rxContext ), m_nOpenMode( nOpenMode ),
86  m_bCountFinal( false ), m_bThrowException( false ) {}
88 };
89 
90 
91 DataSupplier_Impl::~DataSupplier_Impl()
92 {
93  for ( auto& rResultPtr : m_aResults )
94  {
95  delete rResultPtr;
96  }
97 }
98 
99 }
100 
101 
102 // DataSupplier Implementation.
103 
104 
105 DataSupplier::DataSupplier(
106  const uno::Reference< uno::XComponentContext >& rxContext,
107  const rtl::Reference< Content >& rContent,
108  sal_Int32 nOpenMode )
109 : m_pImpl(std::make_unique<DataSupplier_Impl>(rxContext, rContent, nOpenMode))
110 {
111 }
112 
113 
114 // virtual
116 {}
117 
118 
119 // virtual
120 OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
121 {
122  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
123 
124  if ( nIndex < m_pImpl->m_aResults.size() )
125  {
126  OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
127  if ( aId.getLength() )
128  {
129  // Already cached.
130  return aId;
131  }
132  }
133 
134  if ( getResult( nIndex ) )
135  {
136  OUString aId = m_pImpl->m_xContent->getResourceAccess().getURL();
137 
138  const ContentProperties& props
139  = *( m_pImpl->m_aResults[ nIndex ]->pData );
140 
141  if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
142  aId += "/";
143 
144  aId += props.getEscapedTitle();
145 
146  if ( props.isTrailingSlash() )
147  aId += "/";
148 
149  m_pImpl->m_aResults[ nIndex ]->aId = aId;
150  return aId;
151  }
152  return OUString();
153 }
154 
155 
156 // virtual
157 uno::Reference< ucb::XContentIdentifier >
159 {
160  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
161 
162  if ( nIndex < m_pImpl->m_aResults.size() )
163  {
164  uno::Reference< ucb::XContentIdentifier > xId
165  = m_pImpl->m_aResults[ nIndex ]->xId;
166  if ( xId.is() )
167  {
168  // Already cached.
169  return xId;
170  }
171  }
172 
173  OUString aId = queryContentIdentifierString( nIndex );
174  if ( aId.getLength() )
175  {
176  uno::Reference< ucb::XContentIdentifier > xId
177  = new ::ucbhelper::ContentIdentifier( aId );
178  m_pImpl->m_aResults[ nIndex ]->xId = xId;
179  return xId;
180  }
181  return uno::Reference< ucb::XContentIdentifier >();
182 }
183 
184 
185 // virtual
186 uno::Reference< ucb::XContent >
187 DataSupplier::queryContent( sal_uInt32 nIndex )
188 {
189  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
190 
191  if ( nIndex < m_pImpl->m_aResults.size() )
192  {
193  uno::Reference< ucb::XContent > xContent
194  = m_pImpl->m_aResults[ nIndex ]->xContent;
195  if ( xContent.is() )
196  {
197  // Already cached.
198  return xContent;
199  }
200  }
201 
202  uno::Reference< ucb::XContentIdentifier > xId
203  = queryContentIdentifier( nIndex );
204  if ( xId.is() )
205  {
206  try
207  {
208  uno::Reference< ucb::XContent > xContent
209  = m_pImpl->m_xContent->getProvider()->queryContent( xId );
210  m_pImpl->m_aResults[ nIndex ]->xContent = xContent;
211  return xContent;
212 
213  }
214  catch ( ucb::IllegalIdentifierException& )
215  {
216  }
217  }
218  return uno::Reference< ucb::XContent >();
219 }
220 
221 
222 // virtual
223 bool DataSupplier::getResult( sal_uInt32 nIndex )
224 {
225  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
226 
227  if ( m_pImpl->m_aResults.size() > nIndex )
228  {
229  // Result already present.
230  return true;
231  }
232 
233  // Obtain values...
234  if ( getData() )
235  {
236  if ( m_pImpl->m_aResults.size() > nIndex )
237  {
238  // Result already present.
239  return true;
240  }
241  }
242 
243  return false;
244 }
245 
246 
247 // virtual
249 {
250  // Obtain values...
251  getData();
252 
253  return m_pImpl->m_aResults.size();
254 }
255 
256 
257 // virtual
259 {
260  return m_pImpl->m_aResults.size();
261 }
262 
263 
264 // virtual
266 {
267  return m_pImpl->m_bCountFinal;
268 }
269 
270 
271 // virtual
272 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues(
273  sal_uInt32 nIndex )
274 {
275  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
276 
277  if ( nIndex < m_pImpl->m_aResults.size() )
278  {
279  uno::Reference< sdbc::XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
280  if ( xRow.is() )
281  {
282  // Already cached.
283  return xRow;
284  }
285  }
286 
287  if ( getResult( nIndex ) )
288  {
289  uno::Reference< sdbc::XRow > xRow
291  m_pImpl->m_xContext,
292  getResultSet()->getProperties(),
293  *(m_pImpl->m_aResults[ nIndex ]->pData),
295  m_pImpl->m_xContent->getProvider().get() ),
296  queryContentIdentifierString( nIndex ) );
297  m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
298  return xRow;
299  }
300 
301  return uno::Reference< sdbc::XRow >();
302 }
303 
304 
305 // virtual
306 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
307 {
308  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
309 
310  if ( nIndex < m_pImpl->m_aResults.size() )
311  m_pImpl->m_aResults[ nIndex ]->xRow.clear();
312 }
313 
314 
315 // virtual
317 {
318 }
319 
320 
321 // virtual
323 {
324  if ( m_pImpl->m_bThrowException )
325  throw ucb::ResultSetException();
326 }
327 
329 {
330  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
331 
332  if ( !m_pImpl->m_bCountFinal )
333  {
334  std::vector< OUString > propertyNames;
336  getResultSet()->getProperties(), propertyNames );
337 
338  // Append "resourcetype", if not already present. It's value is
339  // needed to get a valid ContentProperties::pIsFolder value, which
340  // is needed for OpenMode handling.
341 
342  bool isNoResourceType = std::none_of(propertyNames.begin(), propertyNames.end(),
343  [](const OUString& rPropName) { return rPropName.equals(DAVProperties::RESOURCETYPE); });
344 
345  if ( isNoResourceType )
346  propertyNames.push_back( DAVProperties::RESOURCETYPE );
347 
348  std::vector< DAVResource > resources;
349  try
350  {
351  // propfind depth 1, get property values for parent AND for each
352  // child
353  m_pImpl->m_xContent->getResourceAccess()
354  .PROPFIND( DAVONE,
355  propertyNames,
356  resources,
358  }
359  catch ( DAVException & )
360  {
361  TOOLS_WARN_EXCEPTION( "ucb.ucp.webdav", "PROPFIND : DAVException" );
362  m_pImpl->m_bThrowException = true;
363  }
364 
365  if ( !m_pImpl->m_bThrowException )
366  {
367  try
368  {
369  SerfUri aURI(
370  m_pImpl->m_xContent->getResourceAccess().getURL() );
371  OUString aPath = aURI.GetPath();
372 
373  if ( aPath.endsWith("/") )
374  aPath = aPath.copy( 0, aPath.getLength() - 1 );
375 
376  aPath = SerfUri::unescape( aPath );
377  bool bFoundParent = false;
378 
379  for ( size_t n = 0; n < resources.size(); ++n )
380  {
381  const DAVResource & rRes = resources[ n ];
382 
383  // Filter parent, which is contained somewhere(!) in
384  // the vector.
385  if ( !bFoundParent )
386  {
387  try
388  {
389  SerfUri aCurrURI( rRes.uri );
390  OUString aCurrPath = aCurrURI.GetPath();
391  if ( aCurrPath.endsWith("/") )
392  aCurrPath
393  = aCurrPath.copy(
394  0,
395  aCurrPath.getLength() - 1 );
396 
397  aCurrPath = SerfUri::unescape( aCurrPath );
398  if ( aPath == aCurrPath )
399  {
400  bFoundParent = true;
401  continue;
402  }
403  }
404  catch ( DAVException const & )
405  {
406  // do nothing, ignore error. continue.
407  }
408  }
409 
410  std::unique_ptr<ContentProperties> pContentProperties
411  = std::make_unique<ContentProperties>( rRes );
412 
413  // Check resource against open mode.
414  switch ( m_pImpl->m_nOpenMode )
415  {
416  case ucb::OpenMode::FOLDERS:
417  {
418  bool bFolder = false;
419 
420  const uno::Any & rValue
421  = pContentProperties->getValue( "IsFolder" );
422  rValue >>= bFolder;
423 
424  if ( !bFolder )
425  continue;
426 
427  break;
428  }
429 
430  case ucb::OpenMode::DOCUMENTS:
431  {
432  bool bDocument = false;
433 
434  const uno::Any & rValue
435  = pContentProperties->getValue( "IsDocument" );
436  rValue >>= bDocument;
437 
438  if ( !bDocument )
439  continue;
440 
441  break;
442  }
443 
444  case ucb::OpenMode::ALL:
445  default:
446  break;
447  }
448 
449  m_pImpl->m_aResults.push_back(
450  new ResultListEntry( std::move(pContentProperties) ) );
451  }
452  }
453  catch ( DAVException const & )
454  {
455  }
456  }
457 
458  m_pImpl->m_bCountFinal = true;
459 
460  // Callback possible, because listeners may be informed!
461  aGuard.clear();
462  getResultSet()->rowCountFinal();
463  }
464  return !m_pImpl->m_bThrowException;
465 }
466 
467 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Environment getEnvironment(OUString const &name, OUString const &implementation)
static const OUString RESOURCETYPE
std::unique_ptr< ContentProperties > pData
uno::Reference< uno::XComponentContext > m_xContext
sal_Int64 n
virtual css::uno::Reference< css::sdbc::XRow > queryPropertyValues(sal_uInt32 nIndex) override
static void UCBNamesToDAVNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources, bool bIncludeUnmatched=true)
virtual void releasePropertyValues(sal_uInt32 nIndex) override
virtual bool isCountFinal() override
virtual bool getResult(sal_uInt32 nIndex) override
std::unique_ptr< DataSupplier_Impl > m_pImpl
const OUString & getEscapedTitle() const
#define TOOLS_WARN_EXCEPTION(area, stream)
DataSupplier_Impl(const uno::Reference< uno::XComponentContext > &rxContext, const rtl::Reference< Content > &rContent, sal_Int32 nOpenMode)
OUString aId
rtl::Reference< Content > m_xContent
virtual sal_uInt32 totalCount() override
uno::Reference< sdbc::XRow > xRow
virtual sal_uInt32 currentCount() override
dictionary props
virtual css::uno::Reference< css::ucb::XContentIdentifier > queryContentIdentifier(sal_uInt32 nIndex) override
const OUString & GetPath() const
Definition: SerfUri.hxx:75
rtl::Reference< ResultSet > getResultSet() const
uno::Reference< ucb::XContentIdentifier > xId
virtual void close() override
virtual css::uno::Reference< css::ucb::XContent > queryContent(sal_uInt32 nIndex) override
virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual void validate() override
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
uno::Reference< ucb::XContent > xContent
std::vector< ResultListEntry * > ResultList
static OUString unescape(const OUString &string)
Definition: SerfUri.cxx:214