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 <strings.hrc>
22 #include <dp_services.hxx>
23 #include "dp_lib_container.h"
24 #include <dp_backend.h>
26 #include <rtl/uri.hxx>
27 #include <ucbhelper/content.hxx>
28 #include <cppuhelper/exc_hlp.hxx>
29 #include <cppuhelper/implbase.hxx>
30 #include <comphelper/servicedecl.hxx>
31 #include <svl/inettype.hxx>
32 #include <com/sun/star/util/XUpdatable.hpp>
33 #include <com/sun/star/script/XLibraryContainer3.hpp>
34 #include <com/sun/star/util/XMacroExpander.hpp>
36 #include "dp_scriptbackenddb.hxx"
38 using namespace ::dp_misc
;
39 using namespace ::com::sun::star
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::ucb
;
43 namespace dp_registry
{
48 typedef ::cppu::ImplInheritanceHelper
<
49 ::dp_registry::backend::PackageRegistryBackend
, util::XUpdatable
> t_helper
;
51 class BackendImpl
: public t_helper
53 class PackageImpl
: public ::dp_registry::backend::Package
55 BackendImpl
* getMyBackend() const;
57 const OUString m_scriptURL
;
58 const OUString m_dialogURL
;
59 OUString m_dialogName
;
62 virtual beans::Optional
< beans::Ambiguous
<sal_Bool
> > isRegistered_(
63 ::osl::ResettableMutexGuard
& guard
,
64 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
65 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
66 virtual void processPackage_(
67 ::osl::ResettableMutexGuard
& guard
,
70 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
71 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
75 ::rtl::Reference
<BackendImpl
> const & myBackend
,
77 Reference
<XCommandEnvironment
> const &xCmdEnv
,
78 OUString
const & scriptURL
, OUString
const & dialogURL
,
79 bool bRemoved
, OUString
const & identifier
);
81 friend class PackageImpl
;
83 // PackageRegistryBackend
84 virtual Reference
<deployment::XPackage
> bindPackage_(
85 OUString
const & url
, OUString
const & mediaType
,
86 bool bRemoved
, OUString
const & identifier
,
87 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
89 void addDataToDb(OUString
const & url
);
90 bool hasActiveEntry(OUString
const & url
);
91 void revokeEntryFromDb(OUString
const & url
);
93 const Reference
<deployment::XPackageTypeInfo
> m_xBasicLibTypeInfo
;
94 const Reference
<deployment::XPackageTypeInfo
> m_xDialogLibTypeInfo
;
95 Sequence
< Reference
<deployment::XPackageTypeInfo
> > m_typeInfos
;
96 std::unique_ptr
<ScriptBackendDb
> m_backendDb
;
98 BackendImpl( Sequence
<Any
> const & args
,
99 Reference
<XComponentContext
> const & xComponentContext
);
102 virtual void SAL_CALL
update() override
;
105 virtual Sequence
< Reference
<deployment::XPackageTypeInfo
> > SAL_CALL
106 getSupportedPackageTypes() override
;
107 virtual void SAL_CALL
packageRemoved(OUString
const & url
, OUString
const & mediaType
) override
;
112 BackendImpl::PackageImpl::PackageImpl(
113 ::rtl::Reference
<BackendImpl
> const & myBackend
,
114 OUString
const & url
,
115 Reference
<XCommandEnvironment
> const &xCmdEnv
,
116 OUString
const & scriptURL
, OUString
const & dialogURL
, bool bRemoved
,
117 OUString
const & identifier
)
118 : Package( myBackend
.get(), url
,
119 OUString(), OUString(), // will be late-initialized
120 !scriptURL
.isEmpty() ? myBackend
->m_xBasicLibTypeInfo
121 : myBackend
->m_xDialogLibTypeInfo
, bRemoved
, identifier
),
122 m_scriptURL( scriptURL
),
123 m_dialogURL( dialogURL
)
125 // name, displayName:
126 if (!dialogURL
.isEmpty()) {
127 m_dialogName
= LibraryContainer::get_libname(
128 dialogURL
, xCmdEnv
, myBackend
->getComponentContext() );
130 if (!scriptURL
.isEmpty()) {
131 assert(m_name
.pData
);
132 m_name
= LibraryContainer::get_libname(
133 scriptURL
, xCmdEnv
, myBackend
->getComponentContext() );
136 m_name
= m_dialogName
;
137 m_displayName
= m_name
;
141 BackendImpl::BackendImpl(
142 Sequence
<Any
> const & args
,
143 Reference
<XComponentContext
> const & xComponentContext
)
144 : t_helper( args
, xComponentContext
),
145 m_xBasicLibTypeInfo( new Package::TypeInfo(
146 "application/vnd.sun.star.basic-library",
147 OUString() /* no file filter */,
148 DpResId(RID_STR_BASIC_LIB
)
150 m_xDialogLibTypeInfo( new Package::TypeInfo(
151 "application/vnd.sun.star.dialog-library",
152 OUString() /* no file filter */,
153 DpResId(RID_STR_DIALOG_LIB
)
157 m_typeInfos
[ 0 ] = m_xBasicLibTypeInfo
;
158 m_typeInfos
[ 1 ] = m_xDialogLibTypeInfo
;
160 OSL_ASSERT( ! transientMode() );
162 if (!transientMode())
164 OUString dbFile
= makeURL(getCachePath(), "backenddb.xml");
166 new ScriptBackendDb(getComponentContext(), dbFile
));
170 void BackendImpl::addDataToDb(OUString
const & url
)
173 m_backendDb
->addEntry(url
);
176 bool BackendImpl::hasActiveEntry(OUString
const & url
)
179 return m_backendDb
->hasActiveEntry(url
);
185 void BackendImpl::update()
187 // Nothing to do here after fixing i70283!?
192 Sequence
< Reference
<deployment::XPackageTypeInfo
> >
193 BackendImpl::getSupportedPackageTypes()
197 void BackendImpl::revokeEntryFromDb(OUString
const & url
)
200 m_backendDb
->revokeEntry(url
);
203 void BackendImpl::packageRemoved(OUString
const & url
, OUString
const & /*mediaType*/)
206 m_backendDb
->removeEntry(url
);
209 // PackageRegistryBackend
211 Reference
<deployment::XPackage
> BackendImpl::bindPackage_(
212 OUString
const & url
, OUString
const & mediaType_
,
213 bool bRemoved
, OUString
const & identifier
,
214 Reference
<XCommandEnvironment
> const & xCmdEnv
)
216 OUString
mediaType( mediaType_
);
217 if (mediaType
.isEmpty())
219 // detect media-type:
220 ::ucbhelper::Content ucbContent
;
221 if (create_ucb_content( &ucbContent
, url
, xCmdEnv
) &&
222 ucbContent
.isFolder())
224 // probe for script.xlb:
225 if (create_ucb_content(
226 nullptr, makeURL( url
, "script.xlb" ),
227 xCmdEnv
, false /* no throw */ ))
228 mediaType
= "application/vnd.sun.star.basic-library";
229 // probe for dialog.xlb:
230 else if (create_ucb_content(
231 nullptr, makeURL( url
, "dialog.xlb" ),
232 xCmdEnv
, false /* no throw */ ))
233 mediaType
= "application/vnd.sun.star.dialog-library";
235 if (mediaType
.isEmpty())
236 throw lang::IllegalArgumentException(
237 StrCannotDetectMediaType() + url
,
238 static_cast<OWeakObject
*>(this), static_cast<sal_Int16
>(-1) );
241 OUString type
, subType
;
242 INetContentTypeParameterList params
;
243 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
245 if (type
.equalsIgnoreAsciiCase("application"))
247 OUString
dialogURL( makeURL( url
, "dialog.xlb" ) );
248 if (! create_ucb_content(
249 nullptr, dialogURL
, xCmdEnv
, false /* no throw */ )) {
253 if (subType
.equalsIgnoreAsciiCase("vnd.sun.star.basic-library"))
255 OUString
scriptURL( makeURL( url
, "script.xlb"));
256 if (! create_ucb_content(
257 nullptr, scriptURL
, xCmdEnv
, false /* no throw */ )) {
261 return new PackageImpl(
262 this, url
, xCmdEnv
, scriptURL
,
263 dialogURL
, bRemoved
, identifier
);
265 else if (subType
.equalsIgnoreAsciiCase(
266 "vnd.sun.star.dialog-library")) {
267 return new PackageImpl(
269 OUString() /* no script lib */,
271 bRemoved
, identifier
);
275 throw lang::IllegalArgumentException(
276 StrUnsupportedMediaType() + mediaType
,
277 static_cast<OWeakObject
*>(this),
278 static_cast<sal_Int16
>(-1) );
283 BackendImpl
* BackendImpl::PackageImpl::getMyBackend() const
285 BackendImpl
* pBackend
= static_cast<BackendImpl
*>(m_myBackend
.get());
286 if (nullptr == pBackend
)
288 //May throw a DisposedException
290 //We should never get here...
291 throw RuntimeException(
292 "Failed to get the BackendImpl",
293 static_cast<OWeakObject
*>(const_cast<PackageImpl
*>(this)));
298 beans::Optional
< beans::Ambiguous
<sal_Bool
> >
299 BackendImpl::PackageImpl::isRegistered_(
300 ::osl::ResettableMutexGuard
& /* guard */,
301 ::rtl::Reference
<AbortChannel
> const & /* abortChannel */,
302 Reference
<XCommandEnvironment
> const & /* xCmdEnv */ )
304 BackendImpl
* that
= getMyBackend();
305 Reference
< deployment::XPackage
> xThisPackage( this );
307 bool registered
= that
->hasActiveEntry(getURL());
308 return beans::Optional
< beans::Ambiguous
<sal_Bool
> >(
309 true /* IsPresent */,
310 beans::Ambiguous
<sal_Bool
>( registered
, false /* IsAmbiguous */ ) );
314 lcl_maybeRemoveScript(
316 OUString
const& rName
,
317 OUString
const& rScriptURL
,
318 Reference
<css::script::XLibraryContainer3
> const& xScriptLibs
)
320 if (bExists
&& xScriptLibs
.is() && xScriptLibs
->hasByName(rName
))
322 const OUString sScriptUrl
= xScriptLibs
->getOriginalLibraryLinkURL(rName
);
323 if (sScriptUrl
== rScriptURL
)
324 xScriptLibs
->removeLibrary(rName
);
331 OUString
const& rName
,
332 OUString
const& rScriptURL
,
333 Reference
<css::script::XLibraryContainer3
> const& xScriptLibs
)
335 if (bExists
&& xScriptLibs
.is())
338 if (xScriptLibs
->hasByName(rName
))
340 const OUString sOriginalUrl
= xScriptLibs
->getOriginalLibraryLinkURL(rName
);
341 //We assume here that library names in extensions are unique, which may not be the case
342 //ToDo: If the script exist in another extension, then both extensions must have the
344 if (sOriginalUrl
.match("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")
345 || sOriginalUrl
.match("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")
346 || sOriginalUrl
.match("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")
347 || sOriginalUrl
.match("$(INST)/share/basic/Access2Base/"))
349 xScriptLibs
->removeLibrary(rName
);
360 xScriptLibs
->createLibraryLink(rName
, rScriptURL
, false);
361 return xScriptLibs
->hasByName(rName
);
368 void BackendImpl::PackageImpl::processPackage_(
369 ::osl::ResettableMutexGuard
& /* guard */,
370 bool doRegisterPackage
,
372 ::rtl::Reference
<AbortChannel
> const & /* abortChannel */,
373 Reference
<XCommandEnvironment
> const & /* xCmdEnv */ )
375 BackendImpl
* that
= getMyBackend();
377 Reference
< deployment::XPackage
> xThisPackage( this );
378 Reference
<XComponentContext
> const & xComponentContext
= that
->getComponentContext();
380 bool bScript
= !m_scriptURL
.isEmpty();
381 Reference
<css::script::XLibraryContainer3
> xScriptLibs
;
383 bool bDialog
= !m_dialogURL
.isEmpty();
384 Reference
<css::script::XLibraryContainer3
> xDialogLibs
;
386 bool bRunning
= !startup
&& office_is_running();
392 xComponentContext
->getServiceManager()->createInstanceWithContext(
393 "com.sun.star.script.ApplicationScriptLibraryContainer",
394 xComponentContext
), UNO_QUERY_THROW
);
400 xComponentContext
->getServiceManager()->createInstanceWithContext(
401 "com.sun.star.script.ApplicationDialogLibraryContainer",
402 xComponentContext
), UNO_QUERY_THROW
);
405 bool bRegistered
= getMyBackend()->hasActiveEntry(getURL());
406 if( !doRegisterPackage
)
408 //We cannot just call removeLibrary(name) because this could remove a
409 //script which was added by an extension in a different repository. For
410 //example, extension foo is contained in the bundled repository and then
411 //the user adds it to the user repository. The extension manager will
412 //then register the new script and revoke the script from the bundled
413 //extension. removeLibrary(name) would now remove the script from the
414 //user repository. That is, the script of the newly added user extension does
415 //not work anymore. Therefore we must check if the currently active
416 //script comes in fact from the currently processed extension.
420 //we also prevent and live deployment at startup
421 if (!isRemoved() && !startup
)
423 lcl_maybeRemoveScript(bScript
, m_name
, m_scriptURL
, xScriptLibs
);
424 lcl_maybeRemoveScript(bDialog
, m_dialogName
, m_dialogURL
, xDialogLibs
);
426 getMyBackend()->revokeEntryFromDb(getURL());
431 return; // Already registered
433 // Update LibraryContainer
434 bool bScriptSuccess
= false;
435 bool bDialogSuccess
= false;
438 //If there is a bundled extension, and the user installs the same extension
439 //then the script from the bundled extension must be removed. If this does not work
440 //then live deployment does not work for scripts.
441 bScriptSuccess
= lcl_maybeAddScript(bScript
, m_name
, m_scriptURL
, xScriptLibs
);
442 bDialogSuccess
= lcl_maybeAddScript(bDialog
, m_dialogName
, m_dialogURL
, xDialogLibs
);
444 bool bSuccess
= bScript
|| bDialog
; // Something must have happened
446 if( (bScript
&& !bScriptSuccess
) || (bDialog
&& !bDialogSuccess
) )
450 getMyBackend()->addDataToDb(getURL());
455 namespace sdecl
= comphelper::service_decl
;
456 sdecl::class_
<BackendImpl
, sdecl::with_args
<true> > serviceBI
;
457 sdecl::ServiceDecl
const serviceDecl(
459 "com.sun.star.comp.deployment.script.PackageRegistryBackend",
460 BACKEND_SERVICE_NAME
);
462 } // namespace script
463 } // namespace backend
464 } // namespace dp_registry
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */