xref: /aoo41x/main/cppu/source/uno/EnvStack.cxx (revision cdf0e10c)
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 #include "uno/environment.hxx"
29 
30 #include "cppu/EnvDcp.hxx"
31 #include "cppu/Enterable.hxx"
32 
33 #include "osl/thread.h"
34 #include "osl/mutex.hxx"
35 
36 #include <hash_map>
37 
38 
39 using namespace com::sun::star;
40 
41 
42 struct SAL_DLLPRIVATE oslThreadIdentifier_equal
43 {
44 	bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
45 };
46 
47 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
48 {
49 	bool result = s1 == s2;
50 
51 	return result;
52 }
53 
54 
55 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
56 {
57 	size_t operator()(oslThreadIdentifier s1) const;
58 };
59 
60 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
61 {
62 	return s1;
63 }
64 
65 typedef ::std::hash_map<oslThreadIdentifier,
66 						uno_Environment *,
67 						oslThreadIdentifier_hash,
68 						oslThreadIdentifier_equal>  ThreadMap;
69 
70 static osl::Mutex s_threadMap_mutex;
71 static ThreadMap  s_threadMap;
72 
73 
74 static rtl::OUString s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));
75 
76 static void s_setCurrent(uno_Environment * pEnv)
77 {
78 	oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
79 
80 	osl::MutexGuard guard(s_threadMap_mutex);
81 	if (pEnv)
82 		s_threadMap[threadId] = pEnv;
83 
84 	else
85 	{
86 		ThreadMap::iterator iEnv = s_threadMap.find(threadId);
87 		s_threadMap.erase(iEnv);
88 	}
89 }
90 
91 static uno_Environment * s_getCurrent(void)
92 {
93 	uno_Environment * pEnv = NULL;
94 
95 	oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
96 
97 	osl::MutexGuard guard(s_threadMap_mutex);
98 	ThreadMap::iterator iEnv = s_threadMap.find(threadId);
99 	if(iEnv != s_threadMap.end())
100 		pEnv = iEnv->second;
101 
102 	return pEnv;
103 }
104 
105 
106 extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
107 	SAL_THROW_EXTERN_C()
108 {
109 	if (*ppEnv)
110 	{
111 		(*ppEnv)->release(*ppEnv);
112 		*ppEnv = NULL;
113 	}
114 
115 	rtl::OUString currPurpose;
116 
117 	uno_Environment * pCurrEnv = s_getCurrent();
118 	if (pCurrEnv) // no environment means no purpose
119 		currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
120 
121 	if (pTypeName && rtl_uString_getLength(pTypeName))
122 	{
123 		rtl::OUString envDcp(pTypeName);
124 		envDcp += currPurpose;
125 
126 		uno_getEnvironment(ppEnv, envDcp.pData, NULL);
127 	}
128 	else
129 	{
130 		if (pCurrEnv)
131 		{
132 			*ppEnv = pCurrEnv;
133 			(*ppEnv)->acquire(*ppEnv);
134 		}
135 		else
136 			uno_getEnvironment(ppEnv, s_uno_envDcp.pData, NULL);
137 
138 	}
139 }
140 
141 static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
142 {
143 	sal_Int32 nIndex1 = 0;
144 	sal_Int32 nIndex2 = 0;
145 	sal_Int32 sim = 0;
146 
147 	rtl::OUString token1;
148 	rtl::OUString token2;
149 
150 	do
151 	{
152 		token1 = str1.getToken(0, ':', nIndex1);
153 		token2 = str2.getToken(0, ':', nIndex2);
154 
155 		if (token1.equals(token2))
156 			sim += token1.getLength() + 1;
157 	}
158 	while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
159 
160 	rtl::OUString result;
161 
162 	if (sim)
163 		result = str1.copy(0, sim - 1);
164 
165 	return result;
166 }
167 
168 static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
169 {
170 	int res = 0;
171 
172 	rtl::OUString nextPurpose;
173 
174 	rtl::OUString currPurpose;
175 	if (pCurrEnv)
176 		currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
177 
178 	rtl::OUString targetPurpose;
179 	if (pTargetEnv)
180 		targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
181 
182 	rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
183 	if (currPurpose.getLength() > intermPurpose.getLength())
184 	{
185 		sal_Int32 idx = currPurpose.lastIndexOf(':');
186 		nextPurpose = currPurpose.copy(0, idx);
187 
188 		res = -1;
189 	}
190 	else if (intermPurpose.getLength() < targetPurpose.getLength())
191 	{
192 		sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
193 		if (idx == -1)
194 			nextPurpose = targetPurpose;
195 
196 		else
197 			nextPurpose = targetPurpose.copy(0, idx);
198 
199 		res = 1;
200 	}
201 
202 	if (nextPurpose.getLength())
203 	{
204 		rtl::OUString next_envDcp(s_uno_envDcp);
205 		next_envDcp += nextPurpose;
206 
207 		uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
208 	}
209 	else
210 	{
211 		if (*ppEnv)
212 			(*ppEnv)->release(*ppEnv);
213 
214 		*ppEnv = NULL;
215 	}
216 
217 	return res;
218 }
219 
220 extern "C" { static void s_pull(va_list * pParam)
221 {
222 	uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
223     va_list       * pXparam = va_arg(*pParam, va_list *);
224 
225     pCallee(pXparam);
226 }}
227 
228 static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
229 {
230 	cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
231 	if (pEnterable)
232 		pEnterable->callInto(s_pull, pCallee, pParam);
233 
234 	else
235 		pCallee(pParam);
236 }
237 
238 static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
239 {
240 	va_list param;
241 
242 	va_start(param, pCallee);
243 	s_callInto_v(pEnv, pCallee, &param);
244 	va_end(param);
245 }
246 
247 static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
248 {
249 	cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
250 	if (pEnterable)
251 		pEnterable->callOut_v(pCallee, pParam);
252 
253 	else
254 		pCallee(pParam);
255 }
256 
257 static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
258 {
259 	va_list param;
260 
261 	va_start(param, pCallee);
262 	s_callOut_v(pEnv, pCallee, &param);
263 	va_end(param);
264 }
265 
266 static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
267 
268 extern "C" { static void s_environment_invoke_vv(va_list * pParam)
269 {
270 	uno_Environment * pCurrEnv    = va_arg(*pParam, uno_Environment *);
271 	uno_Environment * pTargetEnv  = va_arg(*pParam, uno_Environment *);
272 	uno_EnvCallee   * pCallee     = va_arg(*pParam, uno_EnvCallee *);
273     va_list         * pXparam     = va_arg(*pParam, va_list *);
274 
275     s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
276 }}
277 
278 static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
279 {
280 	uno_Environment * pNextEnv = NULL;
281 	switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
282 	{
283 	case -1:
284 		s_setCurrent(pNextEnv);
285 		s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
286 		s_setCurrent(pCurrEnv);
287 		break;
288 
289 	case 0: {
290 		uno_Environment * hld = s_getCurrent();
291 		s_setCurrent(pCurrEnv);
292 		pCallee(pParam);
293 		s_setCurrent(hld);
294 	}
295 		break;
296 
297 	case 1:
298 		s_setCurrent(pNextEnv);
299 		s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
300 		s_setCurrent(pCurrEnv);
301 		break;
302 	}
303 
304 	if (pNextEnv)
305 		pNextEnv->release(pNextEnv);
306 }
307 
308 extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
309 	SAL_THROW_EXTERN_C()
310 {
311 	s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
312 }
313 
314 extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
315 	SAL_THROW_EXTERN_C()
316 {
317 	va_list param;
318 
319 	va_start(param, pCallee);
320 	uno_Environment_invoke_v(pEnv, pCallee, &param);
321 	va_end(param);
322 }
323 
324 extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
325 	SAL_THROW_EXTERN_C()
326 {
327 	uno_Environment * pNextEnv = NULL;
328 	uno_Environment * pCurrEnv = s_getCurrent();
329 
330 	int res;
331 	while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
332 	{
333 		cppu::Enterable * pEnterable;
334 
335 		switch(res)
336 		{
337 		case -1:
338 			pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
339 			if (pEnterable)
340 				pEnterable->leave();
341 			pCurrEnv->release(pCurrEnv);
342 			break;
343 
344 		case 1:
345 			pNextEnv->acquire(pNextEnv);
346 			pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
347 			if (pEnterable)
348 				pEnterable->enter();
349 			break;
350 		}
351 
352 		s_setCurrent(pNextEnv);
353 		pCurrEnv = pNextEnv;
354 	}
355 }
356 
357 int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
358 	SAL_THROW_EXTERN_C()
359 {
360 	int result = 1;
361 
362 	rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
363 	if (typeName.equals(s_uno_envDcp))
364 	{
365 		cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
366 		if (pEnterable)
367 			result = pEnterable->isValid((rtl::OUString *)pReason);
368 	}
369 	else
370 	{
371 		rtl::OUString envDcp(s_uno_envDcp);
372 		envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);
373 
374 		uno::Environment env(envDcp);
375 
376 		result = env.isValid((rtl::OUString *)pReason);
377 	}
378 
379 	return result;
380 }
381