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_lib_container.h"
23 #include <dp_backend.h>
26 #include <ucbhelper/content.hxx>
27 #include <cppuhelper/implbase.hxx>
28 #include <svl/inettype.hxx>
29 #include <com/sun/star/util/XUpdatable.hpp>
30 #include <com/sun/star/script/XLibraryContainer3.hpp>
32 #include <string_view>
34 #include "dp_scriptbackenddb.hxx"
35 #include <cppuhelper/supportsservice.hxx>
37 using namespace ::dp_misc
;
38 using namespace ::com::sun::star
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::ucb
;
42 namespace dp_registry::backend::script
{
45 typedef ::cppu::ImplInheritanceHelper
<
46 ::dp_registry::backend::PackageRegistryBackend
, util::XUpdatable
> t_helper
;
48 class BackendImpl
: public t_helper
50 class PackageImpl
: public ::dp_registry::backend::Package
52 BackendImpl
* getMyBackend() const;
54 const OUString m_scriptURL
;
55 const OUString m_dialogURL
;
56 OUString m_dialogName
;
59 virtual beans::Optional
< beans::Ambiguous
<sal_Bool
> > isRegistered_(
60 ::osl::ResettableMutexGuard
& guard
,
61 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
62 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
63 virtual void processPackage_(
64 ::osl::ResettableMutexGuard
& guard
,
67 ::rtl::Reference
<AbortChannel
> const & abortChannel
,
68 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
72 ::rtl::Reference
<BackendImpl
> const & myBackend
,
74 Reference
<XCommandEnvironment
> const &xCmdEnv
,
75 OUString
const & scriptURL
, OUString
const & dialogURL
,
76 bool bRemoved
, OUString
const & identifier
);
78 friend class PackageImpl
;
80 // PackageRegistryBackend
81 virtual Reference
<deployment::XPackage
> bindPackage_(
82 OUString
const & url
, OUString
const & mediaType
,
83 bool bRemoved
, OUString
const & identifier
,
84 Reference
<XCommandEnvironment
> const & xCmdEnv
) override
;
86 void addDataToDb(OUString
const & url
);
87 bool hasActiveEntry(std::u16string_view url
);
88 void revokeEntryFromDb(std::u16string_view url
);
90 const Reference
<deployment::XPackageTypeInfo
> m_xBasicLibTypeInfo
;
91 const Reference
<deployment::XPackageTypeInfo
> m_xDialogLibTypeInfo
;
92 Sequence
< Reference
<deployment::XPackageTypeInfo
> > m_typeInfos
;
93 std::unique_ptr
<ScriptBackendDb
> m_backendDb
;
95 BackendImpl( Sequence
<Any
> const & args
,
96 Reference
<XComponentContext
> const & xComponentContext
);
99 virtual OUString SAL_CALL
getImplementationName() override
;
100 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) override
;
101 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
104 virtual void SAL_CALL
update() override
;
107 virtual Sequence
< Reference
<deployment::XPackageTypeInfo
> > SAL_CALL
108 getSupportedPackageTypes() override
;
109 virtual void SAL_CALL
packageRemoved(OUString
const & url
, OUString
const & mediaType
) override
;
114 BackendImpl::PackageImpl::PackageImpl(
115 ::rtl::Reference
<BackendImpl
> const & myBackend
,
116 OUString
const & url
,
117 Reference
<XCommandEnvironment
> const &xCmdEnv
,
118 OUString
const & scriptURL
, OUString
const & dialogURL
, bool bRemoved
,
119 OUString
const & identifier
)
120 : Package( myBackend
, url
,
121 OUString(), OUString(), // will be late-initialized
122 !scriptURL
.isEmpty() ? myBackend
->m_xBasicLibTypeInfo
123 : myBackend
->m_xDialogLibTypeInfo
, bRemoved
, identifier
),
124 m_scriptURL( scriptURL
),
125 m_dialogURL( dialogURL
)
127 // name, displayName:
128 if (!dialogURL
.isEmpty()) {
129 m_dialogName
= LibraryContainer::get_libname(
130 dialogURL
, xCmdEnv
, myBackend
->getComponentContext() );
132 if (!scriptURL
.isEmpty()) {
133 assert(m_name
.pData
);
134 m_name
= LibraryContainer::get_libname(
135 scriptURL
, xCmdEnv
, myBackend
->getComponentContext() );
138 m_name
= m_dialogName
;
139 m_displayName
= m_name
;
143 BackendImpl::BackendImpl(
144 Sequence
<Any
> const & args
,
145 Reference
<XComponentContext
> const & xComponentContext
)
146 : t_helper( args
, xComponentContext
),
147 m_xBasicLibTypeInfo( new Package::TypeInfo(
148 u
"application/vnd.sun.star.basic-library"_ustr
,
149 OUString() /* no file filter */,
150 DpResId(RID_STR_BASIC_LIB
)
152 m_xDialogLibTypeInfo( new Package::TypeInfo(
153 u
"application/vnd.sun.star.dialog-library"_ustr
,
154 OUString() /* no file filter */,
155 DpResId(RID_STR_DIALOG_LIB
)
157 m_typeInfos
{ m_xBasicLibTypeInfo
, m_xDialogLibTypeInfo
}
159 OSL_ASSERT( ! transientMode() );
161 if (!transientMode())
163 OUString dbFile
= makeURL(getCachePath(), u
"backenddb.xml"_ustr
);
165 new ScriptBackendDb(getComponentContext(), dbFile
));
171 OUString
BackendImpl::getImplementationName()
173 return u
"com.sun.star.comp.deployment.script.PackageRegistryBackend"_ustr
;
176 sal_Bool
BackendImpl::supportsService( const OUString
& ServiceName
)
178 return cppu::supportsService(this, ServiceName
);
181 css::uno::Sequence
< OUString
> BackendImpl::getSupportedServiceNames()
183 return { BACKEND_SERVICE_NAME
};
186 void BackendImpl::addDataToDb(OUString
const & url
)
189 m_backendDb
->addEntry(url
);
192 bool BackendImpl::hasActiveEntry(std::u16string_view url
)
195 return m_backendDb
->hasActiveEntry(url
);
201 void BackendImpl::update()
203 // Nothing to do here after fixing i70283!?
208 Sequence
< Reference
<deployment::XPackageTypeInfo
> >
209 BackendImpl::getSupportedPackageTypes()
213 void BackendImpl::revokeEntryFromDb(std::u16string_view url
)
216 m_backendDb
->revokeEntry(url
);
219 void BackendImpl::packageRemoved(OUString
const & url
, OUString
const & /*mediaType*/)
222 m_backendDb
->removeEntry(url
);
225 // PackageRegistryBackend
227 Reference
<deployment::XPackage
> BackendImpl::bindPackage_(
228 OUString
const & url
, OUString
const & mediaType_
,
229 bool bRemoved
, OUString
const & identifier
,
230 Reference
<XCommandEnvironment
> const & xCmdEnv
)
232 OUString
mediaType( mediaType_
);
233 if (mediaType
.isEmpty())
235 // detect media-type:
236 ::ucbhelper::Content ucbContent
;
237 if (create_ucb_content( &ucbContent
, url
, xCmdEnv
) &&
238 ucbContent
.isFolder())
240 // probe for script.xlb:
241 if (create_ucb_content(
242 nullptr, makeURL( url
, u
"script.xlb"_ustr
),
243 xCmdEnv
, false /* no throw */ ))
244 mediaType
= "application/vnd.sun.star.basic-library";
245 // probe for dialog.xlb:
246 else if (create_ucb_content(
247 nullptr, makeURL( url
, u
"dialog.xlb"_ustr
),
248 xCmdEnv
, false /* no throw */ ))
249 mediaType
= "application/vnd.sun.star.dialog-library";
251 if (mediaType
.isEmpty())
252 throw lang::IllegalArgumentException(
253 StrCannotDetectMediaType() + url
,
254 static_cast<OWeakObject
*>(this), static_cast<sal_Int16
>(-1) );
257 OUString type
, subType
;
258 INetContentTypeParameterList params
;
259 if (INetContentTypes::parse( mediaType
, type
, subType
, ¶ms
))
261 if (type
.equalsIgnoreAsciiCase("application"))
263 OUString
dialogURL( makeURL( url
, u
"dialog.xlb"_ustr
) );
264 if (! create_ucb_content(
265 nullptr, dialogURL
, xCmdEnv
, false /* no throw */ )) {
269 if (subType
.equalsIgnoreAsciiCase("vnd.sun.star.basic-library"))
271 OUString
scriptURL( makeURL( url
, u
"script.xlb"_ustr
));
272 if (! create_ucb_content(
273 nullptr, scriptURL
, xCmdEnv
, false /* no throw */ )) {
277 return new PackageImpl(
278 this, url
, xCmdEnv
, scriptURL
,
279 dialogURL
, bRemoved
, identifier
);
281 else if (subType
.equalsIgnoreAsciiCase(
282 "vnd.sun.star.dialog-library")) {
283 return new PackageImpl(
285 OUString() /* no script lib */,
287 bRemoved
, identifier
);
291 throw lang::IllegalArgumentException(
292 StrUnsupportedMediaType() + mediaType
,
293 static_cast<OWeakObject
*>(this),
294 static_cast<sal_Int16
>(-1) );
299 BackendImpl
* BackendImpl::PackageImpl::getMyBackend() const
301 BackendImpl
* pBackend
= static_cast<BackendImpl
*>(m_myBackend
.get());
302 if (nullptr == pBackend
)
304 //May throw a DisposedException
306 //We should never get here...
307 throw RuntimeException(
308 u
"Failed to get the BackendImpl"_ustr
,
309 static_cast<OWeakObject
*>(const_cast<PackageImpl
*>(this)));
314 beans::Optional
< beans::Ambiguous
<sal_Bool
> >
315 BackendImpl::PackageImpl::isRegistered_(
316 ::osl::ResettableMutexGuard
& /* guard */,
317 ::rtl::Reference
<AbortChannel
> const & /* abortChannel */,
318 Reference
<XCommandEnvironment
> const & /* xCmdEnv */ )
320 BackendImpl
* that
= getMyBackend();
321 Reference
< deployment::XPackage
> xThisPackage( this );
323 bool registered
= that
->hasActiveEntry(getURL());
324 return beans::Optional
< beans::Ambiguous
<sal_Bool
> >(
325 true /* IsPresent */,
326 beans::Ambiguous
<sal_Bool
>( registered
, false /* IsAmbiguous */ ) );
330 lcl_maybeRemoveScript(
332 OUString
const& rName
,
333 std::u16string_view rScriptURL
,
334 Reference
<css::script::XLibraryContainer3
> const& xScriptLibs
)
336 if (bExists
&& xScriptLibs
.is() && xScriptLibs
->hasByName(rName
))
338 const OUString sScriptUrl
= xScriptLibs
->getOriginalLibraryLinkURL(rName
);
339 if (sScriptUrl
== rScriptURL
)
340 xScriptLibs
->removeLibrary(rName
);
347 OUString
const& rName
,
348 OUString
const& rScriptURL
,
349 Reference
<css::script::XLibraryContainer3
> const& xScriptLibs
)
351 if (!bExists
|| !xScriptLibs
)
355 if (xScriptLibs
->hasByName(rName
))
357 const OUString sOriginalUrl
= xScriptLibs
->getOriginalLibraryLinkURL(rName
);
358 //We assume here that library names in extensions are unique, which may not be the case
359 //ToDo: If the script exist in another extension, then both extensions must have the
361 if (sOriginalUrl
.match("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")
362 || sOriginalUrl
.match("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")
363 || sOriginalUrl
.match("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")
364 || sOriginalUrl
.match("$(INST)/share/basic/Access2Base/"))
366 xScriptLibs
->removeLibrary(rName
);
377 xScriptLibs
->createLibraryLink(rName
, rScriptURL
, false);
378 return xScriptLibs
->hasByName(rName
);
384 void BackendImpl::PackageImpl::processPackage_(
385 ::osl::ResettableMutexGuard
& /* guard */,
386 bool doRegisterPackage
,
388 ::rtl::Reference
<AbortChannel
> const & /* abortChannel */,
389 Reference
<XCommandEnvironment
> const & /* xCmdEnv */ )
391 BackendImpl
* that
= getMyBackend();
393 Reference
< deployment::XPackage
> xThisPackage( this );
394 Reference
<XComponentContext
> const & xComponentContext
= that
->getComponentContext();
396 bool bScript
= !m_scriptURL
.isEmpty();
397 Reference
<css::script::XLibraryContainer3
> xScriptLibs
;
399 bool bDialog
= !m_dialogURL
.isEmpty();
400 Reference
<css::script::XLibraryContainer3
> xDialogLibs
;
402 bool bRunning
= !startup
&& office_is_running();
408 xComponentContext
->getServiceManager()->createInstanceWithContext(
409 u
"com.sun.star.script.ApplicationScriptLibraryContainer"_ustr
,
410 xComponentContext
), UNO_QUERY_THROW
);
416 xComponentContext
->getServiceManager()->createInstanceWithContext(
417 u
"com.sun.star.script.ApplicationDialogLibraryContainer"_ustr
,
418 xComponentContext
), UNO_QUERY_THROW
);
421 bool bRegistered
= getMyBackend()->hasActiveEntry(getURL());
422 if( !doRegisterPackage
)
424 //We cannot just call removeLibrary(name) because this could remove a
425 //script which was added by an extension in a different repository. For
426 //example, extension foo is contained in the bundled repository and then
427 //the user adds it to the user repository. The extension manager will
428 //then register the new script and revoke the script from the bundled
429 //extension. removeLibrary(name) would now remove the script from the
430 //user repository. That is, the script of the newly added user extension does
431 //not work anymore. Therefore we must check if the currently active
432 //script comes in fact from the currently processed extension.
436 //we also prevent and live deployment at startup
437 if (!isRemoved() && !startup
)
439 lcl_maybeRemoveScript(bScript
, m_name
, m_scriptURL
, xScriptLibs
);
440 lcl_maybeRemoveScript(bDialog
, m_dialogName
, m_dialogURL
, xDialogLibs
);
442 getMyBackend()->revokeEntryFromDb(getURL());
447 return; // Already registered
449 // Update LibraryContainer
450 bool bScriptSuccess
= false;
451 bool bDialogSuccess
= false;
454 //If there is a bundled extension, and the user installs the same extension
455 //then the script from the bundled extension must be removed. If this does not work
456 //then live deployment does not work for scripts.
457 bScriptSuccess
= lcl_maybeAddScript(bScript
, m_name
, m_scriptURL
, xScriptLibs
);
458 bDialogSuccess
= lcl_maybeAddScript(bDialog
, m_dialogName
, m_dialogURL
, xDialogLibs
);
460 bool bSuccess
= bScript
|| bDialog
; // Something must have happened
462 if( (bScript
&& !bScriptSuccess
) || (bDialog
&& !bDialogSuccess
) )
466 getMyBackend()->addDataToDb(getURL());
471 } // namespace dp_registry::backend::script
473 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
474 com_sun_star_comp_deployment_script_PackageRegistryBackend_get_implementation(
475 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& args
)
477 return cppu::acquire(new dp_registry::backend::script::BackendImpl(args
, context
));
480 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */