Salome HOME
bf126c17b35654806c9b3b091861a7c56fc0cefa
[modules/shaper.git] / src / Model / Model_Validator.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_Validator.cpp
4 // Created:     2 Jul 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_Validator.h"
8
9 #include "Model_AttributeValidator.h"
10 #include "Model_FeatureValidator.h"
11
12 #include <ModelAPI_Attribute.h>
13 #include <ModelAPI_AttributeString.h>
14 #include <ModelAPI_AttributeValidator.h>
15 #include <ModelAPI_Feature.h>
16 #include <ModelAPI_Result.h>
17 #include <Model_Data.h>
18
19 #include <Config_Translator.h>
20
21 #include <Events_InfoMessage.h>
22
23 void Model_ValidatorsFactory::registerValidator(const std::string& theID,
24   ModelAPI_Validator* theValidator)
25 {
26   if (myIDs.find(theID) != myIDs.end()) {
27     Events_InfoMessage("Model_Validator", "Validator %1 is already registered").arg(theID).send();
28   } else {
29     myIDs[theID] = theValidator;
30   }
31 }
32
33 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
34   const std::string& theFeatureID)
35 {
36   if (myFeatures.find(theFeatureID) == myFeatures.end()) {
37     myFeatures[theFeatureID] = AttrValidators();
38   }
39   if (myFeatures[theFeatureID].find(theID) != myFeatures[theFeatureID].end()) {
40     //Events_Error::send(std::string("Validator ") + theID +
41     //  " for feature " + theFeatureID + "is already registered");
42   } else {
43     myFeatures[theFeatureID][theID] = std::list<std::string>();
44   }
45 }
46
47 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
48   const std::string& theFeatureID,
49   const std::list<std::string>& theArguments)
50 {
51   if (myFeatures.find(theFeatureID) == myFeatures.end()) {
52     myFeatures[theFeatureID] = AttrValidators();
53   }
54
55   if (myFeatures[theFeatureID].find(theID) != myFeatures[theFeatureID].end()) {
56     //Events_Error::send(std::string("Validator ") + theID +
57     //  " for feature " + theFeatureID + "is already registered");
58   } else {
59     myFeatures[theFeatureID][theID] = theArguments;
60   }
61 }
62
63 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
64   const std::string& theFeatureID,
65   const std::string& theAttrID,
66   const std::list<std::string>& theArguments)
67 {
68   // create feature-structures if not exist
69   std::map<std::string, std::map<std::string, AttrValidators> >::iterator aFeature = myAttrs.find(
70     theFeatureID);
71   if (aFeature == myAttrs.end()) {
72     myAttrs[theFeatureID] = std::map<std::string, AttrValidators>();
73     aFeature = myAttrs.find(theFeatureID);
74   }
75   // add attr-structure if not exist, or generate error if already exist
76   std::map<std::string, AttrValidators>::iterator anAttr = aFeature->second.find(theAttrID);
77   if (anAttr == aFeature->second.end()) {
78     aFeature->second[theAttrID] = AttrValidators();
79   }
80   aFeature->second[theAttrID][theID] = theArguments;
81 }
82
83 void Model_ValidatorsFactory::validators(const std::string& theFeatureID,
84                                          Validators& theValidators) const
85 {
86   std::map<std::string, AttrValidators>::const_iterator aFeatureIt =
87       myFeatures.find(theFeatureID);
88   if (aFeatureIt != myFeatures.cend()) {
89     AttrValidators::const_iterator aValidatorsIt = aFeatureIt->second.cbegin();
90     for (; aValidatorsIt != aFeatureIt->second.cend(); aValidatorsIt++) {
91       if (!validator(aValidatorsIt->first)) {
92         Events_InfoMessage("Model_Validator", "Validator %1 was not registered")
93           .arg(aValidatorsIt->first).send();
94       } else {
95         theValidators.push_back(std::make_pair(aValidatorsIt->first, aValidatorsIt->second));
96       }
97     }
98   }
99   addDefaultValidators(theValidators);
100 }
101
102 void Model_ValidatorsFactory::validators(const std::string& theFeatureID,
103                                          const std::string& theAttrID,
104                                          Validators& theValidators) const
105 {
106   std::map<std::string, std::map<std::string, AttrValidators> >::const_iterator aFeatureIt =
107       myAttrs.find(theFeatureID);
108   if (aFeatureIt != myAttrs.cend()) {
109     std::map<std::string, AttrValidators>::const_iterator anAttrIt =
110       aFeatureIt->second.find(theAttrID);
111     if (anAttrIt != aFeatureIt->second.end()) {
112       AttrValidators::const_iterator aValidatorsIt = anAttrIt->second.cbegin();
113       for (; aValidatorsIt != anAttrIt->second.cend(); aValidatorsIt++) {
114         if (!validator(aValidatorsIt->first)) {
115           Events_InfoMessage("Model_Validator", "Validator %1 was not registered")
116             .arg(aValidatorsIt->first).send();
117         } else {
118           theValidators.push_back(std::make_pair(aValidatorsIt->first, aValidatorsIt->second));
119         }
120       }
121     }
122   }
123   addDefaultAttributeValidators(theValidators);
124 }
125
126 Model_ValidatorsFactory::Model_ValidatorsFactory()
127   : ModelAPI_ValidatorsFactory()
128 {
129   registerValidator("Model_FeatureValidator", new Model_FeatureValidator);
130   registerValidator("Model_AttributeValidator", new Model_AttributeValidator);
131 }
132
133 const ModelAPI_Validator* Model_ValidatorsFactory::validator(const std::string& theID) const
134 {
135   std::map<std::string, ModelAPI_Validator*>::const_iterator aIt = myIDs.find(theID);
136   if (aIt != myIDs.end()) {
137     return aIt->second;
138   }
139   return NULL;
140 }
141
142 void Model_ValidatorsFactory::addDefaultValidators(Validators& theValidators) const
143 {
144   const static std::string kDefaultId = "Model_FeatureValidator";
145   if (!validator(kDefaultId))
146     return;
147   theValidators.push_back(std::make_pair(kDefaultId, std::list<std::string>()));
148 }
149
150 void Model_ValidatorsFactory::addDefaultAttributeValidators(Validators& theValidators) const
151 {
152   const static std::string kDefaultId = "Model_AttributeValidator";
153   if (!validator(kDefaultId))
154     return;
155   theValidators.push_back(std::make_pair(kDefaultId, std::list<std::string>()));
156 }
157
158 bool Model_ValidatorsFactory::validate(const std::shared_ptr<ModelAPI_Feature>& theFeature) const
159 {
160   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theFeature->data());
161   if (aData.get() && aData->isValid()) {
162     if (aData->execState() == ModelAPI_StateDone)
163       aData->eraseErrorString(); // no error => erase the information string
164   } else {
165     return false; // feature is broken, already not presented in the data structure
166   }
167
168   // check feature validators first
169   Validators aValidators;
170   validators(theFeature->getKind(), aValidators);
171
172   if (!aValidators.empty()) {
173     Validators::const_iterator aValidatorIt = aValidators.cbegin();
174     for(; aValidatorIt != aValidators.cend(); aValidatorIt++) {
175       const std::string& aValidatorID = aValidatorIt->first;
176       const std::list<std::string>& anArguments = aValidatorIt->second;
177       // validators() checks invalid validator names
178       //if (!aValidator) {
179       //  Events_Error::send(std::string("Validator ") + aValidatorID + " was not registered");
180       //  continue;
181       //}
182       const ModelAPI_FeatureValidator* aFValidator =
183         dynamic_cast<const ModelAPI_FeatureValidator*>(validator(aValidatorID));
184       if (aFValidator) {
185         Events_InfoMessage anError;
186         if (!aFValidator->isValid(theFeature, anArguments, anError)) {
187           if (anError.empty())
188             anError = "Unknown error.";
189           if (anError.context().empty()) {
190             anError.setContext(theFeature->getKind() + ":" + aValidatorID);
191           }
192           theFeature->setError(Config_Translator::translate(anError), false, false);
193           theFeature->data()->execState(ModelAPI_StateInvalidArgument);
194           return false;
195         }
196       }
197     }
198   }
199   // The default validator was retrned by validators() and was checked in previous cycle
200   //// check default validator
201   //std::map<std::string, ModelAPI_Validator*>::const_iterator aDefaultVal = myIDs.find(kDefaultId);
202   //if(aDefaultVal != myIDs.end()) {
203   //  static const std::list<std::string> anEmptyArgList;
204   //  const ModelAPI_FeatureValidator* aFValidator =
205   //    dynamic_cast<const ModelAPI_FeatureValidator*>(aDefaultVal->second);
206   //  if (aFValidator) {
207   //    std::string anError;
208   //    if (!aFValidator->isValid(theFeature, anEmptyArgList, anError)) {
209   //      if (anError.empty())
210   //        anError = "Unknown error.";
211   //      anError = "Feature invalidated by \"" + kDefaultId + "\" with error: " + anError;
212   //      theFeature->setError(anError, false);
213   //      theFeature->data()->execState(ModelAPI_StateInvalidArgument);
214   //      return false;
215   //    }
216   //  }
217   //}
218
219   // check all attributes for validity
220   // Validity of data is checked by "Model_FeatureValidator" (kDefaultId)
221   // if (!aData || !aData->isValid())
222   //   return false;
223   static const std::string kAllTypes = "";
224   std::list<std::string> aLtAttributes = aData->attributesIDs(kAllTypes);
225   std::list<std::string>::const_iterator anAttrIt = aLtAttributes.cbegin();
226   for (; anAttrIt != aLtAttributes.cend(); anAttrIt++) {
227     const std::string& anAttributeID = *anAttrIt;
228     AttributePtr anAttribute = theFeature->data()->attribute(anAttributeID);
229
230     std::string aValidatorID;
231     Events_InfoMessage anError;
232     if (!validate(anAttribute, aValidatorID, anError)) {
233       if (anError.empty())
234         anError = "Unknown error.";
235       if (anError.context().empty()) {
236         anError.setContext(theFeature->getKind() + ":" + anAttributeID + ":" + aValidatorID);
237       }
238       theFeature->setError(Config_Translator::translate(anError), false, false);
239       theFeature->data()->execState(ModelAPI_StateInvalidArgument);
240       return false;
241     }
242   }
243
244   return true;
245 }
246
247 bool Model_ValidatorsFactory::validate(const std::shared_ptr<ModelAPI_Attribute>& theAttribute,
248                                        std::string& theValidator,
249                                        Events_InfoMessage& theError) const
250 {
251   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
252   if (!aFeature.get()) {
253     theValidator = "Model_ValidatorsFactory";
254     theError = "Attribute has no feature.";
255     return false;
256   }
257
258   // skip not-case attributes, that really may be invalid (issue 671)
259   if (!const_cast<Model_ValidatorsFactory*>(this)->isCase(aFeature, theAttribute->id()))
260     return true;
261
262   Validators aValidators;
263   validators(aFeature->getKind(), theAttribute->id(), aValidators);
264
265   Validators::iterator aValidatorIt = aValidators.begin();
266   for (; aValidatorIt != aValidators.end(); ++aValidatorIt) {
267     const std::string& aValidatorID = aValidatorIt->first;
268     const std::list<std::string>& anArguments = aValidatorIt->second;
269     const ModelAPI_AttributeValidator* anAttrValidator =
270         dynamic_cast<const ModelAPI_AttributeValidator*>(validator(aValidatorID));
271     if (!anAttrValidator)
272       continue;
273     if (!anAttrValidator->isValid(theAttribute, anArguments, theError)) {
274       theValidator = aValidatorID;
275       return false;
276     }
277   }
278
279   return true;
280 }
281
282 void Model_ValidatorsFactory::registerNotObligatory(std::string theFeature,
283                                                     std::string theAttribute)
284 {
285   const static std::string kDefaultId = "Model_FeatureValidator";
286   std::map<std::string, ModelAPI_Validator*>::const_iterator it = myIDs.find(kDefaultId);
287   if (it != myIDs.end()) {
288     Model_FeatureValidator* aValidator = dynamic_cast<Model_FeatureValidator*>(it->second);
289     if (aValidator) {
290       aValidator->registerNotObligatory(theFeature, theAttribute);
291     }
292   }
293 }
294
295 bool Model_ValidatorsFactory::isNotObligatory(std::string theFeature, std::string theAttribute)
296 {
297   const static std::string kDefaultId = "Model_FeatureValidator";
298   std::map<std::string, ModelAPI_Validator*>::const_iterator it = myIDs.find(kDefaultId);
299   if (it != myIDs.end()) {
300     Model_FeatureValidator* aValidator = dynamic_cast<Model_FeatureValidator*>(it->second);
301     if (aValidator) {
302       return aValidator->isNotObligatory(theFeature, theAttribute);
303     }
304   }
305   return false; // default
306 }
307
308 void Model_ValidatorsFactory::registerConcealment(std::string theFeature, std::string theAttribute)
309 {
310   std::map<std::string, std::set<std::string> >::iterator aFind = myConcealed.find(theFeature);
311   if (aFind == myConcealed.end()) {
312     std::set<std::string> aNewSet;
313     aNewSet.insert(theAttribute);
314     myConcealed[theFeature] = aNewSet;
315   } else {
316     aFind->second.insert(theAttribute);
317   }
318 }
319
320 bool Model_ValidatorsFactory::isConcealed(std::string theFeature, std::string theAttribute)
321 {
322   std::map<std::string, std::set<std::string> >::iterator aFind = myConcealed.find(theFeature);
323   return aFind != myConcealed.end() && aFind->second.find(theAttribute) != aFind->second.end();
324 }
325
326 void Model_ValidatorsFactory::registerCase(std::string theFeature, std::string theAttribute,
327                             const std::list<std::pair<std::string, std::string> >& theCases)
328 {
329   std::map<std::string, std::map<std::string, std::map<std::string, std::set<std::string> > > >
330     ::iterator aFindFeature = myCases.find(theFeature);
331   if (aFindFeature == myCases.end()) {
332     myCases[theFeature] = std::map<std::string, std::map<std::string, std::set<std::string> > >();
333     aFindFeature = myCases.find(theFeature);
334   }
335   std::map<std::string, std::map<std::string, std::set<std::string> > >::iterator aFindAttrID =
336     aFindFeature->second.find(theAttribute);
337
338   if (aFindAttrID == aFindFeature->second.end()) {
339     aFindFeature->second[theAttribute] =
340       std::map<std::string, std::set<std::string> >();
341     aFindAttrID = aFindFeature->second.find(theAttribute);
342   }
343   std::list<std::pair<std::string, std::string> >::const_iterator aCasesIt = theCases.begin(),
344                                                                        aCasesLast = theCases.end();
345   std::map<std::string, std::set<std::string> > aFindCases = aFindAttrID->second;
346   for (; aCasesIt != aCasesLast; aCasesIt++) {
347     std::pair<std::string, std::string> aCasePair = *aCasesIt;
348     std::string aSwitch = aCasePair.first;
349     if (aFindAttrID->second.find(aSwitch) == aFindAttrID->second.end()) {
350       aFindAttrID->second[aSwitch] = std::set<std::string>();
351     }
352     aFindAttrID->second[aSwitch].insert(aCasePair.second);
353   }
354 }
355
356 bool Model_ValidatorsFactory::isCase(FeaturePtr theFeature, std::string theAttribute)
357 {
358   bool anInCase = true;
359   std::map<std::string, std::map<std::string, std::map<std::string, std::set<std::string> > > >
360     ::iterator aFindFeature = myCases.find(theFeature->getKind());
361   if (aFindFeature != myCases.end()) {
362     std::map<std::string, std::map<std::string, std::set<std::string> > >::iterator
363       aFindAttrID = aFindFeature->second.find(theAttribute);
364     if (aFindAttrID != aFindFeature->second.end()) {
365       std::map<std::string, std::set<std::string> >::iterator
366               aCasesIt = aFindAttrID->second.begin(), aCasesLast = aFindAttrID->second.end();
367       for (; aCasesIt != aCasesLast && anInCase; aCasesIt++) {
368         // the the switch-attribute that contains the case value
369         AttributeStringPtr aSwitch = theFeature->string(aCasesIt->first);
370         if (aSwitch.get()) {
371           // the second has the case identifier
372           anInCase =  aCasesIt->second.find(aSwitch->value()) != aCasesIt->second.end();
373         }
374       }
375     }
376   }
377   return anInCase; // if no additional conditions, this attribute is the case to be validated
378 }