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 <memory>
43 #include <vector>
44 #include "webdavdatasupplier.hxx"
45 #include "webdavcontent.hxx"
46 #include "ContentProperties.hxx"
47 #include "NeonUri.hxx"
48 
49 using namespace com::sun::star;
50 using namespace webdav_ucp;
51 
52 namespace webdav_ucp
53 {
54 
55 
56 // struct ResultListEntry.
57 
58 namespace {
59 
60 struct ResultListEntry
61 {
62  OUString aId;
63  uno::Reference< ucb::XContentIdentifier > xId;
64  uno::Reference< ucb::XContent > xContent;
65  uno::Reference< sdbc::XRow > xRow;
66  std::shared_ptr<ContentProperties> const pData;
67 
68  explicit ResultListEntry(std::shared_ptr<ContentProperties> const& pEntry)
69  : pData(pEntry)
70  {}
71 };
72 
73 }
74 
75 // ResultList.
76 
77 
78 typedef std::vector<std::unique_ptr<ResultListEntry>> ResultList;
79 
80 
81 // struct DataSupplier_Impl.
82 
83 
85 {
86  osl::Mutex m_aMutex;
87  ResultList m_Results;
89  uno::Reference< uno::XComponentContext > m_xContext;
90  sal_Int32 m_nOpenMode;
93 
95  const uno::Reference< uno::XComponentContext >& rxContext,
96  const rtl::Reference< Content >& rContent,
97  sal_Int32 nOpenMode )
98  : m_xContent( rContent ), m_xContext( rxContext ), m_nOpenMode( nOpenMode ),
99  m_bCountFinal( false ), m_bThrowException( false ) {}
100 };
101 
102 }
103 
104 
105 // DataSupplier Implementation.
106 
107 
108 DataSupplier::DataSupplier(
109  const uno::Reference< uno::XComponentContext >& rxContext,
110  const rtl::Reference< Content >& rContent,
111  sal_Int32 nOpenMode )
112 : m_pImpl( new DataSupplier_Impl( rxContext, rContent, nOpenMode ) )
113 {
114 }
115 
116 
117 // virtual
119 {
120 }
121 
122 
123 // virtual
124 OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
125 {
126  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
127 
128  if (nIndex < m_pImpl->m_Results.size())
129  {
130  OUString aId = m_pImpl->m_Results[ nIndex ]->aId;
131  if ( !aId.isEmpty() )
132  {
133  // Already cached.
134  return aId;
135  }
136  }
137 
138  if ( getResult( nIndex ) )
139  {
140  OUString aId = m_pImpl->m_xContent->getResourceAccess().getURL();
141 
142  const ContentProperties& props(*(m_pImpl->m_Results[ nIndex ]->pData));
143 
144  if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
145  aId += "/";
146 
147  aId += props.getEscapedTitle();
148 
149  if ( props.isTrailingSlash() )
150  aId += "/";
151 
152  m_pImpl->m_Results[ nIndex ]->aId = aId;
153  return aId;
154  }
155  return OUString();
156 }
157 
158 
159 // virtual
160 uno::Reference< ucb::XContentIdentifier >
162 {
163  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
164 
165  if (nIndex < m_pImpl->m_Results.size())
166  {
167  uno::Reference< ucb::XContentIdentifier > xId
168  = m_pImpl->m_Results[ nIndex ]->xId;
169  if ( xId.is() )
170  {
171  // Already cached.
172  return xId;
173  }
174  }
175 
176  OUString aId = queryContentIdentifierString( nIndex );
177  if ( !aId.isEmpty() )
178  {
179  uno::Reference< ucb::XContentIdentifier > xId
180  = new ::ucbhelper::ContentIdentifier( aId );
181  m_pImpl->m_Results[ nIndex ]->xId = xId;
182  return xId;
183  }
184  return uno::Reference< ucb::XContentIdentifier >();
185 }
186 
187 
188 // virtual
189 uno::Reference< ucb::XContent >
190 DataSupplier::queryContent( sal_uInt32 nIndex )
191 {
192  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
193 
194  if (nIndex < m_pImpl->m_Results.size())
195  {
196  uno::Reference< ucb::XContent > xContent
197  = m_pImpl->m_Results[ nIndex ]->xContent;
198  if ( xContent.is() )
199  {
200  // Already cached.
201  return xContent;
202  }
203  }
204 
205  uno::Reference< ucb::XContentIdentifier > xId
206  = queryContentIdentifier( nIndex );
207  if ( xId.is() )
208  {
209  try
210  {
211  uno::Reference< ucb::XContent > xContent
212  = m_pImpl->m_xContent->getProvider()->queryContent( xId );
213  m_pImpl->m_Results[ nIndex ]->xContent = xContent;
214  return xContent;
215 
216  }
217  catch ( ucb::IllegalIdentifierException& )
218  {
219  }
220  }
221  return uno::Reference< ucb::XContent >();
222 }
223 
224 
225 // virtual
226 bool DataSupplier::getResult( sal_uInt32 nIndex )
227 {
228  osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
229 
230  if (nIndex < m_pImpl->m_Results.size())
231  {
232  // Result already present.
233  return true;
234  }
235 
236  // Obtain values...
237  if ( getData() )
238  {
239  if (nIndex < m_pImpl->m_Results.size())
240  {
241  // Result already present.
242  return true;
243  }
244  }
245 
246  return false;
247 }
248 
249 
250 // virtual
252 {
253  // Obtain values...
254  getData();
255 
256  return m_pImpl->m_Results.size();
257 }
258 
259 
260 // virtual
262 {
263  return m_pImpl->m_Results.size();
264 }
265 
266 
267 // virtual
269 {
270  return m_pImpl->m_bCountFinal;
271 }
272 
273 
274 // virtual
275 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues(
276  sal_uInt32 nIndex )
277 {
278  osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
279 
280  if (nIndex < m_pImpl->m_Results.size())
281  {
282  uno::Reference< sdbc::XRow > xRow = m_pImpl->m_Results[ nIndex ]->xRow;
283  if ( xRow.is() )
284  {
285  // Already cached.
286  return xRow;
287  }
288  }
289 
290  if ( getResult( nIndex ) )
291  {
292  uno::Reference< sdbc::XRow > xRow
294  m_pImpl->m_xContext,
295  getResultSet()->getProperties(),
296  *(m_pImpl->m_Results[ nIndex ]->pData),
298  m_pImpl->m_xContent->getProvider().get() ),
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  SAL_WARN( "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:77
const OUString & getEscapedTitle() const
virtual bool isCountFinal() override
uno::Reference< ucb::XContent > xContent
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)
#define SAL_WARN(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