001 /*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2013
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 *
010 * All Rights Reserved
011 *
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.
014 *
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 *
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023 * GNU Lesser Public License for more details.
024 *
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program. If not, see http://www.gnu.org/licenses.
027 */
028 package edu.wisc.ssec.mcidasv.servermanager;
029
030 import java.util.Collections;
031 import java.util.List;
032 import java.util.Map;
033
034 import org.slf4j.Logger;
035 import org.slf4j.LoggerFactory;
036
037 import edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EntryType;
038
039 /**
040 *
041 *
042 *
043 */
044 public class LocalAddeEntry implements AddeEntry {
045
046 /** Friendly neighborhood logging object. */
047 static final Logger logger = LoggerFactory.getLogger(LocalAddeEntry.class);
048
049 /** Represents a {@literal "bad"} local ADDE entry. */
050 // seriously, don't use null unless you REALLY need it.
051 public static final LocalAddeEntry INVALID_ENTRY = new Builder("INVALID", "INVALID", "/dev/null", AddeFormat.INVALID).build();
052
053 /** Represents a {@literal "bad"} collection of local ADDE entries. */
054 public static final List<LocalAddeEntry> INVALID_ENTRIES = Collections.singletonList(INVALID_ENTRY);
055
056 /** */
057 private static final String CYGWIN_PREFIX = "/cygdrive/";
058
059 /** */
060 private static final int CYGWIN_PREFIX_LEN = CYGWIN_PREFIX.length();
061
062 /** */
063 private EntryStatus entryStatus = EntryStatus.INVALID;
064
065 // RESOLV.SRV FIELDS
066 /** N1 */
067 private final String group;
068
069 /** N2 */
070 // this value is built in a non-obvious way. plz to be dox.
071 private final String descriptor;
072
073 /** RT */
074 private final boolean realtime;
075
076 /** MCV */
077 private final AddeFormat format;
078
079 /** R1 */
080 private final String start;
081
082 /** R2 */
083 private final String end;
084
085 /** MASK */
086 private final String fileMask;
087
088 /** C */
089 private final String name;
090 // END RESOLV.SRV FIELDS
091
092 private String asStringId;
093
094 /** */
095 private final boolean isTemporary;
096
097 /** */
098 private String entryAlias;
099
100 public enum ServerName {
101 AREA, AMSR, AMRR, GINI, FSDX, OMTP, LV1B, MODS, MODX, MOD4, MOD8,
102 MODR, MSGT, MTST, SMIN, TMIN, MD, INVALID;
103 }
104
105 /**
106 * The various kinds of local ADDE data understood by McIDAS-V, along with
107 * some helpful metadata.
108 *
109 * <p><ul>
110 * <li>{@literal "Human readable"} format names ({@link #friendlyName}).</li>
111 * <li>Optional tooltip description ({@link #tooltip}).</li>
112 * <li>Type of data ({@link #type}).</li>
113 * <li>File naming pattern {@link #fileFilter}.</li>
114 * </ul>
115 *
116 * <p>None of {@code AddeFormat}'s fields should contain {@code null}.
117 */
118 public enum AddeFormat {
119 MCIDAS_AREA(ServerName.AREA, "McIDAS AREA"),
120 MCIDAS_MD(ServerName.MD, "McIDAS MD", "McIDAS MD", EntryType.POINT),
121 AMSRE_L1B(ServerName.AMSR, "AMSR-E L 1b", "AMSR-E Level 1b"),
122 AMSRE_RAIN_PRODUCT(ServerName.AMRR, "AMSR-E Rain Product"),
123 GINI(ServerName.GINI, "GINI"),
124 LRIT_GOES9(ServerName.FSDX, "LRIT GOES-9", "EUMETCast LRIT GOES-9"),
125 LRIT_GOES10(ServerName.FSDX, "LRIT GOES-10", "EUMETCast LRIT GOES-10"),
126 LRIT_GOES11(ServerName.FSDX, "LRIT GOES-11", "EUMETCast LRIT GOES-11"),
127 LRIT_GOES12(ServerName.FSDX, "LRIT GOES-12", "EUMETCast LRIT GOES-12"),
128 LRIT_MET5(ServerName.FSDX, "LRIT MET-5", "EUMETCast LRIT MET-5"),
129 LRIT_MET7(ServerName.FSDX, "LRIT MET-7", "EUMETCast LRIT MET-7"),
130 LRIT_MTSAT1R(ServerName.FSDX, "LRIT MTSAT-1R", "EUMETCast LRIT MTSAT-1R"),
131 METEOSAT_OPENMTP(ServerName.OMTP, "Meteosat OpenMTP"),
132 METOP_AVHRR_L1B(ServerName.LV1B, "Metop AVHRR L 1b", "Metop AVHRR Level 1b"),
133 MODIS_L1B_MOD02(ServerName.MODS, "MODIS MOD 02 - Level-1B Calibrated Geolocated Radiances", "MODIS Level 1b"),
134 MODIS_L2_MOD06(ServerName.MODX, "MODIS MOD 06 - Cloud Product", "MODIS Level 2 (Cloud Top Properties)"),
135 MODIS_L2_MOD07(ServerName.MODX, "MODIS MOD 07 - Atmospheric Profiles", "MODIS Level 2 (Atmospheric Profile)"),
136 MODIS_L2_MOD35(ServerName.MODX, "MODIS MOD 35 - Cloud Mask", "MODIS Level 2 (Cloud Mask)"),
137 MODIS_L2_MOD04(ServerName.MOD4, "MODIS MOD 04 - Aerosol Product", "MODIS Level 2 (Aerosol)"),
138 MODIS_L2_MOD28(ServerName.MOD8, "MODIS MOD 28 - Sea Surface Temperature", "MODIS Level 2 (Sea Surface Temperature)"),
139 MODIS_L2_MODR(ServerName.MODR, "MODIS MOD R - Corrected Reflectance", "MODIS Level 2 (Corrected Reflectance)"),
140 MSG_HRIT_FD(ServerName.MSGT, "MSG HRIT FD", "MSG HRIT (Full Disk)"),
141 MSG_HRIT_HRV(ServerName.MSGT, "MSG HRIT HRV", "MSG HRIT (High Resolution Visible)"),
142 MTSAT_HRIT(ServerName.MTST, "MTSAT HRIT"),
143 NOAA_AVHRR_L1B(ServerName.LV1B, "NOAA AVHRR L 1b", "NOAA AVHRR Level 1b"),
144 SSMI(ServerName.SMIN, "SSMI", "Terrascan netCDF (SMIN)"),
145 TRMM(ServerName.TMIN, "TRMM", "Terrascan netCDF (TMIN)"),
146 INVALID(ServerName.INVALID, "", "", EntryType.INVALID);
147
148 /** Name of the McIDAS-X server. */
149 private final ServerName servName;
150
151 /** {@literal "Human readable"} format name. This is returned by {@link #toString()}. */
152 private final String friendlyName;
153
154 /** Description of the format. */
155 private final String tooltip;
156
157 /** Data type. Corresponds to {@code TYPE} in {@literal "RESOLV.SRV"}. */
158 private final EntryType type;
159
160 /**
161 * Filename pattern used when listing files in a directory.
162 * If {@link #servName} is {@link ServerName#MSGT} then
163 * {@literal "*PRO*"} is used, otherwise {@literal "*"}.
164 */
165 private final String fileFilter;
166
167 /**
168 * Builds an {@literal "ADDE format"} and its associated metadata in
169 * a typesafe way.
170 *
171 * @param servName {@link ServerName} that McIDAS-X uses for this format.
172 * @param friendlyName {@literal "Human readable"} name of the format; returned by {@link #toString()}.
173 * @param tooltip If non-empty, this is used as a tooltip in the local entry editor.
174 * @param type {@link EntryType} used by this format.
175 */
176 private AddeFormat(final ServerName servName, final String friendlyName, final String tooltip, final EntryType type) {
177 this.servName = servName;
178 this.friendlyName = friendlyName;
179 this.tooltip = tooltip;
180 this.type = type;
181 this.fileFilter = (servName != ServerName.MSGT) ? "*" : "*PRO*";
182 }
183
184 /**
185 * Builds an {@literal "imagery ADDE Format"} <b>without</b> a tooltip.
186 *
187 * @param servName {@link ServerName} that McIDAS-X uses for this format.
188 * @param friendlyName {@literal "Human readable"} name of the format; returned by {@link #toString()}.
189 */
190 private AddeFormat(final ServerName servName, final String friendlyName) {
191 this(servName, friendlyName, "", EntryType.IMAGE);
192 }
193
194 /**
195 * Builds an {@literal "imagery ADDE Format"} <b>with</b> a tooltip.
196 *
197 * @param servName {@link ServerName} that McIDAS-X uses for this format.
198 * @param friendlyName {@literal "Human readable"} name of the format; returned by {@link #toString()}.
199 * @param tooltip If non-empty, this is used as a tooltip in the local entry editor.
200 */
201 private AddeFormat(final ServerName servName, final String friendlyName, final String tooltip) {
202 this(servName, friendlyName, tooltip, EntryType.IMAGE);
203 }
204
205 /**
206 * Gets the McIDAS-X {@link ServerName} for this format.
207 *
208 * @return Either the name of this format's McIDAS-X server, or {@link ServerName#INVALID}.
209 */
210 public ServerName getServerName() {
211 return servName;
212 }
213
214 /**
215 * Gets the tooltip text to use in the server manager GUI for this
216 * format.
217 *
218 * @return Text to use as a GUI tooltip. Cannot be {@code null}, though
219 * empty {@code String} values are permitted.
220 */
221 public String getTooltip() {
222 return tooltip;
223 }
224
225 /**
226 * Gets the type of data used by this format. This value dictates the
227 * chooser(s) where this format can appear.
228 *
229 * @return One of {@link EntryType}, or {@link EntryType#INVALID}.
230 */
231 public EntryType getType() {
232 return type;
233 }
234
235 /**
236 * Gets the string used to filter out files that match this format.
237 *
238 * @return Either a specialized {@code String}, like {@literal "*PRO*"} or {@literal "*"}.
239 */
240 public String getFileFilter() {
241 return fileFilter;
242 }
243
244 /**
245 * Gets the {@code String} representation of this format.
246 *
247 * @return the value of {@link #friendlyName}.
248 */
249 @Override public String toString() {
250 return friendlyName;
251 }
252 }
253
254 /**
255 *
256 *
257 * @param builder
258 *
259 * @see LocalAddeEntry.Builder
260 */
261 private LocalAddeEntry(final Builder builder) {
262 this.group = builder.group;
263 this.descriptor = builder.descriptor;
264 this.realtime = builder.realtime;
265 this.format = builder.format;
266 this.fileMask = builder.mask;
267 this.name = builder.name;
268 this.start = builder.start;
269 this.end = builder.end;
270 this.entryStatus = builder.status;
271 this.isTemporary = builder.temporary;
272 this.entryAlias = builder.alias;
273 logger.debug("created local: {}", this);
274 }
275
276 @Override public AddeAccount getAccount() {
277 return RemoteAddeEntry.DEFAULT_ACCOUNT;
278 }
279
280 @Override public String getAddress() {
281 return "localhost";
282 }
283
284 @Override public EntrySource getEntrySource() {
285 return EntrySource.USER;
286 }
287
288 @Override public EntryStatus getEntryStatus() {
289 return entryStatus;
290 }
291
292 @Override public String getEntryText() {
293 return "localhost/"+getGroup();
294 }
295
296 @Override public EntryType getEntryType() {
297 return format.getType();
298 }
299
300 @Override public EntryValidity getEntryValidity() {
301 return (isValid()) ? EntryValidity.VERIFIED : EntryValidity.INVALID;
302 }
303
304 // TODO(jon): fix this noop
305 @Override public String getEntryAlias() {
306 if (entryAlias == null) {
307 return "";
308 }
309 return entryAlias;
310 }
311
312 // TODO(jon): fix this noop
313 @Override public void setEntryAlias(final String newAlias) {
314 if (newAlias == null) {
315 throw new NullPointerException("Null aliases are not allowable.");
316 }
317 this.entryAlias = newAlias;
318 }
319
320 @Override public void setEntryStatus(EntryStatus newStatus) {
321 entryStatus = newStatus;
322 }
323
324 @Override public boolean isEntryTemporary() {
325 return isTemporary;
326 }
327
328 @Override public String getGroup() {
329 return group;
330 }
331
332 @Override public String getName() {
333 return name;
334 }
335
336 /**
337 * Gets the ADDE descriptor for the current local ADDE entry.
338 *
339 * @return ADDE descriptor (corresponds to the {@literal "N2"} section of a RESOLV.SRV
340 * entry).
341 */
342 public String getDescriptor() {
343 return descriptor;
344 }
345
346 /**
347 * Gets the ADDE dataset format for the current local ADDE entry.
348 *
349 * @return ADDE format (corresponds to the {@literal "MCV"} section of a RESOLV.SRV
350 * entry).
351 */
352 public AddeFormat getFormat() {
353 return format;
354 }
355
356 /**
357 * Gets the ADDE file mask for the current local ADDE entry.
358 *
359 * @return ADDE file mask (corresponds to the {@literal "MASK"} section of a RESOLV.SRV
360 * entry).
361 */
362 public String getMask() {
363 return fileMask;
364 }
365
366 /**
367 * Gets the ADDE file mask for the current local ADDE entry.
368 *
369 * @return ADDE file mask (corresponds to the {@literal "MASK"} section of a RESOLV.SRV
370 * entry).
371 */
372 public String getFileMask() {
373 return fileMask;
374 }
375
376 /**
377 * Gets the ADDE realtime status of the current local ADDE entry.
378 *
379 * @return Whether or not the current dataset is {@literal "realtime"}.
380 * Corresponds to the {@literal "RT"} section of a RESOLV.SRV entry.
381 */
382 public boolean getRealtime() {
383 return realtime;
384 }
385
386 /**
387 * Gets the starting number of the current local ADDE dataset.
388 *
389 * @return Corresponds to the {@literal "R1"} section of a RESOLV.SRV entry.
390 */
391 public String getStart() {
392 return start;
393 }
394
395 /**
396 * Gets the ending number of the current local ADDE dataset.
397 *
398 * @return Corresponds to the {@literal "R2"} section of a RESOLV.SRV entry.
399 */
400 public String getEnd() {
401 return end;
402 }
403
404 /**
405 * Tests the current local ADDE dataset for validity.
406 *
407 * @return {@code true} iff {@link #group} and {@link #name} are not empty.
408 */
409 public boolean isValid() {
410 // return !((group.isEmpty()) || (descriptor.isEmpty()) || (name.isEmpty()));
411 return !((group.isEmpty()) || (name.isEmpty()));
412 }
413
414 /**
415 * Gets the local ADDE dataset's realtime status as a value suitable for
416 * RESOLV.SRV (one of {@literal "Y"} or {@literal "N"}).
417 *
418 * @return RESOLV.SRV-friendly representation of the current realtime status.
419 */
420 public String getRealtimeAsString() {
421 return (realtime) ? "Y" : "N";
422 }
423
424 /**
425 * @see LocalAddeEntry#generateHashCode(String, String, String, String, boolean, AddeFormat)
426 */
427 @Override public int hashCode() {
428 return generateHashCode(name, group, fileMask, entryAlias, isTemporary, format);
429 }
430
431 /**
432 * Checks a given object for equality with the current {@code LocalAddeEntry}
433 * instance.
434 *
435 * @param obj Object to check. {@code null} values allowed.
436 *
437 * @return {@code true} if {@code obj} is {@literal "equal"} to the current
438 * {@code LocalAddeEntry} instance.
439 */
440 @Override public boolean equals(Object obj) {
441 if (this == obj) {
442 return true;
443 }
444 if (obj == null) {
445 return false;
446 }
447 if (!(obj instanceof LocalAddeEntry)) {
448 return false;
449 }
450 LocalAddeEntry other = (LocalAddeEntry) obj;
451 if (fileMask == null) {
452 if (other.fileMask != null) {
453 return false;
454 }
455 } else if (!fileMask.equals(other.fileMask)) {
456 return false;
457 }
458 if (format == null) {
459 if (other.format != null) {
460 return false;
461 }
462 } else if (!format.toString().equals(other.format.toString())) {
463 return false;
464 }
465 if (group == null) {
466 if (other.group != null) {
467 return false;
468 }
469 } else if (!group.equals(other.group)) {
470 return false;
471 }
472 if (name == null) {
473 if (other.name != null) {
474 return false;
475 }
476 } else if (!name.equals(other.name)) {
477 return false;
478 }
479 if (entryAlias == null) {
480 if (other.entryAlias != null) {
481 return false;
482 }
483 } else if (!entryAlias.equals(other.entryAlias)) {
484 return false;
485 }
486 if (isTemporary != other.isTemporary) {
487 return false;
488 }
489 return true;
490 }
491
492 @Override public String asStringId() {
493 if (asStringId == null) {
494 asStringId = "localhost!"+group+'!'+EntryType.IMAGE.name()+'!'+name;
495 }
496 return asStringId;
497 }
498
499 @Override public String toString() {
500 return String.format(
501 "[LocalAddeEntry@%x: name=%s, group=%s, fileMask=\"%s\", descriptor=%s, serverName=%s, format=%s, description=%s, type=%s, status=%s, temporary=%s, alias=%s]",
502 hashCode(), name, group, fileMask, descriptor, format.getServerName().name(), format.name(), format.getTooltip(), format.getType(), entryStatus.name(), isTemporary, entryAlias);
503
504 }
505
506 public static int generateHashCode(final LocalAddeEntry entry) {
507 return generateHashCode(entry.getName(), entry.getGroup(), entry.getMask(), entry.getEntryAlias(), entry.isEntryTemporary(), entry.getFormat());
508 }
509
510 public static int generateHashCode(String name, String group, String fileMask, String entryAlias, boolean isTemporary, AddeFormat format) {
511 final int prime = 31;
512 int result = 1;
513 result = prime * result
514 + ((fileMask == null) ? 0 : fileMask.hashCode());
515 result = prime * result + ((format == null) ? 0 : format.toString().hashCode());
516 result = prime * result + ((group == null) ? 0 : group.hashCode());
517 result = prime * result + ((name == null) ? 0 : name.hashCode());
518 result = prime * result + ((entryAlias == null) ? 0 : entryAlias.hashCode());
519 result = prime * result + (isTemporary ? 1231 : 1237);
520 return result;
521 }
522
523 /**
524 * A builder of (mostly) immutable {@link LocalAddeEntry} instances.
525 *
526 * <p>Usage example: <pre> {@code
527 * LocalAddeEntry entry = new LocalAddeEntry
528 * .Builder(group, name, format, mask)
529 * .realtime("Y")
530 * .range(start, end)
531 * .type(EntryType.POINT)
532 * .build();}</pre>
533 *
534 * Only the values required by the Builder constructor are required.
535 */
536 public static class Builder {
537 // required
538 /** Corresponds to RESOLV.SRV's {@literal "N1"} section. */
539 private final String group;
540
541 /** Corresponds to RESOLV.SRV's {@literal "C"} section. */
542 private final String name;
543
544 /** Corresponds to RESOLV.SRV's {@literal "MCV"} section. */
545 private final AddeFormat format;
546
547 /** Corresponds to RESOLV.SRV's {@literal "MASK"} section. */
548 private final String mask;
549
550 // generated
551 private String descriptor;
552
553 // optional
554 /**
555 * Corresponds to RESOLV.SRV's {@literal "RT"} section.
556 * Defaults to {@code false}.
557 */
558 private boolean realtime = false;
559
560 /**
561 * Corresponds to RESOLV.SRV's {@literal "R1"} section.
562 * Defaults to {@literal "1"}.
563 */
564 private String start = "1";
565
566 /**
567 * Corresponds to RESOLV.SRV's {@literal "R2"} section.
568 * Defaults to {@literal "999999"}.
569 */
570 private String end = "999999";
571
572 /**
573 * Defaults to {@link edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EntryStatus#INVALID}.
574 */
575 private EntryStatus status = EntryStatus.INVALID;
576
577 /**
578 * Corresponds to RESOLV.SRV's {@literal "TYPE"} section.
579 * Defaults to {@link EntryType#IMAGE}.
580 */
581 private EntryType type = EntryType.IMAGE;
582
583 /**
584 * Corresponds to RESOLV.SRV's {@literal "K"} section.
585 * Defaults to {@literal "NOT_SET"}.
586 */
587 private String kind = "NOT_SET";
588
589 /**
590 * Defaults to {@link ServerName#INVALID}.
591 */
592 private ServerName safeKind = ServerName.INVALID;
593
594 /** */
595 private boolean temporary = false;
596
597 /** */
598 private String alias = "";
599
600 public Builder(final Map<String, String> map) {
601 if (!map.containsKey("C") || !map.containsKey("N1") || !map.containsKey("MASK") || !map.containsKey("MCV")) {
602 throw new IllegalArgumentException("Cannot build a LocalAddeEntry without the following keys: C, N1, MASK, and MCV.");
603 }
604
605 this.name = map.get("C");
606 this.group = map.get("N1");
607 this.mask = map.get("MASK");
608 this.format = EntryTransforms.strToAddeFormat(map.get("MCV"));
609
610 // descriptor(map.get("N2"));
611 type(EntryTransforms.strToEntryType(map.get("TYPE")));
612 kind(map.get("K").toUpperCase());
613 realtime(map.get("RT"));
614 start(map.get("R1"));
615 end(map.get("R2"));
616
617 if (map.containsKey("TEMPORARY")) {
618 temporary(map.get("TEMPORARY"));
619 }
620 }
621
622 /**
623 * Creates a new {@code LocalAddeEntry} {@literal "builder"} with the
624 * required fields for a {@code LocalAddeEntry} object.
625 *
626 * @param name
627 * @param group
628 * @param mask
629 * @param format
630 */
631 public Builder(final String name, final String group, final String mask, final AddeFormat format) {
632 this.name = name;
633 this.group = group;
634 this.mask = mask;
635 this.format = format;
636 }
637
638 /**
639 * This method is currently a no-op.
640 *
641 * @param descriptor
642 *
643 * @return {@code LocalAddeEntry.Builder} with ADDE descriptor.
644 */
645 public Builder descriptor(final String descriptor) {
646 // if (descriptor != null) {
647 // this.descriptor = descriptor;
648 // }
649 return this;
650 }
651
652 /**
653 *
654 *
655 * @param realtimeAsStr
656 *
657 * @return {@code LocalAddeEntry.Builder} with ADDE realtime flag.
658 */
659 // looks like mcidasx understands ("Y"/"N"/"A")
660 // should probably ignore case and accept "YES"/"NO"/"ARCHIVE"
661 // in addition to the normal boolean conversion from String
662 public Builder realtime(final String realtimeAsStr) {
663 if (realtimeAsStr == null) {
664 return this;
665 }
666
667 if ("Y".equalsIgnoreCase(realtimeAsStr) || "YES".equalsIgnoreCase(realtimeAsStr)) {
668 this.realtime = true;
669 } else {
670 this.realtime = Boolean.valueOf(realtimeAsStr);
671 }
672 return this;
673 }
674
675 /**
676 *
677 *
678 * @param realtime
679 *
680 * @return {@code LocalAddeEntry.Builder} with ADDE realtime flag.
681 */
682 public Builder realtime(final boolean realtime) {
683 this.realtime = realtime;
684 return this;
685 }
686
687 /**
688 *
689 *
690 * @param type
691 *
692 * @return {@code LocalAddeEntry.Builder} with ADDE data type.
693 */
694 // my assumption is that if "format" is known, you can infer "type"
695 public Builder type(final EntryType type) {
696 if (type != null) {
697 this.type = type;
698 }
699 return this;
700 }
701
702 /**
703 *
704 *
705 * @param kind
706 *
707 * @return {@code LocalAddeEntry.Builder} with ADDE kind.
708 */
709 // my assumption is that if "format" is known, you can infer "kind"
710 public Builder kind(final String kind) {
711 if (kind == null) {
712 return this;
713 }
714
715 this.kind = kind;
716 try {
717 this.safeKind = ServerName.valueOf(kind);
718 } catch (IllegalArgumentException e) {
719 this.safeKind = ServerName.INVALID;
720 }
721 return this;
722 }
723
724 /**
725 *
726 *
727 * @param start
728 *
729 * @return {@code LocalAddeEntry.Builder} with ADDE dataset {@literal "start"}.
730 */
731 public Builder start(final String start) {
732 if (start != null) {
733 this.start = start;
734 }
735 return this;
736 }
737
738 /**
739 *
740 *
741 * @param end
742 *
743 * @return {@code LocalAddeEntry.Builder} with ADDE dataset {@literal "end"}.
744 */
745 public Builder end(final String end) {
746 if (end != null) {
747 this.end = end;
748 }
749 return this;
750 }
751
752 /**
753 *
754 *
755 * @param start
756 * @param end
757 *
758 * @return {@code LocalAddeEntry.Builder} with ADDE dataset {@literal "start" and "end"} values.
759 */
760 public Builder range(final String start, final String end) {
761 if (start != null && end != null) {
762 this.start = start;
763 this.end = end;
764 }
765 return this;
766 }
767
768 /**
769 *
770 *
771 * @param status
772 *
773 * @return {@code LocalAddeEntry.Builder} with {@link AddeEntry.EntryStatus}.
774 */
775 public Builder status(final String status) {
776 if (status != null && status.length() > 0) {
777 this.status = EntryTransforms.strToEntryStatus(status);
778 }
779 return this;
780 }
781
782 /**
783 *
784 *
785 * @param status
786 *
787 * @return {@code LocalAddeEntry.Builder} with {@link AddeEntry.EntryStatus}.
788 */
789 public Builder status(final EntryStatus status) {
790 if (status != null) {
791 this.status = status;
792 }
793 return this;
794 }
795
796 /**
797 *
798 *
799 * @param temporary
800 *
801 * @return {@code LocalAddeEntry.Builder} with the specified temporary status.
802 */
803 public Builder temporary(final boolean temporary) {
804 this.temporary = temporary;
805 return this;
806 }
807
808 public Builder temporary(final String temporary) {
809 this.temporary = Boolean.valueOf(temporary);
810 return this;
811 }
812
813 /**
814 *
815 *
816 * @param alias
817 *
818 * @return {@code LocalAddeEntry.Builder} with the specified alias.
819 */
820 public Builder alias(final String alias) {
821 this.alias = alias;
822 return this;
823 }
824
825 /**
826 *
827 *
828 * @return New {@code LocalAddeEntry} instance.
829 */
830 public LocalAddeEntry build() {
831 // apparently need to hack up the descriptor for certain formats
832 switch (format) {
833 case MSG_HRIT_FD: this.descriptor = "FD"; break;
834 case MSG_HRIT_HRV: this.descriptor = "HRV"; break;
835 case LRIT_GOES9: this.descriptor = "GOES9"; break;
836 case LRIT_GOES10: this.descriptor = "GOES10"; break;
837 case LRIT_GOES11: this.descriptor = "GOES11"; break;
838 case LRIT_GOES12: this.descriptor = "GOES12"; break;
839 case LRIT_MET5: this.descriptor = "MET5"; break;
840 case LRIT_MET7: this.descriptor = "MET7"; break;
841 case LRIT_MTSAT1R: this.descriptor = "MTSAT1R"; break;
842 default:
843 this.descriptor = Integer.toHexString(generateHashCode(name, group, mask, alias, temporary, format));
844 break;
845 }
846 return new LocalAddeEntry(this);
847 }
848 }
849 }