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 <comphelper/documentinfo.hxx>
23 #include <cppuhelper/implementationentry.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <cppuhelper/factory.hxx>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <tools/diagnose_ex.h>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/lang/EventObject.hpp>
31 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
32 #include <com/sun/star/document/XScriptInvocationContext.hpp>
34 #include <com/sun/star/uri/XUriReference.hpp>
35 #include <com/sun/star/uri/UriReferenceFactory.hpp>
36 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
38 #include <com/sun/star/deployment/XPackage.hpp>
39 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
40 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
41 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
43 #include <util/scriptingconstants.hxx>
44 #include <util/MiscUtils.hxx>
46 #include "ActiveMSPList.hxx"
47 #include "MasterScriptProvider.hxx"
48 #include "URIHelper.hxx"
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::script
;
53 using namespace ::com::sun::star::document
;
54 using namespace ::sf_misc
;
56 namespace func_provider
59 bool endsWith( const OUString
& target
,
60 const OUString
& item
)
63 if ( ( index
= target
.indexOf( item
) ) != -1 &&
64 ( index
== ( target
.getLength() - item
.getLength() ) ) )
71 /* should be available in some central location. */
73 // XScriptProvider implementation
76 MasterScriptProvider::MasterScriptProvider( const Reference
< XComponentContext
> & xContext
) throw ( RuntimeException
):
77 m_xContext( xContext
), m_bIsValid( false ), m_bInitialised( false ),
78 m_bIsPkgMSP( false ), m_pPCache( 0 )
80 ENSURE_OR_THROW( m_xContext
.is(), "MasterScriptProvider::MasterScriptProvider: No context available\n" );
81 m_xMgr
= m_xContext
->getServiceManager();
82 ENSURE_OR_THROW( m_xMgr
.is(), "MasterScriptProvider::MasterScriptProvider: No service manager available\n" );
87 MasterScriptProvider::~MasterScriptProvider()
97 void SAL_CALL
MasterScriptProvider::initialize( const Sequence
< Any
>& args
)
98 throw ( Exception
, RuntimeException
, std::exception
)
100 if ( m_bInitialised
)
105 sal_Int32 len
= args
.getLength();
108 throw RuntimeException(
109 "MasterScriptProvider::initialize: invalid number of arguments" );
112 Sequence
< Any
> invokeArgs( len
);
116 // check if first parameter is a string
117 // if it is, this implies that this is a MSP created
118 // with a user or share ctx ( used for browse functionality )
120 if ( args
[ 0 ] >>= m_sCtxString
)
122 invokeArgs
[ 0 ] = args
[ 0 ];
123 if ( m_sCtxString
.startsWith( "vnd.sun.star.tdoc" ) )
125 m_xModel
= MiscUtils::tDocUrlToModel( m_sCtxString
);
128 else if ( args
[ 0 ] >>= m_xInvocationContext
)
130 m_xModel
.set( m_xInvocationContext
->getScriptContainer(), UNO_QUERY_THROW
);
134 args
[ 0 ] >>= m_xModel
;
139 // from the arguments, we were able to deduce a model. That alone doesn't
140 // suffice, we also need an XEmbeddedScripts which actually indicates support
141 // for embeddeding scripts
142 Reference
< XEmbeddedScripts
> xScripts( m_xModel
, UNO_QUERY
);
143 if ( !xScripts
.is() )
145 throw lang::IllegalArgumentException(
146 OUString( "The given document does not support embedding scripts into it, and cannot be associated with such a document."
155 m_sCtxString
= MiscUtils::xModelToTdocUrl( m_xModel
, m_xContext
);
157 catch ( const Exception
& )
159 Any
aError( ::cppu::getCaughtException() );
162 buf
.appendAscii( "MasterScriptProvider::initialize: caught " );
163 buf
.append ( aError
.getValueTypeName() );
164 buf
.appendAscii( ":" );
166 Exception aException
; aError
>>= aException
;
167 buf
.append ( aException
.Message
);
168 throw lang::WrappedTargetException( buf
.makeStringAndClear(), *this, aError
);
171 if ( m_xInvocationContext
.is() && m_xInvocationContext
!= m_xModel
)
172 invokeArgs
[ 0 ] <<= m_xInvocationContext
;
174 invokeArgs
[ 0 ] <<= m_sCtxString
;
177 OUString pkgSpec
= "uno_packages";
178 sal_Int32 indexOfPkgSpec
= m_sCtxString
.lastIndexOf( pkgSpec
);
180 // if contex string ends with "uno_packages"
181 if ( indexOfPkgSpec
> -1 && m_sCtxString
.match( pkgSpec
, indexOfPkgSpec
) )
192 // use either scriping context or maybe zero args?
193 invokeArgs
= Sequence
< Any
>( 0 ); // no arguments
195 m_sAargs
= invokeArgs
;
196 // don't create pkg mgr MSP for documents, not supported
197 if ( !m_bIsPkgMSP
&& !m_xModel
.is() )
202 m_bInitialised
= true;
208 void MasterScriptProvider::createPkgProvider()
213 OUString sPkgCtx
= m_sCtxString
.concat( ":uno_packages" );
214 location
<<= sPkgCtx
;
216 Reference
< provider::XScriptProviderFactory
> xFac
=
217 provider::theMasterScriptProviderFactory::get( m_xContext
);
220 xFac
->createScriptProvider( location
), UNO_QUERY_THROW
);
223 catch ( const Exception
& e
)
226 OSL_TRACE("Exception creating MasterScriptProvider for uno_packages in context %s: %s",
227 OUStringToOString( m_sCtxString
,
228 RTL_TEXTENCODING_ASCII_US
).pData
->buffer
,
229 OUStringToOString( e
.Message
,
230 RTL_TEXTENCODING_ASCII_US
).pData
->buffer
);
235 Reference
< provider::XScript
>
236 MasterScriptProvider::getScript( const OUString
& scriptURI
)
237 throw ( provider::ScriptFrameworkErrorException
,
238 RuntimeException
, std::exception
)
242 throw provider::ScriptFrameworkErrorException(
243 "MasterScriptProvider not initialised", Reference
< XInterface
>(),
245 provider::ScriptFrameworkErrorType::UNKNOWN
);
248 // need to get the language from the string
250 Reference
< uri::XUriReferenceFactory
> xFac ( uri::UriReferenceFactory::create( m_xContext
) );
252 Reference
< uri::XUriReference
> uriRef(
253 xFac
->parse( scriptURI
), UNO_QUERY
);
255 Reference
< uri::XVndSunStarScriptUrl
> sfUri( uriRef
, UNO_QUERY
);
257 if ( !uriRef
.is() || !sfUri
.is() )
259 OUString errorMsg
= "Incorrect format for Script URI: ";
260 errorMsg
= errorMsg
.concat( scriptURI
);
261 throw provider::ScriptFrameworkErrorException(
262 errorMsg
, Reference
< XInterface
>(),
264 provider::ScriptFrameworkErrorType::UNKNOWN
);
267 OUString
langKey("language");
268 OUString
locKey("location");
270 if ( sfUri
->hasParameter( langKey
) == sal_False
||
271 sfUri
->hasParameter( locKey
) == sal_False
||
272 ( sfUri
->getName().isEmpty() ) )
274 OUString errorMsg
= "Incorrect format for Script URI: ";
275 errorMsg
= errorMsg
.concat( scriptURI
);
276 throw provider::ScriptFrameworkErrorException(
277 errorMsg
, Reference
< XInterface
>(),
279 provider::ScriptFrameworkErrorType::UNKNOWN
);
282 OUString language
= sfUri
->getParameter( langKey
);
283 OUString location
= sfUri
->getParameter( locKey
);
285 // if script us located in uno pkg
286 sal_Int32 index
= -1;
287 OUString
pkgTag(":uno_packages");
288 // for languages other than basic, scripts located in uno packages
289 // are merged into the user/share location context.
290 // For other languages the location attribute in script url has the form
291 // location = [user|share]:uno_packages or location :uno_pacakges/xxxx.uno.pkg
292 // we need to extract the value of location part from the
293 // location attribute of the script, if the script is located in an
294 // uno package then that is the location part up to and including
295 // ":uno_packages", if the script is not in an uno package then the
296 // normal value is used e.g. user or share.
297 // The value extracted will be used to determine if the script is
298 // located in the same location context as this MSP.
299 // For Basic, the language script provider can handle the execution of a
300 // script in any location context
301 if ( ( index
= location
.indexOf( pkgTag
) ) > -1 )
303 location
= location
.copy( 0, index
+ pkgTag
.getLength() );
306 Reference
< provider::XScript
> xScript
;
308 // If the script location is in the same location context as this
309 // MSP then delate to the lanaguage provider controlled by this MSP
310 // ** Special case is BASIC, all calls to getScript will be handled
311 // by the language script provider in the current location context
312 // even if its different
313 if ( ( location
== "document"
316 || ( endsWith( m_sCtxString
, location
) )
317 || ( language
== "Basic" )
320 Reference
< provider::XScriptProvider
> xScriptProvider
;
321 OUStringBuffer
buf( 80 );
322 buf
.appendAscii( "com.sun.star.script.provider.ScriptProviderFor");
323 buf
.append( language
);
324 OUString serviceName
= buf
.makeStringAndClear();
325 if ( providerCache() )
330 providerCache()->getProvider( serviceName
),
333 catch( const Exception
& e
)
335 throw provider::ScriptFrameworkErrorException(
336 e
.Message
, Reference
< XInterface
>(),
337 sfUri
->getName(), language
,
338 provider::ScriptFrameworkErrorType::NOTSUPPORTED
);
343 throw provider::ScriptFrameworkErrorException(
344 "No LanguageProviders detected",
345 Reference
< XInterface
>(),
346 sfUri
->getName(), language
,
347 provider::ScriptFrameworkErrorType::NOTSUPPORTED
);
349 xScript
=xScriptProvider
->getScript( scriptURI
);
353 Reference
< provider::XScriptProviderFactory
> xFac_
=
354 provider::theMasterScriptProviderFactory::get( m_xContext
);
356 Reference
< provider::XScriptProvider
> xSP(
357 xFac_
->createScriptProvider( makeAny( location
) ), UNO_QUERY_THROW
);
358 xScript
= xSP
->getScript( scriptURI
);
367 MasterScriptProvider::providerCache()
371 ::osl::MutexGuard
aGuard( m_mutex
);
374 OUString serviceName1
= "com.sun.star.script.provider.ScriptProviderForBasic";
375 Sequence
< OUString
> blacklist(1);
376 blacklist
[ 0 ] = serviceName1
;
380 m_pPCache
= new ProviderCache( m_xContext
, m_sAargs
);
384 m_pPCache
= new ProviderCache( m_xContext
, m_sAargs
, blacklist
);
394 MasterScriptProvider::getName()
395 throw ( css::uno::RuntimeException
, std::exception
)
397 if ( !isPkgProvider() )
399 OUString sCtx
= getContextString();
400 if ( sCtx
.startsWith( "vnd.sun.star.tdoc" ) )
402 Reference
< frame::XModel
> xModel
= m_xModel
;
405 xModel
= MiscUtils::tDocUrlToModel( sCtx
);
408 m_sNodeName
= ::comphelper::DocumentInfo::getDocumentTitle( xModel
);
412 m_sNodeName
= parseLocationName( getContextString() );
417 m_sNodeName
= "uno_packages";
423 Sequence
< Reference
< browse::XBrowseNode
> > SAL_CALL
424 MasterScriptProvider::getChildNodes()
425 throw ( css::uno::RuntimeException
, std::exception
)
427 Sequence
< Reference
< provider::XScriptProvider
> > providers
= getAllProviders();
429 Reference
< provider::XScriptProvider
> pkgProv
= getPkgProvider();
430 sal_Int32 size
= providers
.getLength();
431 bool hasPkgs
= pkgProv
.is();
436 Sequence
< Reference
< browse::XBrowseNode
> > children( size
);
437 sal_Int32 provIndex
= 0;
438 for ( ; provIndex
< providers
.getLength(); provIndex
++ )
440 children
[ provIndex
] = Reference
< browse::XBrowseNode
>( providers
[ provIndex
], UNO_QUERY
);
445 children
[ provIndex
] = Reference
< browse::XBrowseNode
>( pkgProv
, UNO_QUERY
);
454 MasterScriptProvider::hasChildNodes()
455 throw ( css::uno::RuntimeException
, std::exception
)
462 MasterScriptProvider::getType()
463 throw ( css::uno::RuntimeException
, std::exception
)
465 return browse::BrowseNodeTypes::CONTAINER
;
471 MasterScriptProvider::parseLocationName( const OUString
& location
)
473 // strip out the last leaf of location name
474 // e.g. file://dir1/dir2/Blah.sxw - > Blah.sxw
475 OUString temp
= location
;
476 INetURLObject
aURLObj( temp
);
477 if ( !aURLObj
.HasError() )
478 temp
= aURLObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
485 MasterScriptProvider::insertByName( const OUString
& aName
, const Any
& aElement
) throw ( lang::IllegalArgumentException
, container::ElementExistException
, lang::WrappedTargetException
, css::uno::RuntimeException
, std::exception
)
489 if ( m_xMSPPkg
.is() )
491 Reference
< container::XNameContainer
> xCont( m_xMSPPkg
, UNO_QUERY
);
494 throw RuntimeException(
495 "PackageMasterScriptProvider doesn't implement XNameContainer" );
497 xCont
->insertByName( aName
, aElement
);
501 throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
507 Reference
< deployment::XPackage
> xPkg( aElement
, UNO_QUERY
);
510 throw lang::IllegalArgumentException( "Couldn't convert to XPackage",
511 Reference
< XInterface
> (), 2 );
513 if ( aName
.isEmpty() )
515 throw lang::IllegalArgumentException( "Name not set!!",
516 Reference
< XInterface
> (), 1 );
518 // TODO for library pacakge parse the language, for the moment will try
519 // to get each provider to process the new Package, the first one the succeeds
520 // will terminate processing
521 if ( !providerCache() )
523 throw RuntimeException(
524 "insertByName cannot instantiate "
525 "child script providers." );
527 Sequence
< Reference
< provider::XScriptProvider
> > xSProviders
=
528 providerCache()->getAllProviders();
531 for ( ; index
< xSProviders
.getLength(); index
++ )
533 Reference
< container::XNameContainer
> xCont( xSProviders
[ index
], UNO_QUERY
);
540 xCont
->insertByName( aName
, aElement
);
543 catch ( Exception
& e
)
546 "scripting.provider", "ignoring Exception " << e
.Message
);
550 if ( index
== xSProviders
.getLength() )
552 // No script providers could process the package
553 OUString message
= "Failed to register package for ";
554 message
= message
.concat( aName
);
555 throw lang::IllegalArgumentException( message
,
556 Reference
< XInterface
> (), 2 );
564 MasterScriptProvider::removeByName( const OUString
& Name
) throw ( container::NoSuchElementException
, lang::WrappedTargetException
, RuntimeException
, std::exception
)
568 if ( m_xMSPPkg
.is() )
570 Reference
< container::XNameContainer
> xCont( m_xMSPPkg
, UNO_QUERY
);
573 throw RuntimeException(
574 "PackageMasterScriptProvider doesn't implement XNameContainer" );
576 xCont
->removeByName( Name
);
580 throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
586 if ( Name
.isEmpty() )
588 throw lang::IllegalArgumentException( "Name not set!!",
589 Reference
< XInterface
> (), 1 );
591 // TODO for Script library pacakge url parse the language,
592 // for the moment will just try to get each provider to process remove/revoke
593 // request, the first one the succeeds will terminate processing
595 if ( !providerCache() )
597 throw RuntimeException(
598 "removeByName() cannot instantiate "
599 "child script providers." );
601 Sequence
< Reference
< provider::XScriptProvider
> > xSProviders
=
602 providerCache()->getAllProviders();
604 for ( ; index
< xSProviders
.getLength(); index
++ )
606 Reference
< container::XNameContainer
> xCont( xSProviders
[ index
], UNO_QUERY
);
613 xCont
->removeByName( Name
);
621 if ( index
== xSProviders
.getLength() )
623 // No script providers could process the package
624 OUString message
= "Failed to revoke package for ";
625 message
= message
.concat( Name
);
626 throw lang::IllegalArgumentException( message
,
627 Reference
< XInterface
> (), 1 );
635 MasterScriptProvider::replaceByName( const OUString
& aName
, const Any
& aElement
) throw ( lang::IllegalArgumentException
, container::NoSuchElementException
, lang::WrappedTargetException
, RuntimeException
, std::exception
)
640 // TODO needs implementing
643 throw RuntimeException( "replaceByName not implemented!!!!" );
648 MasterScriptProvider::getByName( const OUString
& aName
) throw ( container::NoSuchElementException
, lang::WrappedTargetException
, RuntimeException
, std::exception
)
652 // TODO needs to be implemented
656 throw RuntimeException( "getByName not implemented!!!!" );
662 MasterScriptProvider::hasByName( const OUString
& aName
) throw (RuntimeException
, std::exception
)
667 if ( m_xMSPPkg
.is() )
669 Reference
< container::XNameContainer
> xCont( m_xMSPPkg
, UNO_QUERY
);
672 throw RuntimeException(
673 "PackageMasterScriptProvider doesn't implement XNameContainer" );
676 result
= xCont
->hasByName( aName
);
678 // If this is a document provider then we shouldn't
679 // have a PackageProvider
680 else if (!m_xModel
.is())
682 throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
688 if ( aName
.isEmpty() )
690 throw lang::IllegalArgumentException( "Name not set!!",
691 Reference
< XInterface
> (), 1 );
693 // TODO for Script library pacakge url parse the language,
694 // for the moment will just try to get each provider to see if the
695 // package exists in any provider, first one that succeed will
696 // terminate the loop
698 if ( !providerCache() )
700 throw RuntimeException(
701 "removeByName() cannot instantiate "
702 "child script providers." );
704 Sequence
< Reference
< provider::XScriptProvider
> > xSProviders
=
705 providerCache()->getAllProviders();
706 for ( sal_Int32 index
= 0; index
< xSProviders
.getLength(); index
++ )
708 Reference
< container::XNameContainer
> xCont( xSProviders
[ index
], UNO_QUERY
);
715 result
= xCont
->hasByName( aName
);
731 Sequence
< OUString
> SAL_CALL
732 MasterScriptProvider::getElementNames( ) throw ( RuntimeException
, std::exception
)
734 // TODO needs implementing
735 Sequence
< OUString
> names
;
738 throw RuntimeException( "getElementNames not implemented!!!!" );
744 MasterScriptProvider::getElementType( ) throw ( RuntimeException
, std::exception
)
746 // TODO needs implementing
751 sal_Bool SAL_CALL
MasterScriptProvider::hasElements( ) throw ( RuntimeException
, std::exception
)
753 // TODO needs implementing
756 throw RuntimeException( "hasElements not implemented!!!!" );
762 Sequence
< Reference
< provider::XScriptProvider
> > SAL_CALL
763 MasterScriptProvider::getAllProviders() throw ( css::uno::RuntimeException
)
765 if ( providerCache() )
767 return providerCache()->getAllProviders();
772 "MasterScriptProvider::getAllProviders, cache not initialised");
773 throw RuntimeException( errorMsg
.concat( errorMsg
) );
779 OUString SAL_CALL
MasterScriptProvider::getImplementationName( )
780 throw( RuntimeException
, std::exception
)
782 return OUString( "com.sun.star.script.provider.MasterScriptProvider" );
785 sal_Bool SAL_CALL
MasterScriptProvider::supportsService( const OUString
& serviceName
)
786 throw( RuntimeException
, std::exception
)
788 return cppu::supportsService(this, serviceName
);
792 Sequence
< OUString
> SAL_CALL
MasterScriptProvider::getSupportedServiceNames( )
793 throw( RuntimeException
, std::exception
)
797 names
[0] = "com.sun.star.script.provider.MasterScriptProvider";
798 names
[1] = "com.sun.star.script.browse.BrowseNode";
799 names
[2] = "com.sun.star.script.provider.ScriptProvider";
801 return Sequence
< OUString
>( names
, 3 );
804 } // namespace func_provider
807 namespace scripting_runtimemgr
810 Reference
< XInterface
> SAL_CALL
sp_create(
811 const Reference
< XComponentContext
> & xCompC
)
813 return ( cppu::OWeakObject
* ) new ::func_provider::MasterScriptProvider( xCompC
);
817 Sequence
< OUString
> sp_getSupportedServiceNames( )
821 names
[0] = "com.sun.star.script.provider.MasterScriptProvider";
822 names
[1] = "com.sun.star.script.browse.BrowseNode";
823 names
[2] = "com.sun.star.script.provider.ScriptProvider";
825 return Sequence
< OUString
>( names
, 3 );
829 OUString
sp_getImplementationName( )
831 return OUString( "com.sun.star.script.provider.MasterScriptProvider" );
834 // ***** registration or ScriptingFrameworkURIHelper
835 Reference
< XInterface
> SAL_CALL
urihelper_create(
836 const Reference
< XComponentContext
> & xCompC
)
838 return ( cppu::OWeakObject
* )
839 new ::func_provider::ScriptingFrameworkURIHelper( xCompC
);
842 Sequence
< OUString
> urihelper_getSupportedServiceNames( )
844 OUString serviceNameList
[] = {
846 "com.sun.star.script.provider.ScriptURIHelper" ) };
848 Sequence
< OUString
> serviceNames
= Sequence
<
849 OUString
> ( serviceNameList
, 1 );
854 OUString
urihelper_getImplementationName( )
857 "com.sun.star.script.provider.ScriptURIHelper");
860 static const struct cppu::ImplementationEntry s_entries
[] =
863 sp_create
, sp_getImplementationName
,
864 sp_getSupportedServiceNames
, cppu::createSingleComponentFactory
,
869 urihelper_getImplementationName
,
870 urihelper_getSupportedServiceNames
,
871 cppu::createSingleComponentFactory
,
875 func_provider::mspf_create
, func_provider::mspf_getImplementationName
,
876 func_provider::mspf_getSupportedServiceNames
, cppu::createSingleComponentFactory
,
880 browsenodefactory::bnf_create
, browsenodefactory::bnf_getImplementationName
,
881 browsenodefactory::bnf_getSupportedServiceNames
, cppu::createSingleComponentFactory
,
889 //#### EXPORTED ##############################################################
895 * This function is called to get service factories for an implementation.
897 * @param pImplName name of implementation
898 * @param pServiceManager a service manager, need for component creation
899 * @param pRegistryKey the registry key for this component, need for persistent
901 * @return a component factory
903 SAL_DLLPUBLIC_EXPORT
void * SAL_CALL
scriptframe_component_getFactory(
904 const sal_Char
* pImplName
,
905 void * pServiceManager
,
906 void * pRegistryKey
)
908 return ::cppu::component_getFactoryHelper( pImplName
, pServiceManager
,
909 pRegistryKey
, ::scripting_runtimemgr::s_entries
);
913 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */