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.protocol.configuration;
21  
22  import com.fasterxml.jackson.databind.node.ObjectNode;
23  import org.waarp.common.digest.FilesystemBasedDigest.DigestAlgo;
24  import org.waarp.common.json.JsonHandler;
25  import org.waarp.common.logging.WaarpLogger;
26  import org.waarp.common.logging.WaarpLoggerFactory;
27  import org.waarp.openr66.protocol.utils.R66Versions;
28  import org.waarp.openr66.protocol.utils.Version;
29  
30  import java.util.Map;
31  
32  /**
33   * Partner Configuration
34   */
35  public class PartnerConfiguration {
36    /**
37     * Internal Logger
38     */
39    private static final WaarpLogger logger =
40        WaarpLoggerFactory.getLogger(PartnerConfiguration.class);
41  
42    /**
43     * Uses as separator in field
44     */
45    public static final String BAR_JSON_FIELD = "{";
46    /**
47     * Uses as separator in field
48     */
49    public static final String BAR_SEPARATOR_FIELD = ";";
50    /**
51     * Uses as separator in field
52     */
53    public static final String BLANK_SEPARATOR_FIELD = " ";
54    public static final String VERSION_R66_SOFTWARE_3_6_1 = "3.6.1";
55    /**
56     * Uses as separator in field
57     */
58    private static String SEPARATOR_FIELD = BAR_SEPARATOR_FIELD;
59  
60    /**
61     * JSON Fields
62     */
63    public enum FIELDS {
64      HOSTID("nohostid"), VERSION(R66Versions.V2_4_12.getVersion()),
65      DIGESTALGO(DigestAlgo.MD5.algoName), FILESIZE(false), FINALHASH(false),
66      PROXIFIED(false), SEPARATOR(BLANK_SEPARATOR_FIELD),
67      R66VERSION(R66Versions.V2_4_12.getVersion()), COMPRESSION(false);
68  
69      final String name;
70      final Object defaultValue;
71  
72      FIELDS(final Object def) {
73        name = name();
74        defaultValue = def;
75      }
76    }
77  
78    private final String id;
79    private final ObjectNode root = JsonHandler.createObjectNode();
80    private final String version;
81    private final String r66Version;
82    private final boolean useJson;
83    private final boolean changeFileInfoEnabled;
84    private final DigestAlgo digestAlgo;
85    private final boolean compression;
86    private final String separator;
87    private final boolean supportReuseAuthentication;
88  
89    /**
90     * Constructor for an external HostId
91     *
92     * @param id
93     * @param json mainly the version information
94     */
95    public PartnerConfiguration(final String id, final String json) {
96      this.id = id;
97      JsonHandler.setValue(root, FIELDS.HOSTID, id);
98      final int pos = json == null? -1 : json.indexOf('{');
99      if (pos > 1) {
100       version = json.substring(0, pos - 1);
101     } else {
102       version = json;
103     }
104     JsonHandler.setValue(root, FIELDS.VERSION, version);
105     String r66 = R66Versions.V2_4_12.getVersion();
106     if (isVersion2GEQVersion1(R66Versions.V2_4_12.getVersion(), version)) {
107       JsonHandler.setValue(root, FIELDS.FILESIZE, true);
108       JsonHandler.setValue(root, FIELDS.FINALHASH, true);
109     } else {
110       JsonHandler.setValue(root, FIELDS.FILESIZE,
111                            (Boolean) FIELDS.FILESIZE.defaultValue);
112       JsonHandler.setValue(root, FIELDS.FINALHASH,
113                            (Boolean) FIELDS.FINALHASH.defaultValue);
114     }
115     JsonHandler.setValue(root, FIELDS.DIGESTALGO,
116                          Configuration.configuration.getDigest().algoName);
117     JsonHandler.setValue(root, FIELDS.PROXIFIED,
118                          (Boolean) FIELDS.PROXIFIED.defaultValue);
119     String sep = getSEPARATOR_FIELD();
120     if (!isVersion2GEQVersion1(R66Versions.V2_4_13.getVersion(), version)) {
121       r66 = R66Versions.V2_4_12.getVersion();
122       sep = BLANK_SEPARATOR_FIELD;
123     }
124     if (isVersion2GEQVersion1(R66Versions.V2_4_17.getVersion(), version)) {
125       r66 = R66Versions.V2_4_17.getVersion();
126       logger.debug("UseJson for {}:{}", id, json);
127       useJson = true;
128     } else {
129       logger.debug("NOT UseJson for {}:{}", id, json);
130       useJson = false;
131     }
132     if (isVersion2GEQVersion1(R66Versions.V3_0_4.getVersion(), version)) {
133       r66 = R66Versions.V3_0_4.getVersion();
134       changeFileInfoEnabled = true;
135     } else {
136       changeFileInfoEnabled = false;
137     }
138     final boolean comp = false;
139     if (isVersion2GEQVersion1(R66Versions.V3_1_0.getVersion(), version)) {
140       r66 = R66Versions.V3_1_0.getVersion();
141     }
142     JsonHandler.setValue(root, FIELDS.R66VERSION, r66);
143     JsonHandler.setValue(root, FIELDS.COMPRESSION, comp);
144     JsonHandler.setValue(root, FIELDS.SEPARATOR, sep);
145 
146     if (json != null && pos > 1) {
147       final String realjson = json.substring(pos);
148       final ObjectNode info = JsonHandler.getFromString(realjson);
149       if (info != null) {
150         root.setAll(info);
151       }
152     }
153     if (isProxified()) {
154       Configuration.configuration.setBlacklistBadAuthent(false);
155     }
156     digestAlgo = getDigestAlgoInternal();
157     compression = root.get(FIELDS.COMPRESSION.name).asBoolean();
158     r66Version = root.get(FIELDS.R66VERSION.name).asText();
159     separator = root.get(FIELDS.SEPARATOR.name).asText();
160     supportReuseAuthentication =
161         isVersion2GEQVersion1(VERSION_R66_SOFTWARE_3_6_1, r66Version);
162     logger.info("Info on HostId: {}", root);
163   }
164 
165   /**
166    * Self constructor
167    *
168    * @param id
169    */
170   public PartnerConfiguration(final String id) {
171     this.id = id;
172     JsonHandler.setValue(root, FIELDS.HOSTID, id);
173     version = Version.ID;
174     JsonHandler.setValue(root, FIELDS.VERSION, Version.ID);
175     JsonHandler.setValue(root, FIELDS.FILESIZE, true);
176     JsonHandler.setValue(root, FIELDS.FINALHASH,
177                          Configuration.configuration.isGlobalDigest());
178     JsonHandler.setValue(root, FIELDS.DIGESTALGO,
179                          Configuration.configuration.getDigest().algoName);
180     JsonHandler.setValue(root, FIELDS.PROXIFIED,
181                          Configuration.configuration.isHostProxyfied());
182     JsonHandler.setValue(root, FIELDS.SEPARATOR, getSEPARATOR_FIELD());
183     JsonHandler.setValue(root, FIELDS.R66VERSION,
184                          org.waarp.common.utility.Version.version());
185     r66Version = org.waarp.common.utility.Version.version();
186     compression = Configuration.configuration.isCompressionAvailable();
187     JsonHandler.setValue(root, FIELDS.COMPRESSION, compression);
188     useJson = true;
189     changeFileInfoEnabled = true;
190     digestAlgo = getDigestAlgoInternal();
191     separator = getSEPARATOR_FIELD();
192     supportReuseAuthentication =
193         isVersion2GEQVersion1(VERSION_R66_SOFTWARE_3_6_1, r66Version);
194     logger.debug("Info on HostId: {}", root);
195   }
196 
197   /**
198    * @return the associated HostId
199    */
200   public final String getId() {
201     return id;
202   }
203 
204   /**
205    * @return the version for this Host
206    */
207   public final String getVersion() {
208     return version;
209   }
210 
211   /**
212    * @return the R66Version for this Host
213    */
214   public final String getR66Version() {
215     return r66Version;
216   }
217 
218   /**
219    * @return True if compression is supported
220    */
221   public final boolean isCompression() {
222     return compression;
223   }
224 
225   /**
226    * @return True if this Host returns FileSize
227    */
228   public final boolean useFileSize() {
229     return root.path(FIELDS.FILESIZE.name)
230                .asBoolean((Boolean) FIELDS.FILESIZE.defaultValue);
231   }
232 
233   /**
234    * @return True if this Host returns a final hash
235    */
236   public final boolean useFinalHash() {
237     return root.path(FIELDS.FINALHASH.name)
238                .asBoolean((Boolean) FIELDS.FINALHASH.defaultValue);
239   }
240 
241   /**
242    * @return DigestAlgo if this Host returns Digest Algo used
243    */
244   public final DigestAlgo getDigestAlgo() {
245     return digestAlgo;
246   }
247 
248   /**
249    * Used to initialize the DigestAlgo for this partner
250    *
251    * @return the DigestAlgo
252    */
253   private DigestAlgo getDigestAlgoInternal() {
254     final String algo = root.path(FIELDS.DIGESTALGO.name).asText();
255     return getDigestAlgo(algo);
256   }
257 
258   /**
259    * @return True if this Host is proxified
260    */
261   public final boolean isProxified() {
262     return root.path(FIELDS.PROXIFIED.name)
263                .asBoolean((Boolean) FIELDS.PROXIFIED.defaultValue);
264   }
265 
266   /**
267    * @return the separator for this Host
268    */
269   public final String getSeperator() {
270     return separator;
271   }
272 
273   /**
274    * @return the useJson
275    */
276   public final boolean useJson() {
277     return useJson;
278   }
279 
280   /**
281    * @return the changeFileInfoEnabled
282    */
283   public final boolean changeFileInfoEnabled() {
284     return changeFileInfoEnabled;
285   }
286 
287   /**
288    * @return True if this Host support Reuse Authentication
289    */
290   public final boolean supportReuseAuthentication() {
291     return supportReuseAuthentication;
292   }
293 
294   /**
295    * @return the String representation as version.json
296    */
297   @Override
298   public final String toString() {
299     return version + '.' + JsonHandler.writeAsString(root);
300   }
301 
302   /**
303    * @param algo
304    *
305    * @return the DigestAlgo corresponding
306    */
307   public static DigestAlgo getDigestAlgo(final String algo) {
308     for (final DigestAlgo alg : DigestAlgo.values()) {
309       if (alg.algoName.equals(algo)) {
310         return alg;
311       }
312     }
313     try {
314       return DigestAlgo.valueOf(algo);
315     } catch (final IllegalArgumentException ignored) {
316       // ignore
317     }
318     return Configuration.configuration.getDigest();
319   }
320 
321   /**
322    * @param remoteHost
323    *
324    * @return the separator to be used
325    */
326   public static String getSeparator(final String remoteHost) {
327     logger.debug("Versions: search: {} in {}", remoteHost,
328                  Configuration.configuration.getVersions());
329     final PartnerConfiguration partner =
330         Configuration.configuration.getVersions().get(remoteHost);
331     if (partner != null) {
332       return partner.getSeperator();
333     }
334     return BLANK_SEPARATOR_FIELD;
335   }
336 
337   /**
338    * Compare 2 versions
339    *
340    * @param version1
341    * @param version2
342    *
343    * @return True if version2 >= version1
344    */
345   public static boolean isVersion2GEQVersion1(final String version1,
346                                               final String version2) {
347     if (version1 == null || version2 == null) {
348       return false;
349     }
350     try {
351       final int major1;
352       final int rank1;
353       final int subversion1;
354       String[] vals = version1.split("\\.");
355       major1 = Integer.parseInt(vals[0]);
356       rank1 = Integer.parseInt(vals[1]);
357       final int pos = vals[2].indexOf('-');
358       if (pos > 0) {
359         subversion1 = Integer.parseInt(vals[2].substring(0, pos));
360       } else {
361         subversion1 = Integer.parseInt(vals[2]);
362       }
363       final int major2;
364       final int rank2;
365       final int subversion2;
366       vals = version2.split("\\.");
367       major2 = Integer.parseInt(vals[0]);
368       rank2 = Integer.parseInt(vals[1]);
369       final int pos2 = vals[2].indexOf('-');
370       if (pos2 > 0) {
371         subversion2 = Integer.parseInt(vals[2].substring(0, pos2));
372       } else {
373         subversion2 = Integer.parseInt(vals[2]);
374       }
375       final boolean b = major1 < major2 || (major1 == major2 &&
376                                             (rank1 < rank2 || (rank1 == rank2 &&
377                                                                subversion1 <=
378                                                                subversion2)));
379       logger.trace("1: {}:{}:{} <=? {}:{}:{} = {}", major1, rank1, subversion1,
380                    major2, rank2, subversion2, b);
381       return b;
382     } catch (final Exception e) {
383       logger.error("Error while comparing versions {} vs {}: {}", version1,
384                    version2, e.getMessage());
385       return false;
386     }
387   }
388 
389   /**
390    * Compare strictly 2 versions
391    *
392    * @param version1
393    * @param version2
394    *
395    * @return True if version2 > version1
396    */
397   public static boolean isVersion2GTVersion1(final String version1,
398                                              final String version2) {
399     if (version1 == null || version2 == null) {
400       return false;
401     }
402     try {
403       final int major1;
404       final int rank1;
405       final int subversion1;
406       String[] vals = version1.split("\\.");
407       major1 = Integer.parseInt(vals[0]);
408       rank1 = Integer.parseInt(vals[1]);
409       final int pos = vals[2].indexOf('-');
410       if (pos > 0) {
411         subversion1 = Integer.parseInt(vals[2].substring(0, pos));
412       } else {
413         subversion1 = Integer.parseInt(vals[2]);
414       }
415       final int major2;
416       final int rank2;
417       final int subversion2;
418       vals = version2.split("\\.");
419       major2 = Integer.parseInt(vals[0]);
420       rank2 = Integer.parseInt(vals[1]);
421       final int pos2 = vals[2].indexOf('-');
422       if (pos2 > 0) {
423         subversion2 = Integer.parseInt(vals[2].substring(0, pos2));
424       } else {
425         subversion2 = Integer.parseInt(vals[2]);
426       }
427       final boolean b = major1 < major2 || (major1 == major2 &&
428                                             (rank1 < rank2 || (rank1 == rank2 &&
429                                                                subversion1 <
430                                                                subversion2)));
431       logger.debug("1: {}:{}:{} <? {}:{}:{} = {}", major1, rank1, subversion1,
432                    major2, rank2, subversion2, b);
433       return b;
434     } catch (final Exception e) {
435       logger.error("Error while comparing versions {} vs {}: {}", version1,
436                    version2, e.getMessage());
437       return false;
438     }
439   }
440 
441   /**
442    * @param host
443    *
444    * @return True if this host is referenced as using Json
445    */
446   public static boolean useJson(final String host) {
447     if (logger.isDebugEnabled()) {
448       logger.debug("UseJson host: '{}':{}", host,
449                    Configuration.configuration.getVersions().containsKey(host)?
450                        Configuration.configuration.getVersions().get(host)
451                                                   .useJson() : "no:" +
452                                                                ((Map<String, PartnerConfiguration>) Configuration.configuration.getVersions()).keySet());
453     }
454     return Configuration.configuration.getVersions().containsKey(host) &&
455            Configuration.configuration.getVersions().get(host).useJson();
456   }
457 
458   /**
459    * @return the sEPARATOR_FIELD
460    */
461   public static String getSEPARATOR_FIELD() {
462     return SEPARATOR_FIELD;
463   }
464 
465   /**
466    * @param separatorFIELD the sEPARATOR_FIELD to set
467    */
468   public static void setSEPARATOR_FIELD(final String separatorFIELD) {
469     SEPARATOR_FIELD = separatorFIELD;
470   }
471 }