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 }