View Javadoc

1   package org.lsst.ccs.config;
2   
3   import org.hibernate.annotations.Immutable;
4   import org.lsst.gruth.jutils.ComponentNode;
5   import org.lsst.gruth.jutils.HollowParm;
6   
7   import javax.persistence.*;
8   import java.util.*;
9   
10  /**
11   * An actual configuration profile.
12   * Once registered instances of this class are immutable except for  comments
13   * and registration of method calls (to be specified).
14   *
15   * @author bamade
16   */
17  // Date: 12/04/12
18  
19  @Table(name = "AConfigProfile",
20          uniqueConstraints = {@UniqueConstraint(columnNames = {"name", "tag"})}
21  )
22  @Entity
23  @Immutable
24  class AConfigProfile extends ConfigProfile implements Cloneable {
25      private static final long serialVersionUID = 3552425996944600856L;
26      @Id
27      @GeneratedValue
28      private long id; //generated
29      @ManyToOne (fetch=FetchType.EAGER)
30      private /*@NotNull*/ ASubsystemDescription subsystemDesc;
31  
32      /**
33       * duplicate information : helps when in an intermediate state where
34       * the subsystemDescription is being deprecated ;
35       */
36      private long subsystemId;
37  
38  
39      //TODO: A map<Path,XXX> instead
40      @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
41      private /*@NotNull*/ Set<AParameterConfiguration> parameterConfigurations =
42              // just in case! not ideal when handled as a bean
43              new HashSet<AParameterConfiguration>();
44  
45      @Transient
46      private /*@NotNull*/ Set<AParameterConfiguration> unModifiableConfigurations =
47              Collections.unmodifiableSet(parameterConfigurations);
48  
49      ////////////////////////////////// CONSTRUCTORS
50  
51      AConfigProfile() {
52      }
53  
54      /**
55       * creates a config profile pointing to a Subsystem Description that must be registered in the database.
56       *
57       * @param subsystemDesc
58       * @param name
59       * @param tag
60       * @param userName
61       * @param level
62       * @throws IllegalArgumentException if the subsystem description is not registered or is deprecated
63       */
64      public AConfigProfile(ASubsystemDescription subsystemDesc, String name, String tag, String userName, int level) {
65          super(name, tag, userName, level);
66          this.subsystemDesc = subsystemDesc;
67          this.subsystemId = subsystemDesc.getId();
68          if (subsystemId == 0) {
69              throw new IllegalArgumentException("Subsystem description should have been registered in database");
70          }
71          //TODO: tautological all instances of ASubsystemDescription have a STILL_VALID date!
72          long endDate = subsystemDesc.getEndTimestamp();
73          // when in remote operation this tet may not suffice
74          if (!(endDate == PackCst.STILL_VALID)) {
75              throw new IllegalArgumentException("using deprecated subsystem");
76          }
77      }
78  
79  
80      /**
81       * creates a copy of an active ConfigProfile (for instance to start an engineering mode or to validate
82       * a new tagged configuration from an engineering mode configuration).
83       *
84       * @param anotherConfig
85       * @param name
86       * @param tag
87       * @param userName
88       * @param level
89       * @param toEngineering
90       */
91      public AConfigProfile(AConfigProfile anotherConfig, String name, String tag,
92                            String userName, int level, boolean toEngineering) {
93          this(anotherConfig.getSubsystemDesc(), name, tag, userName, level);
94          setBeenInEngineeringMode(toEngineering);
95          for (AParameterConfiguration parmConfig : anotherConfig.getParameterConfigurations()) {
96              AParameterConfiguration copyParm = AParameterConfiguration.copyWithoutEvents(parmConfig);
97              if (anotherConfig.isBeenInEngineeringMode()) {
98                  List<AValueEvent> eventList = parmConfig.valueEvents;
99                  if (toEngineering) {
100                     //copy the history (use case?)
101                     if (eventList != null) {
102                         for (AValueEvent event : eventList) {
103                             copyParm.addValueEvent(event);
104                         }
105                     }
106                     copyParm.setCopy(true);
107 
108                 } else {
109                     //move last in history to value
110                     if (eventList != null) {
111                         int size = eventList.size();
112                         // "belt and suspenders" strategy
113                         if (size > 0) {
114                             AValueEvent event = eventList.get(size - 1);
115                             copyParm.setValue(event.getValue());
116                         }
117                     }
118                 }
119             }
120             this.addParameterConfigurations(copyParm);
121         }
122     }
123 
124     /////////////////////////////////// ACCESSORS/MUTATORS
125     @Override
126     public long getId() {
127         return id;
128     }
129 
130     @Override
131     protected void setId(long id) {
132         this.id = id;
133     }
134 
135 
136     @Override
137     public SubsystemDescription getSubsystemDescription() {
138         return subsystemDesc;
139     }
140 
141 
142     /**
143      * return <TT>getParameterConfigurations</TT>
144      *
145      * @return
146      */
147     @Override
148     public Set<? extends ParameterConfiguration> getModifiedParameters() {
149         return getParameterConfigurations();
150     }
151 
152     /**
153      * changes a parameter in Engineering mode.
154      * @param parameter
155      * @param time
156      * @param value
157      */
158     @Override
159     public void temporaryChangeConfigurationValue(ParameterConfiguration parameter, long time, String value) {
160         // if not in engineering mode stops
161         if (!isBeenInEngineeringMode()) {
162             throw new IllegalStateException("ConfigProfile not in Engineering mode");
163         }
164         // if parameter is null ->  exception
165         if (null == parameter) {
166             throw new IllegalArgumentException("no such ParameterConfiguration");
167         }
168         //  cast to AParemeterConfiguration
169         // wrong AParameterConfiguration aParameterConfiguration = (AParameterConfiguration) parameter;
170         AParameterConfiguration aParameterConfiguration = (AParameterConfiguration) this.fetch(parameter);
171         // TODO if(aParameterConfiguration == null) {
172         aParameterConfiguration.addValueEvent(new AValueEvent(time, value));
173     }
174 
175     public   ParameterConfiguration temporaryChangeConfigurationValue(String  parameterPath, long time, String value) {
176 
177         ParameterPath path = ParameterPath.valueOf(parameterPath) ;
178         // fetch the ParameterConfiguration
179         ParameterConfiguration parameter = this.fetch(path) ;
180         if(parameter == null) {
181           //creates a new Parameter
182             AParameterDescription description = (AParameterDescription)subsystemDesc.fetch(path) ;
183           // register it to the  configProfile
184             parameter = new AParameterConfiguration(description) ;
185             this.addParameterConfigurations(parameter);
186         }
187         //calls the other method
188         temporaryChangeConfigurationValue(parameter, time, value);
189         return parameter ;
190     }
191 
192     ASubsystemDescription getSubsystemDesc() {
193         return subsystemDesc;
194     }
195 
196     void setSubsystemDesc(ASubsystemDescription subsystemDesc) {
197         this.subsystemDesc = subsystemDesc;
198     }
199 
200     /**
201      * @return an unmodifiable set
202      */
203     public Set<AParameterConfiguration> getParameterConfigurations() {
204         return unModifiableConfigurations;
205     }
206 
207 
208     void setParameterConfigurations(Set<AParameterConfiguration> parameterConfigurations) {
209         this.parameterConfigurations = parameterConfigurations;
210         this.unModifiableConfigurations = Collections.unmodifiableSet(parameterConfigurations);
211     }
212 
213     public AConfigProfile clone() {
214         AConfigProfile res = null;
215         try {
216             res = (AConfigProfile) super.clone();
217             HashSet<AParameterConfiguration> newSet = new HashSet<AParameterConfiguration>();
218             for (AParameterConfiguration parmConfig : parameterConfigurations) {
219                 newSet.add(parmConfig.clone());
220             }
221             res.setParameterConfigurations(newSet);
222         } catch (CloneNotSupportedException e) { /*IGNORE*/}
223         return res;
224 
225     }
226 
227     public long getSubsystemId() {
228         return subsystemId;
229     }
230 
231     void setSubsystemId(long subsystemId) {
232         this.subsystemId = subsystemId;
233     }
234 
235     public void setBeenInEngineeringMode(boolean beenInEngineeringMode) {
236         super.setBeenInEngineeringMode(beenInEngineeringMode);
237     }
238 
239     /**
240      * the only public mutator
241      * <p/>
242      * TODO: no persistence of this for the moment
243      *
244      * @param remarks
245      */
246     public void setRemarks(String remarks) {
247         //TODO add a transient modification boolean checked by the persistence
248         super.setRemarks(remarks);
249     }
250 
251     /**
252      * Modifies the current object by using a properties object (built from a .properties file)
253      * @param props
254      */
255     //TODO: what happens if a value is illegal right in the middle of a modification?
256     @Override
257     public void mergeProperties(Properties props) {
258         if (getId() != 0L) {
259             throw new ImmutableStateException("no modification of registered data");
260         }
261         // creates a Map of all ParameterDescription using name and simple names
262         Map<String, ParameterDescription> map = subsystemDesc.generateDescriptionMap();
263         for (String name : props.stringPropertyNames()) {
264             ParameterDescription description = map.get(name);
265             if (description != null) {
266                 // is there a modifiable configuration or not?
267                 ParameterConfiguration configuration = this.fetch(description);
268                 String value = props.getProperty(name);
269                 if (configuration != null) {
270                     configuration.modifyValue(value);
271                 } else {
272                     AParameterDescription realDescription = (AParameterDescription) description;
273                     configuration = new AParameterConfiguration(realDescription, value);
274                     this.addParameterConfigurations(configuration);
275                 }
276 
277             }
278         }
279     }
280     //////////////////////////// IDENT METHODS
281 ///////////////////////////////// UTILITIES METHODS
282 
283     /**
284      * to build a list of Parameter configurations one needs a list of possible parameter descriptions
285      * that can be used.
286      *
287      * @return
288      */
289     public Set<AParameterDescription> getPossibleParameters() {
290         Set<AParameterDescription> res = new HashSet<AParameterDescription>();
291         for (ParameterDescription parmDesc : this.getSubsystemDescription().getParamDescriptionSet()) {
292             if (parmDesc.getLevel() <= this.getLevel()) {
293                 res.add(new AParameterDescription(parmDesc));
294             }
295         }
296         return res;
297     }
298 
299     /**
300      * registers a list of parameter configurations
301      *
302      * @param parameterConfigurations
303      * @throws ImmutableStateException  if the object is already registered in database
304      * @throws IllegalArgumentException if levels are incompatibles
305      * @throws IllegalArgumentException if the corresponding parameter descriptions are not alive in the current
306      *                                  subsystem description
307      */
308     // TODO: check if Description not deprecated!
309     public void addParameterConfigurations(AParameterConfiguration... parameterConfigurations) {
310         if (isReadOnly()) {
311             throw new ImmutableStateException("Parameter Configuration list");
312         }
313         for (AParameterConfiguration parameterConfiguration : parameterConfigurations) {
314             AParameterDescription description = parameterConfiguration.getParameterDescription();
315             // check for level
316             if (description.getLevel() > this.getLevel()) {
317                 throw new IllegalArgumentException("incompatible levels. profile is : " + getLevel()
318                         + " and description is :" + description.getLevel());
319             }
320             // check for deprecation
321             this.parameterConfigurations.add(parameterConfiguration);
322         }
323     }
324 
325     /**
326      * adds parameter configuration objects to this profile
327      * @param parameterConfigurations
328      */
329     public void addParameterConfigurations(ParameterConfiguration... parameterConfigurations) {
330         addParameterConfigurations(buildSafeArray(parameterConfigurations));
331     }
332 
333     private AParameterConfiguration[] buildSafeArray(ParameterConfiguration... parameterConfigurations) {
334         AParameterConfiguration[] parms = new AParameterConfiguration[parameterConfigurations.length];
335         for (int ix = 0; ix < parameterConfigurations.length; ix++) {
336             ParameterConfiguration conf = parameterConfigurations[ix];
337             if (!(conf instanceof AParameterConfiguration)) {
338                 throw new IllegalArgumentException("deprecated parameter Configuration");
339             }
340             parms[ix] = (AParameterConfiguration) conf;
341 
342         }
343         return parms;
344     }
345 
346     /**
347      * removes a list of parameter configurations
348      *
349      * @param parameterConfigurations
350      * @throws ImmutableStateException if operated on an object registered to the database
351      */
352     public void removeParameterConfigurations(ParameterConfiguration... parameterConfigurations) {
353         if (isReadOnly()) {
354             throw new ImmutableStateException("Parameter Configuration list");
355         }
356         for (ParameterConfiguration parameterConfiguration : parameterConfigurations) {
357             this.parameterConfigurations.remove(parameterConfiguration);
358         }
359     }
360 
361 
362     /**
363      * prepares a new executable configuration data with these modified parameters.
364      * used by <TT>PreparedConfiguration</TT> objects.
365      *
366      * @return
367      */
368     public ComponentNode getModifiedConfigurationData() {
369         ComponentNode res = null;
370         ComponentNode componentNode = subsystemDesc.getTopComponentNode() ;
371         componentNode = componentNode.clone();
372         for (AParameterConfiguration parameterConfiguration : getParameterConfigurations()) {
373             ParameterPath path = parameterConfiguration.getPath();
374             String componentName = path.getComponentName();
375             String codeName = path.getCodeName();
376             if (codeName != null && !"".equals(codeName)) {
377                 throw new UnsupportedOperationException(" no change on methods yet --> " + codeName);
378             }
379             String parameterName = path.getParameterName();
380             ComponentNode goalComponent = (ComponentNode) componentNode.getNodeByName(componentName);
381             if(goalComponent == null) {
382                 throw new IllegalArgumentException("no component for name :" + componentName) ;
383             }
384             Map mapAttributes = goalComponent.getAttributes() ;
385             // not null
386             if(mapAttributes == null ) {
387                 throw new  IllegalArgumentException("incompatible attribute list for component/parameter " +componentName +"/" +parameterName) ;
388             }
389             // get Parameter
390             Object rawParm = mapAttributes.get(parameterName);
391             if (rawParm instanceof HollowParm) {
392                 HollowParm hollow = (HollowParm) rawParm;
393                 hollow.modifyChecked(parameterConfiguration.getValue());
394             } else {
395                 throw new IllegalArgumentException("parameter not modifiable" + rawParm);
396             }
397         }
398         res = componentNode;
399 
400         return res;
401     }
402 
403 }