1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //	my own includes
33 //_________________________________________________________________________________________________________________
34 #include <dispatch/servicehandler.hxx>
35 #include <threadhelp/readguard.hxx>
36 #include <general.h>
37 #include <services.h>
38 
39 //_________________________________________________________________________________________________________________
40 //	interface includes
41 //_________________________________________________________________________________________________________________
42 #include <com/sun/star/frame/DispatchResultState.hpp>
43 #include <com/sun/star/task/XJobExecutor.hpp>
44 
45 //_________________________________________________________________________________________________________________
46 //	includes of other projects
47 //_________________________________________________________________________________________________________________
48 
49 #include <vcl/svapp.hxx>
50 
51 //_________________________________________________________________________________________________________________
52 //	namespace
53 //_________________________________________________________________________________________________________________
54 
55 namespace framework{
56 
57 //_________________________________________________________________________________________________________________
58 //	non exported const
59 //_________________________________________________________________________________________________________________
60 
61 #define PROTOCOL_VALUE      "service:"
62 #define PROTOCOL_LENGTH     8
63 
64 //_________________________________________________________________________________________________________________
65 //	non exported definitions
66 //_________________________________________________________________________________________________________________
67 
68 //_________________________________________________________________________________________________________________
69 //	declarations
70 //_________________________________________________________________________________________________________________
71 
72 //_________________________________________________________________________________________________________________
73 // XInterface, XTypeProvider, XServiceInfo
74 
75 DEFINE_XINTERFACE_5(ServiceHandler                                  ,
76                     OWeakObject                                     ,
77                     DIRECT_INTERFACE(css::lang::XTypeProvider      ),
78                     DIRECT_INTERFACE(css::lang::XServiceInfo       ),
79                     DIRECT_INTERFACE(css::frame::XDispatchProvider ),
80                     DIRECT_INTERFACE(css::frame::XNotifyingDispatch),
81                     DIRECT_INTERFACE(css::frame::XDispatch         ))
82 
83 DEFINE_XTYPEPROVIDER_5(ServiceHandler                ,
84                        css::lang::XTypeProvider      ,
85                        css::lang::XServiceInfo       ,
86                        css::frame::XDispatchProvider ,
87                        css::frame::XNotifyingDispatch,
88                        css::frame::XDispatch         )
89 
90 DEFINE_XSERVICEINFO_MULTISERVICE(ServiceHandler                   ,
91                                  ::cppu::OWeakObject              ,
92                                  SERVICENAME_PROTOCOLHANDLER      ,
93                                  IMPLEMENTATIONNAME_SERVICEHANDLER)
94 
95 DEFINE_INIT_SERVICE(ServiceHandler,
96                     {
97                         /*Attention
98                             I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
99                             to create a new instance of this class by our own supported service factory.
100                             see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
101                         */
102                     }
103                    )
104 
105 //_________________________________________________________________________________________________________________
106 
107 /**
108     @short      standard ctor
109     @descr      These initialize a new instance of ths class with needed informations for work.
110 
111     @param      xFactory
112                 reference to uno servicemanager for creation of new services
113 
114     @modified   02.05.2002 08:16, as96863
115 */
116 ServiceHandler::ServiceHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory )
117 		//	Init baseclasses first
118         : ThreadHelpBase( &Application::GetSolarMutex() )
119         , OWeakObject   (                               )
120         // Init member
121         , m_xFactory    ( xFactory                      )
122 {
123 }
124 
125 //_________________________________________________________________________________________________________________
126 
127 /**
128     @short      standard dtor
129     @descr      -
130 
131     @modified   02.05.2002 08:16, as96863
132 */
133 ServiceHandler::~ServiceHandler()
134 {
135     m_xFactory = NULL;
136 }
137 
138 //_________________________________________________________________________________________________________________
139 
140 /**
141     @short      decide if this dispatch implementation can be used for requested URL or not
142     @descr      A protocol handler is registerd for an URL pattern inside configuration and will
143                 be asked by the generic dispatch mechanism inside framework, if he can handle this
144                 special URL wich match his registration. He can agree by returning of a valid dispatch
145                 instance or disagree by returning <NULL/>.
146                 We don't create new dispatch instances here realy - we return THIS as result to handle it
147                 at the same implementation.
148 
149     @modified   02.05.2002 15:25, as96863
150 */
151 css::uno::Reference< css::frame::XDispatch > SAL_CALL ServiceHandler::queryDispatch( const css::util::URL&  aURL    ,
152                                                                                      const ::rtl::OUString& /*sTarget*/ ,
153                                                                                            sal_Int32        /*nFlags*/  ) throw( css::uno::RuntimeException )
154 {
155     css::uno::Reference< css::frame::XDispatch > xDispatcher;
156     if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0)
157         xDispatcher = this;
158     return xDispatcher;
159 }
160 
161 //_________________________________________________________________________________________________________________
162 
163 /**
164     @short      do the same like dispatch() but for multiple requests at the same time
165     @descr      -
166 
167     @modified   02.05.2002 15:27, as96863
168 */
169 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 )
170 {
171     sal_Int32 nCount = lDescriptor.getLength();
172     css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
173     for( sal_Int32 i=0; i<nCount; ++i )
174     {
175         lDispatcher[i] = this->queryDispatch(
176                             lDescriptor[i].FeatureURL,
177                             lDescriptor[i].FrameName,
178                             lDescriptor[i].SearchFlags);
179     }
180     return lDispatcher;
181 }
182 
183 //_________________________________________________________________________________________________________________
184 
185 /**
186     @short      dispatch URL with arguments
187     @descr      We use threadsafe internal method to do so. It returns a state value - but we ignore it.
188                 Because we doesn't support status listener notifications here.
189 
190     @param      aURL
191                     uno URL which should be executed
192     @param      lArguments
193                     list of optional arguments for this request
194 
195     @modified   02.05.2002 08:19, as96863
196 */
197 void SAL_CALL ServiceHandler::dispatch( const css::util::URL&                                  aURL       ,
198                                     const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
199 {
200     // dispatch() is an [oneway] call ... and may our user release his reference to us immediatly.
201     // So we should hold us self alive till this call ends.
202     css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
203     implts_dispatch(aURL,lArguments);
204     // No notification for status listener!
205 }
206 
207 //_________________________________________________________________________________________________________________
208 
209 /**
210     @short      dispatch with guaranteed notifications about success
211     @descr      We use threadsafe internal method to do so. Return state of this function will be used
212                 for notification if an optional listener is given.
213 
214     @param      aURL
215                     uno URL which should be executed
216     @param      lArguments
217                     list of optional arguments for this request
218     @param      xListener
219                     optional listener for state events
220 
221     @modified   30.04.2002 14:49, as96863
222 */
223 void SAL_CALL ServiceHandler::dispatchWithNotification( const css::util::URL&                                             aURL      ,
224                                                         const css::uno::Sequence< css::beans::PropertyValue >&            lArguments,
225                                                         const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException )
226 {
227     // This class was designed to die by reference. And if user release his reference to us immediatly after calling this method
228     // we can run into some problems. So we hold us self alive till this method ends.
229     // Another reason: We can use this reference as source of sending event at the end too.
230     css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
231 
232     css::uno::Reference< css::uno::XInterface > xService = implts_dispatch(aURL,lArguments);
233     if (xListener.is())
234     {
235         css::frame::DispatchResultEvent aEvent;
236         if (xService.is())
237             aEvent.State = css::frame::DispatchResultState::SUCCESS;
238         else
239             aEvent.State = css::frame::DispatchResultState::FAILURE;
240         aEvent.Result <<= xService; // may NULL for state=FAILED!
241         aEvent.Source = xThis;
242 
243         xListener->dispatchFinished( aEvent );
244     }
245 }
246 
247 //_________________________________________________________________________________________________________________
248 
249 /**
250     @short      threadsafe helper for dispatch calls
251     @descr      We support two interfaces for the same process - dispatch URLs. That the reason for this internal
252                 function. It implements the real dispatch operation and returns a state value which inform caller
253                 about success. He can notify listener then by using this return value.
254 
255     @param      aURL
256                     uno URL which should be executed
257     @param      lArguments
258                     list of optional arguments for this request
259 
260     @return     <NULL/> if requested service couldn't be created successullfy;
261                 a valid reference otherwise. This return value can be used to indicate,
262                 if dispatch was successfully or not.
263 
264     @modified   02.05.2002 10:51, as96863
265 */
266 css::uno::Reference< css::uno::XInterface > ServiceHandler::implts_dispatch( const css::util::URL&                                  aURL       ,
267                                                                              const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/ ) throw( css::uno::RuntimeException )
268 {
269     /* SAFE */
270     ReadGuard aReadLock( m_aLock );
271     css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory;
272     aReadLock.unlock();
273     /* SAFE */
274 
275     if (!xFactory.is())
276         return css::uno::Reference< css::uno::XInterface >();
277 
278     // extract service name and may optional given parameters from given URL
279     // and use it to create and start the component
280     ::rtl::OUString sServiceAndArguments = aURL.Complete.copy(PROTOCOL_LENGTH);
281     ::rtl::OUString sServiceName;
282     ::rtl::OUString sArguments  ;
283 
284     sal_Int32 nArgStart = sServiceAndArguments.indexOf('?',0);
285     if (nArgStart!=-1)
286     {
287         sServiceName = sServiceAndArguments.copy(0,nArgStart);
288         ++nArgStart; // ignore '?'!
289         sArguments   = sServiceAndArguments.copy(nArgStart);
290     }
291     else
292     {
293         sServiceName = sServiceAndArguments;
294     }
295 
296     if (!sServiceName.getLength())
297         return css::uno::Reference< css::uno::XInterface >();
298 
299     // If a service doesnt support an optional job executor interface - he can't get
300     // any given parameters!
301     // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ...
302 
303     css::uno::Reference< css::uno::XInterface > xService;
304     try
305     {
306         // => a) a service starts running inside his own ctor and we create it only
307         xService = xFactory->createInstance(sServiceName);
308         // or b) he implements the right interface and starts there (may with optional parameters)
309         css::uno::Reference< css::task::XJobExecutor > xExecuteable(xService, css::uno::UNO_QUERY);
310         if (xExecuteable.is())
311             xExecuteable->trigger(sArguments);
312     }
313     // ignore all errors - inclusive runtime errors!
314     // E.g. a script based service (written in phyton) could not be executed
315     // because it contains syntax errors, which was detected at runtime ...
316     catch(const css::uno::Exception&)
317         { xService.clear(); }
318 
319     return xService;
320 }
321 
322 //_________________________________________________________________________________________________________________
323 
324 /**
325     @short      add/remove listener for state events
326     @descr      We use an internal container to hold such registered listener. This container lives if we live.
327                 And if call pas registration as non breakable transaction - we can accept the request without
328                 any explicit lock. Because we share our mutex with this container.
329 
330     @param      xListener
331                     reference to a valid listener for state events
332     @param      aURL
333                     URL about listener will be informed, if something occured
334 
335     @modified   30.04.2002 14:49, as96863
336 */
337 void SAL_CALL ServiceHandler::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
338                                                  const css::util::URL&                                     /*aURL*/      ) throw( css::uno::RuntimeException )
339 {
340     // not suported yet
341 }
342 
343 //_________________________________________________________________________________________________________________
344 
345 void SAL_CALL ServiceHandler::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
346                                                     const css::util::URL&                                     /*aURL*/      ) throw( css::uno::RuntimeException )
347 {
348     // not suported yet
349 }
350 
351 }       //  namespace framework
352