1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <jobs/configaccess.hxx>
25 #include <jobs/jobdata.hxx>
26 #include <classes/converter.hxx>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/beans/XMultiHierarchicalPropertySet.hpp>
30 #include <com/sun/star/container/XNameAccess.hpp>
31 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
33 #include <tools/wldcrd.hxx>
34 #include <unotools/configpaths.hxx>
36 #include <vcl/svapp.hxx>
42 @descr It initialize this new instance.
43 But for real working it's necessary to call setAlias() or setService() later.
44 Because we need the job data ...
47 reference to the uno service manager
49 JobData::JobData( css::uno::Reference
< css::uno::XComponentContext
> xContext
)
50 : m_xContext (std::move(xContext
))
52 // share code for member initialization with defaults!
58 @descr Sometimes such job data container must be moved from one using place
59 to another one. Then a copy ctor and copy operator must be available.
62 the original instance, from which we must copy all data
64 JobData::JobData( const JobData
& rCopy
)
66 // use the copy operator to share the same code
71 @short operator for copying JobData instances
72 @descr Sometimes such job data container must be moved from one using place
73 to another one. Then a copy ctor and copy operator must be available.
76 the original instance, from which we must copy all data
78 JobData
& JobData::operator=( const JobData
& rCopy
)
81 // Please don't copy the uno service manager reference.
82 // That can change the uno context, which isn't a good idea!
83 m_eMode
= rCopy
.m_eMode
;
84 m_eEnvironment
= rCopy
.m_eEnvironment
;
85 m_sAlias
= rCopy
.m_sAlias
;
86 m_sService
= rCopy
.m_sService
;
87 m_sContext
= rCopy
.m_sContext
;
88 m_sEvent
= rCopy
.m_sEvent
;
89 m_lArguments
= rCopy
.m_lArguments
;
94 @short let this instance die
95 @descr There is no chance any longer to work. We have to
96 release all used resources and free used memory.
104 @short initialize this instance as a job with configuration
105 @descr They given alias can be used to address some configuration data.
106 We read it and fill our internal structures. Of course old information
107 will be lost doing so.
110 the alias name of this job, used to locate job properties inside cfg
112 void JobData::setAlias( const OUString
& sAlias
)
115 // delete all old information! Otherwise we mix it with the new one ...
118 // take over the new information
122 // try to open the configuration set of this job directly and get a property access to it
123 // We open it readonly here
124 ConfigAccess
aConfig(
126 ("/org.openoffice.Office.Jobs/Jobs/"
127 + utl::wrapConfigurationElementName(m_sAlias
)));
128 aConfig
.open(ConfigAccess::E_READONLY
);
129 if (aConfig
.getMode()==ConfigAccess::E_CLOSED
)
135 css::uno::Reference
< css::beans::XPropertySet
> xJobProperties(aConfig
.cfg(), css::uno::UNO_QUERY
);
136 if (xJobProperties
.is())
138 css::uno::Any aValue
;
140 // read uno implementation name
141 aValue
= xJobProperties
->getPropertyValue("Service");
142 aValue
>>= m_sService
;
144 // read module context list
145 aValue
= xJobProperties
->getPropertyValue("Context");
146 aValue
>>= m_sContext
;
148 // read whole argument list
149 aValue
= xJobProperties
->getPropertyValue("Arguments");
150 css::uno::Reference
< css::container::XNameAccess
> xArgumentList
;
152 (aValue
>>= xArgumentList
) &&
153 (xArgumentList
.is() )
156 css::uno::Sequence
< OUString
> lArgumentNames
= xArgumentList
->getElementNames();
157 sal_Int32 nCount
= lArgumentNames
.getLength();
158 m_lArguments
.resize(nCount
);
159 for (sal_Int32 i
=0; i
<nCount
; ++i
)
161 m_lArguments
[i
].Name
= lArgumentNames
[i
];
162 m_lArguments
[i
].Value
= xArgumentList
->getByName(m_lArguments
[i
].Name
);
171 @short initialize this instance as a job without configuration
172 @descr This job has no configuration data. We have to forget all old information
173 and set only some of them new, so this instance can work.
176 the uno service name of this "non configured" job
178 void JobData::setService( const OUString
& sService
)
181 // delete all old information! Otherwise we mix it with the new one ...
183 // take over the new information
184 m_sService
= sService
;
189 @short initialize this instance with new job values.
190 @descr It reads automatically all properties of the specified
191 job (using it's alias name) and "register it" for the
192 given event. This registration will not be validated against
193 the underlying configuration! (That must be done from outside.
194 Because the caller must have the configuration already open to
195 get the values for sEvent and sAlias! And doing so it can perform
196 only, if the time stamp values are read outside too.
197 Further it makes no sense to initialize and start a disabled job.
198 So this initialization method will be called for enabled jobs only.)
201 the triggered event, for which this job should be started
204 mark the required job inside event registration list
206 void JobData::setEvent( const OUString
& sEvent
,
207 const OUString
& sAlias
)
209 // share code to read all job properties!
213 // take over the new information - which differ against set one of method setAlias()!
219 @short set the new job specific arguments
220 @descr If a job finish his work, it can give us a new list of arguments (which
221 will not interpreted by us). We write it back to the configuration only
222 (if this job has its own configuration!).
223 So a job can have persistent data without implementing anything
224 or define own config areas for that.
227 list of arguments, which should be set for this job
229 void JobData::setJobConfig( std::vector
< css::beans::NamedValue
>&& lArguments
)
234 m_lArguments
= std::move(lArguments
);
236 // update the configuration ... if possible!
237 if (m_eMode
!=E_ALIAS
)
240 // It doesn't matter if this config object was already opened before.
241 // It doesn nothing here then ... or it change the mode automatically, if
242 // it was opened using another one before.
243 ConfigAccess
aConfig(
245 ("/org.openoffice.Office.Jobs/Jobs/"
246 + utl::wrapConfigurationElementName(m_sAlias
)));
247 aConfig
.open(ConfigAccess::E_READWRITE
);
248 if (aConfig
.getMode()==ConfigAccess::E_CLOSED
)
251 css::uno::Reference
< css::beans::XMultiHierarchicalPropertySet
> xArgumentList(aConfig
.cfg(), css::uno::UNO_QUERY
);
252 if (xArgumentList
.is())
254 sal_Int32 nCount
= m_lArguments
.size();
255 css::uno::Sequence
< OUString
> lNames (nCount
);
256 auto lNamesRange
= asNonConstRange(lNames
);
257 css::uno::Sequence
< css::uno::Any
> lValues(nCount
);
258 auto lValuesRange
= asNonConstRange(lValues
);
260 for (sal_Int32 i
=0; i
<nCount
; ++i
)
262 lNamesRange
[i
] = m_lArguments
[i
].Name
;
263 lValuesRange
[i
] = m_lArguments
[i
].Value
;
266 xArgumentList
->setHierarchicalPropertyValues(lNames
, lValues
);
272 @short set a new environment descriptor for this job
273 @descr It must(!) be done every time this container is initialized
274 with new job data e.g.: setAlias()/setEvent()/setService() ...
275 Otherwise the environment will be unknown!
277 void JobData::setEnvironment( EEnvironment eEnvironment
)
280 m_eEnvironment
= eEnvironment
;
284 @short these functions provides access to our internal members
285 @descr These member represent any information about the job
286 and can be used from outside to e.g. start a job.
288 JobData::EMode
JobData::getMode() const
294 JobData::EEnvironment
JobData::getEnvironment() const
297 return m_eEnvironment
;
300 OUString
JobData::getEnvironmentDescriptor() const
302 OUString sDescriptor
;
304 switch(m_eEnvironment
)
307 sDescriptor
= "EXECUTOR";
311 sDescriptor
= "DISPATCH";
314 case E_DOCUMENTEVENT
:
315 sDescriptor
= "DOCUMENTEVENT";
323 OUString
JobData::getService() const
329 OUString
JobData::getEvent() const
335 std::vector
< css::beans::NamedValue
> JobData::getJobConfig() const
341 css::uno::Sequence
< css::beans::NamedValue
> JobData::getConfig() const
344 css::uno::Sequence
< css::beans::NamedValue
> lConfig
;
345 if (m_eMode
==E_ALIAS
)
347 lConfig
= { { "Alias", css::uno::Any(m_sAlias
) },
348 { "Service", css::uno::Any(m_sService
) },
349 { "Context", css::uno::Any(m_sContext
) } };
355 @short return information, if this job is part of the global configuration package
356 org.openoffice.Office.Jobs
357 @descr Because jobs can be executed by the dispatch framework using a uno service name
358 directly - an executed job must not have any configuration really. Such jobs
359 must provide the right interfaces only! But after finishing jobs can return
360 some information (e.g. for updating her configuration ...). We must know
361 if such request is valid or not then.
363 @return sal_True if the represented job is part of the underlying configuration package.
365 bool JobData::hasConfig() const
368 return (m_eMode
==E_ALIAS
|| m_eMode
==E_EVENT
);
372 @short mark a job as non startable for further requests
373 @descr We don't remove the configuration entry! We set a timestamp value only.
374 And there exist two of them: one for an administrator... and one for the
375 current user. We change it for the user layer only. So this JobDispatch can't be
376 started any more... till the administrator change his timestamp.
377 That can be useful for post setup scenarios, which must run one time only.
379 Note: This method don't do anything, if this represented job doesn't have a configuration!
381 void JobData::disableJob()
385 // No configuration - not used from EXECUTOR and not triggered from an event => no chance!
386 if (m_eMode
!=E_EVENT
)
389 // update the configuration
390 // It doesn't matter if this config object was already opened before.
391 // It doesn nothing here then ... or it change the mode automatically, if
392 // it was opened using another one before.
393 ConfigAccess
aConfig(
395 ("/org.openoffice.Office.Jobs/Events/"
396 + utl::wrapConfigurationElementName(m_sEvent
) + "/JobList/"
397 + utl::wrapConfigurationElementName(m_sAlias
)));
398 aConfig
.open(ConfigAccess::E_READWRITE
);
399 if (aConfig
.getMode()==ConfigAccess::E_CLOSED
)
402 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(aConfig
.cfg(), css::uno::UNO_QUERY
);
405 // Convert and write the user timestamp to the configuration.
406 css::uno::Any aValue
;
407 aValue
<<= Converter::convert_DateTime2ISO8601(DateTime( DateTime::SYSTEM
));
408 xPropSet
->setPropertyValue("UserTime", aValue
);
414 static bool isEnabled( std::u16string_view sAdminTime
,
415 std::u16string_view sUserTime
)
418 To prevent interpreting of TriGraphs inside next const string value,
419 we have to encode all '?' signs. Otherwise e.g. "??-" will be translated
422 WildCard
aISOPattern(u
"\?\?\?\?-\?\?-\?\?*");
424 bool bValidAdmin
= aISOPattern
.Matches(sAdminTime
);
425 bool bValidUser
= aISOPattern
.Matches(sUserTime
);
427 // We check for "isEnabled()" here only.
428 // Note further: ISO8601 formatted strings can be compared as strings directly!
429 // FIXME: this is not true! "T1215" is the same time as "T12:15" or "T121500"
431 (!bValidAdmin
&& !bValidUser
) ||
432 ( bValidAdmin
&& bValidUser
&& sAdminTime
>=sUserTime
)
436 void JobData::appendEnabledJobsForEvent( const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
437 const OUString
& sEvent
,
438 ::std::vector
< JobData::TJob2DocEventBinding
>& lJobs
)
440 std::vector
< OUString
> lAdditionalJobs
= JobData::getEnabledJobsForEvent(rxContext
, sEvent
);
441 sal_Int32 c
= lAdditionalJobs
.size();
446 JobData::TJob2DocEventBinding
aBinding(lAdditionalJobs
[i
], sEvent
);
447 lJobs
.push_back(aBinding
);
451 bool JobData::hasCorrectContext(std::u16string_view rModuleIdent
) const
453 sal_Int32 nContextLen
= m_sContext
.getLength();
454 sal_Int32 nModuleIdLen
= rModuleIdent
.size();
456 if ( nContextLen
== 0 )
459 if ( nModuleIdLen
> 0 )
461 sal_Int32 nIndex
= m_sContext
.indexOf( rModuleIdent
);
462 if ( nIndex
>= 0 && ( nIndex
+nModuleIdLen
<= nContextLen
))
464 std::u16string_view sContextModule
= m_sContext
.subView( nIndex
, nModuleIdLen
);
465 return sContextModule
== rModuleIdent
;
472 std::vector
< OUString
> JobData::getEnabledJobsForEvent( const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
,
473 std::u16string_view sEvent
)
475 // create a config access to "/org.openoffice.Office.Jobs/Events"
476 ConfigAccess
aConfig(rxContext
, "/org.openoffice.Office.Jobs/Events");
477 aConfig
.open(ConfigAccess::E_READONLY
);
478 if (aConfig
.getMode()==ConfigAccess::E_CLOSED
)
479 return std::vector
< OUString
>();
481 css::uno::Reference
< css::container::XHierarchicalNameAccess
> xEventRegistry(aConfig
.cfg(), css::uno::UNO_QUERY
);
482 if (!xEventRegistry
.is())
483 return std::vector
< OUString
>();
485 // check if the given event exist inside list of registered ones
486 OUString
sPath(OUString::Concat(sEvent
) + "/JobList");
487 if (!xEventRegistry
->hasByHierarchicalName(sPath
))
488 return std::vector
< OUString
>();
490 // step to the job list, which is a child of the event node inside cfg
491 // e.g. "/org.openoffice.Office.Jobs/Events/<event name>/JobList"
492 css::uno::Any aJobList
= xEventRegistry
->getByHierarchicalName(sPath
);
493 css::uno::Reference
< css::container::XNameAccess
> xJobList
;
494 if (!(aJobList
>>= xJobList
) || !xJobList
.is())
495 return std::vector
< OUString
>();
497 // get all alias names of jobs, which are part of this job list
498 // But Some of them can be disabled by its timestamp values.
499 // We create an additional job name list with the same size, then the original list...
500 // step over all job entries... check her timestamps... and put only job names to the
501 // destination list, which represent an enabled job.
502 const css::uno::Sequence
< OUString
> lAllJobs
= xJobList
->getElementNames();
503 sal_Int32 c
= lAllJobs
.getLength();
505 std::vector
< OUString
> lEnabledJobs(c
);
508 for (OUString
const & jobName
: lAllJobs
)
510 css::uno::Reference
< css::beans::XPropertySet
> xJob
;
512 !(xJobList
->getByName(jobName
) >>= xJob
) ||
520 xJob
->getPropertyValue("AdminTime") >>= sAdminTime
;
523 xJob
->getPropertyValue("UserTime") >>= sUserTime
;
525 if (!isEnabled(sAdminTime
, sUserTime
))
528 lEnabledJobs
[d
] = jobName
;
531 lEnabledJobs
.resize(d
);
539 @short reset all internal structures
540 @descr If someone recycles this instance, he can switch from one
541 using mode to another one. But then we have to reset all currently
542 used information. Otherwise we mix it and they can make trouble.
544 But note: that does not set defaults for internal used members, which
545 does not relate to any job property! e.g. the reference to the global
546 uno service manager. Such information is used for internal processes only
547 and are necessary for our work.
549 void JobData::impl_reset()
552 m_eMode
= E_UNKNOWN_MODE
;
553 m_eEnvironment
= E_UNKNOWN_ENVIRONMENT
;
558 m_lArguments
.clear();
561 } // namespace framework
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */