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