tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / desktop / source / deployment / registry / dp_backenddb.cxx
blob5b9d35d28dce38308830518f38f13b3bbbc2079e
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/diagnose.h>
23 #include <osl/file.hxx>
24 #include <com/sun/star/deployment/DeploymentException.hpp>
25 #include <com/sun/star/uno/XComponentContext.hpp>
26 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
27 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
28 #include <com/sun/star/io/XActiveDataSource.hpp>
29 #include <com/sun/star/io/XActiveDataControl.hpp>
30 #include <dp_misc.h>
31 #include <ucbhelper/content.hxx>
32 #include <xmlscript/xml_helper.hxx>
33 #include <dp_backenddb.hxx>
36 using namespace ::com::sun::star::uno;
39 namespace dp_registry::backend {
41 BackendDb::BackendDb(
42 Reference<css::uno::XComponentContext> const & xContext,
43 OUString const & url):
44 m_xContext(xContext)
46 m_urlDb = dp_misc::expandUnoRcUrl(url);
49 void BackendDb::save()
51 const Reference<css::io::XActiveDataSource> xDataSource(m_doc,css::uno::UNO_QUERY_THROW);
52 std::vector<sal_Int8> bytes;
53 xDataSource->setOutputStream(::xmlscript::createOutputStream(&bytes));
54 const Reference<css::io::XActiveDataControl> xDataControl(m_doc,css::uno::UNO_QUERY_THROW);
55 xDataControl->start();
57 const Reference<css::io::XInputStream> xData(
58 ::xmlscript::createInputStream(std::move(bytes)));
59 ::ucbhelper::Content ucbDb(m_urlDb, nullptr, m_xContext);
60 ucbDb.writeStream(xData, true /*replace existing*/);
63 css::uno::Reference<css::xml::dom::XDocument> const & BackendDb::getDocument()
65 if (!m_doc.is())
67 const Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
68 css::xml::dom::DocumentBuilder::create(m_xContext) );
70 ::osl::DirectoryItem item;
71 ::osl::File::RC err = ::osl::DirectoryItem::get(m_urlDb, item);
72 if (err == ::osl::File::E_None)
74 ::ucbhelper::Content descContent(
75 m_urlDb, css::uno::Reference<css::ucb::XCommandEnvironment>(),
76 m_xContext);
77 Reference<css::io::XInputStream> xIn = descContent.openStream();
78 m_doc = xDocBuilder->parse(xIn);
80 else if (err == ::osl::File::E_NOENT)
82 //Create a new document and insert some basic stuff
83 m_doc = xDocBuilder->newDocument();
84 const Reference<css::xml::dom::XElement> rootNode =
85 m_doc->createElementNS(getDbNSName(), getNSPrefix() +
86 ":" + getRootElementName());
88 m_doc->appendChild(Reference<css::xml::dom::XNode>(
89 rootNode, UNO_QUERY_THROW));
90 save();
92 else
93 throw css::uno::RuntimeException(
94 "Extension manager could not access database file:"
95 + m_urlDb, nullptr);
97 if (!m_doc.is())
98 throw css::uno::RuntimeException(
99 "Extension manager could not get root node of data base file: "
100 + m_urlDb, nullptr);
103 return m_doc;
106 Reference<css::xml::xpath::XXPathAPI> const & BackendDb::getXPathAPI()
108 if (!m_xpathApi.is())
110 m_xpathApi = css::xml::xpath::XPathAPI::create( m_xContext );
112 m_xpathApi->registerNS( getNSPrefix(), getDbNSName() );
115 return m_xpathApi;
118 void BackendDb::removeElement(OUString const & sXPathExpression)
122 const Reference<css::xml::dom::XDocument> doc = getDocument();
123 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
124 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
125 //find the extension element that is to be removed
126 const Reference<css::xml::dom::XNode> aNode =
127 xpathApi->selectSingleNode(root, sXPathExpression);
129 if (aNode.is())
131 root->removeChild(aNode);
132 save();
135 #if OSL_DEBUG_LEVEL > 0
136 //There must not be any other entry with the same url
137 const Reference<css::xml::dom::XNode> nextNode =
138 xpathApi->selectSingleNode(root, sXPathExpression);
139 OSL_ASSERT(! nextNode.is());
140 #endif
142 catch(const css::uno::Exception &)
144 Any exc( ::cppu::getCaughtException() );
145 throw css::deployment::DeploymentException(
146 "Extension Manager: failed to write data entry in backend db: " +
147 m_urlDb, nullptr, exc);
151 void BackendDb::removeEntry(std::u16string_view url)
153 const OUString sKeyElement = getKeyElementName();
154 const OUString sPrefix = getNSPrefix();
155 OUString sExpression =
156 sPrefix +
157 ":" +
158 sKeyElement +
159 "[@url = \"" +
160 url +
161 "\"]";
163 removeElement(sExpression);
166 void BackendDb::revokeEntry(std::u16string_view url)
170 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
171 if (entry.is())
173 entry->setAttribute(u"revoked"_ustr, u"true"_ustr);
174 save();
177 catch(const css::uno::Exception &)
179 Any exc( ::cppu::getCaughtException() );
180 throw css::deployment::DeploymentException(
181 "Extension Manager: failed to revoke data entry in backend db: " +
182 m_urlDb, nullptr, exc);
186 bool BackendDb::activateEntry(std::u16string_view url)
190 bool ret = false;
191 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
192 if (entry.is())
194 //no attribute "active" means it is active, that is, registered.
195 entry->removeAttribute(u"revoked"_ustr);
196 save();
197 ret = true;
199 return ret;
201 catch(const css::uno::Exception &)
203 Any exc( ::cppu::getCaughtException() );
204 throw css::deployment::DeploymentException(
205 "Extension Manager: failed to revoke data entry in backend db: " +
206 m_urlDb, nullptr, exc);
210 bool BackendDb::hasActiveEntry(std::u16string_view url)
214 bool ret = false;
215 Reference<css::xml::dom::XElement> entry(getKeyElement(url), UNO_QUERY);
216 if (entry.is())
218 OUString sActive = entry->getAttribute(u"revoked"_ustr);
219 if (!(sActive == "true"))
220 ret = true;
222 return ret;
225 catch(const css::uno::Exception &)
227 Any exc( ::cppu::getCaughtException() );
228 throw css::deployment::DeploymentException(
229 "Extension Manager: failed to determine an active entry in backend db: " +
230 m_urlDb, nullptr, exc);
234 Reference<css::xml::dom::XNode> BackendDb::getKeyElement(
235 std::u16string_view url)
239 const OUString sPrefix = getNSPrefix();
240 const OUString sKeyElement = getKeyElementName();
241 OUString sExpression =
242 sPrefix +
243 ":" +
244 sKeyElement +
245 "[@url = \"" +
246 url +
247 "\"]";
249 const Reference<css::xml::dom::XDocument> doc = getDocument();
250 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
251 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
252 return xpathApi->selectSingleNode(root, sExpression);
254 catch(const css::uno::Exception &)
256 Any exc( ::cppu::getCaughtException() );
257 throw css::deployment::DeploymentException(
258 "Extension Manager: failed to read key element in backend db: " +
259 m_urlDb, nullptr, exc);
263 //Only writes the data if there is at least one entry
264 void BackendDb::writeVectorOfPair(
265 std::vector< std::pair< OUString, OUString > > const & vecPairs,
266 std::u16string_view sVectorTagName,
267 std::u16string_view sPairTagName,
268 std::u16string_view sFirstTagName,
269 std::u16string_view sSecondTagName,
270 css::uno::Reference<css::xml::dom::XNode> const & xParent)
272 try{
273 if (vecPairs.empty())
274 return;
275 const OUString sNameSpace = getDbNSName();
276 OSL_ASSERT(!sNameSpace.isEmpty());
277 const OUString sPrefix(getNSPrefix() + ":");
278 const Reference<css::xml::dom::XDocument> doc = getDocument();
280 const Reference<css::xml::dom::XElement> vectorNode(
281 doc->createElementNS(sNameSpace, sPrefix + sVectorTagName));
283 xParent->appendChild(
284 Reference<css::xml::dom::XNode>(
285 vectorNode, css::uno::UNO_QUERY_THROW));
286 for (auto const& vecPair : vecPairs)
288 const Reference<css::xml::dom::XElement> pairNode(
289 doc->createElementNS(sNameSpace, sPrefix + sPairTagName));
291 vectorNode->appendChild(
292 Reference<css::xml::dom::XNode>(
293 pairNode, css::uno::UNO_QUERY_THROW));
295 const Reference<css::xml::dom::XElement> firstNode(
296 doc->createElementNS(sNameSpace, sPrefix + sFirstTagName));
298 pairNode->appendChild(
299 Reference<css::xml::dom::XNode>(
300 firstNode, css::uno::UNO_QUERY_THROW));
302 const Reference<css::xml::dom::XText> firstTextNode(
303 doc->createTextNode( vecPair.first));
305 firstNode->appendChild(
306 Reference<css::xml::dom::XNode>(
307 firstTextNode, css::uno::UNO_QUERY_THROW));
309 const Reference<css::xml::dom::XElement> secondNode(
310 doc->createElementNS(sNameSpace, sPrefix + sSecondTagName));
312 pairNode->appendChild(
313 Reference<css::xml::dom::XNode>(
314 secondNode, css::uno::UNO_QUERY_THROW));
316 const Reference<css::xml::dom::XText> secondTextNode(
317 doc->createTextNode( vecPair.second));
319 secondNode->appendChild(
320 Reference<css::xml::dom::XNode>(
321 secondTextNode, css::uno::UNO_QUERY_THROW));
324 catch(const css::uno::Exception &)
326 Any exc( ::cppu::getCaughtException() );
327 throw css::deployment::DeploymentException(
328 "Extension Manager: failed to write data entry in backend db: " +
329 m_urlDb, nullptr, exc);
333 std::vector< std::pair< OUString, OUString > >
334 BackendDb::readVectorOfPair(
335 Reference<css::xml::dom::XNode> const & parent,
336 std::u16string_view sListTagName,
337 std::u16string_view sPairTagName,
338 std::u16string_view sFirstTagName,
339 std::u16string_view sSecondTagName)
343 OSL_ASSERT(parent.is());
344 const OUString sPrefix(getNSPrefix() + ":");
345 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
346 const OUString sExprPairs(
347 sPrefix + sListTagName + "/" + sPrefix + sPairTagName);
348 const Reference<css::xml::dom::XNodeList> listPairs =
349 xpathApi->selectNodeList(parent, sExprPairs);
351 std::vector< std::pair< OUString, OUString > > retVector;
352 sal_Int32 length = listPairs->getLength();
353 for (sal_Int32 i = 0; i < length; i++)
355 const Reference<css::xml::dom::XNode> aPair = listPairs->item(i);
356 const OUString sExprFirst(sPrefix + sFirstTagName + "/text()");
357 const Reference<css::xml::dom::XNode> first =
358 xpathApi->selectSingleNode(aPair, sExprFirst);
360 const OUString sExprSecond(sPrefix + sSecondTagName + "/text()");
361 const Reference<css::xml::dom::XNode> second =
362 xpathApi->selectSingleNode(aPair, sExprSecond);
363 OSL_ASSERT(first.is() && second.is());
365 retVector.emplace_back(
366 first->getNodeValue(), second->getNodeValue());
368 return retVector;
370 catch(const css::uno::Exception &)
372 Any exc( ::cppu::getCaughtException() );
373 throw css::deployment::DeploymentException(
374 "Extension Manager: failed to read data entry in backend db: " +
375 m_urlDb, nullptr, exc);
379 //Only writes the data if there is at least one entry
380 void BackendDb::writeSimpleList(
381 std::deque< OUString> const & list,
382 std::u16string_view sListTagName,
383 std::u16string_view sMemberTagName,
384 Reference<css::xml::dom::XNode> const & xParent)
388 if (list.empty())
389 return;
390 const OUString sNameSpace = getDbNSName();
391 const OUString sPrefix(getNSPrefix() + ":");
392 const Reference<css::xml::dom::XDocument> doc = getDocument();
394 const Reference<css::xml::dom::XElement> listNode(
395 doc->createElementNS(sNameSpace, sPrefix + sListTagName));
397 xParent->appendChild(
398 Reference<css::xml::dom::XNode>(
399 listNode, css::uno::UNO_QUERY_THROW));
401 for (auto const& elem : list)
403 const Reference<css::xml::dom::XNode> memberNode(
404 doc->createElementNS(sNameSpace, sPrefix + sMemberTagName), css::uno::UNO_QUERY_THROW);
406 listNode->appendChild(memberNode);
408 const Reference<css::xml::dom::XNode> textNode(
409 doc->createTextNode(elem), css::uno::UNO_QUERY_THROW);
411 memberNode->appendChild(textNode);
414 catch(const css::uno::Exception &)
416 Any exc( ::cppu::getCaughtException() );
417 throw css::deployment::DeploymentException(
418 "Extension Manager: failed to write data entry in backend db: " +
419 m_urlDb, nullptr, exc);
423 //Writes only the element if is has a value.
424 //The prefix is automatically added to the element name
425 void BackendDb::writeSimpleElement(
426 std::u16string_view sElementName, OUString const & value,
427 Reference<css::xml::dom::XNode> const & xParent)
431 if (value.isEmpty())
432 return;
433 const OUString sPrefix = getNSPrefix();
434 const Reference<css::xml::dom::XDocument> doc = getDocument();
435 const OUString sNameSpace = getDbNSName();
436 const Reference<css::xml::dom::XNode> dataNode(
437 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName),
438 UNO_QUERY_THROW);
439 xParent->appendChild(dataNode);
441 const Reference<css::xml::dom::XNode> dataValue(
442 doc->createTextNode(value), UNO_QUERY_THROW);
443 dataNode->appendChild(dataValue);
445 catch(const css::uno::Exception &)
447 Any exc( ::cppu::getCaughtException() );
448 throw css::deployment::DeploymentException(
449 "Extension Manager: failed to write data entry(writeSimpleElement) in backend db: " +
450 m_urlDb, nullptr, exc);
455 /// The key elements have a url attribute and are always children of the root element.
456 Reference<css::xml::dom::XNode> BackendDb::writeKeyElement(
457 OUString const & url)
461 const OUString sNameSpace = getDbNSName();
462 const OUString sPrefix = getNSPrefix();
463 const OUString sElementName = getKeyElementName();
464 const Reference<css::xml::dom::XDocument> doc = getDocument();
465 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
467 //Check if there are an entry with the same url. This can be the case if the
468 //status of an XPackage is ambiguous. In this case a call to activateExtension
469 //(dp_extensionmanager.cxx), will register the package again. See also
470 //Package::processPackage_impl in dp_backend.cxx.
471 //A package can become
472 //invalid after its successful registration, for example if a second extension with
473 //the same service is installed.
474 const OUString sExpression(
475 sPrefix + ":" + sElementName + "[@url = \"" + url + "\"]");
476 const Reference<css::xml::dom::XNode> existingNode =
477 getXPathAPI()->selectSingleNode(root, sExpression);
478 if (existingNode.is())
480 OSL_ASSERT(false);
481 //replace the existing entry.
482 removeEntry(url);
485 const Reference<css::xml::dom::XElement> keyElement(
486 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName));
488 keyElement->setAttribute(u"url"_ustr, url);
490 const Reference<css::xml::dom::XNode> keyNode(
491 keyElement, UNO_QUERY_THROW);
492 root->appendChild(keyNode);
493 return keyNode;
495 catch(const css::uno::Exception &)
497 Any exc( ::cppu::getCaughtException() );
498 throw css::deployment::DeploymentException(
499 "Extension Manager: failed to write key element in backend db: " +
500 m_urlDb, nullptr, exc);
504 OUString BackendDb::readSimpleElement(
505 std::u16string_view sElementName, Reference<css::xml::dom::XNode> const & xParent)
509 const OUString sPrefix = getNSPrefix();
510 const OUString sExpr(sPrefix + ":" + sElementName + "/text()");
511 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
512 const Reference<css::xml::dom::XNode> val =
513 xpathApi->selectSingleNode(xParent, sExpr);
514 if (val.is())
515 return val->getNodeValue();
516 return OUString();
518 catch(const css::uno::Exception &)
520 Any exc( ::cppu::getCaughtException() );
521 throw css::deployment::DeploymentException(
522 "Extension Manager: failed to read data (readSimpleElement) in backend db: " +
523 m_urlDb, nullptr, exc);
528 std::deque< OUString> BackendDb::readList(
529 Reference<css::xml::dom::XNode> const & parent,
530 std::u16string_view sListTagName,
531 std::u16string_view sMemberTagName)
535 OSL_ASSERT(parent.is());
536 const OUString sPrefix(getNSPrefix() + ":");
537 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
538 const OUString sExprList(
539 sPrefix + sListTagName + "/" + sPrefix + sMemberTagName + "/text()");
540 const Reference<css::xml::dom::XNodeList> list =
541 xpathApi->selectNodeList(parent, sExprList);
543 std::deque<OUString > retList;
544 sal_Int32 length = list->getLength();
545 for (sal_Int32 i = 0; i < length; i++)
547 const Reference<css::xml::dom::XNode> member = list->item(i);
548 retList.push_back(member->getNodeValue());
550 return retList;
552 catch(const css::uno::Exception &)
554 Any exc( ::cppu::getCaughtException() );
555 throw css::deployment::DeploymentException(
556 "Extension Manager: failed to read data entry in backend db: " +
557 m_urlDb, nullptr, exc);
561 std::vector<OUString> BackendDb::getOneChildFromAllEntries(
562 std::u16string_view name)
566 std::vector<OUString> listRet;
567 Reference<css::xml::dom::XDocument> doc = getDocument();
568 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
570 Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
571 const OUString sPrefix = getNSPrefix();
572 const OUString sKeyElement = getKeyElementName();
573 OUString sNodeSelectExpr =
574 sPrefix +
575 ":" +
576 sKeyElement +
577 "/" +
578 sPrefix +
579 ":" +
580 name +
581 "/text()";
583 Reference<css::xml::dom::XNodeList> nodes =
584 xpathApi->selectNodeList(root, sNodeSelectExpr);
585 if (nodes.is())
587 sal_Int32 length = nodes->getLength();
588 for (sal_Int32 i = 0; i < length; i++)
589 listRet.push_back(nodes->item(i)->getNodeValue());
591 return listRet;
593 catch ( const css::deployment::DeploymentException& )
595 throw;
597 catch(const css::uno::Exception &)
599 Any exc( ::cppu::getCaughtException() );
600 throw css::deployment::DeploymentException(
601 "Extension Manager: failed to read data entry in backend db: " +
602 m_urlDb, nullptr, exc);
607 RegisteredDb::RegisteredDb(
608 Reference<XComponentContext> const & xContext,
609 OUString const & url):BackendDb(xContext, url)
613 void RegisteredDb::addEntry(OUString const & url)
615 try{
616 if (!activateEntry(url))
618 const OUString sNameSpace = getDbNSName();
619 const OUString sPrefix = getNSPrefix();
620 const OUString sEntry = getKeyElementName();
622 Reference<css::xml::dom::XDocument> doc = getDocument();
623 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
625 #if OSL_DEBUG_LEVEL > 0
626 //There must not be yet an entry with the same url
627 OUString sExpression(
628 sPrefix + ":" + sEntry + "[@url = \"" + url + "\"]");
629 Reference<css::xml::dom::XNode> _extensionNode =
630 getXPathAPI()->selectSingleNode(root, sExpression);
631 OSL_ASSERT(! _extensionNode.is());
632 #endif
633 Reference<css::xml::dom::XElement> helpElement(
634 doc->createElementNS(sNameSpace, sPrefix + ":" + sEntry));
636 helpElement->setAttribute(u"url"_ustr, url);
638 Reference<css::xml::dom::XNode> helpNode(
639 helpElement, UNO_QUERY_THROW);
640 root->appendChild(helpNode);
642 save();
645 catch(const css::uno::Exception &)
647 Any exc( ::cppu::getCaughtException() );
648 throw css::deployment::DeploymentException(
649 "Extension Manager: failed to write data entry in backend db: " +
650 m_urlDb, nullptr, exc);
654 } // namespace dp_registry
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */