LibreOffice Module ucb (master)  1
neon/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  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * Copyright 2000, 2010 Oracle and/or its affiliates.
7  *
8  * OpenOffice.org - a multi-platform office productivity suite
9  *
10  * This file is part of OpenOffice.org.
11  *
12  * OpenOffice.org is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 3
14  * only, as published by the Free Software Foundation.
15  *
16  * OpenOffice.org is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License version 3 for more details
20  * (a copy is included in the LICENSE file that accompanied this code).
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * version 3 along with OpenOffice.org. If not, see
24  * <http://www.openoffice.org/license.html>
25  * for a copy of the LGPLv3 License.
26  *
27  ************************************************************************/
28 
29 
30 /**************************************************************************
31  TODO
32  **************************************************************************
33 
34  *************************************************************************/
35 
36 #include <sal/log.hxx>
37 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
38 #include <com/sun/star/ucb/OpenMode.hpp>
39 #include <com/sun/star/ucb/ResultSetException.hpp>
42 #include <tools/diagnose_ex.h>
43 #include <memory>
44 #include <vector>
45 #include "webdavdatasupplier.hxx"
46 #include "webdavcontent.hxx"
47 #include "ContentProperties.hxx"
48 #include "NeonUri.hxx"
49 
50 using namespace com::sun::star;
51 using namespace webdav_ucp;
52 
53 namespace webdav_ucp
54 {
55 
56 
57 // struct ResultListEntry.
58 
59 namespace {
60 
61 struct ResultListEntry
62 {
63  OUString aId;
64  uno::Reference< ucb::XContentIdentifier > xId;
65  uno::Reference< ucb::XContent > xContent;
66  uno::Reference< sdbc::XRow > xRow;
67  std::shared_ptr<ContentProperties> const pData;
68 
69  explicit ResultListEntry(std::shared_ptr<ContentProperties> const& pEntry)
70  : pData(pEntry)
71  {}
72 };
73 
74 }
75 
76 // ResultList.
77 
78 
79 typedef std::vector<std::unique_ptr<ResultListEntry>> ResultList;
80 
81 
82 // struct DataSupplier_Impl.
83 
84 
86 {
87  osl::Mutex m_aMutex;
88  ResultList m_Results;
90  uno::Reference< uno::XComponentContext > m_xContext;
91  sal_Int32 m_nOpenMode;
94 
96  const uno::Reference< uno::XComponentContext >& rxContext,
97  const rtl::Reference< Content >& rContent,
98  sal_Int32 nOpenMode )
99  : m_xContent( rContent ), m_xContext( rxContext ), m_nOpenMode( nOpenMode ),
100  m_bCountFinal( false ), m_bThrowException( false ) {}
101 };
102 
103 }
104 
105 
106 // DataSupplier Implementation.
107 
108 
109 DataSupplier::DataSupplier(
110  const uno::Reference< uno::XComponentContext >& rxContext,
111  const rtl::Reference< Content >& rContent,
112  sal_Int32 nOpenMode )
113 : m_pImpl( new DataSupplier_Impl( rxContext, rContent, nOpenMode ) )
114 {
115 }
116 
117 
118 // virtual
120 {
121 }
122 
123 
124 // virtual
125 OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
126 {
127  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
128 
129  if (nIndex < m_pImpl->m_Results.size())
130  {
131  OUString aId = m_pImpl->m_Results[ nIndex ]->aId;
132  if ( !aId.isEmpty() )
133  {
134  // Already cached.
135  return aId;
136  }
137  }
138 
139  if ( getResult( nIndex ) )
140  {
141  OUString aId = m_pImpl->m_xContent->getResourceAccess().getURL();
142 
143  const ContentProperties& props(*(m_pImpl->m_Results[ nIndex ]->pData));
144 
145  if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
146  aId += "/";
147 
148  aId += props.getEscapedTitle();
149 
150  if ( props.isTrailingSlash() )
151  aId += "/";
152 
153  m_pImpl->m_Results[ nIndex ]->aId = aId;
154  return aId;
155  }
156  return OUString();
157 }
158 
159 
160 // virtual
161 uno::Reference< ucb::XContentIdentifier >
163 {
164  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
165 
166  if (nIndex < m_pImpl->m_Results.size())
167  {
168  uno::Reference< ucb::XContentIdentifier > xId
169  = m_pImpl->m_Results[ nIndex ]->xId;
170  if ( xId.is() )
171  {
172  // Already cached.
173  return xId;
174  }
175  }
176 
177  OUString aId = queryContentIdentifierString( nIndex );
178  if ( !aId.isEmpty() )
179  {
180  uno::Reference< ucb::XContentIdentifier > xId
181  = new ::ucbhelper::ContentIdentifier( aId );
182  m_pImpl->m_Results[ nIndex ]->xId = xId;
183  return xId;
184  }
185  return uno::Reference< ucb::XContentIdentifier >();
186 }
187 
188 
189 // virtual
190 uno::Reference< ucb::XContent >
191 DataSupplier::queryContent( sal_uInt32 nIndex )
192 {
193  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
194 
195  if (nIndex < m_pImpl->m_Results.size())
196  {
197  uno::Reference< ucb::XContent > xContent
198  = m_pImpl->m_Results[ nIndex ]->xContent;
199  if ( xContent.is() )
200  {
201  // Already cached.
202  return xContent;
203  }
204  }
205 
206  uno::Reference< ucb::XContentIdentifier > xId
207  = queryContentIdentifier( nIndex );
208  if ( xId.is() )
209  {
210  try
211  {
212  uno::Reference< ucb::XContent > xContent
213  = m_pImpl->m_xContent->getProvider()->queryContent( xId );
214  m_pImpl->m_Results[ nIndex ]->xContent = xContent;
215  return xContent;
216 
217  }
218  catch ( ucb::IllegalIdentifierException& )
219  {
220  }
221  }
222  return uno::Reference< ucb::XContent >();
223 }
224 
225 
226 // virtual
227 bool DataSupplier::getResult( sal_uInt32 nIndex )
228 {
229  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
230 
231  if (nIndex < m_pImpl->m_Results.size())
232  {
233  // Result already present.
234  return true;
235  }
236 
237  // Obtain values...
238  if ( getData() )
239  {
240  if (nIndex < m_pImpl->m_Results.size())
241  {
242  // Result already present.
243  return true;
244  }
245  }
246 
247  return false;
248 }
249 
250 
251 // virtual
253 {
254  // Obtain values...
255  getData();
256 
257  return m_pImpl->m_Results.size();
258 }
259 
260 
261 // virtual
263 {
264  return m_pImpl->m_Results.size();
265 }
266 
267 
268 // virtual
270 {
271  return m_pImpl->m_bCountFinal;
272 }
273 
274 
275 // virtual
276 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues(
277  sal_uInt32 nIndex )
278 {
279  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
280 
281  if (nIndex < m_pImpl->m_Results.size())
282  {
283  uno::Reference< sdbc::XRow > xRow = m_pImpl->m_Results[ nIndex ]->xRow;
284  if ( xRow.is() )
285  {
286  // Already cached.
287  return xRow;
288  }
289  }
290 
291  if ( getResult( nIndex ) )
292  {
293  uno::Reference< sdbc::XRow > xRow
295  m_pImpl->m_xContext,
296  getResultSet()->getProperties(),
297  *(m_pImpl->m_Results[ nIndex ]->pData),
299  m_pImpl->m_xContent->getProvider().get() ),
300  queryContentIdentifierString( nIndex ) );
301  m_pImpl->m_Results[ nIndex ]->xRow = xRow;
302  return xRow;
303  }
304 
305  return uno::Reference< sdbc::XRow >();
306 }
307 
308 
309 // virtual
310 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
311 {
312  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
313 
314  if (nIndex < m_pImpl->m_Results.size())
315  m_pImpl->m_Results[ nIndex ]->xRow.clear();
316 }
317 
318 
319 // virtual
321 {
322 }
323 
324 
325 // virtual
327 {
328  if ( m_pImpl->m_bThrowException )
329  throw ucb::ResultSetException();
330 }
331 
332 
334 {
335  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
336 
337  if ( !m_pImpl->m_bCountFinal )
338  {
339  std::vector< OUString > propertyNames;
341  getResultSet()->getProperties(), propertyNames );
342 
343  // Append "resourcetype", if not already present. It's value is
344  // needed to get a valid ContentProperties::pIsFolder value, which
345  // is needed for OpenMode handling.
346 
347  bool isNoResourceType = std::none_of(propertyNames.begin(), propertyNames.end(),
348  [](const OUString& rName) { return rName == DAVProperties::RESOURCETYPE; });
349 
350  if ( isNoResourceType )
351  propertyNames.push_back( DAVProperties::RESOURCETYPE );
352 
353  std::vector< DAVResource > resources;
354  try
355  {
356  // propfind depth 1, get property values for parent AND for each
357  // child
358  m_pImpl->m_xContent->getResourceAccess()
359  .PROPFIND( DAVONE,
360  propertyNames,
361  resources,
363 #if defined SAL_LOG_INFO
364  {
365  //print the resource for every URI returned
366  for ( const auto& rResource : resources )
367  {
368  NeonUri aCurrURI( rResource.uri );
369  OUString aCurrPath = aCurrURI.GetPath();
370  aCurrPath = NeonUri::unescape( aCurrPath );
371  SAL_INFO( "ucb.ucp.webdav", "getData() - resource URL: <" << rResource.uri << ">, unescaped to: <" << aCurrPath << "> )" );
372  for ( const auto& rProp : rResource.properties )
373  {
374  SAL_INFO( "ucb.ucp.webdav", "PROPFIND - property name: " << rProp.Name );
375  }
376  }
377  }
378 #endif
379  }
380  catch ( DAVException & )
381  {
382  TOOLS_WARN_EXCEPTION( "ucb.ucp.webdav", "Running PROPFIND: DAVException" );
383  m_pImpl->m_bThrowException = true;
384  }
385 
386  if ( !m_pImpl->m_bThrowException )
387  {
388  try
389  {
390  NeonUri aURI(
391  m_pImpl->m_xContent->getResourceAccess().getURL() );
392  OUString aPath = aURI.GetPath();
393 
394  if ( aPath.endsWith("/") )
395  aPath = aPath.copy( 0, aPath.getLength() - 1 );
396 
397  aPath = NeonUri::unescape( aPath );
398  bool bFoundParent = false;
399 
400  for (DAVResource & rRes : resources)
401  {
402  // Filter parent, which is contained somewhere(!) in
403  // the vector.
404  if ( !bFoundParent )
405  {
406  try
407  {
408  NeonUri aCurrURI( rRes.uri );
409  OUString aCurrPath = aCurrURI.GetPath();
410  if ( aCurrPath.endsWith("/") )
411  aCurrPath
412  = aCurrPath.copy(
413  0,
414  aCurrPath.getLength() - 1 );
415 
416  aCurrPath = NeonUri::unescape( aCurrPath );
417  if ( aPath == aCurrPath )
418  {
419  bFoundParent = true;
420  continue;
421  }
422  }
423  catch ( DAVException const & )
424  {
425  // do nothing, ignore error. continue.
426  }
427  }
428 
429  std::shared_ptr<ContentProperties> const
430  pContentProperties = std::make_shared<ContentProperties>(rRes);
431 
432  // Check resource against open mode.
433  switch ( m_pImpl->m_nOpenMode )
434  {
435  case ucb::OpenMode::FOLDERS:
436  {
437  bool bFolder = false;
438 
439  const uno::Any & rValue
440  = pContentProperties->getValue(
441  "IsFolder" );
442  rValue >>= bFolder;
443 
444  if ( !bFolder )
445  continue;
446 
447  break;
448  }
449 
450  case ucb::OpenMode::DOCUMENTS:
451  {
452  bool bDocument = false;
453 
454  const uno::Any & rValue
455  = pContentProperties->getValue(
456  "IsDocument" );
457  rValue >>= bDocument;
458 
459  if ( !bDocument )
460  continue;
461 
462  break;
463  }
464 
465  case ucb::OpenMode::ALL:
466  default:
467  break;
468  }
469 
470  m_pImpl->m_Results.push_back(
471  std::make_unique<ResultListEntry>(pContentProperties));
472  }
473  }
474  catch ( DAVException const & )
475  {
476  }
477  }
478 
479  m_pImpl->m_bCountFinal = true;
480 
481  // Callback possible, because listeners may be informed!
482  aGuard.clear();
483  getResultSet()->rowCountFinal();
484  }
485  return !m_pImpl->m_bThrowException;
486 }
487 
488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Environment getEnvironment(OUString const &name, OUString const &implementation)
static constexpr OUStringLiteral RESOURCETYPE
virtual css::uno::Reference< css::ucb::XContent > queryContent(sal_uInt32 nIndex) override
static OUString unescape(const OUString &string)
Definition: NeonUri.cxx:257
virtual void releasePropertyValues(sal_uInt32 nIndex) override
std::shared_ptr< ContentProperties > const pData
uno::Reference< ucb::XContentIdentifier > xId
virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override
DataSupplier_Impl(const uno::Reference< uno::XComponentContext > &rxContext, const rtl::Reference< Content > &rContent, sal_Int32 nOpenMode)
virtual void validate() override
css::uno::Any const & rValue
const OUString & GetPath() const
Definition: NeonUri.hxx:77
const OUString & getEscapedTitle() const
virtual bool isCountFinal() override
uno::Reference< ucb::XContent > xContent
#define TOOLS_WARN_EXCEPTION(area, stream)
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
std::vector< std::unique_ptr< ResultListEntry > > ResultList
virtual sal_uInt32 currentCount() override
dictionary props
uno::Reference< uno::XComponentContext > m_xContext
virtual css::uno::Reference< css::sdbc::XRow > queryPropertyValues(sal_uInt32 nIndex) override
rtl::Reference< ResultSet > getResultSet() const
virtual css::uno::Reference< css::ucb::XContentIdentifier > queryContentIdentifier(sal_uInt32 nIndex) override
virtual bool getResult(sal_uInt32 nIndex) override
#define SAL_INFO(area, stream)
virtual sal_uInt32 totalCount() override
OUString aId
rtl::Reference< Content > m_xContent
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
uno::Reference< sdbc::XRow > xRow
static void UCBNamesToDAVNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources)
std::unique_ptr< DataSupplier_Impl > m_pImpl