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 <cppuhelper/implementationentry.hxx>
21 #include <cppuhelper/factory.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <sal/log.hxx>
24 
25 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
26 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
27 #include "ProviderCache.hxx"
28 
29 using namespace com::sun::star;
30 using namespace com::sun::star::uno;
31 using namespace com::sun::star::script;
32 
33 namespace func_provider
34 {
35 
36 ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext ) : m_Sctx( scriptContext ), m_xContext( xContext )
37 {
38     // initialise m_hProviderDetailsCache with details of ScriptProviders
39     // will use createContentEnumeration
40 
41     m_xMgr = m_xContext->getServiceManager();
42     ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
43     populateCache();
44 }
45 
46 
47 ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext, const Sequence< OUString >& blackList ) : m_sBlackList( blackList ), m_Sctx( scriptContext ), m_xContext( xContext )
48 
49 {
50     // initialise m_hProviderDetailsCache with details of ScriptProviders
51     // will use createContentEnumeration
52 
53     m_xMgr = m_xContext->getServiceManager();
54     ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
55     populateCache();
56 }
57 
58 ProviderCache::~ProviderCache()
59 {
60 }
61 
62 Reference< provider::XScriptProvider >
63 ProviderCache::getProvider( const OUString& providerName )
64 {
65     ::osl::Guard< osl::Mutex > aGuard( m_mutex );
66     Reference< provider::XScriptProvider > provider;
67     ProviderDetails_hash::iterator h_it = m_hProviderDetailsCache.find( providerName );
68     if ( h_it != m_hProviderDetailsCache.end() )
69     {
70         if (  h_it->second.provider.is() )
71         {
72             provider = h_it->second.provider;
73         }
74         else
75         {
76             // need to create provider and insert into hash
77             provider = createProvider( h_it->second );
78         }
79     }
80     return provider;
81 }
82 
83 Sequence < Reference< provider::XScriptProvider > >
84 ProviderCache::getAllProviders()
85 {
86     // need to create providers that haven't been created already
87     // so check what providers exist and what ones don't
88 
89     ::osl::Guard< osl::Mutex > aGuard( m_mutex );
90     Sequence < Reference< provider::XScriptProvider > > providers (  m_hProviderDetailsCache.size() );
91     // should assert if size !>  0
92     if (  !m_hProviderDetailsCache.empty() )
93     {
94         sal_Int32 providerIndex = 0;
95         for (auto& rDetail : m_hProviderDetailsCache)
96         {
97             Reference<provider::XScriptProvider> xScriptProvider = rDetail.second.provider;
98             if ( xScriptProvider.is() )
99             {
100                 providers[ providerIndex++ ] = xScriptProvider;
101             }
102             else
103             {
104                 // create provider
105                 try
106                 {
107                     xScriptProvider = createProvider(rDetail.second);
108                     providers[ providerIndex++ ] = xScriptProvider;
109                 }
110                 catch ( const Exception& )
111                 {
112                     DBG_UNHANDLED_EXCEPTION("scripting");
113                 }
114             }
115         }
116 
117         if (providerIndex < providers.getLength())
118         {
119             providers.realloc( providerIndex );
120         }
121 
122     }
123     else
124     {
125         SAL_WARN("scripting", "no available providers, something very wrong!!!");
126     }
127     return providers;
128 }
129 
130 void
131 ProviderCache::populateCache()
132 {
133     // wrong name in services.rdb
134     OUString serviceName;
135     ::osl::Guard< osl::Mutex > aGuard( m_mutex );
136     try
137     {
138         OUString const languageProviderName( "com.sun.star.script.provider.LanguageScriptProvider"  );
139 
140         Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMgr, UNO_QUERY_THROW );
141         Reference< container::XEnumeration > xEnum = xEnumAccess->createContentEnumeration ( languageProviderName );
142 
143         while ( xEnum->hasMoreElements() )
144         {
145 
146             Reference< lang::XSingleComponentFactory > factory( xEnum->nextElement(), UNO_QUERY_THROW );
147             Reference< lang::XServiceInfo > xServiceInfo( factory, UNO_QUERY_THROW );
148 
149             Sequence< OUString > serviceNames = xServiceInfo->getSupportedServiceNames();
150 
151             if ( serviceNames.getLength() > 0 )
152             {
153                 for ( sal_Int32 index = 0; index < serviceNames.getLength(); index++ )
154                 {
155                     if ( serviceNames[ index ].startsWith( "com.sun.star.script.provider.ScriptProviderFor" )
156                          && !isInBlackList(  serviceNames[ index ] ) )
157                     {
158                         serviceName = serviceNames[ index ];
159                         ProviderDetails details;
160                         details.factory = factory;
161                         m_hProviderDetailsCache[ serviceName ] = details;
162                         break;
163                     }
164                 }
165             }
166         }
167     }
168     catch ( const Exception &e )
169     {
170         css::uno::Any anyEx = cppu::getCaughtException();
171         throw css::lang::WrappedTargetRuntimeException(
172                 "ProviderCache::populateCache: couldn't obtain XSingleComponentFactory for " + serviceName
173                 + " " + e.Message,
174                 nullptr, anyEx );
175     }
176 }
177 
178 Reference< provider::XScriptProvider >
179 ProviderCache::createProvider( ProviderDetails& details )
180 {
181     try
182     {
183         details.provider.set(
184             details.factory->createInstanceWithArgumentsAndContext( m_Sctx, m_xContext ), UNO_QUERY_THROW );
185     }
186     catch ( const Exception& e )
187     {
188         css::uno::Any anyEx = cppu::getCaughtException();
189         throw css::lang::WrappedTargetRuntimeException(
190                 "ProviderCache::createProvider() Error creating provider from factory. " + e.Message,
191                 nullptr, anyEx );
192     }
193 
194     return details.provider;
195 }
196 } //end namespace
197 
198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
199