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 637 : JobData::JobData( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
46 637 : : m_xContext (rxContext )
47 : {
48 : // share code for member initialization with defaults!
49 637 : impl_reset();
50 637 : }
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 13 : void JobData::operator=( const JobData& rCopy )
75 : {
76 13 : 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 13 : m_eMode = rCopy.m_eMode;
80 13 : m_eEnvironment = rCopy.m_eEnvironment;
81 13 : m_sAlias = rCopy.m_sAlias;
82 13 : m_sService = rCopy.m_sService;
83 13 : m_sContext = rCopy.m_sContext;
84 13 : m_sEvent = rCopy.m_sEvent;
85 13 : m_lArguments = rCopy.m_lArguments;
86 13 : m_aLastExecutionResult = rCopy.m_aLastExecutionResult;
87 13 : }
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 1274 : JobData::~JobData()
95 : {
96 637 : impl_reset();
97 637 : }
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 624 : void JobData::setAlias( const OUString& sAlias )
109 : {
110 624 : SolarMutexGuard g;
111 : // delete all old information! Otherwhise we mix it with the new one ...
112 624 : impl_reset();
113 :
114 : // take over the new information
115 624 : m_sAlias = sAlias;
116 624 : 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 1248 : + utl::wrapConfigurationElementName(m_sAlias)));
124 624 : aConfig.open(ConfigAccess::E_READONLY);
125 624 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
126 : {
127 0 : impl_reset();
128 624 : return;
129 : }
130 :
131 1248 : css::uno::Reference< css::beans::XPropertySet > xJobProperties(aConfig.cfg(), css::uno::UNO_QUERY);
132 624 : if (xJobProperties.is())
133 : {
134 624 : css::uno::Any aValue;
135 :
136 : // read uno implementation name
137 624 : aValue = xJobProperties->getPropertyValue("Service");
138 624 : aValue >>= m_sService;
139 :
140 : // read module context list
141 624 : aValue = xJobProperties->getPropertyValue("Context");
142 624 : aValue >>= m_sContext;
143 :
144 : // read whole argument list
145 624 : aValue = xJobProperties->getPropertyValue("Arguments");
146 1248 : css::uno::Reference< css::container::XNameAccess > xArgumentList;
147 624 : if (
148 1248 : (aValue >>= xArgumentList) &&
149 624 : (xArgumentList.is() )
150 : )
151 : {
152 624 : css::uno::Sequence< OUString > lArgumentNames = xArgumentList->getElementNames();
153 624 : sal_Int32 nCount = lArgumentNames.getLength();
154 624 : m_lArguments.realloc(nCount);
155 624 : 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 624 : }
160 624 : }
161 : }
162 :
163 1248 : 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 automatically 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 624 : void JobData::setEvent( const OUString& sEvent ,
203 : const OUString& sAlias )
204 : {
205 : // share code to read all job properties!
206 624 : setAlias(sAlias);
207 :
208 624 : SolarMutexGuard g;
209 : // take over the new information - which differ against set on of method setAlias()!
210 624 : m_sEvent = sEvent;
211 624 : m_eMode = E_EVENT;
212 624 : }
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 automatically, 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 every time this container is initialized
292 : with new job datas e.g.: setAlias()/setEvent()/setService() ...
293 : Otherwhise the environment will be unknown!
294 : */
295 624 : void JobData::setEnvironment( EEnvironment eEnvironment )
296 : {
297 624 : SolarMutexGuard g;
298 624 : m_eEnvironment = eEnvironment;
299 624 : }
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 13 : JobData::EMode JobData::getMode() const
307 : {
308 13 : SolarMutexGuard g;
309 13 : return m_eMode;
310 : }
311 :
312 13 : JobData::EEnvironment JobData::getEnvironment() const
313 : {
314 13 : SolarMutexGuard g;
315 13 : return m_eEnvironment;
316 : }
317 :
318 13 : OUString JobData::getEnvironmentDescriptor() const
319 : {
320 13 : OUString sDescriptor;
321 26 : SolarMutexGuard g;
322 13 : 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 13 : sDescriptor = "DOCUMENTEVENT";
334 13 : break;
335 : default:
336 0 : break;
337 : }
338 26 : return sDescriptor;
339 : }
340 :
341 13 : OUString JobData::getService() const
342 : {
343 13 : SolarMutexGuard g;
344 13 : return m_sService;
345 : }
346 :
347 13 : OUString JobData::getEvent() const
348 : {
349 13 : SolarMutexGuard g;
350 13 : return m_sEvent;
351 : }
352 :
353 13 : css::uno::Sequence< css::beans::NamedValue > JobData::getJobConfig() const
354 : {
355 13 : SolarMutexGuard g;
356 13 : return m_lArguments;
357 : }
358 :
359 13 : css::uno::Sequence< css::beans::NamedValue > JobData::getConfig() const
360 : {
361 13 : SolarMutexGuard g;
362 13 : css::uno::Sequence< css::beans::NamedValue > lConfig;
363 13 : 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 13 : 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 26 : bool JobData::hasConfig() const
395 : {
396 26 : SolarMutexGuard g;
397 26 : 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 this 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 automatically, 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 625 : 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 : static const char PATTERN_ISO8601[] = "\?\?\?\?-\?\?-\?\?*";
454 625 : WildCard aISOPattern(PATTERN_ISO8601);
455 :
456 625 : bool bValidAdmin = aISOPattern.Matches(sAdminTime);
457 625 : bool bValidUser = aISOPattern.Matches(sUserTime );
458 :
459 : // We check for "isEnabled()" here only.
460 : // Note further: ISO8601 formatted 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 1250 : (!bValidAdmin && !bValidUser ) ||
464 625 : ( bValidAdmin && bValidUser && sAdminTime>=sUserTime)
465 625 : );
466 : }
467 :
468 : /**
469 : */
470 625 : void JobData::appendEnabledJobsForEvent( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
471 : const OUString& sEvent ,
472 : ::std::vector< JobData::TJob2DocEventBinding >& lJobs )
473 : {
474 625 : css::uno::Sequence< OUString > lAdditionalJobs = JobData::getEnabledJobsForEvent(rxContext, sEvent);
475 625 : sal_Int32 c = lAdditionalJobs.getLength();
476 625 : sal_Int32 i = 0;
477 :
478 1250 : for (i=0; i<c; ++i)
479 : {
480 625 : JobData::TJob2DocEventBinding aBinding(lAdditionalJobs[i], sEvent);
481 625 : lJobs.push_back(aBinding);
482 1250 : }
483 625 : }
484 :
485 : /**
486 : */
487 624 : bool JobData::hasCorrectContext(const OUString& rModuleIdent) const
488 : {
489 624 : sal_Int32 nContextLen = m_sContext.getLength();
490 624 : sal_Int32 nModuleIdLen = rModuleIdent.getLength();
491 :
492 624 : if ( nContextLen == 0 )
493 0 : return true;
494 :
495 624 : if ( nModuleIdLen > 0 )
496 : {
497 624 : sal_Int32 nIndex = m_sContext.indexOf( rModuleIdent );
498 624 : if ( nIndex >= 0 && ( nIndex+nModuleIdLen <= nContextLen ))
499 : {
500 13 : OUString sContextModule = m_sContext.copy( nIndex, nModuleIdLen );
501 13 : return sContextModule.equals( rModuleIdent );
502 : }
503 : }
504 :
505 611 : return false;
506 : }
507 :
508 : /**
509 : */
510 625 : 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 625 : ConfigAccess aConfig(rxContext, "/org.openoffice.Office.Jobs/Events");
515 625 : aConfig.open(ConfigAccess::E_READONLY);
516 625 : if (aConfig.getMode()==ConfigAccess::E_CLOSED)
517 0 : return css::uno::Sequence< OUString >();
518 :
519 1250 : css::uno::Reference< css::container::XHierarchicalNameAccess > xEventRegistry(aConfig.cfg(), css::uno::UNO_QUERY);
520 625 : if (!xEventRegistry.is())
521 0 : return css::uno::Sequence< OUString >();
522 :
523 : // check if the given event exist inside list of registered ones
524 1250 : OUString sPath(sEvent + "/JobList");
525 625 : 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 1250 : css::uno::Any aJobList = xEventRegistry->getByHierarchicalName(sPath);
531 1250 : css::uno::Reference< css::container::XNameAccess > xJobList;
532 625 : 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 1250 : css::uno::Sequence< OUString > lAllJobs = xJobList->getElementNames();
541 625 : OUString* pAllJobs = lAllJobs.getArray();
542 625 : sal_Int32 c = lAllJobs.getLength();
543 :
544 1250 : css::uno::Sequence< OUString > lEnabledJobs(c);
545 625 : OUString* pEnabledJobs = lEnabledJobs.getArray();
546 625 : sal_Int32 d = 0;
547 :
548 1250 : for (sal_Int32 s=0; s<c; ++s)
549 : {
550 625 : css::uno::Reference< css::beans::XPropertySet > xJob;
551 1250 : if (
552 2500 : !(xJobList->getByName(pAllJobs[s]) >>= xJob) ||
553 625 : !(xJob.is() )
554 : )
555 : {
556 0 : continue;
557 : }
558 :
559 1250 : OUString sAdminTime;
560 625 : xJob->getPropertyValue("AdminTime") >>= sAdminTime;
561 :
562 1250 : OUString sUserTime;
563 625 : xJob->getPropertyValue("UserTime") >>= sUserTime;
564 :
565 625 : if (!isEnabled(sAdminTime, sUserTime))
566 0 : continue;
567 :
568 625 : pEnabledJobs[d] = pAllJobs[s];
569 625 : ++d;
570 625 : }
571 625 : lEnabledJobs.realloc(d);
572 :
573 625 : aConfig.close();
574 :
575 1250 : 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 1898 : void JobData::impl_reset()
590 : {
591 1898 : SolarMutexGuard g;
592 1898 : m_eMode = E_UNKNOWN_MODE;
593 1898 : m_eEnvironment = E_UNKNOWN_ENVIRONMENT;
594 1898 : m_sAlias.clear();
595 1898 : m_sService.clear();
596 1898 : m_sContext.clear();
597 1898 : m_sEvent.clear();
598 1898 : m_lArguments = css::uno::Sequence< css::beans::NamedValue >();
599 1898 : }
600 :
601 : } // namespace framework
602 :
603 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|