View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.database.data;
21  
22  import com.fasterxml.jackson.databind.JsonNode;
23  import com.fasterxml.jackson.databind.node.ObjectNode;
24  import org.dom4j.Document;
25  import org.dom4j.DocumentException;
26  import org.dom4j.DocumentHelper;
27  import org.dom4j.Element;
28  import org.dom4j.Node;
29  import org.joda.time.DateTime;
30  import org.waarp.common.database.DbConstant;
31  import org.waarp.common.database.DbPreparedStatement;
32  import org.waarp.common.database.DbSession;
33  import org.waarp.common.database.exception.WaarpDatabaseException;
34  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
35  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
36  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
37  import org.waarp.common.file.FileUtils;
38  import org.waarp.common.logging.WaarpLogger;
39  import org.waarp.common.logging.WaarpLoggerFactory;
40  import org.waarp.common.role.RoleDefault;
41  import org.waarp.common.role.RoleDefault.ROLE;
42  import org.waarp.common.utility.ParametersChecker;
43  import org.waarp.common.utility.WaarpStringUtils;
44  import org.waarp.common.xml.XmlDecl;
45  import org.waarp.common.xml.XmlHash;
46  import org.waarp.common.xml.XmlType;
47  import org.waarp.common.xml.XmlUtil;
48  import org.waarp.common.xml.XmlValue;
49  import org.waarp.openr66.dao.AbstractDAO;
50  import org.waarp.openr66.dao.BusinessDAO;
51  import org.waarp.openr66.dao.DAOFactory;
52  import org.waarp.openr66.dao.Filter;
53  import org.waarp.openr66.dao.database.DBBusinessDAO;
54  import org.waarp.openr66.dao.database.StatementExecutor;
55  import org.waarp.openr66.dao.exception.DAOConnectionException;
56  import org.waarp.openr66.dao.exception.DAONoDataException;
57  import org.waarp.openr66.pojo.Business;
58  import org.waarp.openr66.protocol.configuration.Configuration;
59  import org.waarp.openr66.protocol.configuration.Messages;
60  import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
61  import org.waarp.openr66.protocol.utils.R66Versions;
62  import org.waarp.openr66.protocol.utils.Version;
63  
64  import java.io.StringReader;
65  import java.sql.SQLException;
66  import java.sql.Types;
67  import java.util.ArrayList;
68  import java.util.Arrays;
69  import java.util.HashMap;
70  import java.util.HashSet;
71  import java.util.List;
72  import java.util.Map.Entry;
73  import java.util.regex.Pattern;
74  
75  /**
76   * Configuration Table object
77   */
78  public class DbHostConfiguration extends AbstractDbDataDao<Business> {
79    /**
80     * Internal Logger
81     */
82    private static final WaarpLogger logger =
83        WaarpLoggerFactory.getLogger(DbHostConfiguration.class);
84    private static final Pattern WHITESPACES = WaarpStringUtils.BLANK;
85    private static final Pattern SPACE_BACKSLASH = Pattern.compile("\\s|\\|");
86    private static final Pattern COMMA = Pattern.compile(",");
87  
88    public enum Columns {
89      BUSINESS, ROLES, ALIASES, OTHERS, UPDATEDINFO, HOSTID
90    }
91  
92    public static final int[] dbTypes = {
93        Types.LONGVARCHAR, Types.LONGVARCHAR, Types.LONGVARCHAR,
94        Types.LONGVARCHAR, Types.INTEGER, Types.NVARCHAR
95    };
96  
97    public static final Columns[] indexes = {
98        Columns.HOSTID, Columns.UPDATEDINFO
99    };
100 
101   public static final String table = " HOSTCONFIG ";
102 
103   public static final String XML_ALIASES = "aliases";
104 
105   public static final String XML_ROLES = "roles";
106 
107   public static final String XML_BUSINESS = "business";
108 
109   /**
110    * Alias Id
111    */
112   public static final String XML_ALIASID = "aliasid";
113 
114   /**
115    * Main ID in alias
116    */
117   public static final String XML_REALID = "realid";
118 
119   /**
120    * Alias
121    */
122   public static final String XML_ALIAS = "alias";
123 
124   /**
125    * Role set
126    */
127   public static final String XML_ROLESET = "roleset";
128 
129   /**
130    * ID in role
131    */
132   public static final String XML_ROLEID = "roleid";
133 
134   /**
135    * Role Main entry
136    */
137   public static final String XML_ROLE = "role";
138 
139   /**
140    * Check version in protocol
141    */
142   public static final String XML_BUSINESSID = "businessid";
143   private static final XmlDecl[] businessDecl = {
144       new XmlDecl(XML_BUSINESS, XmlType.STRING,
145                   XML_BUSINESS + '/' + XML_BUSINESSID, true)
146   };
147 
148   /**
149    * Structure of the Configuration file
150    */
151   public static final XmlDecl[] configRoleDecls = {
152       // roles
153       new XmlDecl(XmlType.STRING, XML_ROLEID),
154       new XmlDecl(XmlType.STRING, XML_ROLESET)
155   };
156   private static final XmlDecl[] roleDecl = {
157       new XmlDecl(XML_ROLES, XmlType.XVAL, XML_ROLES + '/' + XML_ROLE,
158                   configRoleDecls, true)
159   };
160   /**
161    * Structure of the Configuration file
162    */
163   public static final XmlDecl[] configAliasDecls = {
164       // alias
165       new XmlDecl(XmlType.STRING, XML_REALID),
166       new XmlDecl(XmlType.STRING, XML_ALIASID)
167   };
168 
169   private static final XmlDecl[] aliasDecl = {
170       new XmlDecl(XML_ALIASES, XmlType.XVAL, XML_ALIASES + '/' + XML_ALIAS,
171                   configAliasDecls, true)
172   };
173 
174   public enum OtherFields {
175     root, version, seeallid, lastMonitoringDateTime
176   }
177 
178   protected static final String selectAllFields =
179       Columns.BUSINESS.name() + ',' + Columns.ROLES.name() + ',' +
180       Columns.ALIASES.name() + ',' + Columns.OTHERS.name() + ',' +
181       Columns.UPDATEDINFO.name() + ',' + Columns.HOSTID.name();
182 
183   @Override
184   protected final void initObject() {
185     //nothing
186   }
187 
188   @Override
189   protected final String getTable() {
190     return table;
191   }
192 
193   @Override
194   protected final AbstractDAO<Business> getDao(final boolean isCacheable)
195       throws DAOConnectionException {
196     return DAOFactory.getInstance().getBusinessDAO(isCacheable);
197   }
198 
199   @Override
200   protected final String getPrimaryKey() {
201     if (pojo != null) {
202       return pojo.getHostid();
203     }
204     throw new IllegalArgumentException("pojo is null");
205   }
206 
207   @Override
208   protected final String getPrimaryField() {
209     return Columns.HOSTID.name();
210   }
211 
212 
213   /**
214    * @param hostid
215    * @param business Business configuration
216    * @param roles Roles configuration
217    * @param aliases Aliases configuration
218    * @param others Other configuration
219    */
220   public DbHostConfiguration(final String hostid, final String business,
221                              final String roles, final String aliases,
222                              final String others)
223       throws WaarpDatabaseSqlException {
224     this.pojo = new Business(hostid, business, roles, aliases, others);
225   }
226 
227   public DbHostConfiguration(final Business business) {
228     if (business == null) {
229       throw new IllegalArgumentException(
230           "Argument in constructor cannot be null");
231     }
232     this.pojo = business;
233   }
234 
235   /**
236    * Constructor from Json
237    *
238    * @param source
239    *
240    * @throws WaarpDatabaseSqlException
241    */
242   public DbHostConfiguration(final ObjectNode source)
243       throws WaarpDatabaseSqlException {
244     pojo = new Business();
245     setFromJson(source, false);
246     if (ParametersChecker.isEmpty(pojo.getHostid())) {
247       throw new WaarpDatabaseSqlException(
248           "Not enough argument to create the object");
249     }
250     isSaved = false;
251   }
252 
253   /**
254    * @param hostid
255    *
256    * @throws WaarpDatabaseException
257    */
258   public DbHostConfiguration(final String hostid)
259       throws WaarpDatabaseException {
260     BusinessDAO businessAccess = null;
261     try {
262       businessAccess = DAOFactory.getInstance().getBusinessDAO(true);
263       pojo = businessAccess.select(hostid);
264     } catch (final DAOConnectionException e) {
265       throw new WaarpDatabaseException(e);
266     } catch (final DAONoDataException e) {
267       throw new WaarpDatabaseNoDataException("DbHostConfiguration not found",
268                                              e);
269     } finally {
270       DAOFactory.closeDAO(businessAccess);
271     }
272   }
273 
274   @Override
275   protected final void checkValues() throws WaarpDatabaseSqlException {
276     pojo.checkValues();
277   }
278 
279   /**
280    * @return the hostid
281    */
282   public final String getHostid() {
283     return pojo.getHostid();
284   }
285 
286   /**
287    * @return the business
288    */
289   public final String getBusiness() {
290     return pojo.getBusiness();
291   }
292 
293   /**
294    * @param business the business to set
295    */
296   public final void setBusiness(final String business) {
297     this.pojo.setBusiness(business == null? "" : business);
298     int len;
299     do {
300       len = this.pojo.getBusiness().length();
301       this.pojo.setBusiness(
302           WHITESPACES.matcher(this.pojo.getBusiness()).replaceAll(" "));
303     } while (len != this.pojo.getBusiness().length());
304     Configuration.configuration.getBusinessWhiteSet().clear();
305     if (!this.pojo.getBusiness().isEmpty()) {
306       readValuesFromXml(this.pojo.getBusiness(), businessDecl);
307     }
308     isSaved = false;
309   }
310 
311   /**
312    * @return the roles
313    */
314   public final String getRoles() {
315     return pojo.getRoles();
316   }
317 
318   /**
319    * @param roles the roles to set
320    */
321   public final void setRoles(final String roles) {
322     pojo.setRoles(roles == null? "" : roles);
323     int len;
324     do {
325       len = getRoles().length();
326       pojo.setRoles(WHITESPACES.matcher(pojo.getRoles()).replaceAll(" "));
327     } while (len != pojo.getRoles().length());
328     Configuration.configuration.getRoles().clear();
329     if (!pojo.getRoles().isEmpty()) {
330       readValuesFromXml(pojo.getRoles(), roleDecl);
331     }
332     isSaved = false;
333   }
334 
335   /**
336    * @return the aliases
337    */
338   public final String getAliases() {
339     return pojo.getAliases();
340   }
341 
342   /**
343    * @param aliases the aliases to set
344    */
345   public final void setAliases(final String aliases) {
346     pojo.setAliases(aliases == null? "" : aliases);
347     int len;
348     do {
349       len = pojo.getAliases().length();
350       pojo.setAliases(WHITESPACES.matcher(pojo.getAliases()).replaceAll(" "));
351     } while (len != pojo.getAliases().length());
352     Configuration.configuration.getAliases().clear();
353     Configuration.configuration.getReverseAliases().clear();
354     if (!pojo.getAliases().isEmpty()) {
355       readValuesFromXml(pojo.getAliases(), aliasDecl);
356     }
357     isSaved = false;
358   }
359 
360   @SuppressWarnings("unchecked")
361   private void readValuesFromXml(final String input, final XmlDecl[] config) {
362     if (ParametersChecker.isEmpty(input)) {
363       logger.error(Messages.getString(
364           "FileBasedConfiguration.CannotReadXml")); //$NON-NLS-1$
365       return;
366     }
367     final Document document;
368     final StringReader reader = new StringReader(input);
369     // Open config file
370     try {
371       document = XmlUtil.getNewSaxReader().read(reader);
372     } catch (final DocumentException e) {
373       logger.error(
374           Messages.getString("FileBasedConfiguration.CannotReadXml") + input +
375           ": {}", e.getMessage()); //$NON-NLS-1$
376       return;
377     }
378     if (document == null) {
379       logger.error(Messages.getString("FileBasedConfiguration.CannotReadXml") +
380                    input); //$NON-NLS-1$
381       return;
382     }
383     final XmlValue[] configuration = XmlUtil.read(document, config);
384     final XmlHash hashConfig = new XmlHash(configuration);
385     XmlValue value = hashConfig.get(XML_BUSINESS);
386     if (value != null && value.getList() != null) {
387       final List<String> ids = (List<String>) value.getList();
388       if (ids != null) {
389         for (final String sval : ids) {
390           if (sval.isEmpty()) {
391             continue;
392           }
393           logger.info("Business Allow: {}", sval);
394           Configuration.configuration.getBusinessWhiteSet().add(sval.trim());
395         }
396         ids.clear();
397       }
398     }
399     value = hashConfig.get(XML_ALIASES);
400     if (value != null && value.getList() != null) {
401       for (final XmlValue[] xml : (Iterable<XmlValue[]>) value.getList()) {
402         final XmlHash subHash = new XmlHash(xml);
403         value = subHash.get(XML_REALID);
404         if (value == null || value.isEmpty()) {
405           continue;
406         }
407         final String refHostId = value.getString();
408         value = subHash.get(XML_ALIASID);
409         if (value == null || value.isEmpty()) {
410           continue;
411         }
412         final String aliasset = value.getString();
413         final String[] alias = SPACE_BACKSLASH.split(aliasset);
414         for (final String namealias : alias) {
415           Configuration.configuration.getAliases().put(namealias, refHostId);
416         }
417         Configuration.configuration.getReverseAliases().put(refHostId, alias);
418         logger.info("Aliases for: {} = {}", refHostId, aliasset);
419       }
420     }
421     value = hashConfig.get(XML_ROLES);
422     if (value != null && value.getList() != null) {
423       for (final XmlValue[] xml : (Iterable<XmlValue[]>) value.getList()) {
424         final XmlHash subHash = new XmlHash(xml);
425         value = subHash.get(XML_ROLEID);
426         if (value == null || value.isEmpty()) {
427           continue;
428         }
429         final String refHostId = value.getString();
430         value = subHash.get(XML_ROLESET);
431         if (value == null || value.isEmpty()) {
432           continue;
433         }
434         final String roleset = value.getString();
435         final String[] roles = SPACE_BACKSLASH.split(roleset);
436         final RoleDefault newrole = new RoleDefault();
437         for (final String role : roles) {
438           try {
439             final ROLE roletype = ROLE.valueOf(role.toUpperCase());
440             if (roletype == ROLE.NOACCESS) {
441               // reset
442               newrole.setRole(roletype);
443             } else {
444               newrole.addRole(roletype);
445             }
446           } catch (final IllegalArgumentException e) {
447             // ignore
448           }
449         }
450         logger.info("New Role: {}:{}", refHostId, newrole);
451         Configuration.configuration.getRoles().put(refHostId, newrole);
452       }
453     }
454     hashConfig.clear();
455   }
456 
457   /**
458    * @return the others
459    */
460   public final String getOthers() {
461     return pojo.getOthers();
462   }
463 
464   /**
465    * @param others the others to set
466    */
467   public final void setOthers(final String others) {
468     pojo.setOthers(others == null? "" : others);
469     int len;
470     do {
471       len = pojo.getOthers().length();
472       pojo.setOthers(WHITESPACES.matcher(pojo.getOthers()).replaceAll(" "));
473     } while (len != pojo.getOthers().length());
474     isSaved = false;
475   }
476 
477   /**
478    * @return the element for the content of the other part
479    */
480   public final Element getOtherElement() {
481     if (ParametersChecker.isNotEmpty(pojo.getOthers())) {
482       final Document document;
483       try {
484         document = DocumentHelper.parseText(pojo.getOthers());
485       } catch (final DocumentException e) {
486         return DocumentHelper.createElement(OtherFields.root.name());
487       }
488       return document.getRootElement();
489     } else {
490       return DocumentHelper.createElement(OtherFields.root.name());
491     }
492   }
493 
494   /**
495    * @param element the element to set as XML string to other part
496    */
497   public final void setOtherElement(final Element element) {
498     setOthers(element.asXML());
499   }
500 
501   @Override
502   protected final void setFromJson(final String field, final JsonNode value) {
503     if (value == null) {
504       return;
505     }
506     for (final Columns column : Columns.values()) {
507       if (column.name().equalsIgnoreCase(field)) {
508         int len;
509         switch (column) {
510           case ALIASES:
511             String aliases = value.asText();
512             do {
513               len = aliases.length();
514               aliases = WHITESPACES.matcher(aliases).replaceAll(" ");
515             } while (len != aliases.length());
516             pojo.setAliases(aliases);
517             break;
518           case BUSINESS:
519             String business = value.asText();
520             do {
521               len = business.length();
522               business = WHITESPACES.matcher(business).replaceAll(" ");
523             } while (len != business.length());
524             pojo.setBusiness(business);
525             break;
526           case OTHERS:
527             String others = value.asText();
528             do {
529               len = others.length();
530               others = WHITESPACES.matcher(others).replaceAll(" ");
531             } while (len != others.length());
532             pojo.setOthers(others);
533             break;
534           case ROLES:
535             String roles = value.asText();
536             do {
537               len = roles.length();
538               roles = WHITESPACES.matcher(roles).replaceAll(" ");
539             } while (len != roles.length());
540             pojo.setRoles(roles);
541             break;
542           case UPDATEDINFO:
543             pojo.setUpdatedInfo(
544                 org.waarp.openr66.pojo.UpdatedInfo.valueOf(value.asInt()));
545             break;
546           case HOSTID:
547             pojo.setHostid(value.asText());
548             break;
549         }
550       }
551     }
552   }
553 
554   /**
555    * Private constructor for Commander only
556    */
557   private DbHostConfiguration() {
558     pojo = new Business();
559   }
560 
561   /**
562    * For instance from Commander when getting updated information
563    *
564    * @param preparedStatement
565    *
566    * @return the next updated Configuration
567    *
568    * @throws WaarpDatabaseNoConnectionException
569    * @throws WaarpDatabaseSqlException
570    */
571   public static DbHostConfiguration getFromStatement(
572       final DbPreparedStatement preparedStatement)
573       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
574     final DbHostConfiguration dbHostConfiguration = new DbHostConfiguration();
575     AbstractDAO<Business> businessDAO = null;
576     try {
577       businessDAO = dbHostConfiguration.getDao(false);
578       dbHostConfiguration.pojo =
579           ((StatementExecutor<Business>) businessDAO).getFromResultSet(
580               preparedStatement.getResultSet());
581       return dbHostConfiguration;
582     } catch (final SQLException e) {
583       DbConstant.error(e);
584       throw new WaarpDatabaseSqlException("Getting values in error", e);
585     } catch (final DAOConnectionException e) {
586       throw new WaarpDatabaseSqlException("Getting values in error", e);
587     } finally {
588       DAOFactory.closeDAO(businessDAO);
589     }
590   }
591 
592   /**
593    * @return the DbPreparedStatement for getting Updated Object
594    *
595    * @throws WaarpDatabaseNoConnectionException
596    * @throws WaarpDatabaseSqlException
597    */
598   public static DbHostConfiguration[] getUpdatedPrepareStament()
599       throws WaarpDatabaseNoConnectionException {
600     final List<Filter> filters = new ArrayList<Filter>();
601     filters.add(new Filter(DBBusinessDAO.HOSTID_FIELD, "=",
602                            Configuration.configuration.getHostId()));
603     filters.add(new Filter(DBBusinessDAO.UPDATED_INFO_FIELD, "=",
604                            UpdatedInfo.TOSUBMIT.ordinal()));
605 
606     BusinessDAO businessAccess = null;
607     List<Business> businesses;
608     try {
609       businessAccess = DAOFactory.getInstance().getBusinessDAO(false);
610       businesses = businessAccess.find(filters);
611     } catch (final DAOConnectionException e) {
612       throw new WaarpDatabaseNoConnectionException(e);
613     } finally {
614       DAOFactory.closeDAO(businessAccess);
615     }
616     final DbHostConfiguration[] res =
617         new DbHostConfiguration[businesses.size()];
618     int i = 0;
619     for (final Business business : businesses) {
620       res[i] = new DbHostConfiguration(business);
621       res[i].isSaved = true;
622       i++;
623     }
624     return res;
625   }
626 
627   /**
628    * @param session
629    * @param hostid
630    * @param business
631    * @param role
632    * @param alias
633    * @param other
634    *
635    * @return a preparedStatement with the filter set
636    *
637    * @throws WaarpDatabaseNoConnectionException
638    * @throws WaarpDatabaseSqlException
639    */
640   public static DbPreparedStatement getFilterPrepareStament(
641       final DbSession session, final String hostid, final String business,
642       final String role, final String alias, final String other)
643       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
644     final DbPreparedStatement preparedStatement =
645         new DbPreparedStatement(session);
646     final String request = "SELECT " + selectAllFields + " FROM " + table;
647     String condition = null;
648     if (ParametersChecker.isNotEmpty(hostid)) {
649       condition = " WHERE " + Columns.HOSTID.name() + " = '" + hostid + "' ";
650     }
651     if (ParametersChecker.isNotEmpty(business)) {
652       if (condition != null) {
653         condition +=
654             " AND " + Columns.BUSINESS.name() + " LIKE '%" + business + "%' ";
655       } else {
656         condition =
657             " WHERE " + Columns.BUSINESS.name() + " LIKE '%" + business + "%' ";
658       }
659     }
660     if (ParametersChecker.isNotEmpty(role)) {
661       if (condition != null) {
662         condition += " AND " + Columns.ROLES.name() + " LIKE '%" + role + "%' ";
663       } else {
664         condition =
665             " WHERE " + Columns.ROLES.name() + " LIKE '%" + role + "%' ";
666       }
667     }
668     if (ParametersChecker.isNotEmpty(alias)) {
669       if (condition != null) {
670         condition +=
671             " AND " + Columns.ALIASES.name() + " LIKE '%" + alias + "%' ";
672       } else {
673         condition =
674             " WHERE " + Columns.ALIASES.name() + " LIKE '%" + alias + "%' ";
675       }
676     }
677     if (ParametersChecker.isNotEmpty(other)) {
678       if (condition != null) {
679         condition +=
680             " AND " + Columns.OTHERS.name() + " LIKE '%" + other + "%' ";
681       } else {
682         condition =
683             " WHERE " + Columns.OTHERS.name() + " LIKE '%" + other + "%' ";
684       }
685     }
686     if (condition != null) {
687       preparedStatement.createPrepareStatement(
688           request + condition + " ORDER BY " + Columns.HOSTID.name());
689     } else {
690       preparedStatement.createPrepareStatement(
691           request + " ORDER BY " + Columns.HOSTID.name());
692     }
693     return preparedStatement;
694   }
695 
696   @Override
697   public final void changeUpdatedInfo(final UpdatedInfo info) {
698     isSaved = false;
699     pojo.setUpdatedInfo(org.waarp.openr66.pojo.UpdatedInfo.fromLegacy(info));
700   }
701 
702   /**
703    * Update configuration according to new values
704    */
705   public final void updateConfiguration() {
706     updateHostConfiguration(Configuration.configuration, this);
707   }
708 
709   /**
710    * @return True if this Configuration refers to the current host
711    */
712   public final boolean isOwnConfiguration() {
713     return pojo.getHostid().equals(Configuration.configuration.getHostId());
714   }
715 
716   /**
717    * Shortcut to add all paths element from source into set
718    *
719    * @param source
720    * @param path
721    * @param set
722    *
723    * @return True if ok
724    */
725   private boolean updateSet(final String source, final String path,
726                             final HashSet<String> set) {
727     if (ParametersChecker.isNotEmpty(source)) {
728       final Document document;
729       StringReader reader = null;
730       try {
731         reader = new StringReader(source);
732         document = XmlUtil.getNewSaxReader().read(reader);
733       } catch (final DocumentException e) {
734         logger.error(
735             "Unable to read the XML Config " + path + " string: " + source +
736             ": {}", e.getMessage());
737         FileUtils.close(reader);
738         return false;
739       }
740       if (document == null) {
741         logger.error(
742             "Unable to read the XML Config " + path + " string: " + source);
743         FileUtils.close(reader);
744         return false;
745       }
746       final List<Node> list = document.selectNodes(path);
747       for (final Node element : list) {
748         final String sval = element.getText().trim();
749         if (sval.isEmpty()) {
750           continue;
751         }
752         set.add(sval.trim());
753       }
754       list.clear();
755       document.clearContent();
756       FileUtils.close(reader);
757     }
758     return true;
759   }
760 
761   /**
762    * update Business with possible purge and new or added content, and
763    * updating
764    * in memory information
765    *
766    * @param config
767    * @param newbusiness
768    * @param purged
769    *
770    * @return True if updated
771    */
772   public final boolean updateBusiness(final Configuration config,
773                                       final String newbusiness,
774                                       final boolean purged) {
775     final HashSet<String> set = new HashSet<String>();
776     if (!updateSet(newbusiness, XML_BUSINESS + '/' + XML_BUSINESSID, set)) {
777       return false;
778     }
779     if (purged) {
780       config.getBusinessWhiteSet().clear();
781       isSaved = false;
782     } else {
783       final String businessStr = getBusiness();
784       if (!updateSet(businessStr, XML_BUSINESS + '/' + XML_BUSINESSID, set)) {
785         return false;
786       }
787     }
788     config.getBusinessWhiteSet().addAll(set);
789     if (ParametersChecker.isNotEmpty(newbusiness) || purged) {
790       final Document document = DocumentHelper.createDocument(
791           DocumentHelper.createElement(XML_BUSINESS));
792       final Element root = document.getRootElement();
793       for (final String sval : set) {
794         root.addElement(XML_BUSINESSID).setText(sval);
795         logger.info("Business Allow: {}", sval);
796       }
797       setBusiness(root.asXML());
798       try {
799         update();
800       } catch (final WaarpDatabaseException e) {
801         document.clearContent();
802         return false;
803       }
804       document.clearContent();
805     }
806     set.clear();
807     return true;
808   }
809 
810   /**
811    * Update the DbHostConfiguration from Configuration
812    *
813    * @param configuration
814    */
815   public final void updateFromConfiguration(final Configuration configuration) {
816     // Business
817     if (!configuration.getBusinessWhiteSet().isEmpty()) {
818       final Document document = DocumentHelper.createDocument(
819           DocumentHelper.createElement(XML_BUSINESS));
820       final Element root = document.getRootElement();
821       for (final String sval : configuration.getBusinessWhiteSet()) {
822         root.addElement(XML_BUSINESSID).setText(sval);
823         logger.info("Business Allow: {}", sval);
824       }
825       final String xml = root.asXML();
826       this.pojo.setBusiness(xml);
827       isSaved = false;
828       document.clearContent();
829     }
830     // Aliases
831     if (!configuration.getAliases().isEmpty()) {
832       final Document document = DocumentHelper.createDocument(
833           DocumentHelper.createElement(XML_ALIASES));
834       final Element root = document.getRootElement();
835       for (final Entry<String, String[]> entry : configuration.getReverseAliases()
836                                                               .entrySet()) {
837         final Element elt = root.addElement(XML_ALIAS);
838         elt.addElement(XML_REALID).setText(entry.getKey());
839         StringBuilder cumul = null;
840         for (final String namealias : entry.getValue()) {
841           if (cumul == null) {
842             cumul = new StringBuilder(namealias);
843           } else {
844             cumul.append(' ').append(namealias);
845           }
846         }
847         if (cumul == null) {
848           cumul = new StringBuilder();
849         }
850         elt.addElement(XML_ALIASID).setText(cumul.toString());
851       }
852       final String xml = root.asXML();
853       this.pojo.setAliases(xml);
854       isSaved = false;
855       document.clearContent();
856     }
857 
858     // Role
859     if (!configuration.getRoles().isEmpty()) {
860       final Document document = DocumentHelper.createDocument(
861           DocumentHelper.createElement(XML_ROLES));
862       final Element root = document.getRootElement();
863       for (final Entry<String, RoleDefault> entry : configuration.getRoles()
864                                                                  .entrySet()) {
865         final Element elt = root.addElement(XML_ROLE);
866         elt.addElement(XML_ROLEID).setText(entry.getKey());
867         StringBuilder cumul = null;
868         final RoleDefault roleDefault = entry.getValue();
869         if (roleDefault.hasNoAccess()) {
870           cumul = new StringBuilder(ROLE.NOACCESS.name());
871         } else {
872           for (final ROLE role : ROLE.values()) {
873             if (role == ROLE.NOACCESS) {
874               continue;
875             }
876             if (roleDefault.isContaining(role)) {
877               if (cumul == null) {
878                 cumul = new StringBuilder(role.name().toUpperCase());
879               } else {
880                 cumul.append(' ').append(role.name().toUpperCase());
881               }
882             }
883           }
884         }
885         if (cumul == null) {
886           cumul = new StringBuilder();
887         }
888         logger.info("New Role: {}:{}", entry.getKey(), cumul);
889         elt.addElement(XML_ROLESET).setText(cumul.toString());
890       }
891       final String xml = root.asXML();
892       this.pojo.setRoles(xml);
893       isSaved = false;
894       document.clearContent();
895     }
896 
897     // Now save (insert or update)
898     try {
899       update();
900     } catch (final WaarpDatabaseException e) {
901       try {
902         insert();
903       } catch (final WaarpDatabaseException waarpDatabaseException) {
904         // Real issue there
905         logger.error("Cannot update neither save DbHostConfiguration for ",
906                      this.pojo.getHostid());
907       }
908     }
909   }
910 
911   /**
912    * Shortcut to add all paths element with key and value from source into map
913    *
914    * @param source
915    * @param path
916    * @param keypath
917    * @param valpath
918    * @param split
919    * @param map
920    *
921    * @return True if ok
922    */
923   private boolean updateMap(final String source, final String path,
924                             final String keypath, final String valpath,
925                             final String split,
926                             final HashMap<String, HashSet<String>> map) {
927     if (ParametersChecker.isNotEmpty(source)) {
928       final Document document;
929       StringReader reader = null;
930       try {
931         reader = new StringReader(source);
932         document = XmlUtil.getNewSaxReader().read(reader);
933       } catch (final DocumentException e) {
934         logger.error(
935             "Unable to read the XML Config " + path + " string: " + source +
936             ": {}", e.getMessage());
937         FileUtils.close(reader);
938         return false;
939       }
940       if (document == null) {
941         logger.error(
942             "Unable to read the XML Config " + path + " string: " + source);
943         FileUtils.close(reader);
944         return false;
945       }
946       final List<Node> list = document.selectNodes(path);
947       for (final Node element : list) {
948         final Element nodeid = (Element) element.selectSingleNode(keypath);
949         if (nodeid == null) {
950           continue;
951         }
952         final Element nodeset = (Element) element.selectSingleNode(valpath);
953         if (nodeset == null) {
954           continue;
955         }
956         final String refHostId = nodeid.getText();
957         final String aliasesid = nodeset.getText();
958         final String[] aliasid = aliasesid.split(split);
959         final HashSet<String> set;
960         if (map.containsKey(refHostId)) {
961           set = map.get(refHostId);
962         } else {
963           set = new HashSet<String>();
964         }
965         set.addAll(Arrays.asList(aliasid));
966         map.put(refHostId, set);
967       }
968       list.clear();
969       document.clearContent();
970       FileUtils.close(reader);
971     }
972     return true;
973   }
974 
975   /**
976    * update Alias with possible purge and new or added content, and updating
977    * in
978    * memory information
979    *
980    * @param config
981    * @param newalias
982    * @param purged
983    *
984    * @return True if updated
985    */
986   public final boolean updateAlias(final Configuration config,
987                                    final String newalias,
988                                    final boolean purged) {
989     final HashMap<String, HashSet<String>> map =
990         new HashMap<String, HashSet<String>>();
991     if (!updateMap(newalias, XML_ALIASES + '/' + XML_ALIAS, XML_REALID,
992                    XML_ALIASID, " |\\|", map)) {
993       return false;
994     }
995     if (purged) {
996       config.getReverseAliases().clear();
997       config.getAliases().clear();
998       isSaved = false;
999     } else {
1000       final String alias = getAliases();
1001       if (!updateMap(alias, XML_ALIASES + '/' + XML_ALIAS, XML_REALID,
1002                      XML_ALIASID, " |\\|", map)) {
1003         return false;
1004       }
1005     }
1006     if (ParametersChecker.isNotEmpty(newalias) || purged) {
1007       final Document document = DocumentHelper.createDocument(
1008           DocumentHelper.createElement(XML_ALIASES));
1009       final Element root = document.getRootElement();
1010       for (final Entry<String, HashSet<String>> entry : map.entrySet()) {
1011         final Element elt = root.addElement(XML_ALIAS);
1012         elt.addElement(XML_REALID).setText(entry.getKey());
1013         StringBuilder cumul = null;
1014         final String[] oldAlias =
1015             config.getReverseAliases().get(entry.getKey());
1016         final int size = oldAlias == null? 0 : oldAlias.length;
1017         final String[] alias = new String[entry.getValue().size() + size];
1018         int i = 0;
1019         if (oldAlias != null) {
1020           System.arraycopy(oldAlias, 0, alias, 0, size);
1021         }
1022         for (final String namealias : entry.getValue()) {
1023           config.getAliases().put(namealias, entry.getKey());
1024           if (cumul == null) {
1025             cumul = new StringBuilder(namealias);
1026           } else {
1027             cumul.append(' ').append(namealias);
1028           }
1029           alias[i] = namealias;
1030           i++;
1031         }
1032         if (cumul == null) {
1033           cumul = new StringBuilder();
1034         }
1035         elt.addElement(XML_ALIASID).setText(cumul.toString());
1036         config.getReverseAliases().put(entry.getKey(), alias);
1037       }
1038       setAliases(root.asXML());
1039       try {
1040         update();
1041       } catch (final WaarpDatabaseException e) {
1042         document.clearContent();
1043         return false;
1044       }
1045       document.clearContent();
1046     } else {
1047       for (final Entry<String, HashSet<String>> entry : map.entrySet()) {
1048         final String[] oldAlias =
1049             config.getReverseAliases().get(entry.getKey());
1050         final int size = oldAlias == null? 0 : oldAlias.length;
1051         final String[] alias = new String[entry.getValue().size() + size];
1052         int i = 0;
1053         if (oldAlias != null) {
1054           System.arraycopy(oldAlias, 0, alias, 0, size);
1055         }
1056         for (final String namealias : entry.getValue()) {
1057           config.getAliases().put(namealias, entry.getKey());
1058           alias[i] = namealias;
1059           i++;
1060         }
1061         config.getReverseAliases().put(entry.getKey(), alias);
1062       }
1063     }
1064     map.clear();
1065     return true;
1066   }
1067 
1068   /**
1069    * update Roles with possible purge and new or added content, and updating
1070    * in
1071    * memory information
1072    *
1073    * @param config
1074    * @param newroles
1075    * @param purged
1076    *
1077    * @return True if ok
1078    */
1079   public final boolean updateRoles(final Configuration config,
1080                                    final String newroles,
1081                                    final boolean purged) {
1082     final HashMap<String, HashSet<String>> map =
1083         new HashMap<String, HashSet<String>>();
1084     if (!updateMap(newroles, XML_ROLES + '/' + XML_ROLE, XML_ROLEID,
1085                    XML_ROLESET, " |\\|", map)) {
1086       return false;
1087     }
1088     if (purged) {
1089       config.getRoles().clear();
1090       isSaved = false;
1091     } else {
1092       final String roles = getRoles();
1093       if (!updateMap(roles, XML_ROLES + '/' + XML_ROLE, XML_ROLEID, XML_ROLESET,
1094                      " |\\|", map)) {
1095         return false;
1096       }
1097     }
1098     if (ParametersChecker.isNotEmpty(newroles) || purged) {
1099       final Document document = DocumentHelper.createDocument(
1100           DocumentHelper.createElement(XML_ROLES));
1101       final Element root = document.getRootElement();
1102       for (final Entry<String, HashSet<String>> entry : map.entrySet()) {
1103         final RoleDefault newrole = new RoleDefault();
1104         final Element elt = root.addElement(XML_ROLE);
1105         elt.addElement(XML_ROLEID).setText(entry.getKey());
1106         StringBuilder cumul = null;
1107         if (entry.getValue().contains(ROLE.NOACCESS.name())) {
1108           newrole.setRole(ROLE.NOACCESS);
1109           cumul = new StringBuilder(ROLE.NOACCESS.name());
1110         }
1111         for (final String namerole : entry.getValue()) {
1112           try {
1113             final ROLE roletype = ROLE.valueOf(namerole.toUpperCase());
1114             if (roletype != ROLE.NOACCESS) {
1115               newrole.addRole(roletype);
1116               if (cumul == null) {
1117                 cumul = new StringBuilder(namerole.toUpperCase());
1118               } else {
1119                 cumul.append(' ').append(namerole.toUpperCase());
1120               }
1121             }
1122           } catch (final IllegalArgumentException e) {
1123             // ignore
1124           }
1125         }
1126         if (cumul == null) {
1127           cumul = new StringBuilder();
1128         }
1129         logger.info("New Role: {}:{}", entry.getKey(), newrole);
1130         config.getRoles().put(entry.getKey(), newrole);
1131         elt.addElement(XML_ROLESET).setText(cumul.toString());
1132       }
1133       setRoles(root.asXML());
1134       try {
1135         update();
1136       } catch (final WaarpDatabaseException e) {
1137         document.clearContent();
1138         return false;
1139       }
1140       document.clearContent();
1141     } else {
1142       for (final Entry<String, HashSet<String>> entry : map.entrySet()) {
1143         final RoleDefault newrole = new RoleDefault();
1144         if (entry.getValue().contains(ROLE.NOACCESS.name())) {
1145           newrole.setRole(ROLE.NOACCESS);
1146         }
1147         for (final String namerole : entry.getValue()) {
1148           try {
1149             final ROLE roletype = ROLE.valueOf(namerole.toUpperCase());
1150             if (roletype != ROLE.NOACCESS) {
1151               newrole.addRole(roletype);
1152             }
1153           } catch (final IllegalArgumentException e) {
1154             // ignore
1155           }
1156         }
1157         logger.info("New Role: {}:{}", entry.getKey(), newrole);
1158         config.getRoles().put(entry.getKey(), newrole);
1159       }
1160     }
1161     map.clear();
1162     return true;
1163   }
1164 
1165   public static void updateHostConfiguration(final Configuration config,
1166                                              final DbHostConfiguration hostConfiguration) {
1167     hostConfiguration.updateBusiness(config, null, false);
1168     hostConfiguration.updateAlias(config, null, false);
1169     hostConfiguration.updateRoles(config, null, false);
1170   }
1171 
1172   /**
1173    * @param hostid
1174    *
1175    * @return the version of the database from HostConfiguration table
1176    */
1177   public static String getVersionDb(final String hostid) {
1178     final DbHostConfiguration hostConfiguration;
1179     try {
1180       hostConfiguration = new DbHostConfiguration(hostid);
1181     } catch (final WaarpDatabaseException e) {
1182       // ignore and return
1183       return "1.1.0";
1184     }
1185     final Element others = hostConfiguration.getOtherElement();
1186     if (others != null) {
1187       final Element version =
1188           (Element) others.selectSingleNode(OtherFields.version.name());
1189       if (version != null) {
1190         return version.getText();
1191       }
1192     }
1193     return "1.1.0";
1194   }
1195 
1196   public final boolean isSeeAllId(final String id) {
1197     final Element others = getOtherElement();
1198     if (others != null) {
1199       final Element seeallids =
1200           (Element) others.selectSingleNode(OtherFields.seeallid.name());
1201       if (seeallids != null) {
1202         final String[] split = COMMA.split(seeallids.getText());
1203         for (final String string : split) {
1204           if (string.equals(id)) {
1205             return true;
1206           }
1207         }
1208       }
1209     }
1210     return false;
1211   }
1212 
1213   /**
1214    * Update the version for this HostId
1215    *
1216    * @param hostid
1217    * @param version
1218    *
1219    * @return the version updated
1220    */
1221   public static String updateVersionDb(final String hostid,
1222                                        final String version) {
1223     DbHostConfiguration hostConfiguration;
1224     try {
1225       hostConfiguration = new DbHostConfiguration(hostid);
1226     } catch (final WaarpDatabaseNoDataException e) {
1227       try {
1228         hostConfiguration = new DbHostConfiguration(hostid, "", "", "", "");
1229         hostConfiguration.insert();
1230       } catch (final WaarpDatabaseException e1) {
1231         logger.debug("Not inserted?", e1);
1232         // ignore and return
1233         return R66Versions.V2_4_12.name();
1234       }
1235     } catch (final WaarpDatabaseException e) {
1236       logger.debug("Not found?", e);
1237       // ignore and return
1238       return R66Versions.V2_4_12.name();
1239     }
1240     Element others = hostConfiguration.getOtherElement();
1241     if (others != null) {
1242       final Element eversion =
1243           (Element) others.selectSingleNode(OtherFields.version.name());
1244       if (eversion != null) {
1245         final String currentVersion = eversion.getText();
1246         if (PartnerConfiguration.isVersion2GTVersion1(currentVersion,
1247                                                       version)) {
1248           eversion.setText(version);
1249         } else {
1250           return currentVersion;
1251         }
1252       } else {
1253         others.addElement(OtherFields.version.name()).addText(Version.ID);
1254       }
1255     } else {
1256       others = DocumentHelper.createElement(OtherFields.root.name());
1257       others.addElement(OtherFields.version.name()).addText(Version.ID);
1258     }
1259     hostConfiguration.setOtherElement(others);
1260     try {
1261       hostConfiguration.update();
1262     } catch (final WaarpDatabaseException e) {
1263       logger.debug("Not update?", e);
1264       // ignore
1265     }
1266     return version;
1267   }
1268 
1269   /**
1270    * @return the last DateTime for Monitoring
1271    */
1272   public final DateTime getLastDateTimeMonitoring() {
1273     final Element others = getOtherElement();
1274     if (others != null) {
1275       final Element lastMonitoringDT = (Element) others.selectSingleNode(
1276           OtherFields.lastMonitoringDateTime.name());
1277       if (lastMonitoringDT != null) {
1278         final String dateTime = lastMonitoringDT.getText();
1279         if (ParametersChecker.isNotEmpty(dateTime)) {
1280           try {
1281             return DateTime.parse(lastMonitoringDT.getText());
1282           } catch (final Exception ignored) {
1283             return null;
1284           }
1285         }
1286       }
1287     }
1288     return null;
1289   }
1290 
1291   /**
1292    * Update the last DateTime for Monitoring for this HostId
1293    *
1294    * @param lastDateTime
1295    */
1296   public final void updateLastDateTimeMonitoring(final DateTime lastDateTime) {
1297     Element others = getOtherElement();
1298     if (others != null) {
1299       final Element lastMonitoringDT = (Element) others.selectSingleNode(
1300           OtherFields.lastMonitoringDateTime.name());
1301       if (lastMonitoringDT != null) {
1302         lastMonitoringDT.setText(lastDateTime.toString());
1303       } else {
1304         others.addElement(OtherFields.lastMonitoringDateTime.name())
1305               .addText(lastDateTime.toString());
1306       }
1307     } else {
1308       others = DocumentHelper.createElement(OtherFields.root.name());
1309       others.addElement(OtherFields.lastMonitoringDateTime.name())
1310             .addText(lastDateTime.toString());
1311     }
1312     setOtherElement(others);
1313     try {
1314       update();
1315     } catch (final WaarpDatabaseException e) {
1316       logger.debug("Not update?", e);
1317       // ignore
1318     }
1319   }
1320 
1321   /**
1322    * @param hostid
1323    *
1324    * @return the last DateTime for Monitoring
1325    */
1326   public static DateTime getLastDateTimeMonitoring(final String hostid) {
1327     DbHostConfiguration hostConfiguration;
1328     try {
1329       hostConfiguration = new DbHostConfiguration(hostid);
1330     } catch (final WaarpDatabaseNoDataException e) {
1331       try {
1332         hostConfiguration = new DbHostConfiguration(hostid, "", "", "", "");
1333         hostConfiguration.insert();
1334       } catch (final WaarpDatabaseException e1) {
1335         logger.debug("Not inserted?", e1);
1336         // ignore and return
1337         return null;
1338       }
1339     } catch (final WaarpDatabaseException e) {
1340       logger.debug("Not found?", e);
1341       // ignore and return
1342       return null;
1343     }
1344     return hostConfiguration.getLastDateTimeMonitoring();
1345   }
1346 
1347   /**
1348    * Update the last DateTime for Monitoring for this HostId
1349    *
1350    * @param hostid
1351    * @param lastDateTime
1352    */
1353   public static void updateLastDateTimeMonitoring(final String hostid,
1354                                                   final DateTime lastDateTime) {
1355     DbHostConfiguration hostConfiguration;
1356     try {
1357       hostConfiguration = new DbHostConfiguration(hostid);
1358     } catch (final WaarpDatabaseNoDataException e) {
1359       try {
1360         hostConfiguration = new DbHostConfiguration(hostid, "", "", "", "");
1361         hostConfiguration.insert();
1362       } catch (final WaarpDatabaseException e1) {
1363         logger.debug("Not inserted?", e1);
1364         // ignore and return
1365         return;
1366       }
1367     } catch (final WaarpDatabaseException e) {
1368       logger.debug("Not found?", e);
1369       // ignore and return
1370       return;
1371     }
1372     hostConfiguration.updateLastDateTimeMonitoring(lastDateTime);
1373   }
1374 }