bump product version to 4.1.6.2
[LibreOffice.git] / desktop / source / deployment / registry / dp_backenddb.cxx
blob927c47dc807020e822844b9cc4945d313cd6c92e
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/uno/XComponentContext.hpp"
27 #include "com/sun/star/xml/dom/DocumentBuilder.hpp"
28 #include "com/sun/star/xml/xpath/XPathAPI.hpp"
29 #include "com/sun/star/io/XActiveDataSource.hpp"
30 #include "com/sun/star/io/XActiveDataControl.hpp"
31 #include "dp_ucb.h"
32 #include "dp_misc.h"
33 #include "ucbhelper/content.hxx"
34 #include "xmlscript/xml_helper.hxx"
35 #include "dp_backenddb.hxx"
38 using namespace ::com::sun::star::uno;
41 namespace dp_registry {
42 namespace backend {
44 BackendDb::BackendDb(
45 Reference<css::uno::XComponentContext> const & xContext,
46 OUString const & url):
47 m_xContext(xContext)
49 m_urlDb = dp_misc::expandUnoRcUrl(url);
52 void BackendDb::save()
54 const Reference<css::io::XActiveDataSource> xDataSource(m_doc,css::uno::UNO_QUERY_THROW);
55 ::rtl::ByteSequence bytes;
56 xDataSource->setOutputStream(::xmlscript::createOutputStream(&bytes));
57 const Reference<css::io::XActiveDataControl> xDataControl(m_doc,css::uno::UNO_QUERY_THROW);
58 xDataControl->start();
60 const Reference<css::io::XInputStream> xData(
61 ::xmlscript::createInputStream(bytes));
62 ::ucbhelper::Content ucbDb(m_urlDb, 0, m_xContext);
63 ucbDb.writeStream(xData, true /*replace existing*/);
66 css::uno::Reference<css::xml::dom::XDocument> BackendDb::getDocument()
68 if (!m_doc.is())
70 const Reference<css::xml::dom::XDocumentBuilder> xDocBuilder(
71 css::xml::dom::DocumentBuilder::create(m_xContext) );
73 ::osl::DirectoryItem item;
74 ::osl::File::RC err = ::osl::DirectoryItem::get(m_urlDb, item);
75 if (err == ::osl::File::E_None)
77 ::ucbhelper::Content descContent(
78 m_urlDb, css::uno::Reference<css::ucb::XCommandEnvironment>(),
79 m_xContext);
80 Reference<css::io::XInputStream> xIn = descContent.openStream();
81 m_doc = xDocBuilder->parse(xIn);
83 else if (err == ::osl::File::E_NOENT)
85 //Create a new document and insert some basic stuff
86 m_doc = xDocBuilder->newDocument();
87 const Reference<css::xml::dom::XElement> rootNode =
88 m_doc->createElementNS(getDbNSName(), getNSPrefix() +
89 ":" + getRootElementName());
91 m_doc->appendChild(Reference<css::xml::dom::XNode>(
92 rootNode, UNO_QUERY_THROW));
93 save();
95 else
96 throw css::uno::RuntimeException(
97 "Extension manager could not access database file:"
98 + m_urlDb, 0);
100 if (!m_doc.is())
101 throw css::uno::RuntimeException(
102 "Extension manager could not get root node of data base file: "
103 + m_urlDb, 0);
106 return m_doc;
109 Reference<css::xml::xpath::XXPathAPI> BackendDb::getXPathAPI()
111 if (!m_xpathApi.is())
113 m_xpathApi = css::xml::xpath::XPathAPI::create( m_xContext );
115 m_xpathApi->registerNS( getNSPrefix(), getDbNSName() );
118 return m_xpathApi;
121 void BackendDb::removeElement(OUString const & sXPathExpression)
125 const Reference<css::xml::dom::XDocument> doc = getDocument();
126 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
127 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
128 //find the extension element that is to be removed
129 const Reference<css::xml::dom::XNode> aNode =
130 xpathApi->selectSingleNode(root, sXPathExpression);
132 if (aNode.is())
134 root->removeChild(aNode);
135 save();
138 #if OSL_DEBUG_LEVEL > 0
139 //There must not be any other entry with the same url
140 const Reference<css::xml::dom::XNode> nextNode =
141 xpathApi->selectSingleNode(root, sXPathExpression);
142 OSL_ASSERT(! nextNode.is());
143 #endif
145 catch(const css::uno::Exception &)
147 Any exc( ::cppu::getCaughtException() );
148 throw css::deployment::DeploymentException(
149 "Extension Manager: failed to write data entry in backend db: " +
150 m_urlDb, 0, exc);
154 void BackendDb::removeEntry(OUString const & url)
156 const OUString sKeyElement = getKeyElementName();
157 const OUString sPrefix = getNSPrefix();
158 OUStringBuffer sExpression(500);
159 sExpression.append(sPrefix);
160 sExpression.appendAscii(":");
161 sExpression.append(sKeyElement);
162 sExpression.append("[@url = \"");
163 sExpression.append(url);
164 sExpression.appendAscii("\"]");
166 removeElement(sExpression.makeStringAndClear());
169 void BackendDb::revokeEntry(OUString const & url)
173 Reference<css::xml::dom::XElement> entry = Reference<css::xml::dom::XElement>(getKeyElement(url), UNO_QUERY);
174 if (entry.is())
176 entry->setAttribute("revoked", "true");
177 save();
180 catch(const css::uno::Exception &)
182 Any exc( ::cppu::getCaughtException() );
183 throw css::deployment::DeploymentException(
184 "Extension Manager: failed to revoke data entry in backend db: " +
185 m_urlDb, 0, exc);
189 bool BackendDb::activateEntry(OUString const & url)
193 bool ret = false;
194 Reference<css::xml::dom::XElement> entry = Reference<css::xml::dom::XElement>(getKeyElement(url), UNO_QUERY);
195 if (entry.is())
197 //no attribute "active" means it is active, that is, registered.
198 entry->removeAttribute("revoked");
199 save();
200 ret = true;
202 return ret;
204 catch(const css::uno::Exception &)
206 Any exc( ::cppu::getCaughtException() );
207 throw css::deployment::DeploymentException(
208 "Extension Manager: failed to revoke data entry in backend db: " +
209 m_urlDb, 0, exc);
213 bool BackendDb::hasActiveEntry(OUString const & url)
217 bool ret = false;
218 Reference<css::xml::dom::XElement> entry = Reference<css::xml::dom::XElement>(getKeyElement(url), UNO_QUERY);
219 if (entry.is())
221 OUString sActive = entry->getAttribute("revoked");
222 if (!(sActive == "true"))
223 ret = true;
225 return ret;
228 catch(const css::uno::Exception &)
230 Any exc( ::cppu::getCaughtException() );
231 throw css::deployment::DeploymentException(
232 "Extension Manager: failed to determine an active entry in backend db: " +
233 m_urlDb, 0, exc);
237 Reference<css::xml::dom::XNode> BackendDb::getKeyElement(
238 OUString const & url)
242 const OUString sPrefix = getNSPrefix();
243 const OUString sKeyElement = getKeyElementName();
244 OUStringBuffer sExpression(500);
245 sExpression.append(sPrefix);
246 sExpression.appendAscii(":");
247 sExpression.append(sKeyElement);
248 sExpression.append("[@url = \"");
249 sExpression.append(url);
250 sExpression.appendAscii("\"]");
252 const Reference<css::xml::dom::XDocument> doc = getDocument();
253 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
254 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
255 return xpathApi->selectSingleNode(root, sExpression.makeStringAndClear());
257 catch(const css::uno::Exception &)
259 Any exc( ::cppu::getCaughtException() );
260 throw css::deployment::DeploymentException(
261 "Extension Manager: failed to read key element in backend db: " +
262 m_urlDb, 0, exc);
266 //Only writes the data if there is at least one entry
267 void BackendDb::writeVectorOfPair(
268 ::std::vector< ::std::pair< OUString, OUString > > const & vecPairs,
269 OUString const & sVectorTagName,
270 OUString const & sPairTagName,
271 OUString const & sFirstTagName,
272 OUString const & sSecondTagName,
273 css::uno::Reference<css::xml::dom::XNode> const & xParent)
275 try{
276 if (vecPairs.empty())
277 return;
278 const OUString sNameSpace = getDbNSName();
279 OSL_ASSERT(!sNameSpace.isEmpty());
280 const OUString sPrefix(getNSPrefix() + ":");
281 const Reference<css::xml::dom::XDocument> doc = getDocument();
282 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
284 const Reference<css::xml::dom::XElement> vectorNode(
285 doc->createElementNS(sNameSpace, sPrefix + sVectorTagName));
287 xParent->appendChild(
288 Reference<css::xml::dom::XNode>(
289 vectorNode, css::uno::UNO_QUERY_THROW));
290 typedef ::std::vector< ::std::pair< OUString, OUString > >::const_iterator CIT;
291 for (CIT i = vecPairs.begin(); i != vecPairs.end(); ++i)
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( i->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( i->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, 0, 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.push_back(::std::make_pair(
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, 0, exc);
384 //Only writes the data if there is at least one entry
385 void BackendDb::writeSimpleList(
386 ::std::list< 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 typedef ::std::list<OUString>::const_iterator ITC_ITEMS;
407 for (ITC_ITEMS i = list.begin(); i != list.end(); ++i)
409 const Reference<css::xml::dom::XNode> memberNode(
410 doc->createElementNS(sNameSpace, sPrefix + sMemberTagName), css::uno::UNO_QUERY_THROW);
412 listNode->appendChild(memberNode);
414 const Reference<css::xml::dom::XNode> textNode(
415 doc->createTextNode( *i), css::uno::UNO_QUERY_THROW);
417 memberNode->appendChild(textNode);
420 catch(const css::uno::Exception &)
422 Any exc( ::cppu::getCaughtException() );
423 throw css::deployment::DeploymentException(
424 "Extension Manager: failed to write data entry in backend db: " +
425 m_urlDb, 0, exc);
429 //Writes only the element if is has a value.
430 //The prefix is automatically added to the element name
431 void BackendDb::writeSimpleElement(
432 OUString const & sElementName, OUString const & value,
433 Reference<css::xml::dom::XNode> const & xParent)
437 if (value.isEmpty())
438 return;
439 const OUString sPrefix = getNSPrefix();
440 const Reference<css::xml::dom::XDocument> doc = getDocument();
441 const OUString sNameSpace = getDbNSName();
442 const Reference<css::xml::dom::XNode> dataNode(
443 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName),
444 UNO_QUERY_THROW);
445 xParent->appendChild(dataNode);
447 const Reference<css::xml::dom::XNode> dataValue(
448 doc->createTextNode(value), UNO_QUERY_THROW);
449 dataNode->appendChild(dataValue);
451 catch(const css::uno::Exception &)
453 Any exc( ::cppu::getCaughtException() );
454 throw css::deployment::DeploymentException(
455 "Extension Manager: failed to write data entry(writeSimpleElement) in backend db: " +
456 m_urlDb, 0, exc);
461 /** The key elements have an url attribute and are always children of the root
462 element.
464 Reference<css::xml::dom::XNode> BackendDb::writeKeyElement(
465 OUString const & url)
469 const OUString sNameSpace = getDbNSName();
470 const OUString sPrefix = getNSPrefix();
471 const OUString sElementName = getKeyElementName();
472 const Reference<css::xml::dom::XDocument> doc = getDocument();
473 const Reference<css::xml::dom::XNode> root = doc->getFirstChild();
475 //Check if there are an entry with the same url. This can be the case if the
476 //the status of an XPackage is ambiguous. In this case a call to activateExtension
477 //(dp_extensionmanager.cxx), will register the package again. See also
478 //Package::processPackage_impl in dp_backend.cxx.
479 //A package can become
480 //invalid after its successful registration, for example if a second extension with
481 //the same service is installed.
482 const OUString sExpression(
483 sPrefix + ":" + sElementName + "[@url = \"" + url + "\"]");
484 const Reference<css::xml::dom::XNode> existingNode =
485 getXPathAPI()->selectSingleNode(root, sExpression);
486 if (existingNode.is())
488 OSL_ASSERT(0);
489 //replace the existing entry.
490 removeEntry(url);
493 const Reference<css::xml::dom::XElement> keyElement(
494 doc->createElementNS(sNameSpace, sPrefix + ":" + sElementName));
496 keyElement->setAttribute("url", url);
498 const Reference<css::xml::dom::XNode> keyNode(
499 keyElement, UNO_QUERY_THROW);
500 root->appendChild(keyNode);
501 return keyNode;
503 catch(const css::uno::Exception &)
505 Any exc( ::cppu::getCaughtException() );
506 throw css::deployment::DeploymentException(
507 "Extension Manager: failed to write key element in backend db: " +
508 m_urlDb, 0, exc);
512 OUString BackendDb::readSimpleElement(
513 OUString const & sElementName, Reference<css::xml::dom::XNode> const & xParent)
517 const OUString sPrefix = getNSPrefix();
518 const OUString sExpr(sPrefix + ":" + sElementName + "/text()");
519 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
520 const Reference<css::xml::dom::XNode> val =
521 xpathApi->selectSingleNode(xParent, sExpr);
522 if (val.is())
523 return val->getNodeValue();
524 return OUString();
526 catch(const css::uno::Exception &)
528 Any exc( ::cppu::getCaughtException() );
529 throw css::deployment::DeploymentException(
530 "Extension Manager: failed to read data (readSimpleElement) in backend db: " +
531 m_urlDb, 0, exc);
536 ::std::list< OUString> BackendDb::readList(
537 Reference<css::xml::dom::XNode> const & parent,
538 OUString const & sListTagName,
539 OUString const & sMemberTagName)
543 OSL_ASSERT(parent.is());
544 const OUString sPrefix(getNSPrefix() + ":");
545 const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
546 const OUString sExprList(
547 sPrefix + sListTagName + "/" + sPrefix + sMemberTagName + "/text()");
548 const Reference<css::xml::dom::XNodeList> list =
549 xpathApi->selectNodeList(parent, sExprList);
551 ::std::list<OUString > retList;
552 sal_Int32 length = list->getLength();
553 for (sal_Int32 i = 0; i < length; i++)
555 const Reference<css::xml::dom::XNode> member = list->item(i);
556 retList.push_back(member->getNodeValue());
558 return retList;
560 catch(const css::uno::Exception &)
562 Any exc( ::cppu::getCaughtException() );
563 throw css::deployment::DeploymentException(
564 "Extension Manager: failed to read data entry in backend db: " +
565 m_urlDb, 0, exc);
569 ::std::list<OUString> BackendDb::getOneChildFromAllEntries(
570 OUString const & name)
574 ::std::list<OUString> listRet;
575 Reference<css::xml::dom::XDocument> doc = getDocument();
576 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
578 Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
579 const OUString sPrefix = getNSPrefix();
580 const OUString sKeyElement = getKeyElementName();
581 OUStringBuffer buf(512);
582 buf.append(sPrefix);
583 buf.appendAscii(":");
584 buf.append(sKeyElement);
585 buf.appendAscii("/");
586 buf.append(sPrefix);
587 buf.appendAscii(":");
588 buf.append(name);
589 buf.append("/text()");
591 Reference<css::xml::dom::XNodeList> nodes =
592 xpathApi->selectNodeList(root, buf.makeStringAndClear());
593 if (nodes.is())
595 sal_Int32 length = nodes->getLength();
596 for (sal_Int32 i = 0; i < length; i++)
597 listRet.push_back(nodes->item(i)->getNodeValue());
599 return listRet;
601 catch ( const css::deployment::DeploymentException& )
603 throw;
605 catch(const css::uno::Exception &)
607 Any exc( ::cppu::getCaughtException() );
608 throw css::deployment::DeploymentException(
609 "Extension Manager: failed to read data entry in backend db: " +
610 m_urlDb, 0, exc);
615 RegisteredDb::RegisteredDb(
616 Reference<XComponentContext> const & xContext,
617 OUString const & url):BackendDb(xContext, url)
621 void RegisteredDb::addEntry(OUString const & url)
623 try{
624 if (!activateEntry(url))
626 const OUString sNameSpace = getDbNSName();
627 const OUString sPrefix = getNSPrefix();
628 const OUString sEntry = getKeyElementName();
630 Reference<css::xml::dom::XDocument> doc = getDocument();
631 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
633 #if OSL_DEBUG_LEVEL > 0
634 //There must not be yet an entry with the same url
635 OUString sExpression(
636 sPrefix + ":" + sEntry + "[@url = \"" + url + "\"]");
637 Reference<css::xml::dom::XNode> _extensionNode =
638 getXPathAPI()->selectSingleNode(root, sExpression);
639 OSL_ASSERT(! _extensionNode.is());
640 #endif
641 Reference<css::xml::dom::XElement> helpElement(
642 doc->createElementNS(sNameSpace, sPrefix + ":" + sEntry));
644 helpElement->setAttribute("url", url);
646 Reference<css::xml::dom::XNode> helpNode(
647 helpElement, UNO_QUERY_THROW);
648 root->appendChild(helpNode);
650 save();
653 catch(const css::uno::Exception &)
655 Any exc( ::cppu::getCaughtException() );
656 throw css::deployment::DeploymentException(
657 "Extension Manager: failed to write data entry in backend db: " +
658 m_urlDb, 0, exc);
662 bool RegisteredDb::getEntry(OUString const & url)
666 const OUString sPrefix = getNSPrefix();
667 const OUString sEntry = getKeyElementName();
668 const OUString sExpression(
669 sPrefix + ":" + sEntry + "[@url = \"" + url + "\"]");
670 Reference<css::xml::dom::XDocument> doc = getDocument();
671 Reference<css::xml::dom::XNode> root = doc->getFirstChild();
673 Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI();
674 Reference<css::xml::dom::XNode> aNode =
675 xpathApi->selectSingleNode(root, sExpression);
677 return aNode.is();
679 catch(const css::uno::Exception &)
681 Any exc( ::cppu::getCaughtException() );
682 throw css::deployment::DeploymentException(
683 "Extension Manager: failed to read data entry in backend db: " +
684 m_urlDb, 0, exc);
688 } // namespace backend
689 } // namespace dp_registry
691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */