001package jmri.implementation; 002 003import com.fasterxml.jackson.databind.util.StdDateFormat; 004 005import java.text.*; 006import java.util.Calendar; 007import java.util.Date; 008import java.util.Locale; 009import java.util.Objects; 010import java.time.LocalDateTime; 011import java.time.ZoneId; 012import java.time.format.DateTimeParseException; 013import java.time.format.DateTimeFormatter; 014 015import javax.annotation.CheckForNull; 016 017import jmri.*; 018 019import org.jdom2.Element; 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023/** 024 * Concrete implementation of the {@link jmri.IdTag} interface for the Internal 025 * system. 026 * <hr> 027 * This file is part of JMRI. 028 * <p> 029 * JMRI is free software; you can redistribute it and/or modify it under the 030 * terms of version 2 of the GNU General Public License as published by the Free 031 * Software Foundation. See the "COPYING" file for a copy of this license. 032 * <p> 033 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 034 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 035 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 036 * 037 * @author Matthew Harris Copyright (C) 2011 038 * @since 2.11.4 039 */ 040public class DefaultIdTag extends AbstractIdTag { 041 042 private int currentState = UNKNOWN; 043 044 public DefaultIdTag(String systemName) { 045 super(systemName); 046 setWhereLastSeen(null); 047 } 048 049 public DefaultIdTag(String systemName, String userName) { 050 super(systemName, userName); 051 setWhereLastSeen(null); 052 } 053 054 public final static String PROPERTY_WHEN_LAST_SEEN = "whenLastSeen"; 055 public final static String PROPERTY_WHERE_LAST_SEEN = "whereLastSeen"; 056 057 @Override 058 public int compareTo(NamedBean n2) { 059 Objects.requireNonNull(n2); 060 String o1 = this.getSystemName(); 061 String o2 = n2.getSystemName(); 062 int p1len = Manager.getSystemPrefixLength(o1); 063 int p2len = Manager.getSystemPrefixLength(o2); 064 int comp = o1.substring(0, p1len).compareTo(o2.substring(0, p2len)); 065 if (comp != 0) 066 return comp; 067 comp = o1.compareTo(o2); 068 return comp; 069 } 070 071 @Override 072 public final void setWhereLastSeen(@CheckForNull Reporter r) { 073 Reporter oldWhere = this.whereLastSeen; 074 Date oldWhen = this.whenLastSeen; 075 this.whereLastSeen = r; 076 if (r != null) { 077 this.whenLastSeen = getDateNow(); 078 } else { 079 this.whenLastSeen = null; 080 } 081 setCurrentState(r != null ? SEEN : UNSEEN); 082 firePropertyChange(PROPERTY_WHERE_LAST_SEEN, oldWhere, this.whereLastSeen); 083 firePropertyChange(PROPERTY_WHEN_LAST_SEEN, oldWhen, this.whenLastSeen); 084 } 085 086 private Date getDateNow() { 087 return InstanceManager.getDefault(IdTagManager.class).isFastClockUsed() 088 ? InstanceManager.getDefault(ClockControl.class).getTime() 089 : Calendar.getInstance().getTime(); 090 } 091 092 private void setCurrentState(int state) { 093 try { 094 setState(state); 095 } catch (JmriException ex) { 096 log.warn("Problem setting state of IdTag {} {}", getSystemName(),ex.getMessage()); 097 } 098 } 099 100 @Override 101 public void setState(int s) throws JmriException { 102 this.currentState = s; 103 } 104 105 @Override 106 public int getState() { 107 return this.currentState; 108 } 109 110 @Override 111 public Element store(boolean storeState) { 112 Element e = new Element("idtag"); // NOI18N 113 e.addContent(new Element("systemName").addContent(this.mSystemName)); // NOI18N 114 String uName = this.getUserName(); 115 if (uName != null && !uName.isEmpty()) { 116 e.addContent(new Element("userName").addContent(uName)); // NOI18N 117 } 118 String comment = this.getComment(); 119 if ((comment != null) && (!comment.isEmpty())) { 120 e.addContent(new Element("comment").addContent(comment)); // NOI18N 121 } 122 Reporter whereLast = this.getWhereLastSeen(); 123 if (whereLast != null && storeState) { 124 e.addContent(new Element(PROPERTY_WHERE_LAST_SEEN).addContent(whereLast.getSystemName())); 125 } 126 if (this.getWhenLastSeen() != null && storeState) { 127 e.addContent(new Element(PROPERTY_WHEN_LAST_SEEN).addContent(new StdDateFormat().format(this.getWhenLastSeen()))); 128 } 129 return e; 130 } 131 132 /** 133 * Load an idtag xml element. 134 * whenLastSeen formats accepted JMRI 5.3.6 include 135 * yyyy-MM-dd'T'HH:mm:ss.SSSX 136 * yyyy-MM-dd'T'HH:mm:ss.SSS 137 * EEE, dd MMM yyyy HH:mm:ss zzz 138 * 139 * @param e element to load. 140 */ 141 @Override 142 public void load(Element e) { 143 if (e.getName().equals("idtag")) { // NOI18N 144 log.debug("Load IdTag element for {}", this.getSystemName()); 145 if (e.getChild("userName") != null) { // NOI18N 146 this.setUserName(e.getChild("userName").getText()); // NOI18N 147 } 148 if (e.getChild("comment") != null) { // NOI18N 149 this.setComment(e.getChild("comment").getText()); // NOI18N 150 } 151 if (e.getChild(PROPERTY_WHERE_LAST_SEEN) != null) { 152 try { 153 Reporter r = InstanceManager.getDefault(ReporterManager.class) 154 .provideReporter(e.getChild(PROPERTY_WHERE_LAST_SEEN).getText()); 155 this.setWhereLastSeen(r); 156 this.whenLastSeen = null; 157 } catch (IllegalArgumentException ex) { 158 log.warn("Failed to provide Reporter \"{}\" in load of \"{}\"", e.getChild(PROPERTY_WHERE_LAST_SEEN).getText(), getDisplayName()); 159 } 160 } 161 if (e.getChild(PROPERTY_WHEN_LAST_SEEN) != null) { 162 String lastSeenText = e.getChildText(PROPERTY_WHEN_LAST_SEEN); 163 log.debug("Loading {} When Last Seen: {}", getDisplayName(), lastSeenText); 164 try { // parse using ISO 8601 date format 165 this.whenLastSeen = new StdDateFormat().parse(lastSeenText); 166 } catch (ParseException ex) { 167 log.debug("ParseException in whenLastSeen ISO attempt: \"{}\"", lastSeenText, ex); 168 // next, try parse using how it was saved by JMRI < 5.3.5 169 try { 170 // the result of this string may change between Java versions 171 this.whenLastSeen = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).parse(lastSeenText); 172 } catch (ParseException ex2) { 173 // next, try parse fixed format JMRI < 5.3.5, Java8 Locale US 174 try { 175 DateTimeFormatter previousUsFormatter = 176 DateTimeFormatter.ofPattern("MMM d, yyyy, h:mm:ss a", Locale.US); 177 LocalDateTime ldt = LocalDateTime.parse(lastSeenText, previousUsFormatter); 178 this.whenLastSeen = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()); 179 } catch (DateTimeParseException ex3) { 180 log.warn("During load of IdTag \"{}\" {}", getDisplayName(), ex.getMessage()); 181 } 182 } 183 } 184 } 185 } else { 186 log.error("Not an IdTag element: \"{}\" for Tag \"{}\"", e.getName(), this.getDisplayName()); 187 } 188 } 189 190 private static final Logger log = LoggerFactory.getLogger(DefaultIdTag.class); 191 192}