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