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 <cppuhelper/exc_hlp.hxx> 23 #include <util/MiscUtils.hxx> 24 25 #include <com/sun/star/beans/XPropertySet.hpp> 26 #include <com/sun/star/util/XMacroExpander.hpp> 27 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> 28 29 #include "MasterScriptProvider.hxx" 30 #include "ActiveMSPList.hxx" 31 32 #include <tools/diagnose_ex.h> 33 34 using namespace com::sun::star; 35 using namespace com::sun::star::uno; 36 using namespace com::sun::star::script; 37 using namespace ::sf_misc; 38 39 namespace func_provider 40 { 41 42 ActiveMSPList::ActiveMSPList( const Reference< XComponentContext > & xContext ) : m_xContext( xContext ) 43 { 44 userDirString = "user"; 45 shareDirString = "share"; 46 bundledDirString = "bundled"; 47 } 48 49 ActiveMSPList::~ActiveMSPList() 50 { 51 } 52 53 Reference< provider::XScriptProvider > 54 ActiveMSPList::createNewMSP( const uno::Any& context ) 55 { 56 Sequence< Any > args( &context, 1 ); 57 58 Reference< provider::XScriptProvider > msp( 59 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( 60 "com.sun.star.script.provider.MasterScriptProvider", args, m_xContext ), UNO_QUERY ); 61 return msp; 62 } 63 64 class NonDocMSPCreator 65 { 66 public: 67 explicit NonDocMSPCreator(ActiveMSPList *pList) 68 { 69 pList->createNonDocMSPs(); 70 } 71 }; 72 73 namespace 74 { 75 //thread-safe double-locked class to ensure createNonDocMSPs is called once 76 class theNonDocMSPCreator : public rtl::StaticWithArg<NonDocMSPCreator, ActiveMSPList*, theNonDocMSPCreator> {}; 77 78 void ensureNonDocMSPs(ActiveMSPList *pList) 79 { 80 theNonDocMSPCreator::get(pList); 81 } 82 } 83 84 Reference< provider::XScriptProvider > 85 ActiveMSPList::getMSPFromAnyContext( const Any& aContext ) 86 { 87 Reference< provider::XScriptProvider > msp; 88 OUString sContext; 89 if ( aContext >>= sContext ) 90 { 91 msp = getMSPFromStringContext( sContext ); 92 return msp; 93 } 94 95 Reference< frame::XModel > xModel( aContext, UNO_QUERY ); 96 97 Reference< document::XScriptInvocationContext > xScriptContext( aContext, UNO_QUERY ); 98 if ( xScriptContext.is() ) 99 { 100 try 101 { 102 // the component supports executing scripts embedded in a - possibly foreign document. 103 // Check whether this other document it's the component itself. 104 if ( !xModel.is() || ( xModel != xScriptContext->getScriptContainer() ) ) 105 { 106 msp = getMSPFromInvocationContext( xScriptContext ); 107 return msp; 108 } 109 } 110 catch( const lang::IllegalArgumentException& ) 111 { 112 xModel.set( Reference< frame::XModel >() ); 113 } 114 } 115 116 if ( xModel.is() ) 117 { 118 sContext = MiscUtils::xModelToTdocUrl( xModel, m_xContext ); 119 msp = getMSPFromStringContext( sContext ); 120 return msp; 121 } 122 123 ensureNonDocMSPs(this); 124 return m_hMsps[ shareDirString ]; 125 } 126 127 Reference< provider::XScriptProvider > 128 ActiveMSPList::getMSPFromInvocationContext( const Reference< document::XScriptInvocationContext >& xContext ) 129 { 130 Reference< provider::XScriptProvider > msp; 131 132 Reference< document::XEmbeddedScripts > xScripts; 133 if ( xContext.is() ) 134 xScripts.set( xContext->getScriptContainer() ); 135 if ( !xScripts.is() ) 136 { 137 throw lang::IllegalArgumentException( 138 "Failed to create MasterScriptProvider for ScriptInvocationContext: " 139 "Component supporting XEmbeddScripts interface not found.", 140 nullptr, 1 ); 141 } 142 143 ::osl::MutexGuard guard( m_mutex ); 144 145 Reference< XInterface > xNormalized( xContext, UNO_QUERY ); 146 ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized ); 147 if ( pos == m_mScriptComponents.end() ) 148 { 149 // TODO 150 msp = createNewMSP( uno::makeAny( xContext ) ); 151 addActiveMSP( xNormalized, msp ); 152 } 153 else 154 { 155 msp = pos->second; 156 } 157 158 return msp; 159 } 160 161 Reference< provider::XScriptProvider > 162 ActiveMSPList::getMSPFromStringContext( const OUString& context ) 163 { 164 Reference< provider::XScriptProvider > msp; 165 try 166 { 167 if ( context.startsWith( "vnd.sun.star.tdoc" ) ) 168 { 169 Reference< frame::XModel > xModel( MiscUtils::tDocUrlToModel( context ) ); 170 171 Reference< document::XEmbeddedScripts > xScripts( xModel, UNO_QUERY ); 172 Reference< document::XScriptInvocationContext > xScriptsContext( xModel, UNO_QUERY ); 173 if ( !xScripts.is() && !xScriptsContext.is() ) 174 { 175 throw lang::IllegalArgumentException( 176 "Failed to create MasterScriptProvider for '" 177 + context + 178 "': Either XEmbeddScripts or XScriptInvocationContext need to be supported by the document.", 179 nullptr, 1 ); 180 } 181 182 ::osl::MutexGuard guard( m_mutex ); 183 Reference< XInterface > xNormalized( xModel, UNO_QUERY ); 184 ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized ); 185 if ( pos == m_mScriptComponents.end() ) 186 { 187 msp = createNewMSP( context ); 188 addActiveMSP( xNormalized, msp ); 189 } 190 else 191 { 192 msp = pos->second; 193 } 194 } 195 else 196 { 197 ::osl::MutexGuard guard( m_mutex ); 198 Msp_hash::iterator h_itEnd = m_hMsps.end(); 199 Msp_hash::const_iterator itr = m_hMsps.find( context ); 200 if ( itr == h_itEnd ) 201 { 202 msp = createNewMSP( context ); 203 m_hMsps[ context ] = msp; 204 } 205 else 206 { 207 msp = m_hMsps[ context ]; 208 } 209 } 210 } 211 catch( const lang::IllegalArgumentException& ) 212 { 213 // allowed to leave 214 } 215 catch( const RuntimeException& ) 216 { 217 // allowed to leave 218 } 219 catch( const Exception& ) 220 { 221 css::uno::Any anyEx = cppu::getCaughtException(); 222 throw lang::WrappedTargetRuntimeException( 223 "Failed to create MasterScriptProvider for context '" 224 + context + "'.", 225 *this, anyEx ); 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("scripting"); 252 } 253 } 254 } 255 256 257 void SAL_CALL ActiveMSPList::disposing( const css::lang::EventObject& Source ) 258 259 { 260 try 261 { 262 Reference< XInterface > xNormalized( Source.Source, UNO_QUERY ); 263 if ( xNormalized.is() ) 264 { 265 ::osl::MutexGuard guard( m_mutex ); 266 ScriptComponent_map::iterator pos = m_mScriptComponents.find( xNormalized ); 267 if ( pos != m_mScriptComponents.end() ) 268 m_mScriptComponents.erase( pos ); 269 } 270 } 271 catch ( const Exception& ) 272 { 273 // if we get an exception here, there is not much we can do about 274 // it can't throw as it will screw up the model that is calling dispose 275 DBG_UNHANDLED_EXCEPTION("scripting"); 276 } 277 } 278 279 void 280 ActiveMSPList::createNonDocMSPs() 281 { 282 // do creation of user and share MSPs here 283 OUString serviceName("com.sun.star.script.provider.MasterScriptProvider"); 284 Sequence< Any > args(1); 285 286 args[ 0 ] <<= userDirString; 287 Reference< provider::XScriptProvider > userMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY ); 288 // should check if provider reference is valid 289 m_hMsps[ userDirString ] = userMsp; 290 291 args[ 0 ] <<= shareDirString; 292 Reference< provider::XScriptProvider > shareMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY ); 293 // should check if provider reference is valid 294 m_hMsps[ shareDirString ] = shareMsp; 295 296 args[ 0 ] <<= bundledDirString; 297 Reference< provider::XScriptProvider > bundledMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY ); 298 // should check if provider reference is valid 299 m_hMsps[ bundledDirString ] = bundledMsp; 300 } 301 302 } // namespace func_provider 303 304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 305
