xref: /trunk/main/comphelper/inc/comphelper/servicedecl.hxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 #if ! defined(COMPHELPER_SERVICEDECL_HXX_INCLUDED)
24 #define COMPHELPER_SERVICEDECL_HXX_INCLUDED
25 
26 #include <comphelper/comphelperdllapi.h>
27 #include <cppuhelper/implbase1.hxx>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/registry/XRegistryKey.hpp>
31 #include <uno/environment.h>
32 #include <boost/utility.hpp>
33 #include <boost/function.hpp>
34 #include <boost/preprocessor/cat.hpp>
35 #include <boost/preprocessor/repetition.hpp>
36 #include <boost/preprocessor/seq/enum.hpp>
37 
38 namespace comphelper {
39 namespace service_decl {
40 
41 class ServiceDecl;
42 
43 namespace detail {
44 namespace css = ::com::sun::star;
45 typedef ::boost::function3<
46     css::uno::Reference<css::uno::XInterface> /* return */,
47     ServiceDecl const&,
48     css::uno::Sequence<css::uno::Any> const&,
49     css::uno::Reference<css::uno::XComponentContext> const&> CreateFuncF;
50 }
51 
52 /** Class to declare a service implementation.  There is no need to implement
53     lang::XServiceInfo nor lang::XInitialization anymore.
54     The declaration can be done in various ways, the (simplest) form is
55 
56     <pre>
57     class MyClass : public cppu::WeakImplHelper2<XInterface1, XInterface2> {
58     public:
59         MyClass( uno::Reference<uno::XComponentContext> const& xContext )
60         [...]
61     };
62     [...]
63     namespace sdecl = comphelper::service_decl;
64     sdecl::ServiceDecl const myDecl(
65         sdecl::class_<MyClass>(),
66         "my.unique.implementation.name",
67         "MyServiceSpec1;MyServiceSpec2" );
68     </pre>
69 
70     If the service demands initialization by arguments, the implementation
71     class has to define a constructor taking both arguments and component
72     context:
73 
74     <pre>
75     class MyClass : public cppu::WeakImplHelper2<XInterface1, XInterface2> {
76     public:
77         MyClass( uno::Sequence<uno::Any> const& args,
78                  uno::Reference<uno:XComponentContext> const& xContext )
79         [...]
80     };
81     [...]
82     namespace sdecl = comphelper::service_decl;
83     sdecl::ServiceDecl const myDecl(
84         sdecl::class_<MyClass, sdecl::with_args<true> >(),
85         "my.unique.implementation.name",
86         "MyServiceSpec1;MyServiceSpec2" );
87     </pre>
88 
89     Additionally, there is the possibility to process some code after creation,
90     e.g. to add the newly created object as a listener or perform aggregation
91     (C++-UNO only):
92 
93     <pre>
94     uno::Reference<uno::XInterface> somePostProcCode( MyClass * p );
95     [...]
96     namespace sdecl = comphelper::service_decl;
97     sdecl::ServiceDecl const myDecl(
98         sdecl::class_<MyClass, ... >(&somePostProcCode),
99         "my.unique.implementation.name",
100         "MyServiceSpec1;MyServiceSpec2" );
101     </pre>
102 
103     In the latter case, somePostProcCode gets the yet unacquired "raw" pointer.
104 */
105 class COMPHELPER_DLLPUBLIC ServiceDecl : private ::boost::noncopyable
106 {
107 public:
108     /** Ctor for multiple supported service names.
109 
110         @param implClass implementation class description
111         @param pImplName implementation name
112         @param pSupportedServiceNames supported service names
113         @param cDelim delimiter for supported service names
114     */
115     template <typename ImplClassT>
ServiceDecl(ImplClassT const & implClass,char const * pImplName,char const * pSupportedServiceNames,char cDelim=';')116     ServiceDecl( ImplClassT const& implClass,
117                  char const* pImplName,
118                  char const* pSupportedServiceNames, char cDelim = ';' )
119         : m_createFunc(implClass.m_createFunc),
120           m_pImplName(pImplName),
121           m_pServiceNames(pSupportedServiceNames),
122           m_cDelim(cDelim) {}
123 
124     /// @internal gets called by component_getFactoryHelper()
125     void * getFactory( sal_Char const* pImplName ) const;
126 
127     /// @return supported service names
128     ::com::sun::star::uno::Sequence< ::rtl::OUString>
129     getSupportedServiceNames() const;
130 
131     /// @return whether name is in set of supported service names
132     bool supportsService( ::rtl::OUString const& name ) const;
133 
134     /// @return implementation name
135     ::rtl::OUString getImplementationName() const;
136 
137 private:
138     class Factory;
139     friend class Factory;
140 
141     detail::CreateFuncF const m_createFunc;
142     char const* const m_pImplName;
143     char const* const m_pServiceNames;
144     char const m_cDelim;
145 };
146 
147 /** To specify whether the implementation class expects arguments
148     (uno::Sequence<uno::Any>).
149 */
150 template <bool> struct with_args;
151 
152 /// @internal
153 namespace detail {
154 template <typename ImplT>
155 class OwnServiceImpl
156     : public ImplT,
157       private ::boost::noncopyable
158 {
159     typedef ImplT BaseT;
160 
161 public:
OwnServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Sequence<css::uno::Any> const & args,css::uno::Reference<css::uno::XComponentContext> const & xContext)162     OwnServiceImpl(
163         ServiceDecl const& rServiceDecl,
164         css::uno::Sequence<css::uno::Any> const& args,
165         css::uno::Reference<css::uno::XComponentContext> const& xContext )
166         :BaseT(args, xContext), m_rServiceDecl(rServiceDecl) {}
OwnServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Reference<css::uno::XComponentContext> const & xContext)167     OwnServiceImpl(
168         ServiceDecl const& rServiceDecl,
169         css::uno::Reference<css::uno::XComponentContext> const& xContext )
170         : BaseT(xContext), m_rServiceDecl(rServiceDecl) {}
171 
172     // XServiceInfo
getImplementationName()173     virtual ::rtl::OUString SAL_CALL getImplementationName() {
174         return m_rServiceDecl.getImplementationName();
175     }
supportsService(::rtl::OUString const & name)176     virtual sal_Bool SAL_CALL supportsService( ::rtl::OUString const& name ) {
177         return m_rServiceDecl.supportsService(name);
178     }
179     virtual css::uno::Sequence< ::rtl::OUString>
getSupportedServiceNames()180     SAL_CALL getSupportedServiceNames() {
181         return m_rServiceDecl.getSupportedServiceNames();
182     }
183 
184 private:
185     ServiceDecl const& m_rServiceDecl;
186 };
187 
188 template <typename ImplT>
189 class ServiceImpl : public OwnServiceImpl< ::cppu::ImplInheritanceHelper1<ImplT,css::lang::XServiceInfo> >
190 {
191 typedef OwnServiceImpl< ::cppu::ImplInheritanceHelper1<ImplT,css::lang::XServiceInfo> > ServiceImpl_BASE;
192 public:
ServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Sequence<css::uno::Any> const & args,css::uno::Reference<css::uno::XComponentContext> const & xContext)193     ServiceImpl(
194         ServiceDecl const& rServiceDecl,
195         css::uno::Sequence<css::uno::Any> const& args,
196         css::uno::Reference<css::uno::XComponentContext> const& xContext )
197         : ServiceImpl_BASE(rServiceDecl, args, xContext) {}
ServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Reference<css::uno::XComponentContext> const & xContext)198     ServiceImpl(
199         ServiceDecl const& rServiceDecl,
200         css::uno::Reference<css::uno::XComponentContext> const& xContext )
201         : ServiceImpl_BASE(rServiceDecl, xContext) {}
202 };
203 
204 template <typename ServiceImplT>
205 struct PostProcessDefault {
206     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::PostProcessDefault207     operator()( ServiceImplT * p ) const {
208         return static_cast<css::lang::XServiceInfo *>(p);
209     }
210 };
211 
212 template <typename ImplT, typename PostProcessFuncT, typename WithArgsT>
213 struct CreateFunc;
214 
215 template <typename ImplT, typename PostProcessFuncT>
216 struct CreateFunc<ImplT, PostProcessFuncT, with_args<false> > {
217     PostProcessFuncT const m_postProcessFunc;
CreateFunccomphelper::service_decl::detail::CreateFunc218     explicit CreateFunc( PostProcessFuncT const& postProcessFunc )
219         : m_postProcessFunc(postProcessFunc) {}
220 
221     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::CreateFunc222     operator()( ServiceDecl const& rServiceDecl,
223                 css::uno::Sequence<css::uno::Any> const&,
224                 css::uno::Reference<css::uno::XComponentContext>
225                 const& xContext ) const
226     {
227         return m_postProcessFunc(
228             new ImplT( rServiceDecl, xContext ) );
229     }
230 };
231 
232 template <typename ImplT, typename PostProcessFuncT>
233 struct CreateFunc<ImplT, PostProcessFuncT, with_args<true> > {
234     PostProcessFuncT const m_postProcessFunc;
CreateFunccomphelper::service_decl::detail::CreateFunc235     explicit CreateFunc( PostProcessFuncT const& postProcessFunc )
236         : m_postProcessFunc(postProcessFunc) {}
237 
238     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::CreateFunc239     operator()( ServiceDecl const& rServiceDecl,
240                 css::uno::Sequence<css::uno::Any> const& args,
241                 css::uno::Reference<css::uno::XComponentContext>
242                 const& xContext ) const
243     {
244         return m_postProcessFunc(
245             new ImplT( rServiceDecl, args, xContext ) );
246     }
247 };
248 
249 } // namespace detail
250 
251 /** Defines a service implementation class.
252 
253     @tpl ImplT_ service implementation class
254     @WithArgsT whether the implementation class ctor expects arguments
255                (uno::Sequence<uno::Any>, uno::Reference<uno::XComponentContext>)
256                or just (uno::Reference<uno::XComponentContext>)
257 */
258 template <typename ImplT_, typename WithArgsT = with_args<false> >
259 struct serviceimpl_base {
260     typedef ImplT_ ImplT;
261 
262     detail::CreateFuncF const m_createFunc;
263 
264     typedef detail::PostProcessDefault<ImplT> PostProcessDefaultT;
265 
266     /** Default ctor.  Implementation class without args, expecting
267         component context as single argument.
268     */
serviceimpl_basecomphelper::service_decl::serviceimpl_base269     serviceimpl_base() : m_createFunc(
270         detail::CreateFunc<ImplT, PostProcessDefaultT, WithArgsT>(
271             PostProcessDefaultT() ) ) {}
272 
273     /** Ctor to pass a post processing function/functor.
274 
275         @tpl PostProcessDefaultT let your compiler deduce this
276         @param postProcessFunc function/functor that gets the yet unacquired
277                                ImplT_ pointer returning a
278                                uno::Reference<uno::XInterface>
279     */
280     template <typename PostProcessFuncT>
serviceimpl_basecomphelper::service_decl::serviceimpl_base281     explicit serviceimpl_base( PostProcessFuncT const& postProcessFunc )
282         : m_createFunc( detail::CreateFunc<ImplT, PostProcessFuncT, WithArgsT>(
283                             postProcessFunc ) ) {}
284 };
285 
286 template <typename ImplT_, typename WithArgsT = with_args<false> >
287 struct class_ : public serviceimpl_base< detail::ServiceImpl<ImplT_>, WithArgsT >
288 {
289     typedef serviceimpl_base< detail::ServiceImpl<ImplT_>, WithArgsT > baseT;
290     /** Default ctor.  Implementation class without args, expecting
291         component context as single argument.
292     */
class_comphelper::service_decl::class_293     class_() : baseT() {}
294     template <typename PostProcessFuncT>
295     /** Ctor to pass a post processing function/functor.
296 
297         @tpl PostProcessDefaultT let your compiler deduce this
298         @param postProcessFunc function/functor that gets the yet unacquired
299                                ImplT_ pointer returning a
300                                uno::Reference<uno::XInterface>
301     */
class_comphelper::service_decl::class_302     explicit class_( PostProcessFuncT const& postProcessFunc ) : baseT( postProcessFunc ) {}
303 };
304 
305 //
306 // component_... helpers with arbitrary service declarations:
307 //
308 
309 #define COMPHELPER_SERVICEDECL_getFactory(z_, n_, unused_) \
310     if (pRet == 0) \
311         pRet = BOOST_PP_CAT(s, n_).getFactory(pImplName);
312 
313 /** The following preprocessor repetitions generate functions like
314 
315     <pre>
316         inline void * component_getFactoryHelper(
317             sal_Char const* pImplName,
318             ::com::sun::star::lang::XMultiServiceFactory *,
319             ::com::sun::star::registry::XRegistryKey * xRegistryKey,
320             ServiceDecl const& s0, ServiceDecl const& s1, ... );
321     </pre>
322 
323     which call on the passed service declarations.
324 
325     The maximum number of service declarations can be set by defining
326     COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS; its default is 8.
327 */
328 #define COMPHELPER_SERVICEDECL_make(z_, n_, unused_) \
329 inline void * component_getFactoryHelper( \
330     sal_Char const* pImplName, \
331     ::com::sun::star::lang::XMultiServiceFactory *, \
332     ::com::sun::star::registry::XRegistryKey *, \
333     BOOST_PP_ENUM_PARAMS(n_, ServiceDecl const& s) ) \
334 { \
335     void * pRet = 0; \
336     BOOST_PP_REPEAT(n_, COMPHELPER_SERVICEDECL_getFactory, ~) \
337     return pRet; \
338 }
339 
340 #if ! defined(COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS)
341 #define COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS 8
342 #endif
343 
344 BOOST_PP_REPEAT_FROM_TO(1, COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS,
345                         COMPHELPER_SERVICEDECL_make, ~)
346 
347 #undef COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS
348 #undef COMPHELPER_SERVICEDECL_make
349 #undef COMPHELPER_SERVICEDECL_getFactory
350 
351 } // namespace service_decl
352 } // namespace comphelper
353 
354 /** The following preprocessor macro generates the C access functions,
355     that are used to initialize and register the components of a
356     shared library object.
357 
358     If you have, say, written a lib that contains three distinct
359     components, each with its own ServiceDecl object, you might want
360     to employ the following code:
361 
362     <pre>
363         // must reside outside _any_ namespace
364         COMPHELPER_SERVICEDECL_EXPORTS3(yourServiceDecl1,
365                                        yourServiceDecl2,
366                                        yourServiceDecl3);
367     </pre>
368 
369     For your convenience, the COMPHELPER_SERVICEDECL_EXPORTS<N> macro
370     comes pre-defined up to N=8, if you should need more arguments,
371     call COMPHELPER_SERVICEDECL_make_exports directly, like this:
372 
373     <pre>
374         // must reside outside _any_ namespace
375         COMPHELPER_SERVICEDECL_make_exports((yourServiceDecl1)(yourServiceDecl2)...(yourServiceDeclN));
376     </pre>
377 
378     Note the missing colons between the bracketed arguments.
379  */
380 #define COMPHELPER_SERVICEDECL_make_exports(varargs_ )  \
381 extern "C" \
382 { \
383     SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( const sal_Char**  ppEnvTypeName, \
384                                                           uno_Environment** /*ppEnv*/ ) \
385     { \
386         *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; \
387     } \
388  \
389     SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( sal_Char const*                                pImplName, \
390                                          ::com::sun::star::lang::XMultiServiceFactory*  pServiceManager, \
391                                          ::com::sun::star::registry::XRegistryKey*      pRegistryKey ) \
392     { \
393         return component_getFactoryHelper( pImplName, pServiceManager, \
394                                            pRegistryKey, \
395                                            BOOST_PP_SEQ_ENUM(varargs_) ); \
396     } \
397 }
398 
399 #define COMPHELPER_SERVICEDECL_EXPORTS1(comp0_) \
400     COMPHELPER_SERVICEDECL_make_exports((comp0_))
401 #define COMPHELPER_SERVICEDECL_EXPORTS2(comp0_,comp1_) \
402     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_))
403 #define COMPHELPER_SERVICEDECL_EXPORTS3(comp0_,comp1_,comp2_) \
404     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_))
405 #define COMPHELPER_SERVICEDECL_EXPORTS4(comp0_,comp1_,comp2_,comp3_) \
406     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_))
407 #define COMPHELPER_SERVICEDECL_EXPORTS5(comp0_,comp1_,comp2_,comp3_,comp4_) \
408     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_))
409 #define COMPHELPER_SERVICEDECL_EXPORTS6(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_) \
410     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_))
411 #define COMPHELPER_SERVICEDECL_EXPORTS7(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_,comp6_) \
412     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_)(comp6_))
413 #define COMPHELPER_SERVICEDECL_EXPORTS8(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_,comp6_,comp7_) \
414     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_)(comp6_)(comp7_))
415 
416 #endif //  ! defined(COMPHELPER_SERVICEDECL_HXX_INCLUDED)
417