1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <dispatch/servicehandler.hxx>
21#include <threadhelp/readguard.hxx>
22#include <general.h>
23#include <services.h>
24
25#include <com/sun/star/frame/DispatchResultState.hpp>
26#include <com/sun/star/task/XJobExecutor.hpp>
27
28#include <vcl/svapp.hxx>
29
30namespace framework{
31
32#define PROTOCOL_VALUE "service:"
33#define PROTOCOL_LENGTH 8
34
35//_________________________________________________________________________________________________________________
36// XInterface, XTypeProvider, XServiceInfo
37
38DEFINE_XSERVICEINFO_MULTISERVICE(ServiceHandler ,
39 ::cppu::OWeakObject ,
40 SERVICENAME_PROTOCOLHANDLER ,
41 IMPLEMENTATIONNAME_SERVICEHANDLER)
42
43DEFINE_INIT_SERVICE(ServiceHandler,
44 {
45 /*Attention
46 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
47 to create a new instance of this class by our own supported service factory.
48 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further information!
49 */
50 }
51 )
52
53//_________________________________________________________________________________________________________________
54
55/**
56 @short standard ctor
57 @descr These initialize a new instance of ths class with needed information for work.
58
59 @param xFactory
60 reference to uno servicemanager for creation of new services
61*/
62ServiceHandler::ServiceHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory )
63 // Init baseclasses first
64 : ThreadHelpBase( &Application::GetSolarMutex() )
65 // Init member
66 , m_xFactory ( xFactory )
67{
68}
69
70//_________________________________________________________________________________________________________________
71
72/**
73 @short standard dtor
74 @descr -
75*/
76ServiceHandler::~ServiceHandler()
77{
78 m_xFactory = NULL;
79}
80
81//_________________________________________________________________________________________________________________
82
83/**
84 @short decide if this dispatch implementation can be used for requested URL or not
85 @descr A protocol handler is registerd for an URL pattern inside configuration and will
86 be asked by the generic dispatch mechanism inside framework, if he can handle this
87 special URL which match his registration. He can agree by returning of a valid dispatch
88 instance or disagree by returning <NULL/>.
89 We don't create new dispatch instances here really - we return THIS as result to handle it
90 at the same implementation.
91*/
92css::uno::Reference< css::frame::XDispatch > SAL_CALL ServiceHandler::queryDispatch( const css::util::URL& aURL ,
93 const OUString& /*sTarget*/ ,
94 sal_Int32 /*nFlags*/ ) throw( css::uno::RuntimeException )
95{
96 css::uno::Reference< css::frame::XDispatch > xDispatcher;
97 if (aURL.Complete.startsWith(PROTOCOL_VALUE))
98 xDispatcher = this;
99 return xDispatcher;
100}
101
102//_________________________________________________________________________________________________________________
103
104/**
105 @short do the same like dispatch() but for multiple requests at the same time
106 @descr -
107*/
108css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL ServiceHandler::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException )
109{
110 sal_Int32 nCount = lDescriptor.getLength();
111 css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
112 for( sal_Int32 i=0; i<nCount; ++i )
113 {
114 lDispatcher[i] = this->queryDispatch(
115 lDescriptor[i].FeatureURL,
116 lDescriptor[i].FrameName,
117 lDescriptor[i].SearchFlags);
118 }
119 return lDispatcher;
120}
121
122//_________________________________________________________________________________________________________________
123
124/**
125 @short dispatch URL with arguments
126 @descr We use threadsafe internal method to do so. It returns a state value - but we ignore it.
127 Because we don't support status listener notifications here.
128
129 @param aURL
130 uno URL which should be executed
131 @param lArguments
132 list of optional arguments for this request
133*/
134void SAL_CALL ServiceHandler::dispatch( const css::util::URL& aURL ,
135 const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
136{
137 // dispatch() is an [oneway] call ... and may our user release his reference to us immediately.
138 // So we should hold us self alive till this call ends.
139 css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
140 implts_dispatch(aURL,lArguments);
141 // No notification for status listener!
142}
143
144//_________________________________________________________________________________________________________________
145
146/**
147 @short dispatch with guaranteed notifications about success
148 @descr We use threadsafe internal method to do so. Return state of this function will be used
149 for notification if an optional listener is given.
150
151 @param aURL
152 uno URL which should be executed
153 @param lArguments
154 list of optional arguments for this request
155 @param xListener
156 optional listener for state events
157*/
158void SAL_CALL ServiceHandler::dispatchWithNotification( const css::util::URL& aURL ,
159 const css::uno::Sequence< css::beans::PropertyValue >& lArguments,
160 const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException )
161{
162 // This class was designed to die by reference. And if user release his reference to us immediately after calling this method
163 // we can run into some problems. So we hold us self alive till this method ends.
164 // Another reason: We can use this reference as source of sending event at the end too.
165 css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
166
167 css::uno::Reference< css::uno::XInterface > xService = implts_dispatch(aURL,lArguments);
168 if (xListener.is())
169 {
170 css::frame::DispatchResultEvent aEvent;
171 if (xService.is())
172 aEvent.State = css::frame::DispatchResultState::SUCCESS;
173 else
174 aEvent.State = css::frame::DispatchResultState::FAILURE;
175 aEvent.Result <<= xService; // may NULL for state=FAILED!
176 aEvent.Source = xThis;
177
178 xListener->dispatchFinished( aEvent );
179 }
180}
181
182//_________________________________________________________________________________________________________________
183
184/**
185 @short threadsafe helper for dispatch calls
186 @descr We support two interfaces for the same process - dispatch URLs. That the reason for this internal
187 function. It implements the real dispatch operation and returns a state value which inform caller
188 about success. He can notify listener then by using this return value.
189
190 @param aURL
191 uno URL which should be executed
192 @param lArguments
193 list of optional arguments for this request
194
195 @return <NULL/> if requested service couldn't be created successullfy;
196 a valid reference otherwise. This return value can be used to indicate,
197 if dispatch was successfully or not.
198*/
199css::uno::Reference< css::uno::XInterface > ServiceHandler::implts_dispatch( const css::util::URL& aURL ,
200 const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/ ) throw( css::uno::RuntimeException )
201{
202 /* SAFE */
203 ReadGuard aReadLock( m_aLock );
204 css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory;
205 aReadLock.unlock();
206 /* SAFE */
207
208 if (!xFactory.is())
209 return css::uno::Reference< css::uno::XInterface >();
210
211 // extract service name and may optional given parameters from given URL
212 // and use it to create and start the component
213 OUString sServiceAndArguments = aURL.Complete.copy(PROTOCOL_LENGTH);
214 OUString sServiceName;
215 OUString sArguments ;
216
217 sal_Int32 nArgStart = sServiceAndArguments.indexOf('?',0);
218 if (nArgStart!=-1)
219 {
220 sServiceName = sServiceAndArguments.copy(0,nArgStart);
221 ++nArgStart; // ignore '?'!
222 sArguments = sServiceAndArguments.copy(nArgStart);
223 }
224 else
225 {
226 sServiceName = sServiceAndArguments;
227 }
228
229 if (sServiceName.isEmpty())
230 return css::uno::Reference< css::uno::XInterface >();
231
232 // If a service doesn't support an optional job executor interface - he can't get
233 // any given parameters!
234 // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ...
235
236 css::uno::Reference< css::uno::XInterface > xService;
237 try
238 {
239 // => a) a service starts running inside his own ctor and we create it only
240 xService = xFactory->createInstance(sServiceName);
241 // or b) he implements the right interface and starts there (may with optional parameters)
242 css::uno::Reference< css::task::XJobExecutor > xExecuteable(xService, css::uno::UNO_QUERY);
243 if (xExecuteable.is())
244 xExecuteable->trigger(sArguments);
245 }
246 // ignore all errors - inclusive runtime errors!
247 // E.g. a script based service (written in phyton) could not be executed
248 // because it contains syntax errors, which was detected at runtime ...
249 catch(const css::uno::Exception& e)
250 {
251 SAL_WARN(
252 "fwk.dispatch", "ignored UNO Exception \"" << e.Message << '"');
253 xService.clear();
254 }
255
256 return xService;
257}
258
259//_________________________________________________________________________________________________________________
260
261/**
262 @short add/remove listener for state events
263 @descr We use an internal container to hold such registered listener. This container lives if we live.
264 And if call pas registration as non breakable transaction - we can accept the request without
265 any explicit lock. Because we share our mutex with this container.
266
267 @param xListener
268 reference to a valid listener for state events
269 @param aURL
270 URL about listener will be informed, if something occurred
271*/
272void SAL_CALL ServiceHandler::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
273 const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException )
274{
275 // not suported yet
276}
277
278//_________________________________________________________________________________________________________________
279
280void SAL_CALL ServiceHandler::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
281 const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException )
282{
283 // not suported yet
284}
285
286} // namespace framework
287
288/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
289