Line data Source code
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 <jobs/jobdata.hxx>
21 : #include <classes/converter.hxx>
22 : #include <general.h>
23 : #include <services.h>
24 :
25 : #include <com/sun/star/beans/XPropertySet.hpp>
26 : #include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
27 : #include <com/sun/star/container/XNameAccess.hpp>
28 : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
29 :
30 : #include <tools/wldcrd.hxx>
31 : #include <unotools/configpaths.hxx>
32 : #include <vcl/svapp.hxx>
33 :
34 : namespace framework{
35 :
36 : /**
37 : @short standard ctor
38 : @descr It initialize this new instance.
39 : But for real working it's necessary to call setAlias() or setService() later.
40 : Because we need the job data ...
41 :
42 : @param rxContext
43 : reference to the uno service manager
44 : */
45 0 : JobData::JobData( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
46 0 : : m_xContext (rxContext )
47 : {
48 : // share code for member initialization with defaults!
49 0 : impl_reset();
50 0 : }
51 :
52 : /**
53 : @short copy ctor
54 : @descr Sometimes such job data container must be moved from one using place
55 : to another one. Then a copy ctor and copy operator must be available.
56 :
57 : @param rCopy
58 : the original instance, from which we must copy all data
59 : */
60 0 : JobData::JobData( const JobData& rCopy )
61 : {
62 : // use the copy operator to share the same code
63 0 : *this = rCopy;
64 0 : }
65 :
66 : /**
67 : @short operator for coping JobData instances
68 : @descr Sometimes such job data container must be moved from one using place
69 : to another one. Then a copy ctor and copy operator must be available.
70 :
71 : @param rCopy
72 : the original instance, from which we must copy all data
73 : */
74 0 : void JobData::operator=( const JobData& rCopy )
75 : {
76 0 : SolarMutexGuard g;
77 : // Please don't copy the uno service manager reference.
78 : // That can change the uno context, which isn't a good idea!
79 0 : m_eMode = rCopy.m_eMode;
80 0 : m_eEnvironment = rCopy.m_eEnvironment;
81 0 : m_sAlias = rCopy.m_sAlias;
82 0 : m_sService = rCopy.m_sService;
83 0 : m_sContext = rCopy.m_sContext;
84 0 : m_sEvent = rCopy.m_sEvent;
85 0 : m_lArguments = rCopy.m_lArguments;
86 0 : m_aLastExecutionResult = rCopy.m_aLastExecutionResult;
87 0 : }
88 :
89 : /**
90 : @short let this instance die
91 : @descr There is no chance any longer to work. We have to
92 : release all used resources and free used memory.
93 : */
94 0 : JobData::~JobData()
95 : {
96 0 : impl_reset();
97 0 : }
98 :
99 : /**
100 : @short initalize this instance as a job with configuration
101 : @descr They given alias can be used to address some configuration data.
102 : We read it and fill our internal structures. Of course old information
103 : will be lost doing so.
104 :
105 : @param sAlias
106 : the alias name of this job, used to locate job properties inside cfg
107 : */
108 0 : void JobData::setAlias( const OUString& sAlias )
109 : {
110 0 : SolarMutexGuard g;
111 : // delete all old information! Otherwhise we mix it with the new one ...
112 0 : impl_reset();
113 :
114 : // take over the new information
115 0 : m_sAlias = sAlias;
116 0 : m_eMode = E_ALIAS;
117 :
118 : // try to open the configuration set of this job directly and get a property access to it
119 : // We open it readonly here
120 : ConfigAccess aConfig(
121 : m_xContext,
122 : ("/org.openoffice.Office.Jobs/Jobs/"
123 0 : + utl::wrapConfigurationElementName(m_sAlias)));
124 0 : aConfig.open(ConfigAccess::E_READONLY);
125 0 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
126 : {
127 0 : impl_reset();
128 0 : return;
129 : }
130 :
131 0 : css::uno::Reference< css::beans::XPropertySet > xJobProperties(aConfig.cfg(), css::uno::UNO_QUERY);
132 0 : if (xJobProperties.is())
133 : {
134 0 : css::uno::Any aValue;
135 :
136 : // read uno implementation name
137 0 : aValue = xJobProperties->getPropertyValue("Service");
138 0 : aValue >>= m_sService;
139 :
140 : // read module context list
141 0 : aValue = xJobProperties->getPropertyValue("Context");
142 0 : aValue >>= m_sContext;
143 :
144 : // read whole argument list
145 0 : aValue = xJobProperties->getPropertyValue("Arguments");
146 0 : css::uno::Reference< css::container::XNameAccess > xArgumentList;
147 0 : if (
148 0 : (aValue >>= xArgumentList) &&
149 0 : (xArgumentList.is() )
150 : )
151 : {
152 0 : css::uno::Sequence< OUString > lArgumentNames = xArgumentList->getElementNames();
153 0 : sal_Int32 nCount = lArgumentNames.getLength();
154 0 : m_lArguments.realloc(nCount);
155 0 : for (sal_Int32 i=0; i<nCount; ++i)
156 : {
157 0 : m_lArguments[i].Name = lArgumentNames[i];
158 0 : m_lArguments[i].Value = xArgumentList->getByName(m_lArguments[i].Name);
159 0 : }
160 0 : }
161 : }
162 :
163 0 : aConfig.close();
164 : }
165 :
166 : /**
167 : @short initalize this instance as a job without configuration
168 : @descr This job has no configuration data. We have to forget all old information
169 : and set only some of them new, so this instance can work.
170 :
171 : @param sService
172 : the uno service name of this "non configured" job
173 : */
174 0 : void JobData::setService( const OUString& sService )
175 : {
176 0 : SolarMutexGuard g;
177 : // delete all old information! Otherwhise we mix it with the new one ...
178 0 : impl_reset();
179 : // take over the new information
180 0 : m_sService = sService;
181 0 : m_eMode = E_SERVICE;
182 0 : }
183 :
184 : /**
185 : @short initialize this instance with new job values.
186 : @descr It reads automaticly all properties of the specified
187 : job (using it's alias name) and "register it" for the
188 : given event. This registration will not be validated against
189 : the underlying configuration! (That must be done from outside.
190 : Because the caller must have the configuration already open to
191 : get the values for sEvent and sAlias! And doing so it can perform
192 : only, if the time stanp values are readed outside too.
193 : Further it make no sense to initialize and start a disabled job.
194 : So this initialization method will be called for enabled jobs only.)
195 :
196 : @param sEvent
197 : the triggered event, for which this job should be started
198 :
199 : @param sAlias
200 : mark the required job inside event registration list
201 : */
202 0 : void JobData::setEvent( const OUString& sEvent ,
203 : const OUString& sAlias )
204 : {
205 : // share code to read all job properties!
206 0 : setAlias(sAlias);
207 :
208 0 : SolarMutexGuard g;
209 : // take over the new information - which differ against set on of method setAlias()!
210 0 : m_sEvent = sEvent;
211 0 : m_eMode = E_EVENT;
212 0 : }
213 :
214 : /**
215 : @short set the new job specific arguments
216 : @descr If a job finish his work, it can give us a new list of arguments (which
217 : will not interpreted by us). We write it back to the configuration only
218 : (if this job has it's own configuration!).
219 : So a job can have persistent data without implementing anything
220 : or define own config areas for that.
221 :
222 : @param lArguments
223 : list of arguments, which should be set for this job
224 : */
225 0 : void JobData::setJobConfig( const css::uno::Sequence< css::beans::NamedValue >& lArguments )
226 : {
227 0 : SolarMutexGuard g;
228 :
229 : // update member
230 0 : m_lArguments = lArguments;
231 :
232 : // update the configuration ... if possible!
233 0 : if (m_eMode==E_ALIAS)
234 : {
235 : // It doesn't matter if this config object was already opened before.
236 : // It doesn nothing here then ... or it change the mode automaticly, if
237 : // it was opened using another one before.
238 : ConfigAccess aConfig(
239 : m_xContext,
240 : ("/org.openoffice.Office.Jobs/Jobs/"
241 0 : + utl::wrapConfigurationElementName(m_sAlias)));
242 0 : aConfig.open(ConfigAccess::E_READWRITE);
243 0 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
244 0 : return;
245 :
246 0 : css::uno::Reference< css::beans::XMultiHierarchicalPropertySet > xArgumentList(aConfig.cfg(), css::uno::UNO_QUERY);
247 0 : if (xArgumentList.is())
248 : {
249 0 : sal_Int32 nCount = m_lArguments.getLength();
250 0 : css::uno::Sequence< OUString > lNames (nCount);
251 0 : css::uno::Sequence< css::uno::Any > lValues(nCount);
252 :
253 0 : for (sal_Int32 i=0; i<nCount; ++i)
254 : {
255 0 : lNames [i] = m_lArguments[i].Name;
256 0 : lValues[i] = m_lArguments[i].Value;
257 : }
258 :
259 0 : xArgumentList->setHierarchicalPropertyValues(lNames, lValues);
260 : }
261 0 : aConfig.close();
262 0 : }
263 : }
264 :
265 : /**
266 : @short set a new excution result
267 : @descr Every executed job can have returned a result.
268 : We set it here, so our user can use it may be later.
269 : But the outside code can use it too, to analyze it and
270 : adopt the configuration of this job too. Because the
271 : result uses a protocol, which allow that. And we provide
272 : right functionality to save it.
273 :
274 : @param aResult
275 : the result of last execution
276 : */
277 0 : void JobData::setResult( const JobResult& aResult )
278 : {
279 0 : SolarMutexGuard g;
280 :
281 : // overwrite the last saved result
282 0 : m_aLastExecutionResult = aResult;
283 :
284 : // Don't use his information to update
285 : // e.g. the arguments of this job. It must be done
286 : // from outside! Here we save this information only.
287 0 : }
288 :
289 : /**
290 : @short set a new environment descriptor for this job
291 : @descr It must(!) be done everytime this container is initialized
292 : with new job datas e.g.: setAlias()/setEvent()/setService() ...
293 : Otherwhise the environment will be unknown!
294 : */
295 0 : void JobData::setEnvironment( EEnvironment eEnvironment )
296 : {
297 0 : SolarMutexGuard g;
298 0 : m_eEnvironment = eEnvironment;
299 0 : }
300 :
301 : /**
302 : @short these functions provides access to our internal members
303 : @descr These member represent any information about the job
304 : and can be used from outside to e.g. start a job.
305 : */
306 0 : JobData::EMode JobData::getMode() const
307 : {
308 0 : SolarMutexGuard g;
309 0 : return m_eMode;
310 : }
311 :
312 0 : JobData::EEnvironment JobData::getEnvironment() const
313 : {
314 0 : SolarMutexGuard g;
315 0 : return m_eEnvironment;
316 : }
317 :
318 0 : OUString JobData::getEnvironmentDescriptor() const
319 : {
320 0 : OUString sDescriptor;
321 0 : SolarMutexGuard g;
322 0 : switch(m_eEnvironment)
323 : {
324 : case E_EXECUTION :
325 0 : sDescriptor = "EXECUTOR";
326 0 : break;
327 :
328 : case E_DISPATCH :
329 0 : sDescriptor = "DISPATCH";
330 0 : break;
331 :
332 : case E_DOCUMENTEVENT :
333 0 : sDescriptor = "DOCUMENTEVENT";
334 0 : break;
335 : default:
336 0 : break;
337 : }
338 0 : return sDescriptor;
339 : }
340 :
341 0 : OUString JobData::getService() const
342 : {
343 0 : SolarMutexGuard g;
344 0 : return m_sService;
345 : }
346 :
347 0 : OUString JobData::getEvent() const
348 : {
349 0 : SolarMutexGuard g;
350 0 : return m_sEvent;
351 : }
352 :
353 0 : css::uno::Sequence< css::beans::NamedValue > JobData::getJobConfig() const
354 : {
355 0 : SolarMutexGuard g;
356 0 : return m_lArguments;
357 : }
358 :
359 0 : css::uno::Sequence< css::beans::NamedValue > JobData::getConfig() const
360 : {
361 0 : SolarMutexGuard g;
362 0 : css::uno::Sequence< css::beans::NamedValue > lConfig;
363 0 : if (m_eMode==E_ALIAS)
364 : {
365 0 : lConfig.realloc(3);
366 0 : sal_Int32 i = 0;
367 :
368 0 : lConfig[i].Name = "Alias";
369 0 : lConfig[i].Value <<= m_sAlias;
370 0 : ++i;
371 :
372 0 : lConfig[i].Name = "Service";
373 0 : lConfig[i].Value <<= m_sService;
374 0 : ++i;
375 :
376 0 : lConfig[i].Name = "Context";
377 0 : lConfig[i].Value <<= m_sContext;
378 0 : ++i;
379 : }
380 0 : return lConfig;
381 : }
382 :
383 : /**
384 : @short return information, if this job is part of the global configuration package
385 : org.openoffice.Office.Jobs
386 : @descr Because jobs can be executed by the dispatch framework using an uno service name
387 : directly - an executed job must not have any configuration really. Such jobs
388 : must provide the right interfaces only! But after finishing jobs can return
389 : some information (e.g. for updating her configuration ...). We must know
390 : if such request is valid or not then.
391 :
392 : @return sal_True if the represented job is part of the underlying configuration package.
393 : */
394 0 : bool JobData::hasConfig() const
395 : {
396 0 : SolarMutexGuard g;
397 0 : return (m_eMode==E_ALIAS || m_eMode==E_EVENT);
398 : }
399 :
400 : /**
401 : @short mark a job as non startable for further requests
402 : @descr We don't remove the configuration entry! We set a timestamp value only.
403 : And there exist two of them: one for an administrator ... and one for the
404 : current user. We change it for the user layer only. So this JobDispatch can't be
405 : started any more ... till the administrator change his timestamp.
406 : That can be useful for post setup scenarios, which must run one time only.
407 :
408 : Note: This method don't do anything, if ths represented job doesn't have a configuration!
409 : */
410 0 : void JobData::disableJob()
411 : {
412 0 : SolarMutexGuard g;
413 :
414 : // No configuration - not used from EXECUTOR and not triggered from an event => no chance!
415 0 : if (m_eMode!=E_EVENT)
416 0 : return;
417 :
418 : // update the configuration
419 : // It doesn't matter if this config object was already opened before.
420 : // It doesn nothing here then ... or it change the mode automaticly, if
421 : // it was opened using another one before.
422 : ConfigAccess aConfig(
423 : m_xContext,
424 : ("/org.openoffice.Office.Jobs/Events/"
425 0 : + utl::wrapConfigurationElementName(m_sEvent) + "/JobList/"
426 0 : + utl::wrapConfigurationElementName(m_sAlias)));
427 0 : aConfig.open(ConfigAccess::E_READWRITE);
428 0 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
429 0 : return;
430 :
431 0 : css::uno::Reference< css::beans::XPropertySet > xPropSet(aConfig.cfg(), css::uno::UNO_QUERY);
432 0 : if (xPropSet.is())
433 : {
434 : // Convert and write the user timestamp to the configuration.
435 0 : css::uno::Any aValue;
436 0 : aValue <<= Converter::convert_DateTime2ISO8601(DateTime( DateTime::SYSTEM));
437 0 : xPropSet->setPropertyValue("UserTime", aValue);
438 : }
439 :
440 0 : aConfig.close();
441 : }
442 :
443 : /**
444 : */
445 0 : bool isEnabled( const OUString& sAdminTime ,
446 : const OUString& sUserTime )
447 : {
448 : /*Attention!
449 : To prevent interpreting of TriGraphs inside next const string value,
450 : we have to encode all '?' signs. Otherwhise e.g. "??-" will be translated
451 : to "~" ...
452 : */
453 0 : static OUString PATTERN_ISO8601("\?\?\?\?-\?\?-\?\?*");
454 0 : WildCard aISOPattern(PATTERN_ISO8601);
455 :
456 0 : bool bValidAdmin = aISOPattern.Matches(sAdminTime);
457 0 : bool bValidUser = aISOPattern.Matches(sUserTime );
458 :
459 : // We check for "isEnabled()" here only.
460 : // Note further: ISO8601 formated strings can be compared as strings directly!
461 : // FIXME: this is not true! "T1215" is the same time as "T12:15" or "T121500"
462 : return (
463 0 : (!bValidAdmin && !bValidUser ) ||
464 0 : ( bValidAdmin && bValidUser && sAdminTime>=sUserTime)
465 0 : );
466 : }
467 :
468 : /**
469 : */
470 0 : void JobData::appendEnabledJobsForEvent( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
471 : const OUString& sEvent ,
472 : ::comphelper::SequenceAsVector< JobData::TJob2DocEventBinding >& lJobs )
473 : {
474 0 : css::uno::Sequence< OUString > lAdditionalJobs = JobData::getEnabledJobsForEvent(rxContext, sEvent);
475 0 : sal_Int32 c = lAdditionalJobs.getLength();
476 0 : sal_Int32 i = 0;
477 :
478 0 : for (i=0; i<c; ++i)
479 : {
480 0 : JobData::TJob2DocEventBinding aBinding(lAdditionalJobs[i], sEvent);
481 0 : lJobs.push_back(aBinding);
482 0 : }
483 0 : }
484 :
485 : /**
486 : */
487 0 : bool JobData::hasCorrectContext(const OUString& rModuleIdent) const
488 : {
489 0 : sal_Int32 nContextLen = m_sContext.getLength();
490 0 : sal_Int32 nModuleIdLen = rModuleIdent.getLength();
491 :
492 0 : if ( nContextLen == 0 )
493 0 : return true;
494 :
495 0 : if ( nModuleIdLen > 0 )
496 : {
497 0 : sal_Int32 nIndex = m_sContext.indexOf( rModuleIdent );
498 0 : if ( nIndex >= 0 && ( nIndex+nModuleIdLen <= nContextLen ))
499 : {
500 0 : OUString sContextModule = m_sContext.copy( nIndex, nModuleIdLen );
501 0 : return sContextModule.equals( rModuleIdent );
502 : }
503 : }
504 :
505 0 : return false;
506 : }
507 :
508 : /**
509 : */
510 0 : css::uno::Sequence< OUString > JobData::getEnabledJobsForEvent( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
511 : const OUString& sEvent )
512 : {
513 : // create a config access to "/org.openoffice.Office.Jobs/Events"
514 0 : ConfigAccess aConfig(rxContext, "/org.openoffice.Office.Jobs/Events");
515 0 : aConfig.open(ConfigAccess::E_READONLY);
516 0 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
517 0 : return css::uno::Sequence< OUString >();
518 :
519 0 : css::uno::Reference< css::container::XHierarchicalNameAccess > xEventRegistry(aConfig.cfg(), css::uno::UNO_QUERY);
520 0 : if (!xEventRegistry.is())
521 0 : return css::uno::Sequence< OUString >();
522 :
523 : // check if the given event exist inside list of registered ones
524 0 : OUString sPath(sEvent + "/JobList");
525 0 : if (!xEventRegistry->hasByHierarchicalName(sPath))
526 0 : return css::uno::Sequence< OUString >();
527 :
528 : // step to the job list, which is a child of the event node inside cfg
529 : // e.g. "/org.openoffice.Office.Jobs/Events/<event name>/JobList"
530 0 : css::uno::Any aJobList = xEventRegistry->getByHierarchicalName(sPath);
531 0 : css::uno::Reference< css::container::XNameAccess > xJobList;
532 0 : if (!(aJobList >>= xJobList) || !xJobList.is())
533 0 : return css::uno::Sequence< OUString >();
534 :
535 : // get all alias names of jobs, which are part of this job list
536 : // But Some of them can be disabled by it's time stamp values.
537 : // We create an additional job name list with the same size, then the original list ...
538 : // step over all job entries ... check her time stamps ... and put only job names to the
539 : // destination list, which represent an enabled job.
540 0 : css::uno::Sequence< OUString > lAllJobs = xJobList->getElementNames();
541 0 : OUString* pAllJobs = lAllJobs.getArray();
542 0 : sal_Int32 c = lAllJobs.getLength();
543 :
544 0 : css::uno::Sequence< OUString > lEnabledJobs(c);
545 0 : OUString* pEnabledJobs = lEnabledJobs.getArray();
546 0 : sal_Int32 d = 0;
547 :
548 0 : for (sal_Int32 s=0; s<c; ++s)
549 : {
550 0 : css::uno::Reference< css::beans::XPropertySet > xJob;
551 0 : if (
552 0 : !(xJobList->getByName(pAllJobs[s]) >>= xJob) ||
553 0 : !(xJob.is() )
554 : )
555 : {
556 0 : continue;
557 : }
558 :
559 0 : OUString sAdminTime;
560 0 : xJob->getPropertyValue("AdminTime") >>= sAdminTime;
561 :
562 0 : OUString sUserTime;
563 0 : xJob->getPropertyValue("UserTime") >>= sUserTime;
564 :
565 0 : if (!isEnabled(sAdminTime, sUserTime))
566 0 : continue;
567 :
568 0 : pEnabledJobs[d] = pAllJobs[s];
569 0 : ++d;
570 0 : }
571 0 : lEnabledJobs.realloc(d);
572 :
573 0 : aConfig.close();
574 :
575 0 : return lEnabledJobs;
576 : }
577 :
578 : /**
579 : @short reset all internal structures
580 : @descr If someone recycles this instance, he can switch from one
581 : using mode to another one. But then we have to reset all currently
582 : used information. Otherwhise we mix it and they can make trouble.
583 :
584 : But note: that does not set defaults for internal used members, which
585 : does not relate to any job property! e.g. the reference to the global
586 : uno service manager. Such information is used for internal processes only
587 : and are necessary for our work.
588 : */
589 0 : void JobData::impl_reset()
590 : {
591 0 : SolarMutexGuard g;
592 0 : m_eMode = E_UNKNOWN_MODE;
593 0 : m_eEnvironment = E_UNKNOWN_ENVIRONMENT;
594 0 : m_sAlias = "";
595 0 : m_sService = "";
596 0 : m_sContext = "";
597 0 : m_sEvent = "";
598 0 : m_lArguments = css::uno::Sequence< css::beans::NamedValue >();
599 0 : }
600 :
601 : } // namespace framework
602 :
603 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|