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         throw (css::uno::RuntimeException) {
175         return m_rServiceDecl.getImplementationName();
176     }
supportsService(::rtl::OUString const & name)177     virtual sal_Bool SAL_CALL supportsService( ::rtl::OUString const& name )
178         throw (css::uno::RuntimeException) {
179         return m_rServiceDecl.supportsService(name);
180     }
181     virtual css::uno::Sequence< ::rtl::OUString>
getSupportedServiceNames()182     SAL_CALL getSupportedServiceNames() throw (css::uno::RuntimeException) {
183         return m_rServiceDecl.getSupportedServiceNames();
184     }
185 
186 private:
187     ServiceDecl const& m_rServiceDecl;
188 };
189 
190 template <typename ImplT>
191 class ServiceImpl : public OwnServiceImpl< ::cppu::ImplInheritanceHelper1<ImplT,css::lang::XServiceInfo> >
192 {
193 typedef OwnServiceImpl< ::cppu::ImplInheritanceHelper1<ImplT,css::lang::XServiceInfo> > ServiceImpl_BASE;
194 public:
ServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Sequence<css::uno::Any> const & args,css::uno::Reference<css::uno::XComponentContext> const & xContext)195     ServiceImpl(
196         ServiceDecl const& rServiceDecl,
197         css::uno::Sequence<css::uno::Any> const& args,
198         css::uno::Reference<css::uno::XComponentContext> const& xContext )
199         : ServiceImpl_BASE(rServiceDecl, args, xContext) {}
ServiceImpl(ServiceDecl const & rServiceDecl,css::uno::Reference<css::uno::XComponentContext> const & xContext)200     ServiceImpl(
201         ServiceDecl const& rServiceDecl,
202         css::uno::Reference<css::uno::XComponentContext> const& xContext )
203         : ServiceImpl_BASE(rServiceDecl, xContext) {}
204 };
205 
206 template <typename ServiceImplT>
207 struct PostProcessDefault {
208     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::PostProcessDefault209     operator()( ServiceImplT * p ) const {
210         return static_cast<css::lang::XServiceInfo *>(p);
211     }
212 };
213 
214 template <typename ImplT, typename PostProcessFuncT, typename WithArgsT>
215 struct CreateFunc;
216 
217 template <typename ImplT, typename PostProcessFuncT>
218 struct CreateFunc<ImplT, PostProcessFuncT, with_args<false> > {
219     PostProcessFuncT const m_postProcessFunc;
CreateFunccomphelper::service_decl::detail::CreateFunc220     explicit CreateFunc( PostProcessFuncT const& postProcessFunc )
221         : m_postProcessFunc(postProcessFunc) {}
222 
223     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::CreateFunc224     operator()( ServiceDecl const& rServiceDecl,
225                 css::uno::Sequence<css::uno::Any> const&,
226                 css::uno::Reference<css::uno::XComponentContext>
227                 const& xContext ) const
228     {
229         return m_postProcessFunc(
230             new ImplT( rServiceDecl, xContext ) );
231     }
232 };
233 
234 template <typename ImplT, typename PostProcessFuncT>
235 struct CreateFunc<ImplT, PostProcessFuncT, with_args<true> > {
236     PostProcessFuncT const m_postProcessFunc;
CreateFunccomphelper::service_decl::detail::CreateFunc237     explicit CreateFunc( PostProcessFuncT const& postProcessFunc )
238         : m_postProcessFunc(postProcessFunc) {}
239 
240     css::uno::Reference<css::uno::XInterface>
operator ()comphelper::service_decl::detail::CreateFunc241     operator()( ServiceDecl const& rServiceDecl,
242                 css::uno::Sequence<css::uno::Any> const& args,
243                 css::uno::Reference<css::uno::XComponentContext>
244                 const& xContext ) const
245     {
246         return m_postProcessFunc(
247             new ImplT( rServiceDecl, args, xContext ) );
248     }
249 };
250 
251 } // namespace detail
252 
253 /** Defines a service implementation class.
254 
255     @tpl ImplT_ service implementation class
256     @WithArgsT whether the implementation class ctor expects arguments
257                (uno::Sequence<uno::Any>, uno::Reference<uno::XComponentContext>)
258                or just (uno::Reference<uno::XComponentContext>)
259 */
260 template <typename ImplT_, typename WithArgsT = with_args<false> >
261 struct serviceimpl_base {
262     typedef ImplT_ ImplT;
263 
264     detail::CreateFuncF const m_createFunc;
265 
266     typedef detail::PostProcessDefault<ImplT> PostProcessDefaultT;
267 
268     /** Default ctor.  Implementation class without args, expecting
269         component context as single argument.
270     */
serviceimpl_basecomphelper::service_decl::serviceimpl_base271     serviceimpl_base() : m_createFunc(
272         detail::CreateFunc<ImplT, PostProcessDefaultT, WithArgsT>(
273             PostProcessDefaultT() ) ) {}
274 
275     /** Ctor to pass a post processing function/functor.
276 
277         @tpl PostProcessDefaultT let your compiler deduce this
278         @param postProcessFunc function/functor that gets the yet unacquired
279                                ImplT_ pointer returning a
280                                uno::Reference<uno::XInterface>
281     */
282     template <typename PostProcessFuncT>
serviceimpl_basecomphelper::service_decl::serviceimpl_base283     explicit serviceimpl_base( PostProcessFuncT const& postProcessFunc )
284         : m_createFunc( detail::CreateFunc<ImplT, PostProcessFuncT, WithArgsT>(
285                             postProcessFunc ) ) {}
286 };
287 
288 template <typename ImplT_, typename WithArgsT = with_args<false> >
289 struct class_ : public serviceimpl_base< detail::ServiceImpl<ImplT_>, WithArgsT >
290 {
291     typedef serviceimpl_base< detail::ServiceImpl<ImplT_>, WithArgsT > baseT;
292     /** Default ctor.  Implementation class without args, expecting
293         component context as single argument.
294     */
class_comphelper::service_decl::class_295     class_() : baseT() {}
296     template <typename PostProcessFuncT>
297     /** Ctor to pass a post processing function/functor.
298 
299         @tpl PostProcessDefaultT let your compiler deduce this
300         @param postProcessFunc function/functor that gets the yet unacquired
301                                ImplT_ pointer returning a
302                                uno::Reference<uno::XInterface>
303     */
class_comphelper::service_decl::class_304     explicit class_( PostProcessFuncT const& postProcessFunc ) : baseT( postProcessFunc ) {}
305 };
306 
307 //
308 // component_... helpers with arbitrary service declarations:
309 //
310 
311 #define COMPHELPER_SERVICEDECL_getFactory(z_, n_, unused_) \
312     if (pRet == 0) \
313         pRet = BOOST_PP_CAT(s, n_).getFactory(pImplName);
314 
315 /** The following preprocessor repetitions generate functions like
316 
317     <pre>
318         inline void * component_getFactoryHelper(
319             sal_Char const* pImplName,
320             ::com::sun::star::lang::XMultiServiceFactory *,
321             ::com::sun::star::registry::XRegistryKey * xRegistryKey,
322             ServiceDecl const& s0, ServiceDecl const& s1, ... );
323     </pre>
324 
325     which call on the passed service declarations.
326 
327     The maximum number of service declarations can be set by defining
328     COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS; its default is 8.
329 */
330 #define COMPHELPER_SERVICEDECL_make(z_, n_, unused_) \
331 inline void * component_getFactoryHelper( \
332     sal_Char const* pImplName, \
333     ::com::sun::star::lang::XMultiServiceFactory *, \
334     ::com::sun::star::registry::XRegistryKey *, \
335     BOOST_PP_ENUM_PARAMS(n_, ServiceDecl const& s) ) \
336 { \
337     void * pRet = 0; \
338     BOOST_PP_REPEAT(n_, COMPHELPER_SERVICEDECL_getFactory, ~) \
339     return pRet; \
340 }
341 
342 #if ! defined(COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS)
343 #define COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS 8
344 #endif
345 
346 BOOST_PP_REPEAT_FROM_TO(1, COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS,
347                         COMPHELPER_SERVICEDECL_make, ~)
348 
349 #undef COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS
350 #undef COMPHELPER_SERVICEDECL_make
351 #undef COMPHELPER_SERVICEDECL_getFactory
352 
353 } // namespace service_decl
354 } // namespace comphelper
355 
356 /** The following preprocessor macro generates the C access functions,
357     that are used to initialize and register the components of a
358     shared library object.
359 
360     If you have, say, written a lib that contains three distinct
361     components, each with its own ServiceDecl object, you might want
362     to employ the following code:
363 
364     <pre>
365         // must reside outside _any_ namespace
366         COMPHELPER_SERVICEDECL_EXPORTS3(yourServiceDecl1,
367                                        yourServiceDecl2,
368                                        yourServiceDecl3);
369     </pre>
370 
371     For your convenience, the COMPHELPER_SERVICEDECL_EXPORTS<N> macro
372     comes pre-defined up to N=8, if you should need more arguments,
373     call COMPHELPER_SERVICEDECL_make_exports directly, like this:
374 
375     <pre>
376         // must reside outside _any_ namespace
377         COMPHELPER_SERVICEDECL_make_exports((yourServiceDecl1)(yourServiceDecl2)...(yourServiceDeclN));
378     </pre>
379 
380     Note the missing colons between the bracketed arguments.
381  */
382 #define COMPHELPER_SERVICEDECL_make_exports(varargs_ )  \
383 extern "C" \
384 { \
385     SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( const sal_Char**  ppEnvTypeName, \
386                                                           uno_Environment** /*ppEnv*/ ) \
387     { \
388         *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; \
389     } \
390  \
391     SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( sal_Char const*                                pImplName, \
392                                          ::com::sun::star::lang::XMultiServiceFactory*  pServiceManager, \
393                                          ::com::sun::star::registry::XRegistryKey*      pRegistryKey ) \
394     { \
395         return component_getFactoryHelper( pImplName, pServiceManager, \
396                                            pRegistryKey, \
397                                            BOOST_PP_SEQ_ENUM(varargs_) ); \
398     } \
399 }
400 
401 #define COMPHELPER_SERVICEDECL_EXPORTS1(comp0_) \
402     COMPHELPER_SERVICEDECL_make_exports((comp0_))
403 #define COMPHELPER_SERVICEDECL_EXPORTS2(comp0_,comp1_) \
404     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_))
405 #define COMPHELPER_SERVICEDECL_EXPORTS3(comp0_,comp1_,comp2_) \
406     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_))
407 #define COMPHELPER_SERVICEDECL_EXPORTS4(comp0_,comp1_,comp2_,comp3_) \
408     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_))
409 #define COMPHELPER_SERVICEDECL_EXPORTS5(comp0_,comp1_,comp2_,comp3_,comp4_) \
410     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_))
411 #define COMPHELPER_SERVICEDECL_EXPORTS6(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_) \
412     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_))
413 #define COMPHELPER_SERVICEDECL_EXPORTS7(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_,comp6_) \
414     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_)(comp6_))
415 #define COMPHELPER_SERVICEDECL_EXPORTS8(comp0_,comp1_,comp2_,comp3_,comp4_,comp5_,comp6_,comp7_) \
416     COMPHELPER_SERVICEDECL_make_exports((comp0_)(comp1_)(comp2_)(comp3_)(comp4_)(comp5_)(comp6_)(comp7_))
417 
418 #endif //  ! defined(COMPHELPER_SERVICEDECL_HXX_INCLUDED)
419 
420