Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
CaseOptionService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* CaseOptions.cc (C) 2000-2023 */
9/* */
10/* Gestion des options du jeu de données. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/core/CaseOptionService.h"
15
16#include "arcane/utils/Collection.h"
17#include "arcane/utils/Enumerator.h"
18#include "arcane/utils/NotImplementedException.h"
19#include "arcane/utils/FatalErrorException.h"
20
21#include "arcane/core/IApplication.h"
22#include "arcane/core/IServiceFactory.h"
23#include "arcane/core/CaseOptionBuildInfo.h"
24#include "arcane/core/CaseOptionException.h"
25#include "arcane/core/CaseOptionError.h"
26#include "arcane/core/XmlNodeList.h"
27#include "arcane/core/ICaseDocumentVisitor.h"
28#include "arcane/core/ICaseDocument.h"
29#include "arcane/core/ICaseMng.h"
30#include "arcane/core/internal/ICaseOptionListInternal.h"
31
32#include <typeinfo>
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane
38{
39
40namespace {
41
42void
43_getAvailableServiceNames(ICaseOptionServiceContainer* container,IApplication* app,
44 StringArray& names)
45{
46 for( ServiceFactory2Collection::Enumerator i(app->serviceFactories2()); ++i; ){
47 Internal::IServiceFactory2* sf2 = *i;
48 IServiceInfo* si = sf2->serviceInfo();
49 // Il faut que le service soit autorisé pour le jeu de données.
50 if (!(si->usageType() & Arcane::ST_CaseOption))
51 continue;
52 if (container->hasInterfaceImplemented(sf2)){
53 names.add(sf2->serviceInfo()->localName());
54 }
55 }
56}
57
58bool
59_tryCreateService(ICaseOptionServiceContainer* container,IApplication* app,
60 const String& service_name,Integer index,ICaseOptions* opt)
61{
62 // Parcours la liste des fabriques et essaie de créer un service avec le nom
63 // qu'on souhaite et qui implémente la bonne interface.
64 bool is_found = false;
65 ServiceBuildInfoBase sbi(_arcaneDeprecatedGetSubDomain(opt),opt);
66 for( ServiceFactory2Collection::Enumerator i(app->serviceFactories2()); ++i; ){
67 Internal::IServiceFactory2* sf2 = *i;
68 IServiceInfo* si = sf2->serviceInfo();
69 if (si->localName()==service_name && container->tryCreateService(index,sf2,sbi)){
70 opt->setCaseServiceInfo(si);
71 is_found = true;
72 break;
73 }
74 }
75 return is_found;
76}
77
78}
79
80/*---------------------------------------------------------------------------*/
81/*---------------------------------------------------------------------------*/
82
84setMeshName(const String& mesh_name)
85{
86 m_impl->setMeshName(mesh_name);
87}
88
89/*---------------------------------------------------------------------------*/
90/*---------------------------------------------------------------------------*/
91
93meshName() const
94{
95 return m_impl->meshName();
96}
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
102setMeshName(const String& mesh_name)
103{
104 m_impl->setMeshName(mesh_name);
105}
106
107/*---------------------------------------------------------------------------*/
108/*---------------------------------------------------------------------------*/
109
111meshName() const
112{
113 return m_impl->meshName();
114}
115
116/*---------------------------------------------------------------------------*/
117/*---------------------------------------------------------------------------*/
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122CaseOptionServiceImpl::
123CaseOptionServiceImpl(const CaseOptionBuildInfo& cob,bool allow_null,bool is_optional)
124: CaseOptions(cob.caseOptionList(),cob.name())
125, m_name(cob.name())
126, m_default_value(cob.defaultValue())
127, m_element(cob.element())
128, m_allow_null(allow_null)
129, m_is_optional(is_optional)
130, m_is_override_default(false)
131, m_container(nullptr)
132{
133}
134
135/*---------------------------------------------------------------------------*/
136/*---------------------------------------------------------------------------*/
137
138void CaseOptionServiceImpl::
139print(const String& lang,std::ostream& o) const
140{
141 ARCANE_UNUSED(lang);
142 o << serviceName();
143}
144
145/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
147
149visit(ICaseDocumentVisitor* visitor) const
150{
151 visitor->beginVisit(this);
152 CaseOptions::visit(visitor);
153 visitor->endVisit(this);
154}
155
156/*---------------------------------------------------------------------------*/
157/*---------------------------------------------------------------------------*/
158
161{
162 m_container = container;
163}
164
165/*---------------------------------------------------------------------------*/
166/*---------------------------------------------------------------------------*/
167
168void CaseOptionServiceImpl::
169_readPhase1()
170{
171 if (!m_container)
172 ARCANE_FATAL("null 'm_container'. did you called setContainer() method ?");
173
174 ITraceMng* tm = traceMng();
175
176 _setTranslatedName();
177 ICaseOptionList* col = configList();
178
179 XmlNode child = m_element.child(rootTagName());
180
181 if (child.null()) {
182 col->_internalApi()->setRootElementWithParent(m_element);
183 }
184 else {
185 if (col->rootElement() != child) // skip when rootElement already set to child (may appear in subDomain service)
186 col->_internalApi()->setRootElement(child);
187 }
188
189 XmlNode element = col->rootElement();
190 String mesh_name = meshName();
191 tm->info(5) << "** CaseOptionService::read() ELEMENT <" << rootTagName() << "> " << col->rootElement().name()
192 << " full=" << col->rootElement().xpathFullName()
193 << " is_present=" << col->isPresent()
194 << " is_optional=" << isOptional()
195 << " allow_null=" << m_allow_null
196 << " mesh-name=" << mesh_name
197 << "\n";
198
199
200 if (_setMeshHandleAndCheckDisabled(mesh_name))
201 return;
202
203 ICaseDocumentFragment* doc = caseDocumentFragment();
204
205 String str_val = element.attrValue("name");
206 //cerr << "** STR_VAL <" << str_val << " - " << m_default_value << ">\n";
207
208 if (str_val.null()){
209 // Utilise la valeur par défaut :
210 // - si elle a été spécifiée par l'utilisateur, utilise celle-ci.
211 // - sinon utilise celle de la catégorie associée aux défauts.
212 // - sinon, la valeur par défaut classique.
213 if (!m_is_override_default){
214 String category = doc->defaultCategory();
215 if (!category.null()){
216 String v = m_default_values.find(category);
217 if (!v.null()){
218 m_default_value = v;
219 }
220 }
221 }
222 str_val = m_default_value;
223 }
224 if (str_val.null() && !isOptional()){
225 CaseOptionError::addOptionNotFoundError(doc,A_FUNCINFO,"@name",element);
226 return;
227 }
228 m_service_name = str_val;
229
230 // Si le service peut-être nul et que l'élément n'est pas présent dans le jeu de données,
231 // on considère qu'il ne doit pas être chargé.
232 bool need_create = col->isPresent() || !isOptional();
233
234 if (need_create){
235 m_container->allocate(1);
236 bool is_found = _tryCreateService(m_container,caseMng()->application(),str_val,0,this);
237
238 if (!is_found && !m_allow_null){
239 // Le service souhaité n'est pas trouvé. Il s'agit d'une erreur.
240 // Recherche les noms des implémentations valides pour affichage dans le message
241 // d'erreur correspondant.
242 StringUniqueArray valid_names;
243 getAvailableNames(valid_names);
244 CaseOptionError::addError(doc,A_FUNCINFO,element.xpathFullName(),
245 String::format("Unable to find a service named '{0}' (valid values:{1})",
246 str_val,valid_names),true);
247 }
248 }
249}
250
251/*---------------------------------------------------------------------------*/
252/*---------------------------------------------------------------------------*/
253
255read(eCaseOptionReadPhase read_phase)
256{
257 if (read_phase==eCaseOptionReadPhase::Phase1)
258 _readPhase1();
259 CaseOptions::read(read_phase);
260}
261
262/*---------------------------------------------------------------------------*/
263/*---------------------------------------------------------------------------*/
264
265void CaseOptionServiceImpl::
266setDefaultValue(const String& def_value)
267{
268 if (!m_service_name.null()){
269 String xpath_name = configList()->rootElement().xpathFullName();
270 ARCANE_FATAL("Can not set default service name because service is already allocated (option='{0}')",
271 xpath_name);
272 }
273 m_default_value = def_value;
274 m_is_override_default = true;
275}
276
277/*---------------------------------------------------------------------------*/
278/*---------------------------------------------------------------------------*/
279
280void CaseOptionServiceImpl::
281addDefaultValue(const String& category,const String& value)
282{
283 m_default_values.add(category,value);
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
290getAvailableNames(StringArray& names) const
291{
292 _getAvailableServiceNames(m_container,caseMng()->application(),names);
293}
294
295/*---------------------------------------------------------------------------*/
296/*---------------------------------------------------------------------------*/
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300
301CaseOptionMultiServiceImpl::
302CaseOptionMultiServiceImpl(const CaseOptionBuildInfo& cob,bool allow_null)
303: CaseOptionsMulti(cob.caseOptionList(),cob.name(),cob.element(),cob.minOccurs(),cob.maxOccurs())
304, m_allow_null(allow_null)
305, m_default_value(cob.defaultValue())
306, m_notify_functor(nullptr)
307, m_container(nullptr)
308{
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
314CaseOptionMultiServiceImpl::
315~CaseOptionMultiServiceImpl()
316{
317}
318
319/*---------------------------------------------------------------------------*/
320/*---------------------------------------------------------------------------*/
321
324{
325 m_container = container;
326}
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
330
332visit(ICaseDocumentVisitor* visitor) const
333{
334 Integer index = 0;
335 for( const auto& o : m_allocated_options ){
336 visitor->beginVisit(this,index);
337 o->visit(visitor);
338 visitor->endVisit(this,index);
339 ++index;
340 }
341}
342
343/*---------------------------------------------------------------------------*/
344/*---------------------------------------------------------------------------*/
345
346void CaseOptionMultiServiceImpl::
347multiAllocate(const XmlNodeList& elem_list)
348{
349 if (!m_container)
350 ARCANE_FATAL("null 'm_container'. did you called setContainer() method ?");
351
352 Integer size = elem_list.size();
353
354 if (size==0)
355 return;
356
358
359 ITraceMng* tm = traceMng();
360
361 m_container->allocate(size);
362 m_allocated_options.resize(size);
363 IApplication* app = caseMng()->application();
364 XmlNode parent_element = configList()->parentElement();
365 ICaseDocumentFragment* doc = caseDocumentFragment();
366
367 String mesh_name = meshName();
368 if (_setMeshHandleAndCheckDisabled(mesh_name))
369 return;
370
371 for( Integer index=0; index<size; ++index ){
372 XmlNode element = elem_list[index];
373
374 String str_val = element.attrValue("name");
375 m_services_name[index] = str_val;
376 tm->info(5) << "CaseOptionMultiServiceImpl name=" << name()
377 << " index=" << index
378 << " v=" << str_val
379 << " default_value='" << _defaultValue() << "'"
380 << " mesh=" << meshHandle().meshName();
381
382 if (str_val.null())
383 str_val = _defaultValue();
384 if (str_val.null())
385 throw CaseOptionException("get_value","@name",element);
386 // TODO: regarder si on ne peut pas créer directement un CaseOptionService.
387 CaseOptions* coptions = new CaseOptions(configList(),name(),parent_element,false,true);
388 coptions->configList()->_internalApi()->setRootElement(element);
389 bool is_found = _tryCreateService(m_container,app,str_val,index,coptions);
390
391 if (!is_found){
392 tm->info(5) << "CaseOptionMultiServiceImpl name=" << name()
393 << " index=" << index
394 << " service not found";
395 delete coptions;
396 coptions = nullptr;
397 // Recherche les noms des implémentations valides
398 StringUniqueArray valid_names;
399 getAvailableNames(valid_names);
400 CaseOptionError::addError(doc,A_FUNCINFO,element.xpathFullName(),
401 String::format("Unable to find a service named '{0}' (valid values:{1})",
402 str_val,valid_names),true);
403 }
404 m_allocated_options[index] = coptions;
405 }
406 if (m_notify_functor)
407 m_notify_functor->executeFunctor();
408}
409
410/*---------------------------------------------------------------------------*/
411/*---------------------------------------------------------------------------*/
412
414getAvailableNames(StringArray& names) const
415{
416 _getAvailableServiceNames(m_container,caseMng()->application(),names);
417}
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
421
422} // End namespace Arcane
423
424/*---------------------------------------------------------------------------*/
425/*---------------------------------------------------------------------------*/
426
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
static void addError(ICaseDocumentFragment *document, const TraceInfo &where, const String &node_name, const String &message, bool is_collective=false)
Erreur générique.
static void addOptionNotFoundError(ICaseDocumentFragment *document, const TraceInfo &where, const String &node_name, const XmlNode &parent)
Erreur lorsqu'une option du jeu de données n'est pas trouvée. Cette erreur est collective.
Exception en rapport avec le jeu de données.
UniqueArray< String > m_services_name
Noms du service pour chaque occurence.
void setContainer(ICaseOptionServiceContainer *container)
Positionne le conteneur d'instances.
UniqueArray< ReferenceCounter< ICaseOptions > > m_allocated_options
Liste des options allouées qu'il faudra supprimer.
void visit(ICaseDocumentVisitor *visitor) const override
Applique le visiteur sur cette option.
void getAvailableNames(StringArray &names) const
Retourne dans names les noms d'implémentations valides pour ce service.
String meshName() const
Nom du maillage auquel le service est associé.
void setMeshName(const String &mesh_name)
Positionne le nom du maillage auquel le service sera associé.
void setContainer(ICaseOptionServiceContainer *container)
Positionne le conteneur d'instances.
void read(eCaseOptionReadPhase phase) override
Effectue la lecture de la phase read_phase des options.
void visit(ICaseDocumentVisitor *visitor) const override
Applique le visiteur sur cette option.
virtual void getAvailableNames(StringArray &names) const
Retourne dans names les noms d'implémentations valides pour ce service.
void setMeshName(const String &mesh_name)
Positionne le nom du maillage auquel le service sera associé.
String meshName() const
Nom du maillage auquel le service est associé.
bool _setMeshHandleAndCheckDisabled(const String &mesh_name)
Positionne le maillage associé à cette option.
void visit(ICaseDocumentVisitor *visitor) const override
Applique le visiteur sur cette option.
String rootTagName() const override
Retourne le nom de l'élément dans le langage du jeu de données.
virtual String name() const
Retourne le nom de l'élément dans le langage du jeu de données.
Interface de l'application.
Interface du visiteur pour une option du jeu de données.
virtual IApplication * application()=0
Application associée.
virtual XmlNode rootElement() const =0
Retourne l'élément lié à cette liste d'option.
virtual XmlNode parentElement() const =0
Retourne l'élément parent.
virtual bool isPresent() const =0
Indique si l'option est présente dans le jeu de données.
virtual ICaseOptionListInternal * _internalApi()=0
API interne à Arcane.
Interface d'un conteneur d'instances de service.
virtual void allocate(Integer size)=0
Alloue un tableau pour size éléments.
void add(const String &key, const String &value)
Ajoute le couple (key,value) au dictionnaire.
String find(const String &key, bool throw_exception=false) const
Retourne la valeur associée à key.
Liste de noeuds d'un arbre DOM.
Definition XmlNodeList.h:33
Noeud d'un arbre DOM.
Definition XmlNode.h:51
String xpathFullName() const
Nom XPath du noeud avec ces ancêtres.
Definition XmlNode.cc:143
String attrValue(const String &name, bool throw_exception=false) const
Valeur de l'attribut name.
Definition XmlNode.cc:225
XmlNode child(const String &name) const
Noeud fils de celui-ci de nom name.
Definition XmlNode.cc:64
bool null() const
Vrai si le noeud est nul.
Definition XmlNode.h:294
String name() const
Nom du noeud.
Definition XmlNode.cc:132
Classe de base des vecteurs 1D de données.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
virtual void executeFunctor()=0
Exécute la méthode associé
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Array< String > StringArray
Tableau dynamique à une dimension de chaînes de caractères.
Definition UtilsTypes.h:337
eCaseOptionReadPhase
Phases de la lecture.
@ ST_CaseOption
Le service s'utilise au niveau du jeu de données.
UniqueArray< String > StringUniqueArray
Tableau dynamique à une dimension de chaînes de caractères.
Definition UtilsTypes.h:525