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 /** address job configuration inside argument set provided on method execute(). */
58 static const ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig");
59
60 /** address job configuration property "Command". */
61 static const ::rtl::OUString PROP_COMMAND = ::rtl::OUString::createFromAscii("Command");
62
63 /** address job configuration property "Arguments". */
64 static const ::rtl::OUString PROP_ARGUMENTS = ::rtl::OUString::createFromAscii("Arguments");
65
66 /** address job configuration property "DeactivateJobIfDone". */
67 static const ::rtl::OUString PROP_DEACTIVATEJOBIFDONE = ::rtl::OUString::createFromAscii("DeactivateJobIfDone");
68
69 /** address job configuration property "CheckExitCode". */
70 static const ::rtl::OUString PROP_CHECKEXITCODE = ::rtl::OUString::createFromAscii("CheckExitCode");
71
72 //-----------------------------------------------
73
DEFINE_XSERVICEINFO_MULTISERVICE(ShellJob,::cppu::OWeakObject,SERVICENAME_JOB,IMPLEMENTATIONNAME_SHELLJOB)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 //-----------------------------------------------
~ShellJob()97 ShellJob::~ShellJob()
98 {
99 }
100
101 //-----------------------------------------------
execute(const css::uno::Sequence<css::beans::NamedValue> & lJobArguments)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 can't 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 //-----------------------------------------------
impl_generateAnswer4Deactivation()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 //-----------------------------------------------
impl_substituteCommandVariables(const::rtl::OUString & sCommand)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 //-----------------------------------------------
impl_execute(const::rtl::OUString & sCommand,const css::uno::Sequence<::rtl::OUString> & lArguments,::sal_Bool bCheckExitCode)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 couldn't 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