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 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_framework.hxx" 26 27 //_______________________________________________ 28 // include own header 29 30 #include <jobs/shelljob.hxx> 31 #include <jobs/jobconst.hxx> 32 #include <threadhelp/readguard.hxx> 33 #include <services.h> 34 35 //_______________________________________________ 36 // include others 37 38 #include <osl/file.hxx> 39 #include <osl/process.h> 40 #include <vcl/svapp.hxx> 41 #include <rtl/ustrbuf.hxx> 42 #include <comphelper/sequenceashashmap.hxx> 43 44 //_______________________________________________ 45 // include interfaces 46 47 #include <com/sun/star/util/XStringSubstitution.hpp> 48 49 //_______________________________________________ 50 // namespace 51 52 namespace framework{ 53 54 //_______________________________________________ 55 // definitions 56 57 /** adress job configuration inside argument set provided on method execute(). */ 58 static const ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig"); 59 60 /** adress job configuration property "Command". */ 61 static const ::rtl::OUString PROP_COMMAND = ::rtl::OUString::createFromAscii("Command"); 62 63 /** adress job configuration property "Arguments". */ 64 static const ::rtl::OUString PROP_ARGUMENTS = ::rtl::OUString::createFromAscii("Arguments"); 65 66 /** adress job configuration property "DeactivateJobIfDone". */ 67 static const ::rtl::OUString PROP_DEACTIVATEJOBIFDONE = ::rtl::OUString::createFromAscii("DeactivateJobIfDone"); 68 69 /** adress job configuration property "CheckExitCode". */ 70 static const ::rtl::OUString PROP_CHECKEXITCODE = ::rtl::OUString::createFromAscii("CheckExitCode"); 71 72 //----------------------------------------------- 73 74 DEFINE_XSERVICEINFO_MULTISERVICE(ShellJob , 75 ::cppu::OWeakObject , 76 SERVICENAME_JOB , 77 IMPLEMENTATIONNAME_SHELLJOB) 78 79 DEFINE_INIT_SERVICE(ShellJob, 80 { 81 /* Attention 82 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() 83 to create a new instance of this class by our own supported service factory. 84 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! 85 */ 86 } 87 ) 88 89 //----------------------------------------------- 90 ShellJob::ShellJob(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) 91 : ThreadHelpBase( ) 92 , m_xSMGR (xSMGR) 93 { 94 } 95 96 //----------------------------------------------- 97 ShellJob::~ShellJob() 98 { 99 } 100 101 //----------------------------------------------- 102 css::uno::Any SAL_CALL ShellJob::execute(const css::uno::Sequence< css::beans::NamedValue >& lJobArguments) 103 throw(css::lang::IllegalArgumentException, 104 css::uno::Exception , 105 css::uno::RuntimeException ) 106 { 107 ::comphelper::SequenceAsHashMap lArgs (lJobArguments); 108 ::comphelper::SequenceAsHashMap lOwnCfg(lArgs.getUnpackedValueOrDefault(PROP_JOBCONFIG, css::uno::Sequence< css::beans::NamedValue >())); 109 110 const ::rtl::OUString sCommand = lOwnCfg.getUnpackedValueOrDefault(PROP_COMMAND , ::rtl::OUString()); 111 const css::uno::Sequence< ::rtl::OUString > lCommandArguments = lOwnCfg.getUnpackedValueOrDefault(PROP_ARGUMENTS , css::uno::Sequence< ::rtl::OUString >()); 112 const ::sal_Bool bDeactivateJobIfDone = lOwnCfg.getUnpackedValueOrDefault(PROP_DEACTIVATEJOBIFDONE , sal_True ); 113 const ::sal_Bool bCheckExitCode = lOwnCfg.getUnpackedValueOrDefault(PROP_CHECKEXITCODE , sal_True ); 114 115 // replace all might existing place holder. 116 ::rtl::OUString sRealCommand = impl_substituteCommandVariables(sCommand); 117 118 // Command is required as minimum. 119 // If it does not exists ... we cant do our job. 120 // Deactivate such miss configured job silently .-) 121 if (sRealCommand.getLength() < 1) 122 return ShellJob::impl_generateAnswer4Deactivation(); 123 124 // do it 125 ::sal_Bool bDone = impl_execute(sRealCommand, lCommandArguments, bCheckExitCode); 126 if (! bDone) 127 return css::uno::Any(); 128 129 // Job was done ... user configured deactivation of this job 130 // in such case. 131 if (bDeactivateJobIfDone) 132 return ShellJob::impl_generateAnswer4Deactivation(); 133 134 // There was no decision about deactivation of this job. 135 // So we have to return nothing here ! 136 return css::uno::Any(); 137 } 138 139 //----------------------------------------------- 140 css::uno::Any ShellJob::impl_generateAnswer4Deactivation() 141 { 142 css::uno::Sequence< css::beans::NamedValue > aAnswer(1); 143 aAnswer[0].Name = JobConst::ANSWER_DEACTIVATE_JOB(); 144 aAnswer[0].Value = css::uno::makeAny(sal_True); 145 146 return css::uno::makeAny(aAnswer); 147 } 148 149 //----------------------------------------------- 150 ::rtl::OUString ShellJob::impl_substituteCommandVariables(const ::rtl::OUString& sCommand) 151 { 152 // SYNCHRONIZED -> 153 ReadGuard aReadLock(m_aLock); 154 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; 155 aReadLock.unlock(); 156 // <- SYNCHRONIZED 157 158 try 159 { 160 css::uno::Reference< css::util::XStringSubstitution > xSubst ( xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES), css::uno::UNO_QUERY_THROW); 161 const ::sal_Bool bSubstRequired = sal_True; 162 const ::rtl::OUString sCompleteCommand = xSubst->substituteVariables(sCommand, bSubstRequired); 163 164 return sCompleteCommand; 165 } 166 catch(const css::uno::Exception&) 167 {} 168 169 return ::rtl::OUString(); 170 } 171 172 //----------------------------------------------- 173 ::sal_Bool ShellJob::impl_execute(const ::rtl::OUString& sCommand , 174 const css::uno::Sequence< ::rtl::OUString >& lArguments , 175 ::sal_Bool bCheckExitCode) 176 { 177 ::rtl_uString** pArgs = NULL; 178 const ::sal_Int32 nArgs = lArguments.getLength (); 179 oslProcessOption nOptions = osl_Process_WAIT; 180 oslProcess hProcess(0); 181 182 if (nArgs > 0) 183 pArgs = reinterpret_cast< ::rtl_uString** >(const_cast< ::rtl::OUString* >(lArguments.getConstArray())); 184 185 oslProcessError eError = osl_executeProcess(sCommand.pData, pArgs, nArgs, nOptions, NULL, NULL, NULL, 0, &hProcess); 186 187 // executable not found or couldnt be started 188 if (eError != osl_Process_E_None) 189 return sal_False; 190 191 ::sal_Bool bRet = sal_True; 192 if (bCheckExitCode) 193 { 194 // check its return codes ... 195 oslProcessInfo aInfo; 196 aInfo.Size = sizeof (oslProcessInfo); 197 eError = osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo); 198 199 if (eError != osl_Process_E_None) 200 bRet = sal_False; 201 else 202 bRet = (aInfo.Code == 0); 203 } 204 osl_freeProcessHandle(hProcess); 205 return bRet; 206 } 207 208 } // namespace framework 209