001 package edu.nrao.sss.model.source; 002 003 import java.net.MalformedURLException; 004 import java.net.URL; 005 006 import edu.nrao.sss.astronomy.StokesParameter; 007 import edu.nrao.sss.measure.Frequency; 008 009 /** 010 * A descriptive link to an image of an astronomical source. 011 * <p> 012 * <b>CVS Info:</b> 013 * <table style="margin-left:2em"> 014 * <tr><td>$Revision: 1911 $</td></tr> 015 * <tr><td>$Date: 2009-01-21 10:27:48 -0700 (Wed, 21 Jan 2009) $</td></tr> 016 * <tr><td>$Author: dharland $</td></tr> 017 * </table></p> 018 * 019 * @author David M. Harland 020 * @since 2006-11-29 021 */ 022 public class SourceImageLink 023 implements Cloneable, Comparable<SourceImageLink> 024 { 025 private static final String NO_COMMENTS = ""; 026 private static final String NO_NAME = "[image]"; 027 028 private static URL DEFAULT_IMAGE_URL; 029 static 030 { 031 try { DEFAULT_IMAGE_URL = new URL("http://www.nrao.edu/brokenLink.html"); } 032 catch (MalformedURLException ex) { DEFAULT_IMAGE_URL = null; } 033 } 034 035 private Frequency frequency; 036 private StokesParameter polarization; 037 private String comments; 038 private URL imageLocation; 039 private String displayName; 040 041 /** 042 * Creates a new instance with a phony URL, an unknown polarization, 043 * and a frequency of zero GHz. 044 */ 045 public SourceImageLink() 046 { 047 this(null, null, null); 048 } 049 050 /** 051 * @param frequency the frequency at which the linked image was observed. 052 * If this parameter is <i>null</i>, 053 * a new frequency of zero GHz will be used. 054 * 055 * @param polarization the polarization for which the linked image was 056 * observed. If this parameter is <i>null</i>, 057 * a default polarization will be used. 058 * 059 * @param imageLocation the URL for the image. 060 * If this parameter is <i>null</i>, 061 * a phony non-null URL will be used. 062 */ 063 public SourceImageLink(Frequency frequency, 064 StokesParameter polarization, 065 URL imageLocation) 066 { 067 //In general, it's not a good idea to call non-final methods 068 //in constructors (due to the fact that these methods could 069 //be overridden in subclasses, and that the overridden methods 070 //might interfere with the valid construction of this object). 071 //However, for this simple class we make this choice consciously. 072 setFrequency(frequency); 073 setPolarization(polarization); 074 setImageLocation(imageLocation); 075 076 comments = NO_COMMENTS; 077 displayName = NO_NAME; 078 } 079 080 /** 081 * Sets the frequency at which the linked image was observed. 082 * 083 * @param newFrequency the frequency at which the linked image was observed. 084 * If this parameter is <i>null</i>, 085 * a new frequency of zero GHz will be used. 086 */ 087 public void setFrequency(Frequency newFrequency) 088 { 089 frequency = (newFrequency == null) ? new Frequency() : newFrequency; 090 } 091 092 /** 093 * Returns the frequency at which the linked image was observed. 094 * The value returned is guaranteed to be non-null. 095 * 096 * @return the frequency at which the linked image was observed. 097 */ 098 public Frequency getFrequency() 099 { 100 return frequency; 101 } 102 103 /** 104 * Sets the polarization for which the linked image was observed. 105 * 106 * @param newPolarization the polarization for which the linked image was 107 * observed. If this parameter is <i>null</i>, 108 * a default polarization will be used. 109 */ 110 public void setPolarization(StokesParameter newPolarization) 111 { 112 polarization = (newPolarization == null) ? StokesParameter.getDefault() 113 : newPolarization; 114 } 115 116 /** 117 * Returns the polarization of this SourceImageLink.java. 118 * The value returned is guaranteed to be non-null. 119 * 120 * @return the polarization of this SourceImageLink.java. 121 */ 122 public StokesParameter getPolarization() 123 { 124 return polarization; 125 } 126 127 /** 128 * Stores free-form text related to this link. 129 * The comments usually relate to the manner in which the 130 * image was obtained. This might include the telescope used, 131 * the date of the acquisition, the person performing the 132 * observation, and anything else that might be of interest 133 * to other astronomers.</p> 134 * 135 * @param replacementComments 136 * free-form text related to this link. 137 * These comments replace all previously set comments. 138 * A <i>null</i> value will be replaced by the empty string (<tt>""</tt>}). 139 * 140 * @see #appendComments(String) 141 */ 142 public void setComments(String replacementComments) 143 { 144 comments = (replacementComments == null) ? NO_COMMENTS : replacementComments; 145 } 146 147 /** 148 * Adds additional comments to those already associated with this link. 149 * 150 * @param additionalComments 151 * new, additional, comments for this link. 152 * 153 * @see #setComments(String) 154 */ 155 public void appendComments(String additionalComments) 156 { 157 if ((additionalComments != null) && (additionalComments.length() > 0)) 158 { 159 if (!comments.equals(NO_COMMENTS)) 160 comments = comments + System.getProperty("line.separator"); 161 162 comments = comments + additionalComments; 163 } 164 } 165 166 /** 167 * Returns free-form text related to this link. 168 * The value returned is guaranteed to be non-null. 169 * <p> 170 * See {@link #setComments(String)} for the typical use 171 * of this property.</p> 172 * 173 * @return free-form text related to this link. 174 */ 175 public String getComments() 176 { 177 return comments; 178 } 179 180 /** 181 * Sets the URL for this image. 182 * 183 * @param imageLocation the URL for the image. 184 * If this parameter is <i>null</i>, 185 * a phony non-null URL will be used. 186 */ 187 public void setImageLocation(URL imageLocation) 188 { 189 this.imageLocation = (imageLocation == null) ? DEFAULT_IMAGE_URL 190 : imageLocation; 191 } 192 193 /** 194 * Returns the URL for this image. 195 * The value returned is guaranteed to be non-null, but it may be 196 * a phony URL. 197 * 198 * @return the URL for this image. 199 */ 200 public URL getImageLocation() 201 { 202 return imageLocation; 203 } 204 205 /** 206 * Sets the display name for this link. 207 * 208 * @param newName the display name for this link. If this value is 209 * <i>null</i>, a non-null default name is used in its 210 * place. 211 */ 212 public void setDisplayName(String newName) 213 { 214 displayName = (newName == null) ? NO_NAME : newName; 215 } 216 217 /** 218 * Returns text that may be used for displaying this link. 219 * @return text that may be used for displaying this link. 220 */ 221 public String getDisplayName() 222 { 223 return displayName; 224 } 225 226 /** 227 * Returns a string in the form 228 * <tt> 229 * <a href="<i>getImageLocation().toString()</i>"><i>getDisplayName()</i></a> 230 * </tt> 231 * @return an HTML anchor representing this link. 232 */ 233 public String toHtmlAnchor() 234 { 235 StringBuilder buff = new StringBuilder("<a href=\""); 236 237 buff.append(getImageLocation().toString()).append("\">"); 238 buff.append(getDisplayName()).append("</a>"); 239 240 return buff.toString(); 241 } 242 243 /** 244 * Returns an image link that is a copy of this one. 245 * <p> 246 * If anything goes wrong during the cloning procedure, 247 * a {@code RuntimeException} will be thrown.</p> 248 */ 249 @Override 250 public SourceImageLink clone() 251 { 252 SourceImageLink clone = null; 253 254 try 255 { 256 //This line takes care of the primitive & immutable fields properly 257 clone = (SourceImageLink)super.clone(); 258 259 clone.frequency = this.frequency.clone(); 260 261 clone.imageLocation = new URL(this.imageLocation.toString()); 262 } 263 catch (Exception ex) 264 { 265 throw new RuntimeException(ex); 266 } 267 268 return clone; 269 } 270 271 /** Returns <i>true</i> if {@code o} is equal to this image link. */ 272 @Override 273 public boolean equals(Object o) 274 { 275 //Quick exit if o is this 276 if (o == this) 277 return true; 278 279 //Quick exit if o is null 280 if (o == null) 281 return false; 282 283 //Quick exit if classes are different 284 if (!o.getClass().equals(this.getClass())) 285 return false; 286 287 SourceImageLink other = (SourceImageLink)o; 288 289 //The comments & displayName are intentionally ignored 290 return other.imageLocation.toString() 291 .equals(this.imageLocation.toString()) && 292 other.polarization.equals (this.polarization) && 293 other.frequency.equals (this.frequency); 294 } 295 296 /** Returns a hash code value for this image link. */ 297 @Override 298 public int hashCode() 299 { 300 //Taken from the Effective Java book by Joshua Bloch. 301 //The constants 17 & 37 are arbitrary & carry no meaning. 302 int result = 17; 303 304 //You MUST keep this method in sync w/ the equals method 305 306 result = 37 * result + imageLocation.toString().hashCode(); 307 result = 37 * result + polarization.hashCode(); 308 result = 37 * result + frequency.hashCode(); 309 310 return result; 311 } 312 313 /** 314 * Compares this image link to {@code other} for order. 315 * <p> 316 * One link is deemed to be "less than" the other if its frequency 317 * is lower than that of the other. 318 * In the case that two links are for the same frequency, the 319 * polarization is used as a tie-breaker. If these are the same, 320 * the text of the image location URL is the final tie-breaker. 321 * The comments are not compared.</p> 322 * 323 * @param other the image link to which this one is compared. 324 * 325 * @return a negative integer, zero, or a positive integer as this link 326 * is less than, equal to, or greater than the other link. 327 */ 328 public int compareTo(SourceImageLink other) 329 { 330 //First compare the frequency 331 int answer = this.frequency.compareTo(other.frequency); 332 if (answer != 0) 333 return answer; 334 335 //Polarization 336 answer = this.polarization.compareTo(other.polarization); 337 if (answer != 0) 338 return answer; 339 340 //Ignore the comments property 341 342 //The link itself 343 return 344 this.imageLocation.toString().compareTo(other.imageLocation.toString()); 345 } 346 347 /* 348 public static void main(String[] args) 349 { 350 SourceBuilder builder = new SourceBuilder(); 351 for (int trial = 1; trial <= 10; trial++) 352 { 353 SourceImageLink l1 = builder.makeImageLink(); 354 SourceImageLink l2 = builder.makeImageLink(); 355 356 System.out.println(l1.equals(l2)); 357 System.out.println(l1.toHtmlAnchor()); 358 } 359 } 360 */ 361 }