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.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.efaps.admin.datamodel.Attribute;
30  import org.efaps.admin.datamodel.Dimension;
31  import org.efaps.admin.datamodel.Type;
32  import org.efaps.ci.CIAdminDataModel;
33  import org.efaps.db.Insert;
34  import org.efaps.db.InstanceQuery;
35  import org.efaps.db.QueryBuilder;
36  import org.efaps.db.Update;
37  import org.efaps.update.AbstractUpdate;
38  import org.efaps.update.UpdateLifecycle;
39  import org.efaps.update.util.InstallationException;
40  import org.efaps.util.EFapsException;
41  
42  /**
43   * Handles the import / update of status groups for eFaps read from a XML
44   * configuration item file. Remark: The StatusGroupDefinition is actual just a
45   * normal Admin_DataModel_Type and the stati belonging to it are instances of
46   * this Type. That leads to the problem that if a StatusGroupUpdate is executed
47   * in one version the cache for the Types must be reloaded.
48   *
49   * @author The eFaps Team
50   * @version $Id$
51   */
52  public class StatusGroupUpdate
53      extends AbstractUpdate
54  {
55  
56      /**
57       * Default constructor to initialize this status group instance for given
58       * <code>_url</code>.
59       *
60       * @param _url url to the file
61       */
62      public StatusGroupUpdate(final URL _url)
63      {
64          super(_url, "Admin_DataModel_Type");
65      }
66  
67      /**
68       * {@inheritDoc}
69       */
70      @Override
71      protected AbstractDefinition newDefinition()
72      {
73          return new StatusGroupDefinition();
74      }
75  
76      /**
77       * Definition of one status.
78       */
79      public class StatusDefintion
80      {
81  
82          /**
83           * Key of this status.
84           */
85          private final String key;
86  
87          /**
88           * Description for this status.
89           */
90          private String description;
91  
92          /**
93           * @param _key key
94           */
95          public StatusDefintion(final String _key)
96          {
97              this.key = _key;
98          }
99  
100         /**
101          * @param _description description
102          */
103         public void setDescription(final String _description)
104         {
105             this.description = _description;
106         }
107 
108         /**
109          * @param _typeName name of the type
110          * @throws EFapsException on error during insert
111          */
112         public void updateInDB(final String _typeName)
113             throws EFapsException
114         {
115             final QueryBuilder queryBldr = new QueryBuilder(Type.get(_typeName));
116             queryBldr.addWhereAttrEqValue("Key", this.key);
117             final InstanceQuery query = queryBldr.getQuery();
118             query.executeWithoutAccessCheck();
119             final Update update;
120             if (query.next()) {
121                 update = new Update(query.getCurrentValue());
122             } else {
123                 update = new Insert(_typeName);
124             }
125             update.add("Key", this.key);
126             update.add("Description", this.description);
127             update.executeWithoutAccessCheck();
128         }
129     }
130 
131     /**
132      * Class for the definition of the type.
133      */
134     public class StatusGroupDefinition
135         extends AbstractDefinition
136     {
137 
138         /**
139          * Name of the parent type.
140          */
141         private String parentType;
142 
143         /**
144          * current definition.
145          */
146         private StatusDefintion currentStatus;
147 
148         /**
149          * Set of all definitions.
150          */
151         private final Set<StatusGroupUpdate.StatusDefintion> stati = new HashSet<StatusGroupUpdate.StatusDefintion>();
152 
153         /**
154          *
155          * @param _tags current path as list of single tags
156          * @param _attributes attributes for current path
157          * @param _text content for current path
158          * @throws EFapsException on error
159          */
160         @Override
161         protected void readXML(final List<String> _tags,
162                                final Map<String, String> _attributes,
163                                final String _text)
164             throws EFapsException
165         {
166             final String value = _tags.get(0);
167             if ("status".equals(value)) {
168                 if (_tags.size() == 1) {
169                     this.currentStatus = new StatusDefintion(_attributes.get("key"));
170                     this.stati.add(this.currentStatus);
171                 } else if (_tags.size() == 2 && "description".equals(_tags.get(1))) {
172                     this.currentStatus.setDescription(_text);
173                 }
174             } else if ("parent".equals(value)) {
175                 this.parentType = _text;
176             } else {
177                 super.readXML(_tags, _attributes, _text);
178             }
179         }
180 
181         /**
182          * If a parent type in {@link #parentType} is defined, the type id is
183          * evaluated and added to attributes to update (if no parent type is
184          * defined, the parent type id is set to <code>null</code>). After the
185          * type is updated (or inserted if needed), all statis must be updated.
186          *
187          * @param _step current step in the Update Lifecycle
188          * @param _allLinkTypes set of all links
189          * @throws InstallationException on error
190          * @see #parentType
191          * @see #attributes
192          */
193         @Override
194         public void updateInDB(final UpdateLifecycle _step,
195                                final Set<Link> _allLinkTypes)
196             throws InstallationException
197         {
198             try {
199                 if (_step == UpdateLifecycle.STATUSGROUP_CREATE) {
200                     super.updateInDB(UpdateLifecycle.EFAPS_CREATE, _allLinkTypes);
201                 }
202 
203                 if (_step == UpdateLifecycle.STATUSGROUP_UPDATE) {
204                     // set the id of the parent type (if defined)
205                     if ((this.parentType != null) && (this.parentType.length() > 0)) {
206                         final QueryBuilder queryBldr = new QueryBuilder(CIAdminDataModel.Type);
207                         queryBldr.addWhereAttrEqValue(CIAdminDataModel.Type.Name, this.parentType);
208                         final InstanceQuery query = queryBldr.getQuery();
209                         query.executeWithoutAccessCheck();
210                         if (query.next()) {
211                             addValue("ParentType", "" + query.getCurrentValue().getId());
212                         } else {
213                             addValue("ParentType", null);
214                         }
215                     } else {
216                         addValue("ParentType", null);
217                     }
218                     super.updateInDB(UpdateLifecycle.EFAPS_UPDATE, _allLinkTypes);
219                 }
220 
221                 if (_step == UpdateLifecycle.STATUS_CREATE) {
222                     // before the Stati can be created it must be checked if the
223                     // type (StatusGroup)
224                     // is already cached.
225                     if (Type.get(getValue("Name")) == null) {
226                         Type.initialize(StatusGroupUpdate.class);
227                         Dimension.initialize(StatusGroupUpdate.class);
228                         Attribute.initialize(StatusGroupUpdate.class);
229                     }
230                     for (final StatusDefintion status : this.stati) {
231                         status.updateInDB(getValue("Name"));
232                     }
233                 }
234             } catch (final EFapsException e) {
235                 throw new InstallationException(" SQLTable can not be updated", e);
236             }
237         }
238     }
239 }