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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_scripting.hxx"
30 #include <cppuhelper/implementationentry.hxx>
31 #include <cppuhelper/factory.hxx>
32 #include <cppuhelper/implbase1.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <util/scriptingconstants.hxx>
35 #include <util/util.hxx>
36 #include <util/MiscUtils.hxx>
37 
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/util/XMacroExpander.hpp>
40 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
41 
42 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
43 
44 #include "MasterScriptProvider.hxx"
45 #include "ActiveMSPList.hxx"
46 
47 #include <tools/diagnose_ex.h>
48 
49 using namespace com::sun::star;
50 using namespace com::sun::star::uno;
51 using namespace com::sun::star::script;
52 using namespace ::sf_misc;
53 
54 namespace func_provider
55 {
56 
57 ActiveMSPList::ActiveMSPList(  const Reference< XComponentContext > & xContext ) : m_xContext( xContext )
58 {
59     userDirString = ::rtl::OUString::createFromAscii("user");
60     shareDirString =  ::rtl::OUString::createFromAscii("share");
61     bundledDirString = ::rtl::OUString::createFromAscii("bundled");
62 }
63 
64 ActiveMSPList::~ActiveMSPList()
65 {
66 }
67 
68 Reference< provider::XScriptProvider >
69 ActiveMSPList::createNewMSP( const uno::Any& context )
70 {
71     ::rtl::OUString serviceName = ::rtl::OUString::createFromAscii("com.sun.star.script.provider.MasterScriptProvider");
72     Sequence< Any > args( &context, 1 );
73 
74     Reference< provider::XScriptProvider > msp(
75         m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
76             serviceName, args, m_xContext ), UNO_QUERY );
77     return msp;
78 }
79 
80 Reference< provider::XScriptProvider >
81 ActiveMSPList::getMSPFromAnyContext( const Any& aContext )
82             SAL_THROW(( lang::IllegalArgumentException, RuntimeException ))
83 {
84     Reference< provider::XScriptProvider > msp;
85     ::rtl::OUString sContext;
86     if ( aContext >>= sContext )
87     {
88         msp = getMSPFromStringContext( sContext );
89         return msp;
90     }
91 
92     Reference< frame::XModel > xModel( aContext, UNO_QUERY );
93 
94     Reference< document::XScriptInvocationContext > xScriptContext( aContext, UNO_QUERY );
95     if ( xScriptContext.is() )
96     {
97 		try
98 		{
99 			// the component supports executing scripts embedded in a - possibly foreign document.
100 			// Check whether this other document its the component itself.
101 			if ( !xModel.is() || ( xModel != xScriptContext->getScriptContainer() ) )
102 			{
103 				msp = getMSPFromInvocationContext( xScriptContext );
104 				return msp;
105 			}
106 		}
107 		catch( const lang::IllegalArgumentException& )
108 		{
109 			xModel.set( Reference< frame::XModel >() );
110 		}
111     }
112 
113     if ( xModel.is() )
114     {
115         sContext = MiscUtils::xModelToTdocUrl( xModel, m_xContext );
116         msp = getMSPFromStringContext( sContext );
117         return msp;
118     }
119 
120     createNonDocMSPs();
121     return m_hMsps[ shareDirString ];
122 }
123 
124 Reference< provider::XScriptProvider >
125     ActiveMSPList::getMSPFromInvocationContext( const Reference< document::XScriptInvocationContext >& xContext )
126         SAL_THROW(( lang::IllegalArgumentException, RuntimeException ))
127 {
128     Reference< provider::XScriptProvider > msp;
129 
130     Reference< document::XEmbeddedScripts > xScripts;
131     if ( xContext.is() )
132         xScripts.set( xContext->getScriptContainer() );
133     if ( !xScripts.is() )
134     {
135         ::rtl::OUStringBuffer buf;
136         buf.appendAscii( "Failed to create MasterScriptProvider for ScriptInvocationContext: " );
137         buf.appendAscii( "Component supporting XEmbeddScripts interface not found." );
138         throw lang::IllegalArgumentException( buf.makeStringAndClear(), NULL, 1 );
139     }
140 
141     ::osl::MutexGuard guard( m_mutex );
142 
143     Reference< XInterface > xNormalized( xContext, UNO_QUERY );
144     ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
145     if ( pos == m_mScriptComponents.end() )
146     {
147         // TODO
148         msp = createNewMSP( uno::makeAny( xContext ) );
149         addActiveMSP( xNormalized, msp );
150     }
151     else
152     {
153         msp = pos->second;
154     }
155 
156     return msp;
157 }
158 
159 Reference< provider::XScriptProvider >
160     ActiveMSPList::getMSPFromStringContext( const ::rtl::OUString& context )
161         SAL_THROW(( lang::IllegalArgumentException, RuntimeException ))
162 {
163     Reference< provider::XScriptProvider > msp;
164     try
165     {
166         if ( context.indexOf( OUSTR( "vnd.sun.star.tdoc" ) ) == 0 )
167         {
168             Reference< frame::XModel > xModel( MiscUtils::tDocUrlToModel( context ) );
169 
170             Reference< document::XEmbeddedScripts > xScripts( xModel, UNO_QUERY );
171             Reference< document::XScriptInvocationContext > xScriptsContext( xModel, UNO_QUERY );
172             if ( !xScripts.is() && !xScriptsContext.is() )
173             {
174                 ::rtl::OUStringBuffer buf;
175                 buf.appendAscii( "Failed to create MasterScriptProvider for '" );
176                 buf.append     ( context );
177                 buf.appendAscii( "': Either XEmbeddScripts or XScriptInvocationContext need to be supported by the document." );
178                 throw lang::IllegalArgumentException( buf.makeStringAndClear(), NULL, 1 );
179             }
180 
181             ::osl::MutexGuard guard( m_mutex );
182             Reference< XInterface > xNormalized( xModel, UNO_QUERY );
183             ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
184             if ( pos == m_mScriptComponents.end() )
185             {
186                 msp = createNewMSP( context );
187                 addActiveMSP( xNormalized, msp );
188             }
189             else
190             {
191                 msp = pos->second;
192             }
193         }
194         else
195         {
196             ::osl::MutexGuard guard( m_mutex );
197             Msp_hash::iterator h_itEnd =  m_hMsps.end();
198             Msp_hash::const_iterator itr = m_hMsps.find( context );
199             if ( itr ==  h_itEnd )
200             {
201                 msp = createNewMSP( context );
202                 m_hMsps[ context ] = msp;
203             }
204             else
205             {
206                 msp = m_hMsps[ context ];
207             }
208         }
209     }
210     catch( const lang::IllegalArgumentException& )
211     {
212         // allowed to leave
213     }
214     catch( const RuntimeException& )
215     {
216         // allowed to leave
217     }
218     catch( const Exception& )
219     {
220         ::rtl::OUStringBuffer aMessage;
221         aMessage.appendAscii( "Failed to create MasterScriptProvider for context '" );
222         aMessage.append     ( context );
223         aMessage.appendAscii( "'." );
224         throw lang::WrappedTargetRuntimeException(
225             aMessage.makeStringAndClear(), *this, ::cppu::getCaughtException() );
226     }
227     return msp;
228 }
229 
230 void
231 ActiveMSPList::addActiveMSP( const Reference< uno::XInterface >& xComponent,
232 	       	const Reference< provider::XScriptProvider >& msp )
233 {
234     ::osl::MutexGuard guard( m_mutex );
235     Reference< XInterface > xNormalized( xComponent, UNO_QUERY );
236     ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
237     if ( pos == m_mScriptComponents.end() )
238     {
239         m_mScriptComponents[ xNormalized ] = msp;
240 
241         // add self as listener for component disposal
242         // should probably throw from this method!!, reexamine
243         try
244         {
245             Reference< lang::XComponent > xBroadcaster =
246                 Reference< lang::XComponent >( xComponent, UNO_QUERY_THROW );
247             xBroadcaster->addEventListener( this );
248         }
249         catch ( const Exception& )
250         {
251             DBG_UNHANDLED_EXCEPTION();
252         }
253     }
254 }
255 
256 //*************************************************************************
257 void SAL_CALL
258 ActiveMSPList::disposing( const ::com::sun::star::lang::EventObject& Source )
259 throw ( ::com::sun::star::uno::RuntimeException )
260 
261 {
262     try
263     {
264         Reference< XInterface > xNormalized( Source.Source, UNO_QUERY );
265         if ( xNormalized.is() )
266         {
267             ::osl::MutexGuard guard( m_mutex );
268             ScriptComponent_map::iterator pos = m_mScriptComponents.find( xNormalized );
269             if ( pos != m_mScriptComponents.end() )
270                 m_mScriptComponents.erase( pos );
271         }
272     }
273     catch ( const Exception& )
274     {
275         // if we get an exception here, there is not much we can do about
276         // it can't throw as it will screw up the model that is calling dispose
277         DBG_UNHANDLED_EXCEPTION();
278     }
279 }
280 
281 
282 void
283 ActiveMSPList::createNonDocMSPs()
284 {
285     static bool created = false;
286     if ( created )
287     {
288         return;
289     }
290     else
291     {
292         ::osl::MutexGuard guard( m_mutex );
293         if ( created )
294         {
295             return;
296         }
297         // do creation of user and share MSPs here
298         ::rtl::OUString serviceName = ::rtl::OUString::createFromAscii("com.sun.star.script.provider.MasterScriptProvider");
299         Sequence< Any > args(1);
300 
301         args[ 0 ] <<= userDirString;
302         Reference< provider::XScriptProvider > userMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
303         // should check if provider reference is valid
304         m_hMsps[ userDirString ] = userMsp;
305 
306         args[ 0 ] <<= shareDirString;
307         Reference< provider::XScriptProvider > shareMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
308         // should check if provider reference is valid
309         m_hMsps[ shareDirString ] = shareMsp;
310 
311         args[ 0 ] <<= bundledDirString;
312         Reference< provider::XScriptProvider > bundledMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
313         // should check if provider reference is valid
314         m_hMsps[ bundledDirString ] = bundledMsp;
315 
316         created = true;
317     }
318 
319 }
320 
321 
322 } // namespace func_provider
323 
324