1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.update.schema.datamodel;
22  
23  import java.net.URL;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.efaps.ci.CIAdminDataModel;
30  import org.efaps.db.Insert;
31  import org.efaps.db.Instance;
32  import org.efaps.db.InstanceQuery;
33  import org.efaps.db.QueryBuilder;
34  import org.efaps.db.Update;
35  import org.efaps.update.AbstractUpdate;
36  import org.efaps.update.UpdateLifecycle;
37  import org.efaps.update.util.InstallationException;
38  import org.efaps.util.EFapsException;
39  
40  /**
41   * Handles the import / update of dimensions for eFaps read from a XML
42   * configuration item file.
43   *
44   * @author The eFaps Team
45   * @version $Id$
46   */
47  public class DimensionUpdate
48      extends AbstractUpdate
49  {
50      /**
51       * Default constructor to initialize this dimension update instance for
52       * given <code>_url</code>.
53       *
54       * @param _url URL of the file
55       */
56      public DimensionUpdate(final URL _url)
57      {
58          super(_url, "Admin_DataModel_Dimension");
59      }
60  
61      /**
62       * Creates new instance of class {@link DimensionUpdate}.
63       *
64       * @return new definition instance
65       * @see DimensionUpdate
66       */
67      @Override
68      protected AbstractDefinition newDefinition()
69      {
70          return new DimensionDefinition();
71      }
72  
73      /**
74       * Handles the related unit of measure definition for one version of a
75       * dimension.
76       */
77      public class UoMDefinition
78          extends AbstractDefinition
79      {
80  
81          /**
82           * Numerator for this UoM.
83           */
84          private String numerator;
85  
86          /**
87           * Denominator for this UoM.
88           */
89          private String denominator;
90  
91          /**
92           * Is this UoM the base UoM.
93           */
94          private boolean base;
95  
96          /**
97           * {@inheritDoc}
98           * @throws EFapsException
99           */
100         @Override
101         protected void readXML(final List<String> _tags,
102                                final Map<String, String> _attributes,
103                                final String _text)
104             throws EFapsException
105         {
106             final String value = _tags.get(0);
107             if ("numerator".equals(value)) {
108                 this.numerator = _text;
109             } else if ("denominator".equals(value)) {
110                 this.denominator = _text;
111             } else if ("base".equals(value)) {
112                 this.base = "true".equalsIgnoreCase(_text);
113             } else {
114                 super.readXML(_tags, _attributes, _text);
115             }
116         }
117 
118         /**
119          * For given type defined with the instance parameter, this attribute is
120          * searched by name. If the attribute exists, the attribute is updated.
121          * Otherwise the attribute is created for this type.
122          *
123          * @param _instance type instance to update with this attribute
124          * @throws InstallationException on error
125          */
126         protected void updateInDB(final Instance _instance)
127             throws InstallationException
128         {
129             try {
130                 final QueryBuilder queryBldr = new QueryBuilder(CIAdminDataModel.UoM);
131                 queryBldr.addWhereAttrEqValue(CIAdminDataModel.UoM.Dimension, _instance.getId());
132                 queryBldr.addWhereAttrEqValue(CIAdminDataModel.UoM.Name, getValue("Name"));
133                 final InstanceQuery query = queryBldr.getQuery();
134                 query.executeWithoutAccessCheck();
135                 Update update;
136                 if (query.next()) {
137                     update = new Update(query.getCurrentValue());
138                 } else {
139                     update = new Insert(CIAdminDataModel.UoM);
140                     update.add(CIAdminDataModel.UoM.Dimension, _instance.getId());
141                     update.add(CIAdminDataModel.UoM.Name, getValue("Name"));
142                 }
143                 update.add(CIAdminDataModel.UoM.Numerator,  this.numerator);
144                 update.add(CIAdminDataModel.UoM.Denominator,  this.denominator);
145                 update.executeWithoutAccessCheck();
146 
147                 if (this.base) {
148                     final Update dimUp = new Update(_instance);
149                     dimUp.add("BaseUoM", "" + update.getInstance().getId());
150                     dimUp.executeWithoutAccessCheck();
151                     dimUp.close();
152                 }
153 
154                 update.close();
155             } catch (final EFapsException e) {
156                 throw new InstallationException("Dimension can not be updated in DB", e);
157             }
158         }
159     }
160 
161     /**
162      * Handles the definition of one version for a dimension defined within XML
163      * configuration item file.
164      */
165     public class DimensionDefinition
166         extends AbstractDefinition
167     {
168         /**
169          * All attributes of the type are stored in this list.
170          *
171          * @see #updateInDB
172          * @see #addAttribute
173          */
174         private final List<DimensionUpdate.UoMDefinition> uoms = new ArrayList<DimensionUpdate.UoMDefinition>();
175 
176         /**
177          * Current read attribute definition instance.
178          *
179          * @see #readXML(List, Map, String)
180          */
181         private UoMDefinition curUoM = null;
182 
183         /**
184          * The description for this Dimension.
185          */
186         private String description;
187 
188         /**
189          * {@inheritDoc}
190          * @throws EFapsException
191          */
192         @Override
193         protected void readXML(final List<String> _tags,
194                                final Map<String, String> _attributes,
195                                final String _text)
196             throws EFapsException
197         {
198             final String value = _tags.get(0);
199             if ("description".equals(value)) {
200                 this.description = _text;
201             } else if ("uom".equals(value)) {
202                 if (_tags.size() == 1) {
203                     this.curUoM = new UoMDefinition();
204                     this.uoms.add(this.curUoM);
205                 } else {
206                     this.curUoM.readXML(_tags.subList(1, _tags.size()), _attributes, _text);
207                 }
208             } else {
209                 super.readXML(_tags, _attributes, _text);
210             }
211         }
212 
213         /**
214          * Overwritten to set the description.
215          *
216          * @see org.efaps.update.AbstractUpdate.AbstractDefinition#createInDB(org.efaps.db.Insert)
217          * @param _insert insert to be executed
218          * @throws InstallationException on error
219          */
220         @Override
221         protected void createInDB(final Insert _insert)
222             throws InstallationException
223         {
224             final String name = super.getValue("Name");
225             try {
226                 _insert.add(CIAdminDataModel.Dimension.Name, (name == null) ? "-" : name);
227             } catch (final EFapsException e) {
228                 throw new InstallationException("Name attribute could not be defined", e);
229             }
230             try {
231                 _insert.add(CIAdminDataModel.Dimension.Description, this.description == null ? "-" : this.description);
232             } catch (final EFapsException e) {
233                 throw new InstallationException("Description attribute could not be defined", e);
234             }
235             AbstractUpdate.LOG.info("    Insert " + _insert.getInstance().getType().getName() + " '" + name + "'");
236             try {
237                 _insert.executeWithoutAccessCheck();
238             } catch (final EFapsException e) {
239                 throw new InstallationException("Insert failed", e);
240             }
241             setInstance(_insert.getInstance());
242         }
243 
244         /**
245          * Only in the life cycle step {@link UpdateLifecycle#EFAPS_UPDATE} the
246          * {@link #description} and the {@link #uoms} are updated.
247          *
248          * @param _step         current step of the update life cycle
249          * @param _allLinkTypes set of all links
250          * @throws InstallationException on error
251          * @see #uoms
252          */
253         @Override
254         public void updateInDB(final UpdateLifecycle _step,
255                                final Set<Link> _allLinkTypes)
256             throws InstallationException
257         {
258             if (_step == UpdateLifecycle.EFAPS_UPDATE)  {
259                 addValue(CIAdminDataModel.Dimension.Description.name, this.description);
260             }
261 
262             super.updateInDB(_step, _allLinkTypes);
263 
264             if (_step == UpdateLifecycle.EFAPS_UPDATE)  {
265                 for (final UoMDefinition uom : this.uoms) {
266                     uom.updateInDB(getInstance());
267                 }
268             }
269         }
270     }
271 }