1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: scripthandler.cxx,v $
10 * $Revision: 1.29.6.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_scripting.hxx"
33 #include "scripthandler.hxx"
35 #include <osl/mutex.hxx>
37 #include <com/sun/star/frame/DispatchResultEvent.hpp>
38 #include <com/sun/star/frame/DispatchResultState.hpp>
39 #include <com/sun/star/frame/XController.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
42 #include <com/sun/star/document/XEmbeddedScripts.hpp>
43 #include <com/sun/star/document/XScriptInvocationContext.hpp>
45 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
47 #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
48 #include <com/sun/star/script/provider/XScriptProviderFactory.hpp>
49 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
51 #include <sfx2/objsh.hxx>
52 #include <sfx2/frame.hxx>
53 #include <sfx2/sfxdlg.hxx>
54 #include <vcl/abstdlg.hxx>
56 #include <cppuhelper/factory.hxx>
57 #include <cppuhelper/exc_hlp.hxx>
58 #include <util/util.hxx>
60 #include "com/sun/star/uno/XComponentContext.hpp"
61 #include "com/sun/star/uri/XUriReference.hpp"
62 #include "com/sun/star/uri/XUriReferenceFactory.hpp"
63 #include "com/sun/star/uri/XVndSunStarScriptUrl.hpp"
64 #include "com/sun/star/beans/XPropertySet.hpp"
66 using namespace ::com::sun::star
;
67 using namespace ::com::sun::star::uno
;
68 using namespace ::com::sun::star::frame
;
69 using namespace ::com::sun::star::util
;
70 using namespace ::com::sun::star::beans
;
71 using namespace ::com::sun::star::lang
;
72 using namespace ::com::sun::star::script
;
73 using namespace ::com::sun::star::script::provider
;
74 using namespace ::com::sun::star::document
;
75 using namespace ::scripting_util
;
77 namespace scripting_protocolhandler
80 const sal_Char
* const MYSERVICENAME
= "com.sun.star.frame.ProtocolHandler";
81 const sal_Char
* const MYIMPLNAME
= "com.sun.star.comp.ScriptProtocolHandler";
82 const sal_Char
* MYSCHEME
= "vnd.sun.star.script";
83 const sal_Int32 MYSCHEME_LEN
= 20;
85 void SAL_CALL
ScriptProtocolHandler::initialize(
86 const css::uno::Sequence
< css::uno::Any
>& aArguments
)
87 throw ( css::uno::Exception
)
94 // first argument contains a reference to the frame (may be empty or the desktop,
95 // but usually it's a "real" frame)
96 if ( aArguments
.getLength() &&
97 sal_False
== ( aArguments
[ 0 ] >>= m_xFrame
) )
99 ::rtl::OUString temp
= OUSTR( "ScriptProtocolHandler::initialize: could not extract reference to the frame" );
100 throw RuntimeException( temp
, Reference
< XInterface
>() );
103 validateXRef( m_xFactory
,
104 "ScriptProtocolHandler::initialize: No Service Manager available" );
105 m_bInitialised
= true;
108 Reference
< XDispatch
> SAL_CALL
ScriptProtocolHandler::queryDispatch(
109 const URL
& aURL
, const ::rtl::OUString
& sTargetFrameName
, sal_Int32 nSearchFlags
)
110 throw( ::com::sun::star::uno::RuntimeException
)
112 (void)sTargetFrameName
;
115 Reference
< XDispatch
> xDispatcher
;
118 Reference
< uri::XUriReferenceFactory
> xFac (
119 m_xFactory
->createInstance( rtl::OUString::createFromAscii(
120 "com.sun.star.uri.UriReferenceFactory") ) , UNO_QUERY
);
123 Reference
< uri::XUriReference
> uriRef(
124 xFac
->parse( aURL
.Complete
), UNO_QUERY
);
127 if ( uriRef
->getScheme().equals( ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYSCHEME
) ) )
137 Sequence
< Reference
< XDispatch
> > SAL_CALL
138 ScriptProtocolHandler::queryDispatches(
139 const Sequence
< DispatchDescriptor
>& seqDescriptor
)
140 throw( RuntimeException
)
142 sal_Int32 nCount
= seqDescriptor
.getLength();
143 Sequence
< Reference
< XDispatch
> > lDispatcher( nCount
);
144 for ( sal_Int32 i
= 0; i
< nCount
; ++i
)
146 lDispatcher
[ i
] = this->queryDispatch( seqDescriptor
[ i
].FeatureURL
,
147 seqDescriptor
[ i
].FrameName
,
148 seqDescriptor
[ i
].SearchFlags
);
153 void SAL_CALL
ScriptProtocolHandler::dispatchWithNotification(
154 const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
,
155 const Reference
< XDispatchResultListener
>& xListener
)
156 throw ( RuntimeException
)
159 sal_Bool bSuccess
= sal_False
;
161 bool bCaughtException
= FALSE
;
164 if ( m_bInitialised
)
168 bool bIsDocumentScript
= ( aURL
.Complete
.indexOf( ::rtl::OUString::createFromAscii( "document" ) ) !=-1 );
169 // TODO: isn't this somewhat strange? This should be a test for a location=document parameter, shouldn't it?
171 if ( bIsDocumentScript
)
173 // obtain the component for our security check
174 Reference
< XEmbeddedScripts
> xDocumentScripts
;
175 if ( getScriptInvocation() )
176 xDocumentScripts
.set( m_xScriptInvocation
->getScriptContainer(), UNO_SET_THROW
);
178 OSL_ENSURE( xDocumentScripts
.is(), "ScriptProtocolHandler::dispatchWithNotification: can't do the security check!" );
179 if ( !xDocumentScripts
.is() || !xDocumentScripts
->getAllowMacroExecution() )
183 // Creates a ScriptProvider ( if one is not created allready )
184 createScriptProvider();
186 Reference
< provider::XScript
> xFunc
=
187 m_xScriptProvider
->getScript( aURL
.Complete
);
189 "ScriptProtocolHandler::dispatchWithNotification: validate xFunc - unable to obtain XScript interface" );
192 Sequence
< Any
> inArgs( 0 );
193 Sequence
< Any
> outArgs( 0 );
194 Sequence
< sal_Int16
> outIndex
;
196 if ( lArgs
.getLength() > 0 )
199 for ( int index
= 0; index
< lArgs
.getLength(); index
++ )
201 // Sometimes we get a propertyval with name = "Referer"
202 // this is not an argument to be passed to script, so
204 if ( lArgs
[ index
].Name
.compareToAscii("Referer") != 0 ||
205 lArgs
[ index
].Name
.getLength() == 0 )
207 inArgs
.realloc( ++argCount
);
208 inArgs
[ argCount
- 1 ] = lArgs
[ index
].Value
;
213 bSuccess
= sal_False
;
216 Any aFirstCaughtException
;
219 invokeResult
= xFunc
->invoke( inArgs
, outIndex
, outArgs
);
222 catch( const provider::ScriptFrameworkErrorException
& se
)
224 if ( !aFirstCaughtException
.hasValue() )
225 aFirstCaughtException
= ::cppu::getCaughtException();
227 if ( se
.errorType
!= provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT
)
228 // the only condition which allows us to retry is if there is no method with the
229 // given name/signature
230 ::cppu::throwException( aFirstCaughtException
);
232 if ( inArgs
.getLength() == 0 )
233 // no chance to retry if we can't strip more in-args
234 ::cppu::throwException( aFirstCaughtException
);
236 // strip one argument, then retry
237 inArgs
.realloc( inArgs
.getLength() - 1 );
241 // Office doesn't handle exceptions rethrown here very well, it cores,
242 // all we can is log them and then set fail for the dispatch event!
243 // (if there is a listener of course)
244 catch ( const Exception
& e
)
246 aException
= ::cppu::getCaughtException();
248 ::rtl::OUString reason
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScriptProtocolHandler::dispatch: caught " ) );
250 invokeResult
<<= reason
.concat( aException
.getValueTypeName() ).concat( e
.Message
);
252 bCaughtException
= TRUE
;
257 ::rtl::OUString reason
= ::rtl::OUString::createFromAscii(
258 "ScriptProtocolHandler::dispatch: caught unknown exception" );
260 invokeResult
<<= reason
;
267 ::rtl::OUString reason
= ::rtl::OUString::createFromAscii(
268 "ScriptProtocolHandler::dispatchWithNotification failed, ScriptProtocolHandler not initialised"
270 invokeResult
<<= reason
;
273 if ( bCaughtException
)
275 SfxAbstractDialogFactory
* pFact
= SfxAbstractDialogFactory::Create();
279 VclAbstractDialog
* pDlg
=
280 pFact
->CreateScriptErrorDialog( NULL
, aException
);
290 if ( xListener
.is() )
292 // always call dispatchFinished(), because we didn't load a document but
293 // executed a macro instead!
294 ::com::sun::star::frame::DispatchResultEvent aEvent
;
296 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
297 aEvent
.Result
= invokeResult
;
300 aEvent
.State
= ::com::sun::star::frame::DispatchResultState::SUCCESS
;
304 aEvent
.State
= ::com::sun::star::frame::DispatchResultState::FAILURE
;
309 xListener
->dispatchFinished( aEvent
) ;
311 catch(RuntimeException
& e
)
314 "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
315 "while dispatchFinished %s",
316 ::rtl::OUStringToOString( e
.Message
,
317 RTL_TEXTENCODING_ASCII_US
).pData
->buffer
);
322 void SAL_CALL
ScriptProtocolHandler::dispatch(
323 const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
)
324 throw ( RuntimeException
)
326 dispatchWithNotification( aURL
, lArgs
, Reference
< XDispatchResultListener
>() );
329 void SAL_CALL
ScriptProtocolHandler::addStatusListener(
330 const Reference
< XStatusListener
>& xControl
, const URL
& aURL
)
331 throw ( RuntimeException
)
336 // implement if status is supported
339 void SAL_CALL
ScriptProtocolHandler::removeStatusListener(
340 const Reference
< XStatusListener
>& xControl
, const URL
& aURL
)
341 throw ( RuntimeException
)
348 ScriptProtocolHandler::getScriptInvocation()
350 if ( !m_xScriptInvocation
.is() && m_xFrame
.is() )
352 Reference
< XController
> xController
= m_xFrame
->getController();
353 if ( xController
.is() )
355 // try to obtain an XScriptInvocationContext interface, preferred from the
356 // mode, then from the controller
357 if ( !m_xScriptInvocation
.set( xController
->getModel(), UNO_QUERY
) )
358 m_xScriptInvocation
.set( xController
, UNO_QUERY
);
361 return m_xScriptInvocation
.is();
365 ScriptProtocolHandler::createScriptProvider()
367 if ( m_xScriptProvider
.is() )
373 // first, ask the component supporting the XScriptInvocationContext interface
374 // (if there is one) for a script provider
375 if ( getScriptInvocation() )
377 Reference
< XScriptProviderSupplier
> xSPS( m_xScriptInvocation
, UNO_QUERY
);
379 m_xScriptProvider
= xSPS
->getScriptProvider();
382 // second, ask the model in our frame
383 if ( !m_xScriptProvider
.is() && m_xFrame
.is() )
385 Reference
< XController
> xController
= m_xFrame
->getController();
386 if ( xController
.is() )
388 Reference
< XScriptProviderSupplier
> xSPS( xController
->getModel(), UNO_QUERY
);
390 m_xScriptProvider
= xSPS
->getScriptProvider();
395 // as a fallback, ask the controller
396 if ( !m_xScriptProvider
.is() && m_xFrame
.is() )
398 Reference
< XScriptProviderSupplier
> xSPS( m_xFrame
->getController(), UNO_QUERY
);
400 m_xScriptProvider
= xSPS
->getScriptProvider();
403 if ( !m_xScriptProvider
.is() )
405 Reference
< XPropertySet
> xProps( m_xFactory
, UNO_QUERY_THROW
);
408 RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
410 Reference
< XComponentContext
> xCtx(
411 xProps
->getPropertyValue( dc
), UNO_QUERY_THROW
);
413 ::rtl::OUString tmspf
= ::rtl::OUString::createFromAscii(
414 "/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory");
416 Reference
< provider::XScriptProviderFactory
> xFac(
417 xCtx
->getValueByName( tmspf
), UNO_QUERY_THROW
);
420 if ( getScriptInvocation() )
421 aContext
= makeAny( m_xScriptInvocation
);
422 m_xScriptProvider
= Reference
< provider::XScriptProvider
> (
423 xFac
->createScriptProvider( aContext
), UNO_QUERY_THROW
);
426 catch ( RuntimeException
& e
)
428 ::rtl::OUString temp
= OUSTR( "ScriptProtocolHandler::createScriptProvider(), " );
429 throw RuntimeException( temp
.concat( e
.Message
), Reference
< XInterface
>() );
431 catch ( Exception
& e
)
433 ::rtl::OUString temp
= OUSTR( "ScriptProtocolHandler::createScriptProvider: " );
434 throw RuntimeException( temp
.concat( e
.Message
), Reference
< XInterface
>() );
439 throw RuntimeException(
440 OUSTR( "ScriptProtocolHandler::createScriptProvider: UnknownException: " ),
441 Reference
< XInterface
> () );
447 ScriptProtocolHandler::ScriptProtocolHandler(
448 Reference
< css::lang::XMultiServiceFactory
> const& rFact
) :
449 m_bInitialised( false ), m_xFactory( rFact
)
453 ScriptProtocolHandler::~ScriptProtocolHandler()
458 ::rtl::OUString SAL_CALL
ScriptProtocolHandler::getImplementationName( )
459 throw( RuntimeException
)
461 return impl_getStaticImplementationName();
465 sal_Bool SAL_CALL
ScriptProtocolHandler::supportsService(
466 const ::rtl::OUString
& sServiceName
)
467 throw( RuntimeException
)
469 Sequence
< ::rtl::OUString
> seqServiceNames
= getSupportedServiceNames();
470 const ::rtl::OUString
* pArray
= seqServiceNames
.getConstArray();
471 for ( sal_Int32 nCounter
= 0; nCounter
< seqServiceNames
.getLength(); nCounter
++ )
473 if ( pArray
[ nCounter
] == sServiceName
)
483 Sequence
< ::rtl::OUString
> SAL_CALL
ScriptProtocolHandler::getSupportedServiceNames()
484 throw( RuntimeException
)
486 return impl_getStaticSupportedServiceNames();
489 /* Helper for XServiceInfo */
490 Sequence
< ::rtl::OUString
> ScriptProtocolHandler::impl_getStaticSupportedServiceNames()
492 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
493 Sequence
< ::rtl::OUString
> seqServiceNames( 1 );
494 seqServiceNames
.getArray() [ 0 ] =
495 ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYSERVICENAME
);
496 return seqServiceNames
;
499 /* Helper for XServiceInfo */
500 ::rtl::OUString
ScriptProtocolHandler::impl_getStaticImplementationName()
502 return ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYIMPLNAME
);
505 /* Helper for registry */
506 Reference
< XInterface
> SAL_CALL
ScriptProtocolHandler::impl_createInstance(
507 const Reference
< css::lang::XMultiServiceFactory
>& xServiceManager
)
508 throw( RuntimeException
)
510 return Reference
< XInterface
> ( *new ScriptProtocolHandler( xServiceManager
) );
513 /* Factory for registration */
514 Reference
< XSingleServiceFactory
> ScriptProtocolHandler::impl_createFactory(
515 const Reference
< XMultiServiceFactory
>& xServiceManager
)
517 Reference
< XSingleServiceFactory
> xReturn (
518 cppu::createSingleFactory( xServiceManager
,
519 ScriptProtocolHandler::impl_getStaticImplementationName(),
520 ScriptProtocolHandler::impl_createInstance
,
521 ScriptProtocolHandler::impl_getStaticSupportedServiceNames() )
526 } // namespace scripting_protocolhandler
528 /* exported functions for registration */
533 #define css ::com::sun::star
535 void SAL_CALL
component_getImplementationEnvironment(
536 const sal_Char
** ppEnvironmentTypeName
, uno_Environment
** ppEnvironment
)
540 *ppEnvironmentTypeName
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
543 sal_Bool SAL_CALL
component_writeInfo( void * pServiceManager
,
544 void * pRegistryKey
)
546 (void)pServiceManager
;
548 Reference
< css::registry::XRegistryKey
> xKey(
549 reinterpret_cast< css::registry::XRegistryKey
* >( pRegistryKey
) ) ;
551 ::rtl::OUString aStr
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) );
553 ::scripting_protocolhandler::ScriptProtocolHandler::impl_getStaticImplementationName();
555 aStr
+= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/UNO/SERVICES" ) );
556 Reference
< css::registry::XRegistryKey
> xNewKey
= xKey
->createKey( aStr
);
558 ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYSERVICENAME
)
564 void* SAL_CALL
component_getFactory( const sal_Char
* pImplementationName
,
565 void * pServiceManager
,
566 void * pRegistryKey
)
570 // Set default return value for this operation - if it failed.
571 void * pReturn
= NULL
;
574 ( pImplementationName
!= NULL
) &&
575 ( pServiceManager
!= NULL
)
578 // Define variables which are used in following macros.
579 ::com::sun::star::uno::Reference
<
580 ::com::sun::star::lang::XSingleServiceFactory
> xFactory
;
581 ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>
582 xServiceManager( reinterpret_cast<
583 ::com::sun::star::lang::XMultiServiceFactory
* >( pServiceManager
) ) ;
585 if ( ::scripting_protocolhandler::ScriptProtocolHandler::impl_getStaticImplementationName().equals(
586 ::rtl::OUString::createFromAscii( pImplementationName
) ) )
588 xFactory
= ::scripting_protocolhandler::ScriptProtocolHandler::impl_createFactory( xServiceManager
);
591 // Factory is valid - service was found.
595 pReturn
= xFactory
.get();
599 // Return with result of this operation.