Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / desktop / source / deployment / registry / dp_backenddb.cxx
blob28effd95c8f5c24d20f9446dc12b2dc604399e98
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 <cppuhelper/exc_hlp.hxx>
22 #include <osl/file.hxx>
23 #include <com/sun/star/deployment/DeploymentException.hpp>
24 #include <com/sun/star/uno/XComponentContext.hpp>
25 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
26 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
27 #include <com/sun/star/io/XActiveDataSource.hpp>
28 #include <com/sun/star/io/XActiveDataControl.hpp>
29 #include <dp_misc.h>
30 #include <ucbhelper/content.hxx>
31 #include <xmlscript/xml_helper.hxx>
32 #include <dp_backenddb.hxx>
35 using namespace ::com::sun::star::uno;
38 namespace dp_registry::backend {
40 BackendDb::BackendDb(
41 Reference<css::uno::XComponentContext> const & xContext,
42 OUString const & url):
43 m_xContext(xContext)
45 m_urlDb = dp_misc::expandUnoRcUrl(url);
48 void BackendDb::save()
50 const Reference<css::io::XActiveDataSource> xDataSource(m_doc,css::uno::UNO_QUERY_THROW);
51 std::vector<sal_Int8> bytes;
52 xDataSource->setOutputStream(::xmlscript::createOutputStream(&bytes));
53 const Reference<css::io::XActiveDataControl> xDataControl(m_doc,css::uno::UNO_QUERY_THROW);
54 xDataControl->start();
56 const Reference<css::io::XInputStream> xData(
57 ::xmlscript::createInputStream(std::move(bytes)));
58 ::ucbhelper::Content ucbDb(m_urlDb, nullptr, m_xContext);
59 ucbDb.writeStream(xData, true /*replace existing*/);
62 css::uno::Reference<css::xml::dom::XDocument> const & BackendDb::getDocument()
64 if (!m_doc.is())
66 const Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
67 css::xml::dom::DocumentBuilder::create(m_xContext) );
69 ::osl::DirectoryItem item;
70 ::osl::File::RC err = ::osl::DirectoryItem::get(m_urlDb, item);
71 if (err == ::osl::File::E_None)
73 ::ucbhelper::Content descContent(
74 m_urlDb, css::uno::Reference<css::ucb::XCommandEnvironment>(),
75 m_xContext);
76 Reference<css::io::XInputStream> xIn = descContent.openStream();
77 m_doc = xDocBuilder->parse(xIn);
79 else if (err == ::osl::File::E_NOENT)
81 //Create a new document and insert some basic stuff
82 m_doc = xDocBuilder->newDocument();
83 const Reference<css::xml::dom::XElement> rootNode =
84 m_doc->createElementNS(getDbNSName(), getNSPrefix() +
85 ":" + getRootElementName());
87 m_doc->appendChild(Reference<css::xml::dom::XNode>(
88 rootNode, UNO_QUERY_THROW));
89 save();
91 else
92 throw css::uno::RuntimeException(
93 "Extension manager could not access database file:"
94 + m_urlDb, nullptr);
96 if (!m_doc.is())
97 throw css::uno::RuntimeException(
98 "Extension manager could not get root node of data base file: "
99 + m_urlDb, nullptr);
102 return m_doc;
105 Reference<css::xml::xpath::XXPathAPI> const & BackendDb::getXPathAPI()
107 if (!m_xpathApi.is())
109 m_xpathApi = css::xml::xpath::XPathAPI::create( m_xContext );
111 m_xpathApi->registerNS( getNSPrefix(), getDbNSName() );
114 return m_xpathApi;
117 void BackendDb::removeElement(OUString const & sXPathExpression)
121 const Reference<css::xml::dom::XDocument> doc = getDocument();
122 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
123 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
124 //find the extension element that is to be removed
125 const Reference<css::xml::dom::XNode> aNode =
126 xpathApi->selectSingleNode(root, sXPathExpression);
128 if (aNode.is())
130 root->removeChild(aNode);
131 save();
134 #if OSL_DEBUG_LEVEL > 0
135 //There must not be any other entry with the same url
136 const Reference<css::xml::dom::XNode> nextNode =
137 xpathApi->selectSingleNode(root, sXPathExpression);
138 OSL_ASSERT(! nextNode.is());
139 #endif
141 catch(const css::uno::Exception &)
143 Any exc( ::cppu::getCaughtException() );
144 throw css::deployment::DeploymentException(
145 "Extension Manager: failed to write data entry in backend db: " +
146 m_urlDb, nullptr, exc);
150 void BackendDb::removeEntry(std::u16string_view url)
152 const OUString sKeyElement = getKeyElementName();
153 const OUString sPrefix = getNSPrefix();
154 OUString sExpression =
155 sPrefix +
156 ":" +
157 sKeyElement +
158 "[@url = \"" +
159 url +
160 "\"]";
162 removeElement(sExpression);
165 void BackendDb::revokeEntry(std::u16string_view url)
169 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
170 if (entry.is())
172 entry->setAttribute("revoked", "true");
173 save();
176 catch(const css::uno::Exception &)
178 Any exc( ::cppu::getCaughtException() );
179 throw css::deployment::DeploymentException(
180 "Extension Manager: failed to revoke data entry in backend db: " +
181 m_urlDb, nullptr, exc);
185 bool BackendDb::activateEntry(std::u16string_view url)
189 bool ret = false;
190 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
191 if (entry.is())
193 //no attribute "active" means it is active, that is, registered.
194 entry->removeAttribute("revoked");
195 save();
196 ret = true;
198 return ret;
200 catch(const css::uno::Exception &)
202 Any exc( ::cppu::getCaughtException() );
203 throw css::deployment::DeploymentException(
204 "Extension Manager: failed to revoke data entry in backend db: " +
205 m_urlDb, nullptr, exc);
209 bool BackendDb::hasActiveEntry(std::u16string_view url)
213 bool ret = false;
214 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
215 if (entry.is())
217 OUString sActive = entry->getAttribute("revoked");
218 if (!(sActive == "true"))
219 ret = true;
221 return ret;
224 catch(const css::uno::Exception &)
226 Any exc( ::cppu::getCaughtException() );
227 throw css::deployment::DeploymentException(
228 "Extension Manager: failed to determine an active entry in backend db: " +
229 m_urlDb, nullptr, exc);
233 Reference<css::xml::dom::XNode> BackendDb::getKeyElement(
234 std::u16string_view url)
238 const OUString sPrefix = getNSPrefix();
239 const OUString sKeyElement = getKeyElementName();
240 OUString sExpression =
241 sPrefix +
242 ":" +
243 sKeyElement +
244 "[@url = \"" +
245 url +
246 "\"]";
248 const Reference<css::xml::dom::XDocument> doc = getDocument();
249 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
250 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
251 return xpathApi->selectSingleNode(root, sExpression);
253 catch(const css::uno::Exception &)
255 Any exc( ::cppu::getCaughtException() );
256 throw css::deployment::DeploymentException(
257 "Extension Manager: failed to read key element in backend db: " +
258 m_urlDb, nullptr, exc);
262 //Only writes the data if there is at least one entry
263 void BackendDb::writeVectorOfPair(
264 std::vector< std::pair< OUString, OUString > > const & vecPairs,
265 std::u16string_view sVectorTagName,
266 std::u16string_view sPairTagName,
267 std::u16string_view sFirstTagName,
268 std::u16string_view sSecondTagName,
269 css::uno::Reference<css::xml::dom::XNode> const & xParent)
271 try{
272 if (vecPairs.empty())
273 return;
274 const OUString sNameSpace = getDbNSName();
275 OSL_ASSERT(!sNameSpace.isEmpty());
276 const OUString sPrefix(getNSPrefix() + ":");
277 const Reference<css::xml::dom::XDocument> doc = getDocument();
279 const Reference<css::xml::dom::XElement> vectorNode(
280 doc->createElementNS(sNameSpace, sPrefix + sVectorTagName));
282 xParent->appendChild(
283 Reference<css::xml::dom::XNode>(
284 vectorNode, css::uno::UNO_QUERY_THROW));
285 for (auto const& vecPair : vecPairs)
287 const Reference<css::xml::dom::XElement> pairNode(
288 doc->createElementNS(sNameSpace, sPrefix + sPairTagName));
290 vectorNode->appendChild(
291 Reference<css::xml::dom::XNode>(
292 pairNode, css::uno::UNO_QUERY_THROW));
294 const Reference<css::xml::dom::XElement> firstNode(
295 doc->createElementNS(sNameSpace, sPrefix + sFirstTagName));
297 pairNode->appendChild(
298 Reference<css::xml::dom::XNode>(
299 firstNode, css::uno::UNO_QUERY_THROW));
301 const Reference<css::xml::dom::XText> firstTextNode(
302 doc->createTextNode( vecPair.first));
304 firstNode->appendChild(
305 Reference<css::xml::dom::XNode>(
306 firstTextNode, css::uno::UNO_QUERY_THROW));
308 const Reference<css::xml::dom::XElement> secondNode(
309 doc->createElementNS(sNameSpace, sPrefix + sSecondTagName));
311 pairNode->appendChild(
312 Reference<css::xml::dom::XNode>(
313 secondNode, css::uno::UNO_QUERY_THROW));
315 const Reference<css::xml::dom::XText> secondTextNode(
316 doc->createTextNode( vecPair.second));
318 secondNode->appendChild(
319 Reference<css::xml::dom::XNode>(
320 secondTextNode, css::uno::UNO_QUERY_THROW));
323 catch(const css::uno::Exception &)
325 Any exc( ::cppu::getCaughtException() );
326 throw css::deployment::DeploymentException(
327 "Extension Manager: failed to write data entry in backend db: " +
328 m_urlDb, nullptr, exc);
332 std::vector< std::pair< OUString, OUString > >
333 BackendDb::readVectorOfPair(
334 Reference<css::xml::dom::XNode> const & parent,
335 std::u16string_view sListTagName,
336 std::u16string_view sPairTagName,
337 std::u16string_view sFirstTagName,
338 std::u16string_view sSecondTagName)
342 OSL_ASSERT(parent.is());
343 const OUString sPrefix(getNSPrefix() + ":");
344 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
345 const OUString sExprPairs(
346 sPrefix + sListTagName + "/" + sPrefix + sPairTagName);
347 const Reference<css::xml::dom::XNodeList> listPairs =
348 xpathApi->selectNodeList(parent, sExprPairs);
350 std::vector< std::pair< OUString, OUString > > retVector;
351 sal_Int32 length = listPairs->getLength();
352 for (sal_Int32 i = 0; i < length; i++)
354 const Reference<css::xml::dom::XNode> aPair = listPairs->item(i);
355 const OUString sExprFirst(sPrefix + sFirstTagName + "/text()");
356 const Reference<css::xml::dom::XNode> first =
357 xpathApi->selectSingleNode(aPair, sExprFirst);
359 const OUString sExprSecond(sPrefix + sSecondTagName + "/text()");
360 const Reference<css::xml::dom::XNode> second =
361 xpathApi->selectSingleNode(aPair, sExprSecond);
362 OSL_ASSERT(first.is() && second.is());
364 retVector.emplace_back(
365 first->getNodeValue(), second->getNodeValue());
367 return retVector;
369 catch(const css::uno::Exception &)
371 Any exc( ::cppu::getCaughtException() );
372 throw css::deployment::DeploymentException(
373 "Extension Manager: failed to read data entry in backend db: " +
374 m_urlDb, nullptr, exc);
378 //Only writes the data if there is at least one entry
379 void BackendDb::writeSimpleList(
380 std::deque< OUString> const & list,
381 std::u16string_view sListTagName,
382 std::u16string_view sMemberTagName,
383 Reference<css::xml::dom::XNode> const & xParent)
387 if (list.empty())
388 return;
389 const OUString sNameSpace = getDbNSName();
390 const OUString sPrefix(getNSPrefix() + ":");
391 const Reference<css::xml::dom::XDocument> doc = getDocument();
393 const Reference<css::xml::dom::XElement> listNode(
394 doc->createElementNS(sNameSpace, sPrefix + sListTagName));
396 xParent->appendChild(
397 Reference<css::xml::dom::XNode>(
398 listNode, css::uno::UNO_QUERY_THROW));
400 for (auto const& elem : list)
402 const Reference<css::xml::dom::XNode> memberNode(
403 doc->createElementNS(sNameSpace, sPrefix + sMemberTagName), css::uno::UNO_QUERY_THROW);
405 listNode->appendChild(memberNode);
407 const Reference<css::xml::dom::XNode> textNode(
408 doc->createTextNode(elem), css::uno::UNO_QUERY_THROW);
410 memberNode->appendChild(textNode);
413 catch(const css::uno::Exception &)
415 Any exc( ::cppu::getCaughtException() );
416 throw css::deployment::DeploymentException(
417 "Extension Manager: failed to write data entry in backend db: " +
418 m_urlDb, nullptr, exc);
422 //Writes only the element if is has a value.
423 //The prefix is automatically added to the element name
424 void BackendDb::writeSimpleElement(
425 std::u16string_view sElementName, OUString const & value,
426 Reference<css::xml::dom::XNode> const & xParent)
430 if (value.isEmpty())
431 return;
432 const OUString sPrefix = getNSPrefix();
433 const Reference<css::xml::dom::XDocument> doc = getDocument();
434 const OUString sNameSpace = getDbNSName();
435 const Reference<css::xml::dom::XNode> dataNode(
436 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName),
437 UNO_QUERY_THROW);
438 xParent->appendChild(dataNode);
440 const Reference<css::xml::dom::XNode> dataValue(
441 doc->createTextNode(value), UNO_QUERY_THROW);
442 dataNode->appendChild(dataValue);
444 catch(const css::uno::Exception &)
446 Any exc( ::cppu::getCaughtException() );
447 throw css::deployment::DeploymentException(
448 "Extension Manager: failed to write data entry(writeSimpleElement) in backend db: " +
449 m_urlDb, nullptr, exc);
454 /// The key elements have a url attribute and are always children of the root element.
455 Reference<css::xml::dom::XNode> BackendDb::writeKeyElement(
456 OUString const & url)
460 const OUString sNameSpace = getDbNSName();
461 const OUString sPrefix = getNSPrefix();
462 const OUString sElementName = getKeyElementName();
463 const Reference<css::xml::dom::XDocument> doc = getDocument();
464 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
466 //Check if there are an entry with the same url. This can be the case if the
467 //status of an XPackage is ambiguous. In this case a call to activateExtension
468 //(dp_extensionmanager.cxx), will register the package again. See also
469 //Package::processPackage_impl in dp_backend.cxx.
470 //A package can become
471 //invalid after its successful registration, for example if a second extension with
472 //the same service is installed.
473 const OUString sExpression(
474 sPrefix + ":" + sElementName + "[@url = \"" + url + "\"]");
475 const Reference<css::xml::dom::XNode> existingNode =
476 getXPathAPI()->selectSingleNode(root, sExpression);
477 if (existingNode.is())
479 OSL_ASSERT(false);
480 //replace the existing entry.
481 removeEntry(url);
484 const Reference<css::xml::dom::XElement> keyElement(
485 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName));
487 keyElement->setAttribute("url", url);
489 const Reference<css::xml::dom::XNode> keyNode(
490 keyElement, UNO_QUERY_THROW);
491 root->appendChild(keyNode);
492 return keyNode;
494 catch(const css::uno::Exception &)
496 Any exc( ::cppu::getCaughtException() );
497 throw css::deployment::DeploymentException(
498 "Extension Manager: failed to write key element in backend db: " +
499 m_urlDb, nullptr, exc);
503 OUString BackendDb::readSimpleElement(
504 std::u16string_view sElementName, Reference<css::xml::dom::XNode> const & xParent)
508 const OUString sPrefix = getNSPrefix();
509 const OUString sExpr(sPrefix + ":" + sElementName + "/text()");
510 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
511 const Reference<css::xml::dom::XNode> val =
512 xpathApi->selectSingleNode(xParent, sExpr);
513 if (val.is())
514 return val->getNodeValue();
515 return OUString();
517 catch(const css::uno::Exception &)
519 Any exc( ::cppu::getCaughtException() );
520 throw css::deployment::DeploymentException(
521 "Extension Manager: failed to read data (readSimpleElement) in backend db: " +
522 m_urlDb, nullptr, exc);
527 std::deque< OUString> BackendDb::readList(
528 Reference<css::xml::dom::XNode> const & parent,
529 std::u16string_view sListTagName,
530 std::u16string_view sMemberTagName)
534 OSL_ASSERT(parent.is());
535 const OUString sPrefix(getNSPrefix() + ":");
536 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
537 const OUString sExprList(
538 sPrefix + sListTagName + "/" + sPrefix + sMemberTagName + "/text()");
539 const Reference<css::xml::dom::XNodeList> list =
540 xpathApi->selectNodeList(parent, sExprList);
542 std::deque<OUString > retList;
543 sal_Int32 length = list->getLength();
544 for (sal_Int32 i = 0; i < length; i++)
546 const Reference<css::xml::dom::XNode> member = list->item(i);
547 retList.push_back(member->getNodeValue());
549 return retList;
551 catch(const css::uno::Exception &)
553 Any exc( ::cppu::getCaughtException() );
554 throw css::deployment::DeploymentException(
555 "Extension Manager: failed to read data entry in backend db: " +
556 m_urlDb, nullptr, exc);
560 std::vector<OUString> BackendDb::getOneChildFromAllEntries(
561 std::u16string_view name)
565 std::vector<OUString> listRet;
566 Reference<css::xml::dom::XDocument> doc = getDocument();
567 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
569 Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
570 const OUString sPrefix = getNSPrefix();
571 const OUString sKeyElement = getKeyElementName();
572 OUString sNodeSelectExpr =
573 sPrefix +
574 ":" +
575 sKeyElement +
576 "/" +
577 sPrefix +
578 ":" +
579 name +
580 "/text()";
582 Reference<css::xml::dom::XNodeList> nodes =
583 xpathApi->selectNodeList(root, sNodeSelectExpr);
584 if (nodes.is())
586 sal_Int32 length = nodes->getLength();
587 for (sal_Int32 i = 0; i < length; i++)
588 listRet.push_back(nodes->item(i)->getNodeValue());
590 return listRet;
592 catch ( const css::deployment::DeploymentException& )
594 throw;
596 catch(const css::uno::Exception &)
598 Any exc( ::cppu::getCaughtException() );
599 throw css::deployment::DeploymentException(
600 "Extension Manager: failed to read data entry in backend db: " +
601 m_urlDb, nullptr, exc);
606 RegisteredDb::RegisteredDb(
607 Reference<XComponentContext> const & xContext,
608 OUString const & url):BackendDb(xContext, url)
612 void RegisteredDb::addEntry(OUString const & url)
614 try{
615 if (!activateEntry(url))
617 const OUString sNameSpace = getDbNSName();
618 const OUString sPrefix = getNSPrefix();
619 const OUString sEntry = getKeyElementName();
621 Reference<css::xml::dom::XDocument> doc = getDocument();
622 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
624 #if OSL_DEBUG_LEVEL > 0
625 //There must not be yet an entry with the same url
626 OUString sExpression(
627 sPrefix + ":" + sEntry + "[@url = \"" + url + "\"]");
628 Reference<css::xml::dom::XNode> _extensionNode =
629 getXPathAPI()->selectSingleNode(root, sExpression);
630 OSL_ASSERT(! _extensionNode.is());
631 #endif
632 Reference<css::xml::dom::XElement> helpElement(
633 doc->createElementNS(sNameSpace, sPrefix + ":" + sEntry));
635 helpElement->setAttribute("url", url);
637 Reference<css::xml::dom::XNode> helpNode(
638 helpElement, UNO_QUERY_THROW);
639 root->appendChild(helpNode);
641 save();
644 catch(const css::uno::Exception &)
646 Any exc( ::cppu::getCaughtException() );
647 throw css::deployment::DeploymentException(
648 "Extension Manager: failed to write data entry in backend db: " +
649 m_urlDb, nullptr, exc);
653 } // namespace dp_registry
655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */