001/* Ptolemy II Version identifiers 002 003 Copyright (c) 2001-2018 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.kernel.attributes; 029 030import java.util.Iterator; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.StringTokenizer; 034 035import ptolemy.kernel.util.IllegalActionException; 036import ptolemy.kernel.util.KernelException; 037import ptolemy.kernel.util.NameDuplicationException; 038import ptolemy.kernel.util.NamedObj; 039import ptolemy.kernel.util.Settable; 040import ptolemy.kernel.util.StringAttribute; 041import ptolemy.kernel.util.Workspace; 042 043/////////////////////////////////////////////////////////////////// 044//// VersionAttribute 045 046/** 047 A nonpersistent attribute that identifies the version of an object. 048 The value of the attribute contains a String version-id that represents 049 the version. 050 A version-id is a string with substrings separated by one of '.', '-' or '_'. 051 The substrings may consist of any characters except space. Version-ids can 052 be compared against each other other with the compareTo() method. 053 054 <p>The JNLP specification at 055 <a href="http://jcp.org/jsr/detail/056.jsp"><code>http://jcp.org/jsr/detail/056.jsp</code></a> 056 gives the following syntax for version-ids:</p> 057 <pre> 058 version-id ::= string ( separator string ) * 059 string ::= char ( char ) * 060 char ::= Any ASCII character except a space, a separator or a 061 modifier 062 separator ::= "." | "-" | "_" 063 </pre> 064 <p> Valid version-id include "1.3", "1.3.1", "1.3-beta_01".</p> 065 066 <p>The JNLP specification includes version-strings, which are used for 067 matching one or more version-ids in a fashion similar to wildcard 068 matches within a regular expression. At this time, this class does 069 not implement version-strings.</p> 070 071 072 @see ptolemy.kernel.util.SingletonConfigurableAttribute 073 @author Christopher Hylands 074 @version $Id$ 075 @since Ptolemy II 2.0 076 @Pt.ProposedRating Red (cxh) 077 @Pt.AcceptedRating Red (cxh) 078 */ 079public class VersionAttribute extends StringAttribute implements Comparable { 080 /** Construct an object in the default workspace with the empty string 081 * as its name. The object is added to the list of objects in the 082 * workspace. Increment the version number of the workspace. 083 * @param expression The initial value of this parameter, set 084 * using setExpression(). 085 * @exception IllegalActionException If the value is of the 086 * incorrect format. 087 * @see #setExpression(String) 088 */ 089 public VersionAttribute(String expression) throws IllegalActionException { 090 super(); 091 setExpression(expression); 092 setVisibility(Settable.NONE); 093 } 094 095 /** Construct an attribute with the given name contained by the 096 * specified container. The container argument must not be null, or a 097 * NullPointerException will be thrown. This attribute will use the 098 * workspace of the container for synchronization and version counts. 099 * If the name argument is null, then the name is set to the empty 100 * string. Increment the version of the workspace. 101 * @param container The container. 102 * @param name The name of this attribute. 103 * @exception IllegalActionException If the attribute is not of an 104 * acceptable class for the container, or if the name contains a period. 105 * @exception NameDuplicationException If the name coincides with 106 * an attribute already in the container. 107 */ 108 public VersionAttribute(NamedObj container, String name) 109 throws IllegalActionException, NameDuplicationException { 110 super(container, name); 111 _tupleList = new LinkedList(); 112 setVisibility(Settable.NONE); 113 } 114 115 /////////////////////////////////////////////////////////////////// 116 //// public methods //// 117 118 /** Clone the attribute into the specified workspace. This calls the 119 * base class and then sets the attribute public members to refer 120 * to the attributes of the new attribute 121 * @param workspace The workspace for the new attribute 122 * @return A new director. 123 * @exception CloneNotSupportedException If a derived class contains 124 * an attribute that cannot be cloned. 125 */ 126 @Override 127 public Object clone(Workspace workspace) throws CloneNotSupportedException { 128 VersionAttribute newObject = (VersionAttribute) super.clone(workspace); 129 newObject._tupleList = new LinkedList(); 130 return newObject; 131 } 132 133 /** Compare the value of this VersionAttribute against the argument 134 * according to the VersionAttribute syntax and padding rules. For 135 * example: 136 * <p> "1.2.2-005" is greater than "1.2.2.4", 137 * <br> "1.3.1" is an greater than "1.3" 138 * <br> "1.3-beta" is an greater than "1.3-alpha" 139 * <p> 140 * Version-id contain one or more elements. When two version-id's 141 * are compared, they are normalized by padding the shortest 142 * version-id with additional elements containing "0". 143 * During comparison, if both elements can be parsed as Java 144 * <code>int</code>s, then they are compared as integers. If the 145 * elements cannot be parsed as integers, they are compared as Strings. 146 * 147 * @param object The VersionAttribute to compare against. 148 * @return A negative integer, zero, or a positive integer if this 149 * object is less than, equal to, or greater than the specified 150 * object, respectively. 151 */ 152 @Override 153 public int compareTo(Object object) { 154 VersionAttribute version = (VersionAttribute) object; 155 Iterator versionTuples = version.iterator(); 156 Iterator tuples; 157 158 if (_tupleList == null) { 159 tuples = null; 160 } else { 161 tuples = _tupleList.iterator(); 162 } 163 164 while (versionTuples.hasNext() || tuples != null && tuples.hasNext()) { 165 String versionTuple; 166 String tuple; 167 168 // FIXME: deal with * and + in the JNLP Version String spec. 169 // Normalize the shortest tuple by padding with 0 170 if (versionTuples.hasNext()) { 171 versionTuple = (String) versionTuples.next(); 172 } else { 173 versionTuple = "0"; 174 } 175 176 if (tuples != null && tuples.hasNext()) { 177 tuple = (String) tuples.next(); 178 } else { 179 tuple = "0"; 180 } 181 182 // If both elements can be parsed as Java ints, then 183 // compare them as ints. If not, then compare them 184 // as Strings. 185 try { 186 // Try parsing as ints. 187 int tupleInt = Integer.parseInt(tuple); 188 int versionInt = Integer.parseInt(versionTuple); 189 190 if (tupleInt < versionInt) { 191 return -1; 192 } else if (tupleInt > versionInt) { 193 return 1; 194 } 195 } catch (NumberFormatException ex) { 196 // Compare as Strings. 197 int compare = tuple.compareTo(versionTuple); 198 199 if (compare < 0) { 200 return -1; 201 } else if (compare > 0) { 202 return 1; 203 } 204 } 205 } 206 207 return 0; 208 } 209 210 /** Return true if the specified object is an instance of 211 * VersionAttribute and represents the same version as this one. 212 * @param object The specified object that is compared against. 213 * @return True if the specified version is the same as this one. 214 */ 215 @Override 216 public boolean equals(Object object) { 217 // If the _tupleList is null, then we are not fully constructed. 218 // Defer to the superclass, so that we return true if the argument 219 // is the same object as this. 220 if (_tupleList == null) { 221 return super.equals(object); 222 } 223 224 if (object instanceof VersionAttribute) { 225 return compareTo(object) == 0; 226 } 227 228 return false; 229 } 230 231 /** Return a hash code value for attribute. This method returns the 232 * hash code of the expression. 233 * @return A hash code value for this token. 234 */ 235 @Override 236 public int hashCode() { 237 String expression = getExpression(); 238 if (expression == null) { 239 return 0; 240 } 241 return expression.hashCode(); 242 } 243 244 /** Return true if this version is less than the specified version. 245 * This method uses compareTo(), but may yield more readable code 246 * in certain circumstances. 247 * @param version The VersionAttribute that is compared against. 248 * @return True if this version is less than the specified version. 249 * @see #compareTo(Object) 250 */ 251 public boolean isLessThan(VersionAttribute version) { 252 return compareTo(version) < 0; 253 } 254 255 /** Return an iterator over the elements of the version, 256 * each of which is a String. 257 * @return An iterator over the elements of the version. 258 */ 259 public Iterator iterator() { 260 return _tupleList.iterator(); 261 } 262 263 /** Return the major version, which consists of the first two 264 * tuples. Thus, if the version is 6.0.1-beta, then this 265 * method will return "6.0". 266 * @return The major version. 267 */ 268 public static String majorCurrentVersion() { 269 Iterator versionTuples = CURRENT_VERSION.iterator(); 270 return (String) versionTuples.next() + "." 271 + (String) versionTuples.next(); 272 } 273 274 /** Set the value of the string attribute and notify the container 275 * of the value of this attribute by calling attributeChanged(). 276 * Notify any value listeners of this attribute. 277 * @param expression The version string, consisting of 278 * version ID tuples separated by '.', '-' or '_'. For example: 279 * "1.2", "1.2_beta-4". 280 * @exception IllegalActionException If the argument contains a 281 * space, which violates the JNLP Version format specification. 282 */ 283 @Override 284 public void setExpression(String expression) throws IllegalActionException { 285 super.setExpression(expression); 286 287 if (expression.indexOf(' ') != -1) { 288 throw new IllegalActionException(this, 289 "Versions cannot contain spaces: '" + expression + "'"); 290 } 291 292 _tupleList = new LinkedList(); 293 294 StringTokenizer tokenizer = new StringTokenizer(expression, ".-_"); 295 296 while (tokenizer.hasMoreTokens()) { 297 _tupleList.add(tokenizer.nextToken()); 298 } 299 } 300 301 /////////////////////////////////////////////////////////////////// 302 //// public variables //// 303 304 /** The VersionAttribute that contains the version of the Ptolemy II 305 * release that is currently running. This variable may be read 306 * to take action if the assumed version does not match the current 307 * version. For example, 308 * 309 * <pre> 310 * VersionAttribute assumedVersion = ...; 311 * if (VersionAttribute.CURRENT_VERSION.isLessThan(assumedVersion)) { 312 * throw new IllegalActionException("You need to upgrade!"); 313 * } 314 * </pre> 315 * <p> 316 * Similarly, this variable may be used to change the Ptolemy II 317 * functionality depending on the version number:</p> 318 * <pre> 319 * if (VersionAttribute.CURRENT_VERSION.compareTo( 320 * new VersionAttribute("2.0")) ≥ 0 ) { 321 * // Perform some operation if the current version is 322 * // Ptolemy II 2.0 or later. 323 * } 324 * </pre> 325 */ 326 public static final VersionAttribute CURRENT_VERSION; 327 328 static { 329 try { 330 CURRENT_VERSION = new VersionAttribute("11.1.devel"); 331 } catch (Exception ex) { 332 throw new ExceptionInInitializerError( 333 "Failed to create CURRENT_VERSION: " 334 + KernelException.stackTraceToString(ex)); 335 } 336 } 337 338 /////////////////////////////////////////////////////////////////// 339 //// private variables //// 340 // A List representation of the version. 341 private List _tupleList; 342}