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 <dispatch/servicehandler.hxx>
23 #include <com/sun/star/frame/DispatchResultState.hpp>
24 #include <com/sun/star/task/XJobExecutor.hpp>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <comphelper/diagnose_ex.hxx>
28 #include <cppuhelper/supportsservice.hxx>
33 constexpr OUString PROTOCOL_VALUE
= u
"service:"_ustr
;
35 // XInterface, XTypeProvider, XServiceInfo
37 OUString SAL_CALL
ServiceHandler::getImplementationName()
39 return u
"com.sun.star.comp.framework.ServiceHandler"_ustr
;
42 sal_Bool SAL_CALL
ServiceHandler::supportsService( const OUString
& sServiceName
)
44 return cppu::supportsService(this, sServiceName
);
47 css::uno::Sequence
< OUString
> SAL_CALL
ServiceHandler::getSupportedServiceNames()
49 return { SERVICENAME_PROTOCOLHANDLER
};
55 @descr This initializes a new instance of this class with needed information for work.
58 reference to uno servicemanager for creation of new services
60 ServiceHandler::ServiceHandler( css::uno::Reference
< css::uno::XComponentContext
> xContext
)
61 : m_xContext (std::move( xContext
))
68 ServiceHandler::~ServiceHandler()
73 @short decide if this dispatch implementation can be used for requested URL or not
74 @descr A protocol handler is registered for a URL pattern inside configuration and will
75 be asked by the generic dispatch mechanism inside framework, if he can handle this
76 special URL which match his registration. He can agree by returning of a valid dispatch
77 instance or disagree by returning <NULL/>.
78 We don't create new dispatch instances here really - we return THIS as result to handle it
79 at the same implementation.
81 css::uno::Reference
< css::frame::XDispatch
> SAL_CALL
ServiceHandler::queryDispatch( const css::util::URL
& aURL
,
82 const OUString
& /*sTarget*/ ,
83 sal_Int32
/*nFlags*/ )
85 css::uno::Reference
< css::frame::XDispatch
> xDispatcher
;
86 if (aURL
.Complete
.startsWith(PROTOCOL_VALUE
))
92 @short do the same like dispatch() but for multiple requests at the same time
94 css::uno::Sequence
< css::uno::Reference
< css::frame::XDispatch
> > SAL_CALL
ServiceHandler::queryDispatches( const css::uno::Sequence
< css::frame::DispatchDescriptor
>& lDescriptor
)
96 sal_Int32 nCount
= lDescriptor
.getLength();
97 css::uno::Sequence
< css::uno::Reference
< css::frame::XDispatch
> > lDispatcher( nCount
);
98 auto lDispatcherRange
= asNonConstRange(lDispatcher
);
99 for( sal_Int32 i
=0; i
<nCount
; ++i
)
101 lDispatcherRange
[i
] = queryDispatch(
102 lDescriptor
[i
].FeatureURL
,
103 lDescriptor
[i
].FrameName
,
104 lDescriptor
[i
].SearchFlags
);
110 @short dispatch URL with arguments
111 @descr We use threadsafe internal method to do so. It returns a state value - but we ignore it.
112 Because we don't support status listener notifications here.
115 uno URL which should be executed
117 list of optional arguments for this request
119 void SAL_CALL
ServiceHandler::dispatch( const css::util::URL
& aURL
,
120 const css::uno::Sequence
< css::beans::PropertyValue
>& /*lArguments*/ )
122 // dispatch() is an [oneway] call ... and may our user release his reference to us immediately.
123 // So we should hold us self alive till this call ends.
124 css::uno::Reference
< css::frame::XNotifyingDispatch
> xSelfHold(this);
125 implts_dispatch(aURL
);
126 // No notification for status listener!
130 @short dispatch with guaranteed notifications about success
131 @descr We use threadsafe internal method to do so. Return state of this function will be used
132 for notification if an optional listener is given.
135 uno URL which should be executed
137 list of optional arguments for this request
139 optional listener for state events
141 void SAL_CALL
ServiceHandler::dispatchWithNotification( const css::util::URL
& aURL
,
142 const css::uno::Sequence
< css::beans::PropertyValue
>& /*lArguments*/,
143 const css::uno::Reference
< css::frame::XDispatchResultListener
>& xListener
)
145 // This class was designed to die by reference. And if user release his reference to us immediately after calling this method
146 // we can run into some problems. So we hold us self alive till this method ends.
147 // Another reason: We can use this reference as source of sending event at the end too.
148 css::uno::Reference
< css::frame::XNotifyingDispatch
> xThis(this);
150 css::uno::Reference
< css::uno::XInterface
> xService
= implts_dispatch(aURL
);
153 css::frame::DispatchResultEvent aEvent
;
155 aEvent
.State
= css::frame::DispatchResultState::SUCCESS
;
157 aEvent
.State
= css::frame::DispatchResultState::FAILURE
;
158 aEvent
.Result
<<= xService
; // may NULL for state=FAILED!
159 aEvent
.Source
= xThis
;
161 xListener
->dispatchFinished( aEvent
);
166 @short threadsafe helper for dispatch calls
167 @descr We support two interfaces for the same process - dispatch URLs. That the reason for this internal
168 function. It implements the real dispatch operation and returns a state value which inform caller
169 about success. He can notify listener then by using this return value.
172 uno URL which should be executed
174 @return <NULL/> if requested service couldn't be created successfully;
175 a valid reference otherwise. This return value can be used to indicate,
176 if dispatch was successful.
178 css::uno::Reference
< css::uno::XInterface
> ServiceHandler::implts_dispatch( const css::util::URL
& aURL
)
180 // extract service name and may optional given parameters from given URL
181 // and use it to create and start the component
182 OUString sServiceAndArguments
= aURL
.Complete
.copy(PROTOCOL_VALUE
.getLength());
183 OUString sServiceName
;
186 sal_Int32 nArgStart
= sServiceAndArguments
.indexOf('?');
189 sServiceName
= sServiceAndArguments
.copy(0,nArgStart
);
190 ++nArgStart
; // ignore '?'!
191 sArguments
= sServiceAndArguments
.copy(nArgStart
);
195 sServiceName
= sServiceAndArguments
;
198 if (sServiceName
.isEmpty())
199 return css::uno::Reference
< css::uno::XInterface
>();
201 // If a service doesn't support an optional job executor interface - he can't get
202 // any given parameters!
203 // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ...
205 css::uno::Reference
< css::uno::XInterface
> xService
;
208 // => a) a service starts running inside his own ctor and we create it only
209 xService
= m_xContext
->getServiceManager()->createInstanceWithContext(sServiceName
, m_xContext
);
210 // or b) he implements the right interface and starts there (may with optional parameters)
211 css::uno::Reference
< css::task::XJobExecutor
> xExecutable(xService
, css::uno::UNO_QUERY
);
212 if (xExecutable
.is())
213 xExecutable
->trigger(sArguments
);
215 // ignore all errors - inclusive runtime errors!
216 // E.g. a script based service (written in Python) could not be executed
217 // because it contains syntax errors, which was detected at runtime...
218 catch(const css::uno::Exception
&)
220 TOOLS_WARN_EXCEPTION("fwk.dispatch", "ignored");
228 @short add/remove listener for state events
229 @descr We use an internal container to hold such registered listener. This container lives if we live.
230 And if call pass registration as non breakable transaction - we can accept the request without
231 any explicit lock. Because we share our mutex with this container.
234 reference to a valid listener for state events
236 URL about listener will be informed, if something occurred
238 void SAL_CALL
ServiceHandler::addStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*xListener*/ ,
239 const css::util::URL
& /*aURL*/ )
244 void SAL_CALL
ServiceHandler::removeStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*xListener*/ ,
245 const css::util::URL
& /*aURL*/ )
250 } // namespace framework
253 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
254 framework_ServiceHandler_get_implementation(
255 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const& )
257 return cppu::acquire(new framework::ServiceHandler(context
));
260 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */