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 .
20 #include <sal/config.h>
24 #include <dp_backend.h>
26 #include <rtl/ustring.hxx>
27 #include <rtl/uri.hxx>
28 #include <rtl/bootstrap.hxx>
29 #include <sal/log.hxx>
30 #include <osl/file.hxx>
31 #include <cppuhelper/exc_hlp.hxx>
32 #include <comphelper/servicedecl.hxx>
33 #include <comphelper/unwrapargs.hxx>
34 #include <ucbhelper/content.hxx>
35 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
36 #include <com/sun/star/deployment/DeploymentException.hpp>
37 #include <com/sun/star/deployment/ExtensionRemovedException.hpp>
38 #include <com/sun/star/deployment/InvalidRemovedParameterException.hpp>
39 #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
40 #include <com/sun/star/ucb/CommandAbortedException.hpp>
41 #include <com/sun/star/ucb/CommandFailedException.hpp>
42 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
43 #include <com/sun/star/ucb/IOErrorCode.hpp>
44 #include <com/sun/star/beans/StringPair.hpp>
45 #include <com/sun/star/sdbc/XResultSet.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
47 #include <unotools/tempfile.hxx>
50 using namespace ::dp_misc
;
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::ucb
;
55 namespace dp_registry
{
59 PackageRegistryBackend::~PackageRegistryBackend()
64 void PackageRegistryBackend::disposing( lang::EventObject
const & event
)
66 Reference
<deployment::XPackage
> xPackage(
67 event
.Source
, UNO_QUERY_THROW
);
68 OUString
url( xPackage
->getURL() );
69 ::osl::MutexGuard
guard( getMutex() );
70 if ( m_bound
.erase( url
) != 1 )
72 SAL_WARN("desktop.deployment", "erase(" << url
<< ") != 1");
77 PackageRegistryBackend::PackageRegistryBackend(
78 Sequence
<Any
> const & args
,
79 Reference
<XComponentContext
> const & xContext
)
80 : t_BackendBase( getMutex() ),
81 m_xComponentContext( xContext
),
82 m_eContext( Context::Unknown
)
84 assert(xContext
.is());
85 boost::optional
<OUString
> cachePath
;
86 boost::optional
<bool> readOnly
;
87 comphelper::unwrapArgs( args
, m_context
, cachePath
, readOnly
);
89 m_cachePath
= *cachePath
;
91 if ( m_context
== "user" )
92 m_eContext
= Context::User
;
93 else if ( m_context
== "shared" )
94 m_eContext
= Context::Shared
;
95 else if ( m_context
== "bundled" )
96 m_eContext
= Context::Bundled
;
97 else if ( m_context
== "tmp" )
98 m_eContext
= Context::Tmp
;
99 else if (m_context
.matchIgnoreAsciiCase("vnd.sun.star.tdoc:/"))
100 m_eContext
= Context::Document
;
102 m_eContext
= Context::Unknown
;
106 void PackageRegistryBackend::check()
108 ::osl::MutexGuard
guard( getMutex() );
109 if (rBHelper
.bInDispose
|| rBHelper
.bDisposed
) {
110 throw lang::DisposedException(
111 "PackageRegistryBackend instance has already been disposed!",
112 static_cast<OWeakObject
*>(this) );
117 void PackageRegistryBackend::disposing()
120 for ( t_string2ref::const_iterator i
= m_bound
.begin(); i
!= m_bound
.end(); ++i
)
121 i
->second
->removeEventListener(this);
123 m_xComponentContext
.clear();
124 WeakComponentImplHelperBase::disposing();
126 catch (const RuntimeException
&) {
129 catch (const Exception
&) {
130 Any
exc( ::cppu::getCaughtException() );
131 throw lang::WrappedTargetRuntimeException(
132 "caught unexpected exception while disposing!",
133 static_cast<OWeakObject
*>(this), exc
);
139 Reference
<deployment::XPackage
> PackageRegistryBackend::bindPackage(
140 OUString
const & url
, OUString
const & mediaType
, sal_Bool bRemoved
,
141 OUString
const & identifier
, Reference
<XCommandEnvironment
> const & xCmdEnv
)
143 ::osl::ResettableMutexGuard
guard( getMutex() );
146 t_string2ref::const_iterator
const iFind( m_bound
.find( url
) );
147 if (iFind
!= m_bound
.end())
149 Reference
<deployment::XPackage
> xPackage( iFind
->second
);
152 if (!mediaType
.isEmpty() &&
153 mediaType
!= xPackage
->getPackageType()->getMediaType())
154 throw lang::IllegalArgumentException
155 ("XPackageRegistry::bindPackage: media type does not match",
156 static_cast<OWeakObject
*>(this), 1);
157 if (xPackage
->isRemoved() != bRemoved
)
158 throw deployment::InvalidRemovedParameterException(
159 "XPackageRegistry::bindPackage: bRemoved parameter does not match",
160 static_cast<OWeakObject
*>(this), xPackage
->isRemoved(), xPackage
);
167 Reference
<deployment::XPackage
> xNewPackage
;
169 xNewPackage
= bindPackage_( url
, mediaType
, bRemoved
,
170 identifier
, xCmdEnv
);
172 catch (const RuntimeException
&) {
175 catch (const CommandFailedException
&) {
178 catch (const deployment::DeploymentException
&) {
181 catch (const Exception
&) {
182 Any
exc( ::cppu::getCaughtException() );
183 throw deployment::DeploymentException(
184 "Error binding package: " + url
,
185 static_cast<OWeakObject
*>(this), exc
);
190 std::pair
< t_string2ref::iterator
, bool > insertion(
191 m_bound
.emplace( url
, xNewPackage
) );
192 if (insertion
.second
)
195 Reference
<XInterface
>(insertion
.first
->second
) != xNewPackage
,
196 "desktop.deployment", "mismatch");
199 { // found existing entry
200 Reference
<deployment::XPackage
> xPackage( insertion
.first
->second
);
203 insertion
.first
->second
= xNewPackage
;
207 xNewPackage
->addEventListener( this ); // listen for disposing events
211 OUString
PackageRegistryBackend::createFolder(
212 Reference
<ucb::XCommandEnvironment
> const & xCmdEnv
)
214 const OUString sDataFolder
= makeURL(getCachePath(), OUString());
215 //make sure the folder exist
216 ucbhelper::Content dataContent
;
217 ::dp_misc::create_folder(&dataContent
, sDataFolder
, xCmdEnv
);
219 const OUString
baseDir(sDataFolder
);
220 ::utl::TempFile
aTemp(&baseDir
, true);
221 const OUString url
= aTemp
.GetURL();
222 return sDataFolder
+ url
.copy(url
.lastIndexOf('/'));
225 //folderURL can have the extension .tmp or .tmp_
226 //Before OOo 3.4 the created a tmp file with osl_createTempFile and
227 //then created a Folder with a same name and a trailing '_'
228 //If the folderURL has no '_' then there is no corresponding tmp file.
229 void PackageRegistryBackend::deleteTempFolder(
230 OUString
const & folderUrl
)
232 if (!folderUrl
.isEmpty())
234 erase_path( folderUrl
, Reference
<XCommandEnvironment
>(),
235 false /* no throw: ignore errors */ );
237 if (folderUrl
.endsWith("_"))
239 const OUString tempFile
= folderUrl
.copy(0, folderUrl
.getLength() - 1);
240 erase_path( tempFile
, Reference
<XCommandEnvironment
>(),
241 false /* no throw: ignore errors */ );
246 //usedFolders can contain folder names which have the extension .tmp or .tmp_
247 //Before OOo 3.4 we created a tmp file with osl_createTempFile and
248 //then created a Folder with a same name and a trailing '_'
249 //If the folderURL has no '_' then there is no corresponding tmp file.
250 void PackageRegistryBackend::deleteUnusedFolders(
251 std::vector
< OUString
> const & usedFolders
)
255 const OUString sDataFolder
= makeURL(getCachePath(), OUString());
256 ::ucbhelper::Content
tempFolder(
257 sDataFolder
, Reference
<ucb::XCommandEnvironment
>(), m_xComponentContext
);
259 Reference
<sdbc::XResultSet
> xResultSet(
260 StrTitle::createCursor( tempFolder
, ::ucbhelper::INCLUDE_FOLDERS_ONLY
) );
262 // get all temp directories:
263 std::vector
<OUString
> tempEntries
;
265 while (xResultSet
->next())
268 Reference
<sdbc::XRow
>(
269 xResultSet
, UNO_QUERY_THROW
)->getString(
272 if (title
.endsWith(".tmp"))
273 tempEntries
.push_back(
274 makeURLAppendSysPathSegment(sDataFolder
, title
));
277 for (OUString
& tempEntrie
: tempEntries
)
279 if (std::find( usedFolders
.begin(), usedFolders
.end(), tempEntrie
) ==
282 deleteTempFolder(tempEntrie
);
286 catch (const ucb::InteractiveAugmentedIOException
& e
)
288 //In case the folder containing all the data folder does not
289 //exist yet, we ignore the exception
290 if (e
.Code
!= ucb::IOErrorCode_NOT_EXISTING
)
302 Package::Package( ::rtl::Reference
<PackageRegistryBackend
> const & myBackend
,
303 OUString
const & url
,
304 OUString
const & rName
,
305 OUString
const & displayName
,
306 Reference
<deployment::XPackageTypeInfo
> const & xPackageType
,
308 OUString
const & identifier
)
309 : t_PackageBase( getMutex() ),
310 m_myBackend( myBackend
),
313 m_displayName( displayName
),
314 m_xPackageType( xPackageType
),
315 m_bRemoved(bRemoved
),
316 m_identifier(identifier
)
320 //We use the last segment of the URL
322 !m_name
.isEmpty(), "desktop.deployment", "non-empty m_name");
323 OUString name
= m_url
;
324 rtl::Bootstrap::expandMacros(name
);
325 sal_Int32 index
= name
.lastIndexOf('/');
326 if (index
!= -1 && index
< name
.getLength())
327 m_name
= name
.copy(index
+ 1);
332 void Package::disposing()
335 WeakComponentImplHelperBase::disposing();
339 void Package::check() const
341 ::osl::MutexGuard
guard( getMutex() );
342 if (rBHelper
.bInDispose
|| rBHelper
.bDisposed
) {
343 throw lang::DisposedException(
344 "Package instance has already been disposed!",
345 static_cast<OWeakObject
*>(const_cast<Package
*>(this)));
351 void Package::dispose()
353 //Do not call check here. We must not throw an exception here if the object
354 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
355 WeakComponentImplHelperBase::dispose();
359 void Package::addEventListener(
360 Reference
<lang::XEventListener
> const & xListener
)
362 //Do not call check here. We must not throw an exception here if the object
363 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
364 WeakComponentImplHelperBase::addEventListener( xListener
);
368 void Package::removeEventListener(
369 Reference
<lang::XEventListener
> const & xListener
)
371 //Do not call check here. We must not throw an exception here if the object
372 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
373 WeakComponentImplHelperBase::removeEventListener( xListener
);
376 // XModifyBroadcaster
378 void Package::addModifyListener(
379 Reference
<util::XModifyListener
> const & xListener
)
382 rBHelper
.addListener( cppu::UnoType
<decltype(xListener
)>::get(), xListener
);
386 void Package::removeModifyListener(
387 Reference
<util::XModifyListener
> const & xListener
)
390 rBHelper
.removeListener( cppu::UnoType
<decltype(xListener
)>::get(), xListener
);
394 void Package::checkAborted(
395 ::rtl::Reference
<AbortChannel
> const & abortChannel
)
397 if (abortChannel
.is() && abortChannel
->isAborted()) {
398 throw CommandAbortedException(
399 "abort!", static_cast<OWeakObject
*>(this) );
405 Reference
<task::XAbortChannel
> Package::createAbortChannel()
408 return new AbortChannel
;
412 sal_Bool
Package::isBundle()
414 return false; // default
418 ::sal_Int32
Package::checkPrerequisites(
419 const css::uno::Reference
< css::task::XAbortChannel
>&,
420 const css::uno::Reference
< css::ucb::XCommandEnvironment
>&,
424 throw deployment::ExtensionRemovedException();
429 sal_Bool
Package::checkDependencies(
430 const css::uno::Reference
< css::ucb::XCommandEnvironment
>& )
433 throw deployment::ExtensionRemovedException();
438 Sequence
< Reference
<deployment::XPackage
> > Package::getBundle(
439 Reference
<task::XAbortChannel
> const &,
440 Reference
<XCommandEnvironment
> const & )
442 return Sequence
< Reference
<deployment::XPackage
> >();
446 OUString
Package::getName()
451 beans::Optional
<OUString
> Package::getIdentifier()
454 return beans::Optional
<OUString
>(true, m_identifier
);
456 return beans::Optional
<OUString
>();
460 OUString
Package::getVersion()
463 throw deployment::ExtensionRemovedException();
468 OUString
Package::getURL()
474 OUString
Package::getDisplayName()
477 throw deployment::ExtensionRemovedException();
478 return m_displayName
;
482 OUString
Package::getDescription()
485 throw deployment::ExtensionRemovedException();
490 OUString
Package::getLicenseText()
493 throw deployment::ExtensionRemovedException();
498 Sequence
<OUString
> Package::getUpdateInformationURLs()
501 throw deployment::ExtensionRemovedException();
502 return Sequence
<OUString
>();
506 css::beans::StringPair
Package::getPublisherInfo()
509 throw deployment::ExtensionRemovedException();
510 css::beans::StringPair aEmptyPair
;
515 uno::Reference
< css::graphic::XGraphic
> Package::getIcon( sal_Bool
/*bHighContrast*/ )
518 throw deployment::ExtensionRemovedException();
520 uno::Reference
< css::graphic::XGraphic
> aEmpty
;
525 Reference
<deployment::XPackageTypeInfo
> Package::getPackageType()
527 return m_xPackageType
;
530 void Package::exportTo(
531 OUString
const & destFolderURL
, OUString
const & newTitle
,
532 sal_Int32 nameClashAction
, Reference
<XCommandEnvironment
> const & xCmdEnv
)
535 throw deployment::ExtensionRemovedException();
537 ::ucbhelper::Content
destFolder( destFolderURL
, xCmdEnv
, getMyBackend()->getComponentContext() );
538 ::ucbhelper::Content
sourceContent( getURL(), xCmdEnv
, getMyBackend()->getComponentContext() );
542 bOk
= destFolder
.transferContent(
543 sourceContent
, ::ucbhelper::InsertOperation::Copy
,
544 newTitle
, nameClashAction
);
546 catch (const css::ucb::ContentCreationException
&)
552 throw RuntimeException( "UCB transferContent() failed!", nullptr );
555 void Package::fireModified()
557 ::cppu::OInterfaceContainerHelper
* container
= rBHelper
.getContainer(
558 cppu::UnoType
<util::XModifyListener
>::get() );
559 if (container
!= nullptr) {
560 Sequence
< Reference
<XInterface
> > elements(
561 container
->getElements() );
562 lang::EventObject
evt( static_cast<OWeakObject
*>(this) );
563 for ( sal_Int32 pos
= 0; pos
< elements
.getLength(); ++pos
)
565 Reference
<util::XModifyListener
> xListener(
566 elements
[ pos
], UNO_QUERY
);
568 xListener
->modified( evt
);
575 beans::Optional
< beans::Ambiguous
<sal_Bool
> > Package::isRegistered(
576 Reference
<task::XAbortChannel
> const & xAbortChannel
,
577 Reference
<XCommandEnvironment
> const & xCmdEnv
)
580 ::osl::ResettableMutexGuard
guard( getMutex() );
581 return isRegistered_( guard
,
582 AbortChannel::get(xAbortChannel
),
585 catch (const RuntimeException
&) {
588 catch (const CommandFailedException
&) {
591 catch (const CommandAbortedException
&) {
594 catch (const deployment::DeploymentException
&) {
597 catch (const Exception
& e
) {
598 Any
exc( ::cppu::getCaughtException() );
599 throw deployment::DeploymentException(
600 "unexpected " + exc
.getValueTypeName() + ": " + e
.Message
,
601 static_cast<OWeakObject
*>(this), exc
);
606 void Package::processPackage_impl(
607 bool doRegisterPackage
,
609 Reference
<task::XAbortChannel
> const & xAbortChannel
,
610 Reference
<XCommandEnvironment
> const & xCmdEnv
)
617 ::osl::ResettableMutexGuard
guard( getMutex() );
618 beans::Optional
< beans::Ambiguous
<sal_Bool
> > option(
619 isRegistered_( guard
, AbortChannel::get(xAbortChannel
),
621 action
= (option
.IsPresent
&&
622 (option
.Value
.IsAmbiguous
||
623 (doRegisterPackage
? !option
.Value
.Value
624 : option
.Value
.Value
)));
627 OUString displayName
= isRemoved() ? getName() : getDisplayName();
628 ProgressLevel
progress(
631 ? PackageRegistryBackend::StrRegisteringPackage()
632 : PackageRegistryBackend::StrRevokingPackage())
634 processPackage_( guard
,
637 AbortChannel::get(xAbortChannel
),
641 catch (lang::IllegalArgumentException
&) {
642 Any
e(cppu::getCaughtException());
643 throw deployment::DeploymentException(
645 ? DpResId(RID_STR_ERROR_WHILE_REGISTERING
)
646 : DpResId(RID_STR_ERROR_WHILE_REVOKING
))
648 static_cast< OWeakObject
* >(this), e
);
650 catch (const RuntimeException
&e
) {
651 SAL_WARN("desktop.deployment", "unexpected " << e
);
654 catch (const CommandFailedException
&) {
657 catch (const CommandAbortedException
&) {
660 catch (const deployment::DeploymentException
&) {
663 catch (const Exception
&) {
664 Any
exc( ::cppu::getCaughtException() );
665 throw deployment::DeploymentException(
667 ? DpResId(RID_STR_ERROR_WHILE_REGISTERING
)
668 : DpResId(RID_STR_ERROR_WHILE_REVOKING
))
669 + getDisplayName(), static_cast<OWeakObject
*>(this), exc
);
682 void Package::registerPackage(
684 Reference
<task::XAbortChannel
> const & xAbortChannel
,
685 Reference
<XCommandEnvironment
> const & xCmdEnv
)
688 throw deployment::ExtensionRemovedException();
689 processPackage_impl( true /* register */, startup
, xAbortChannel
, xCmdEnv
);
693 void Package::revokePackage(
695 Reference
<task::XAbortChannel
> const & xAbortChannel
,
696 Reference
<XCommandEnvironment
> const & xCmdEnv
)
698 processPackage_impl( false /* revoke */, startup
, xAbortChannel
, xCmdEnv
);
702 PackageRegistryBackend
* Package::getMyBackend() const
704 PackageRegistryBackend
* pBackend
= m_myBackend
.get();
705 if (nullptr == pBackend
)
707 //May throw a DisposedException
709 //We should never get here...
710 throw RuntimeException(
711 "Failed to get the BackendImpl",
712 static_cast<OWeakObject
*>(const_cast<Package
*>(this)));
717 OUString
Package::getRepositoryName()
719 PackageRegistryBackend
* backEnd
= getMyBackend();
720 return backEnd
->getContext();
723 beans::Optional
< OUString
> Package::getRegistrationDataURL()
726 throw deployment::ExtensionRemovedException();
727 return beans::Optional
<OUString
>();
730 sal_Bool
Package::isRemoved()
735 Package::TypeInfo::~TypeInfo()
741 OUString
Package::TypeInfo::getMediaType()
747 OUString
Package::TypeInfo::getDescription()
749 return getShortDescription();
753 OUString
Package::TypeInfo::getShortDescription()
758 OUString
Package::TypeInfo::getFileFilter()
763 Any
Package::TypeInfo::getIcon( sal_Bool
/*highContrast*/, sal_Bool
/*smallIcon*/ )
771 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */