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),
298  m_pImpl->m_xContent->getProvider(),
299  queryContentIdentifierString( nIndex ) );
300  m_pImpl->m_Results[ nIndex ]->xRow = xRow;
301  return xRow;
302  }
303 
304  return uno::Reference< sdbc::XRow >();
305 }
306 
307 
308 // virtual
309 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
310 {
311  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
312 
313  if (nIndex < m_pImpl->m_Results.size())
314  m_pImpl->m_Results[ nIndex ]->xRow.clear();
315 }
316 
317 
318 // virtual
320 {
321 }
322 
323 
324 // virtual
326 {
327  if ( m_pImpl->m_bThrowException )
328  throw ucb::ResultSetException();
329 }
330 
331 
333 {
334  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
335 
336  if ( !m_pImpl->m_bCountFinal )
337  {
338  std::vector< OUString > propertyNames;
340  getResultSet()->getProperties(), propertyNames );
341 
342  // Append "resourcetype", if not already present. It's value is
343  // needed to get a valid ContentProperties::pIsFolder value, which
344  // is needed for OpenMode handling.
345 
346  bool isNoResourceType = std::none_of(propertyNames.begin(), propertyNames.end(),
347  [](const OUString& rName) { return rName == DAVProperties::RESOURCETYPE; });
348 
349  if ( isNoResourceType )
350  propertyNames.push_back( DAVProperties::RESOURCETYPE );
351 
352  std::vector< DAVResource > resources;
353  try
354  {
355  // propfind depth 1, get property values for parent AND for each
356  // child
357  m_pImpl->m_xContent->getResourceAccess()
358  .PROPFIND( DAVONE,
359  propertyNames,
360  resources,
362 #if defined SAL_LOG_INFO
363  {
364  //print the resource for every URI returned
365  for ( const auto& rResource : resources )
366  {
367  NeonUri aCurrURI( rResource.uri );
368  OUString aCurrPath = aCurrURI.GetPath();
369  aCurrPath = NeonUri::unescape( aCurrPath );
370  SAL_INFO( "ucb.ucp.webdav", "getData() - resource URL: <" << rResource.uri << ">, unescaped to: <" << aCurrPath << "> )" );
371  for ( const auto& rProp : rResource.properties )
372  {
373  SAL_INFO( "ucb.ucp.webdav", "PROPFIND - property name: " << rProp.Name );
374  }
375  }
376  }
377 #endif
378  }
379  catch ( DAVException & )
380  {
381  TOOLS_WARN_EXCEPTION( "ucb.ucp.webdav", "Running PROPFIND: DAVException" );
382  m_pImpl->m_bThrowException = true;
383  }
384 
385  if ( !m_pImpl->m_bThrowException )
386  {
387  try
388  {
389  NeonUri aURI(
390  m_pImpl->m_xContent->getResourceAccess().getURL() );
391  OUString aPath = aURI.GetPath();
392 
393  if ( aPath.endsWith("/") )
394  aPath = aPath.copy( 0, aPath.getLength() - 1 );
395 
396  aPath = NeonUri::unescape( aPath );
397  bool bFoundParent = false;
398 
399  for (DAVResource & rRes : resources)
400  {
401  // Filter parent, which is contained somewhere(!) in
402  // the vector.
403  if ( !bFoundParent )
404  {
405  try
406  {
407  NeonUri aCurrURI( rRes.uri );
408  OUString aCurrPath = aCurrURI.GetPath();
409  if ( aCurrPath.endsWith("/") )
410  aCurrPath
411  = aCurrPath.copy(
412  0,
413  aCurrPath.getLength() - 1 );
414 
415  aCurrPath = NeonUri::unescape( aCurrPath );
416  if ( aPath == aCurrPath )
417  {
418  bFoundParent = true;
419  continue;
420  }
421  }
422  catch ( DAVException const & )
423  {
424  // do nothing, ignore error. continue.
425  }
426  }
427 
428  std::shared_ptr<ContentProperties> const
429  pContentProperties = std::make_shared<ContentProperties>(rRes);
430 
431  // Check resource against open mode.
432  switch ( m_pImpl->m_nOpenMode )
433  {
434  case ucb::OpenMode::FOLDERS:
435  {
436  bool bFolder = false;
437 
438  const uno::Any & rValue
439  = pContentProperties->getValue(
440  "IsFolder" );
441  rValue >>= bFolder;
442 
443  if ( !bFolder )
444  continue;
445 
446  break;
447  }
448 
449  case ucb::OpenMode::DOCUMENTS:
450  {
451  bool bDocument = false;
452 
453  const uno::Any & rValue
454  = pContentProperties->getValue(
455  "IsDocument" );
456  rValue >>= bDocument;
457 
458  if ( !bDocument )
459  continue;
460 
461  break;
462  }
463 
464  case ucb::OpenMode::ALL:
465  default:
466  break;
467  }
468 
469  m_pImpl->m_Results.push_back(
470  std::make_unique<ResultListEntry>(pContentProperties));
471  }
472  }
473  catch ( DAVException const & )
474  {
475  }
476  }
477 
478  m_pImpl->m_bCountFinal = true;
479 
480  // Callback possible, because listeners may be informed!
481  aGuard.clear();
482  getResultSet()->rowCountFinal();
483  }
484  return !m_pImpl->m_bThrowException;
485 }
486 
487 /* 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:80
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