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/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"
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
{
45 Reference
<css::uno::XComponentContext
> const & xContext
,
46 OUString
const & url
):
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()
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
>(),
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
));
96 throw css::uno::RuntimeException(
97 "Extension manager could not access database file:"
101 throw css::uno::RuntimeException(
102 "Extension manager could not get root node of data base file: "
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() );
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
);
134 root
->removeChild(aNode
);
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());
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: " +
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
);
176 entry
->setAttribute("revoked", "true");
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: " +
189 bool BackendDb::activateEntry(OUString
const & url
)
194 Reference
<css::xml::dom::XElement
> entry
= Reference
<css::xml::dom::XElement
>(getKeyElement(url
), UNO_QUERY
);
197 //no attribute "active" means it is active, that is, registered.
198 entry
->removeAttribute("revoked");
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: " +
213 bool BackendDb::hasActiveEntry(OUString
const & url
)
218 Reference
<css::xml::dom::XElement
> entry
= Reference
<css::xml::dom::XElement
>(getKeyElement(url
), UNO_QUERY
);
221 OUString sActive
= entry
->getAttribute("revoked");
222 if (!(sActive
== "true"))
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: " +
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: " +
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
)
276 if (vecPairs
.empty())
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: " +
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()));
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: " +
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
)
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: " +
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
)
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
),
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: " +
461 /** The key elements have an url attribute and are always children of the root
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())
489 //replace the existing entry.
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
);
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: " +
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
);
523 return val
->getNodeValue();
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: " +
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());
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: " +
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);
583 buf
.appendAscii(":");
584 buf
.append(sKeyElement
);
585 buf
.appendAscii("/");
587 buf
.appendAscii(":");
589 buf
.append("/text()");
591 Reference
<css::xml::dom::XNodeList
> nodes
=
592 xpathApi
->selectNodeList(root
, buf
.makeStringAndClear());
595 sal_Int32 length
= nodes
->getLength();
596 for (sal_Int32 i
= 0; i
< length
; i
++)
597 listRet
.push_back(nodes
->item(i
)->getNodeValue());
601 catch ( const css::deployment::DeploymentException
& )
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: " +
615 RegisteredDb::RegisteredDb(
616 Reference
<XComponentContext
> const & xContext
,
617 OUString
const & url
):BackendDb(xContext
, url
)
621 void RegisteredDb::addEntry(OUString
const & url
)
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());
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
);
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: " +
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
);
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: " +
688 } // namespace backend
689 } // namespace dp_registry
691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */