Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / deployment / registry / dp_backenddb.cxx
blob6361742576b1fef96ea9196c469509b30b49867c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
32 #include <dp_ucb.h>
33 #include <dp_misc.h>
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 {
43 namespace backend {
45 BackendDb::BackendDb(
46 Reference<css::uno::XComponentContext> const & xContext,
47 OUString const & url):
48 m_xContext(xContext)
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()
69 if (!m_doc.is())
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>(),
80 m_xContext);
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));
94 save();
96 else
97 throw css::uno::RuntimeException(
98 "Extension manager could not access database file:"
99 + m_urlDb, nullptr);
101 if (!m_doc.is())
102 throw css::uno::RuntimeException(
103 "Extension manager could not get root node of data base file: "
104 + m_urlDb, nullptr);
107 return m_doc;
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() );
119 return m_xpathApi;
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);
133 if (aNode.is())
135 root->removeChild(aNode);
136 save();
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());
144 #endif
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 =
160 sPrefix +
161 ":" +
162 sKeyElement +
163 "[@url = \"" +
164 url +
165 "\"]";
167 removeElement(sExpression);
170 void BackendDb::revokeEntry(OUString const & url)
174 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
175 if (entry.is())
177 entry->setAttribute("revoked", "true");
178 save();
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)
194 bool ret = false;
195 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
196 if (entry.is())
198 //no attribute "active" means it is active, that is, registered.
199 entry->removeAttribute("revoked");
200 save();
201 ret = true;
203 return ret;
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)
218 bool ret = false;
219 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
220 if (entry.is())
222 OUString sActive = entry->getAttribute("revoked");
223 if (!(sActive == "true"))
224 ret = true;
226 return ret;
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 =
246 sPrefix +
247 ":" +
248 sKeyElement +
249 "[@url = \"" +
250 url +
251 "\"]";
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)
276 try{
277 if (vecPairs.empty())
278 return;
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());
373 return retVector;
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)
393 if (list.empty())
394 return;
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)
436 if (value.isEmpty())
437 return;
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),
443 UNO_QUERY_THROW);
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())
485 OSL_ASSERT(false);
486 //replace the existing entry.
487 removeEntry(url);
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);
498 return 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);
519 if (val.is())
520 return val->getNodeValue();
521 return OUString();
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());
555 return retList;
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 =
579 sPrefix +
580 ":" +
581 sKeyElement +
582 "/" +
583 sPrefix +
584 ":" +
585 name +
586 "/text()";
588 Reference<css::xml::dom::XNodeList> nodes =
589 xpathApi->selectNodeList(root, sNodeSelectExpr);
590 if (nodes.is())
592 sal_Int32 length = nodes->getLength();
593 for (sal_Int32 i = 0; i < length; i++)
594 listRet.push_back(nodes->item(i)->getNodeValue());
596 return listRet;
598 catch ( const css::deployment::DeploymentException& )
600 throw;
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)
620 try{
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());
637 #endif
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);
647 save();
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: */