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