1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <rtl/string.h>
22 #include <rtl/strbuf.hxx>
23 #include <rtl/bootstrap.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <osl/file.hxx>
26 #include <com/sun/star/deployment/DeploymentException.hpp>
27 #include <com/sun/star/uno/XComponentContext.hpp>
28 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
29 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
30 #include <com/sun/star/io/XActiveDataSource.hpp>
31 #include <com/sun/star/io/XActiveDataControl.hpp>
34 #include <ucbhelper/content.hxx>
35 #include <xmlscript/xml_helper.hxx>
36 #include <dp_backenddb.hxx>
39 using namespace ::com::sun::star::uno
;
42 namespace dp_registry
{
46 Reference
<css::uno::XComponentContext
> const & xContext
,
47 OUString
const & url
):
50 m_urlDb
= dp_misc::expandUnoRcUrl(url
);
53 void BackendDb::save()
55 const Reference
<css::io::XActiveDataSource
> xDataSource(m_doc
,css::uno::UNO_QUERY_THROW
);
56 std::vector
<sal_Int8
> bytes
;
57 xDataSource
->setOutputStream(::xmlscript::createOutputStream(&bytes
));
58 const Reference
<css::io::XActiveDataControl
> xDataControl(m_doc
,css::uno::UNO_QUERY_THROW
);
59 xDataControl
->start();
61 const Reference
<css::io::XInputStream
> xData(
62 ::xmlscript::createInputStream(bytes
));
63 ::ucbhelper::Content
ucbDb(m_urlDb
, nullptr, m_xContext
);
64 ucbDb
.writeStream(xData
, true /*replace existing*/);
67 css::uno::Reference
<css::xml::dom::XDocument
> const & BackendDb::getDocument()
71 const Reference
<css::xml::dom::XDocumentBuilder
> xDocBuilder(
72 css::xml::dom::DocumentBuilder::create(m_xContext
) );
74 ::osl::DirectoryItem item
;
75 ::osl::File::RC err
= ::osl::DirectoryItem::get(m_urlDb
, item
);
76 if (err
== ::osl::File::E_None
)
78 ::ucbhelper::Content
descContent(
79 m_urlDb
, css::uno::Reference
<css::ucb::XCommandEnvironment
>(),
81 Reference
<css::io::XInputStream
> xIn
= descContent
.openStream();
82 m_doc
= xDocBuilder
->parse(xIn
);
84 else if (err
== ::osl::File::E_NOENT
)
86 //Create a new document and insert some basic stuff
87 m_doc
= xDocBuilder
->newDocument();
88 const Reference
<css::xml::dom::XElement
> rootNode
=
89 m_doc
->createElementNS(getDbNSName(), getNSPrefix() +
90 ":" + getRootElementName());
92 m_doc
->appendChild(Reference
<css::xml::dom::XNode
>(
93 rootNode
, UNO_QUERY_THROW
));
97 throw css::uno::RuntimeException(
98 "Extension manager could not access database file:"
102 throw css::uno::RuntimeException(
103 "Extension manager could not get root node of data base file: "
110 Reference
<css::xml::xpath::XXPathAPI
> const & BackendDb::getXPathAPI()
112 if (!m_xpathApi
.is())
114 m_xpathApi
= css::xml::xpath::XPathAPI::create( m_xContext
);
116 m_xpathApi
->registerNS( getNSPrefix(), getDbNSName() );
122 void BackendDb::removeElement(OUString
const & sXPathExpression
)
126 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
127 const Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
128 const Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
129 //find the extension element that is to be removed
130 const Reference
<css::xml::dom::XNode
> aNode
=
131 xpathApi
->selectSingleNode(root
, sXPathExpression
);
135 root
->removeChild(aNode
);
139 #if OSL_DEBUG_LEVEL > 0
140 //There must not be any other entry with the same url
141 const Reference
<css::xml::dom::XNode
> nextNode
=
142 xpathApi
->selectSingleNode(root
, sXPathExpression
);
143 OSL_ASSERT(! nextNode
.is());
146 catch(const css::uno::Exception
&)
148 Any
exc( ::cppu::getCaughtException() );
149 throw css::deployment::DeploymentException(
150 "Extension Manager: failed to write data entry in backend db: " +
151 m_urlDb
, nullptr, exc
);
155 void BackendDb::removeEntry(OUString
const & url
)
157 const OUString sKeyElement
= getKeyElementName();
158 const OUString sPrefix
= getNSPrefix();
159 OUString sExpression
=
167 removeElement(sExpression
);
170 void BackendDb::revokeEntry(OUString
const & url
)
174 Reference
<css::xml::dom::XElement
> entry(getKeyElement(url
), UNO_QUERY
);
177 entry
->setAttribute("revoked", "true");
181 catch(const css::uno::Exception
&)
183 Any
exc( ::cppu::getCaughtException() );
184 throw css::deployment::DeploymentException(
185 "Extension Manager: failed to revoke data entry in backend db: " +
186 m_urlDb
, nullptr, exc
);
190 bool BackendDb::activateEntry(OUString
const & url
)
195 Reference
<css::xml::dom::XElement
> entry(getKeyElement(url
), UNO_QUERY
);
198 //no attribute "active" means it is active, that is, registered.
199 entry
->removeAttribute("revoked");
205 catch(const css::uno::Exception
&)
207 Any
exc( ::cppu::getCaughtException() );
208 throw css::deployment::DeploymentException(
209 "Extension Manager: failed to revoke data entry in backend db: " +
210 m_urlDb
, nullptr, exc
);
214 bool BackendDb::hasActiveEntry(OUString
const & url
)
219 Reference
<css::xml::dom::XElement
> entry(getKeyElement(url
), UNO_QUERY
);
222 OUString sActive
= entry
->getAttribute("revoked");
223 if (!(sActive
== "true"))
229 catch(const css::uno::Exception
&)
231 Any
exc( ::cppu::getCaughtException() );
232 throw css::deployment::DeploymentException(
233 "Extension Manager: failed to determine an active entry in backend db: " +
234 m_urlDb
, nullptr, exc
);
238 Reference
<css::xml::dom::XNode
> BackendDb::getKeyElement(
239 OUString
const & url
)
243 const OUString sPrefix
= getNSPrefix();
244 const OUString sKeyElement
= getKeyElementName();
245 OUString sExpression
=
253 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
254 const Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
255 const Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
256 return xpathApi
->selectSingleNode(root
, sExpression
);
258 catch(const css::uno::Exception
&)
260 Any
exc( ::cppu::getCaughtException() );
261 throw css::deployment::DeploymentException(
262 "Extension Manager: failed to read key element in backend db: " +
263 m_urlDb
, nullptr, exc
);
267 //Only writes the data if there is at least one entry
268 void BackendDb::writeVectorOfPair(
269 std::vector
< std::pair
< OUString
, OUString
> > const & vecPairs
,
270 OUString
const & sVectorTagName
,
271 OUString
const & sPairTagName
,
272 OUString
const & sFirstTagName
,
273 OUString
const & sSecondTagName
,
274 css::uno::Reference
<css::xml::dom::XNode
> const & xParent
)
277 if (vecPairs
.empty())
279 const OUString sNameSpace
= getDbNSName();
280 OSL_ASSERT(!sNameSpace
.isEmpty());
281 const OUString
sPrefix(getNSPrefix() + ":");
282 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
283 const Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
285 const Reference
<css::xml::dom::XElement
> vectorNode(
286 doc
->createElementNS(sNameSpace
, sPrefix
+ sVectorTagName
));
288 xParent
->appendChild(
289 Reference
<css::xml::dom::XNode
>(
290 vectorNode
, css::uno::UNO_QUERY_THROW
));
291 for (auto const& vecPair
: vecPairs
)
293 const Reference
<css::xml::dom::XElement
> pairNode(
294 doc
->createElementNS(sNameSpace
, sPrefix
+ sPairTagName
));
296 vectorNode
->appendChild(
297 Reference
<css::xml::dom::XNode
>(
298 pairNode
, css::uno::UNO_QUERY_THROW
));
300 const Reference
<css::xml::dom::XElement
> firstNode(
301 doc
->createElementNS(sNameSpace
, sPrefix
+ sFirstTagName
));
303 pairNode
->appendChild(
304 Reference
<css::xml::dom::XNode
>(
305 firstNode
, css::uno::UNO_QUERY_THROW
));
307 const Reference
<css::xml::dom::XText
> firstTextNode(
308 doc
->createTextNode( vecPair
.first
));
310 firstNode
->appendChild(
311 Reference
<css::xml::dom::XNode
>(
312 firstTextNode
, css::uno::UNO_QUERY_THROW
));
314 const Reference
<css::xml::dom::XElement
> secondNode(
315 doc
->createElementNS(sNameSpace
, sPrefix
+ sSecondTagName
));
317 pairNode
->appendChild(
318 Reference
<css::xml::dom::XNode
>(
319 secondNode
, css::uno::UNO_QUERY_THROW
));
321 const Reference
<css::xml::dom::XText
> secondTextNode(
322 doc
->createTextNode( vecPair
.second
));
324 secondNode
->appendChild(
325 Reference
<css::xml::dom::XNode
>(
326 secondTextNode
, css::uno::UNO_QUERY_THROW
));
329 catch(const css::uno::Exception
&)
331 Any
exc( ::cppu::getCaughtException() );
332 throw css::deployment::DeploymentException(
333 "Extension Manager: failed to write data entry in backend db: " +
334 m_urlDb
, nullptr, exc
);
338 std::vector
< std::pair
< OUString
, OUString
> >
339 BackendDb::readVectorOfPair(
340 Reference
<css::xml::dom::XNode
> const & parent
,
341 OUString
const & sListTagName
,
342 OUString
const & sPairTagName
,
343 OUString
const & sFirstTagName
,
344 OUString
const & sSecondTagName
)
348 OSL_ASSERT(parent
.is());
349 const OUString
sPrefix(getNSPrefix() + ":");
350 const Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
351 const OUString
sExprPairs(
352 sPrefix
+ sListTagName
+ "/" + sPrefix
+ sPairTagName
);
353 const Reference
<css::xml::dom::XNodeList
> listPairs
=
354 xpathApi
->selectNodeList(parent
, sExprPairs
);
356 std::vector
< std::pair
< OUString
, OUString
> > retVector
;
357 sal_Int32 length
= listPairs
->getLength();
358 for (sal_Int32 i
= 0; i
< length
; i
++)
360 const Reference
<css::xml::dom::XNode
> aPair
= listPairs
->item(i
);
361 const OUString
sExprFirst(sPrefix
+ sFirstTagName
+ "/text()");
362 const Reference
<css::xml::dom::XNode
> first
=
363 xpathApi
->selectSingleNode(aPair
, sExprFirst
);
365 const OUString
sExprSecond(sPrefix
+ sSecondTagName
+ "/text()");
366 const Reference
<css::xml::dom::XNode
> second
=
367 xpathApi
->selectSingleNode(aPair
, sExprSecond
);
368 OSL_ASSERT(first
.is() && second
.is());
370 retVector
.emplace_back(
371 first
->getNodeValue(), second
->getNodeValue());
375 catch(const css::uno::Exception
&)
377 Any
exc( ::cppu::getCaughtException() );
378 throw css::deployment::DeploymentException(
379 "Extension Manager: failed to read data entry in backend db: " +
380 m_urlDb
, nullptr, exc
);
384 //Only writes the data if there is at least one entry
385 void BackendDb::writeSimpleList(
386 std::deque
< OUString
> const & list
,
387 OUString
const & sListTagName
,
388 OUString
const & sMemberTagName
,
389 Reference
<css::xml::dom::XNode
> const & xParent
)
395 const OUString sNameSpace
= getDbNSName();
396 const OUString
sPrefix(getNSPrefix() + ":");
397 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
399 const Reference
<css::xml::dom::XElement
> listNode(
400 doc
->createElementNS(sNameSpace
, sPrefix
+ sListTagName
));
402 xParent
->appendChild(
403 Reference
<css::xml::dom::XNode
>(
404 listNode
, css::uno::UNO_QUERY_THROW
));
406 for (auto const& elem
: list
)
408 const Reference
<css::xml::dom::XNode
> memberNode(
409 doc
->createElementNS(sNameSpace
, sPrefix
+ sMemberTagName
), css::uno::UNO_QUERY_THROW
);
411 listNode
->appendChild(memberNode
);
413 const Reference
<css::xml::dom::XNode
> textNode(
414 doc
->createTextNode(elem
), css::uno::UNO_QUERY_THROW
);
416 memberNode
->appendChild(textNode
);
419 catch(const css::uno::Exception
&)
421 Any
exc( ::cppu::getCaughtException() );
422 throw css::deployment::DeploymentException(
423 "Extension Manager: failed to write data entry in backend db: " +
424 m_urlDb
, nullptr, exc
);
428 //Writes only the element if is has a value.
429 //The prefix is automatically added to the element name
430 void BackendDb::writeSimpleElement(
431 OUString
const & sElementName
, OUString
const & value
,
432 Reference
<css::xml::dom::XNode
> const & xParent
)
438 const OUString sPrefix
= getNSPrefix();
439 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
440 const OUString sNameSpace
= getDbNSName();
441 const Reference
<css::xml::dom::XNode
> dataNode(
442 doc
->createElementNS(sNameSpace
, sPrefix
+ ":" + sElementName
),
444 xParent
->appendChild(dataNode
);
446 const Reference
<css::xml::dom::XNode
> dataValue(
447 doc
->createTextNode(value
), UNO_QUERY_THROW
);
448 dataNode
->appendChild(dataValue
);
450 catch(const css::uno::Exception
&)
452 Any
exc( ::cppu::getCaughtException() );
453 throw css::deployment::DeploymentException(
454 "Extension Manager: failed to write data entry(writeSimpleElement) in backend db: " +
455 m_urlDb
, nullptr, exc
);
460 /// The key elements have a url attribute and are always children of the root element.
461 Reference
<css::xml::dom::XNode
> BackendDb::writeKeyElement(
462 OUString
const & url
)
466 const OUString sNameSpace
= getDbNSName();
467 const OUString sPrefix
= getNSPrefix();
468 const OUString sElementName
= getKeyElementName();
469 const Reference
<css::xml::dom::XDocument
> doc
= getDocument();
470 const Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
472 //Check if there are an entry with the same url. This can be the case if the
473 //status of an XPackage is ambiguous. In this case a call to activateExtension
474 //(dp_extensionmanager.cxx), will register the package again. See also
475 //Package::processPackage_impl in dp_backend.cxx.
476 //A package can become
477 //invalid after its successful registration, for example if a second extension with
478 //the same service is installed.
479 const OUString
sExpression(
480 sPrefix
+ ":" + sElementName
+ "[@url = \"" + url
+ "\"]");
481 const Reference
<css::xml::dom::XNode
> existingNode
=
482 getXPathAPI()->selectSingleNode(root
, sExpression
);
483 if (existingNode
.is())
486 //replace the existing entry.
490 const Reference
<css::xml::dom::XElement
> keyElement(
491 doc
->createElementNS(sNameSpace
, sPrefix
+ ":" + sElementName
));
493 keyElement
->setAttribute("url", url
);
495 const Reference
<css::xml::dom::XNode
> keyNode(
496 keyElement
, UNO_QUERY_THROW
);
497 root
->appendChild(keyNode
);
500 catch(const css::uno::Exception
&)
502 Any
exc( ::cppu::getCaughtException() );
503 throw css::deployment::DeploymentException(
504 "Extension Manager: failed to write key element in backend db: " +
505 m_urlDb
, nullptr, exc
);
509 OUString
BackendDb::readSimpleElement(
510 OUString
const & sElementName
, Reference
<css::xml::dom::XNode
> const & xParent
)
514 const OUString sPrefix
= getNSPrefix();
515 const OUString
sExpr(sPrefix
+ ":" + sElementName
+ "/text()");
516 const Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
517 const Reference
<css::xml::dom::XNode
> val
=
518 xpathApi
->selectSingleNode(xParent
, sExpr
);
520 return val
->getNodeValue();
523 catch(const css::uno::Exception
&)
525 Any
exc( ::cppu::getCaughtException() );
526 throw css::deployment::DeploymentException(
527 "Extension Manager: failed to read data (readSimpleElement) in backend db: " +
528 m_urlDb
, nullptr, exc
);
533 std::deque
< OUString
> BackendDb::readList(
534 Reference
<css::xml::dom::XNode
> const & parent
,
535 OUString
const & sListTagName
,
536 OUString
const & sMemberTagName
)
540 OSL_ASSERT(parent
.is());
541 const OUString
sPrefix(getNSPrefix() + ":");
542 const Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
543 const OUString
sExprList(
544 sPrefix
+ sListTagName
+ "/" + sPrefix
+ sMemberTagName
+ "/text()");
545 const Reference
<css::xml::dom::XNodeList
> list
=
546 xpathApi
->selectNodeList(parent
, sExprList
);
548 std::deque
<OUString
> retList
;
549 sal_Int32 length
= list
->getLength();
550 for (sal_Int32 i
= 0; i
< length
; i
++)
552 const Reference
<css::xml::dom::XNode
> member
= list
->item(i
);
553 retList
.push_back(member
->getNodeValue());
557 catch(const css::uno::Exception
&)
559 Any
exc( ::cppu::getCaughtException() );
560 throw css::deployment::DeploymentException(
561 "Extension Manager: failed to read data entry in backend db: " +
562 m_urlDb
, nullptr, exc
);
566 std::vector
<OUString
> BackendDb::getOneChildFromAllEntries(
567 OUString
const & name
)
571 std::vector
<OUString
> listRet
;
572 Reference
<css::xml::dom::XDocument
> doc
= getDocument();
573 Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
575 Reference
<css::xml::xpath::XXPathAPI
> xpathApi
= getXPathAPI();
576 const OUString sPrefix
= getNSPrefix();
577 const OUString sKeyElement
= getKeyElementName();
578 OUString sNodeSelectExpr
=
588 Reference
<css::xml::dom::XNodeList
> nodes
=
589 xpathApi
->selectNodeList(root
, sNodeSelectExpr
);
592 sal_Int32 length
= nodes
->getLength();
593 for (sal_Int32 i
= 0; i
< length
; i
++)
594 listRet
.push_back(nodes
->item(i
)->getNodeValue());
598 catch ( const css::deployment::DeploymentException
& )
602 catch(const css::uno::Exception
&)
604 Any
exc( ::cppu::getCaughtException() );
605 throw css::deployment::DeploymentException(
606 "Extension Manager: failed to read data entry in backend db: " +
607 m_urlDb
, nullptr, exc
);
612 RegisteredDb::RegisteredDb(
613 Reference
<XComponentContext
> const & xContext
,
614 OUString
const & url
):BackendDb(xContext
, url
)
618 void RegisteredDb::addEntry(OUString
const & url
)
621 if (!activateEntry(url
))
623 const OUString sNameSpace
= getDbNSName();
624 const OUString sPrefix
= getNSPrefix();
625 const OUString sEntry
= getKeyElementName();
627 Reference
<css::xml::dom::XDocument
> doc
= getDocument();
628 Reference
<css::xml::dom::XNode
> root
= doc
->getFirstChild();
630 #if OSL_DEBUG_LEVEL > 0
631 //There must not be yet an entry with the same url
632 OUString
sExpression(
633 sPrefix
+ ":" + sEntry
+ "[@url = \"" + url
+ "\"]");
634 Reference
<css::xml::dom::XNode
> _extensionNode
=
635 getXPathAPI()->selectSingleNode(root
, sExpression
);
636 OSL_ASSERT(! _extensionNode
.is());
638 Reference
<css::xml::dom::XElement
> helpElement(
639 doc
->createElementNS(sNameSpace
, sPrefix
+ ":" + sEntry
));
641 helpElement
->setAttribute("url", url
);
643 Reference
<css::xml::dom::XNode
> helpNode(
644 helpElement
, UNO_QUERY_THROW
);
645 root
->appendChild(helpNode
);
650 catch(const css::uno::Exception
&)
652 Any
exc( ::cppu::getCaughtException() );
653 throw css::deployment::DeploymentException(
654 "Extension Manager: failed to write data entry in backend db: " +
655 m_urlDb
, nullptr, exc
);
659 } // namespace backend
660 } // namespace dp_registry
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */