001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojavax; 023import java.util.ArrayList; 024import java.util.List; 025import java.util.zip.Checksum; 026import org.biojava.utils.AbstractChangeable; 027import org.biojava.utils.ChangeEvent; 028import org.biojava.utils.ChangeSupport; 029import org.biojava.utils.ChangeVetoException; 030import org.biojavax.utils.CRC64Checksum; 031 032/** 033 * A basic DocRef implementation. 034 * @author Richard Holland 035 * @author Mark Schreiber 036 * @author George Waldon 037 * @since 1.5 038 */ 039 040public class SimpleDocRef extends AbstractChangeable implements DocRef { 041 042 private CrossRef crossref; 043 private List<DocRefAuthor> authors; 044 private String title; 045 private String location; 046 private String remark; 047 048 /** 049 * Creates a new document reference from the given immutable authors and 050 * location and title. Will throw exceptions if either authors or 051 * location are null, but a null title is allowable. 052 * @param authors The authors of the referenced document, as a set of DocRefAuthor instances. 053 * @param location The location of the document, e.g. the journal name and page range. 054 */ 055 public SimpleDocRef(List<DocRefAuthor> authors, String location) { 056 this(authors, location, null); 057 } 058 059 /** 060 * Creates a new document reference from the given immutable authors and 061 * location and title. Will throw exceptions if either authors or 062 * location are null, but a null title is allowable. 063 * @param authors The authors of the referenced document, as a string to be parsed 064 * with {@link DocRefAuthor.Tools#parseAuthorString(String)}. 065 * @param location The location of the document, eg. the journal name and page range. 066 */ 067 public SimpleDocRef(String authors, String location) { 068 this(DocRefAuthor.Tools.parseAuthorString(authors), location, null); 069 } 070 071 /** 072 * Creates a new document reference from the given immutable authors and 073 * location and title. Will throw exceptions if either authors or 074 * location are null, but a null title is allowable. 075 * @param authors The authors of the referenced document, as a string to be parsed 076 * with {@link DocRefAuthor.Tools#parseAuthorString(String)}. 077 * @param location The location of the document, e.g. the journal name and page range. 078 * @param title The title of the document. 079 */ 080 public SimpleDocRef(String authors, String location, String title) { 081 this(DocRefAuthor.Tools.parseAuthorString(authors), location, title); 082 } 083 084 /** 085 * Creates a new document reference from the given immutable authors and 086 * location and title. Will throw exceptions if either authors or 087 * location are null, but a null title is allowable. 088 * @param authors The authors of the referenced document, as a set of DocRefAuthor instances. 089 * @param location The location of the document, e.g. the journal name and page range. 090 * @param title The title of the document. 091 */ 092 public SimpleDocRef(List<DocRefAuthor> authors, String location, String title) { 093 if (authors==null) throw new IllegalArgumentException("Authors cannot be null"); 094 if (location==null) throw new IllegalArgumentException("Location cannot be null"); 095 this.crossref = null; 096 this.authors = new ArrayList<DocRefAuthor>(); 097 this.authors.addAll(authors); 098 this.title = title; 099 this.location = location; 100 this.remark = null; 101 } 102 103 /** 104 * Construct a doc ref with populated cross ref. 105 * @param authors 106 * @param location 107 * @param title 108 * @param crossRefKey 109 * @param crossRefValue 110 * @param crossRefVersion 111 */ 112 public SimpleDocRef(String authors, String location, String title, String crossRefKey, String crossRefValue, Integer crossRefVersion) { 113 this(DocRefAuthor.Tools.parseAuthorString(authors), location, title, crossRefKey, crossRefValue, crossRefVersion); 114 } 115 116 /** 117 * Construct a doc ref with populated cross ref. 118 * @param authors 119 * @param location 120 * @param title 121 * @param crossRefKey 122 * @param crossRefValue 123 * @param crossRefVersion 124 */ 125 public SimpleDocRef(List authors, String location, String title, String crossRefKey, String crossRefValue, Integer crossRefVersion) { 126 this(authors, location, title); 127 this.setCrossref((CrossRef) RichObjectFactory.getObject(SimpleCrossRef.class, new Object[]{crossRefKey, crossRefValue, crossRefVersion})); 128 } 129 130 // Hibernate requirement - not for public use. 131 protected SimpleDocRef() {} 132 133 /** 134 * {@inheritDoc} 135 */ 136 public void setRemark(String remark) throws ChangeVetoException { 137 if(this.remark!=null && this.remark.equals(remark)) return; 138 else if(this.remark==null && remark==null) return; 139 140 if(!this.hasListeners(DocRef.REMARK)) { 141 this.remark = remark; 142 } else { 143 ChangeEvent ce = new ChangeEvent( 144 this, 145 DocRef.REMARK, 146 remark, 147 this.remark 148 ); 149 ChangeSupport cs = this.getChangeSupport(DocRef.REMARK); 150 synchronized(cs) { 151 cs.firePreChangeEvent(ce); 152 this.remark = remark; 153 cs.firePostChangeEvent(ce); 154 } 155 } 156 } 157 158 // Hibernate requirement - not for public use. 159 void setCRC(String CRC) {} // ignore as field is a calculated value 160 161 /** 162 * {@inheritDoc} 163 */ 164 public void setCrossref(CrossRef crossref) throws ChangeVetoException { 165 if(this.crossref!=null && this.crossref.equals(crossref)) return; 166 else if(this.crossref==null && crossref==null) return; 167 168 if(!this.hasListeners(DocRef.CROSSREF)) { 169 this.crossref = crossref; 170 } else { 171 ChangeEvent ce = new ChangeEvent( 172 this, 173 DocRef.CROSSREF, 174 crossref, 175 this.crossref 176 ); 177 ChangeSupport cs = this.getChangeSupport(DocRef.CROSSREF); 178 synchronized(cs) { 179 cs.firePreChangeEvent(ce); 180 this.crossref = crossref; 181 cs.firePostChangeEvent(ce); 182 } 183 } 184 } 185 186 // Hibernate requirement - not for public use. 187 void setAuthors(String authors) { this.authors = DocRefAuthor.Tools.parseAuthorString(authors); } 188 189 // Hibernate requirement - not for public use. 190 void setLocation(String location) { this.location = location; } 191 192 // Hibernate requirement - not for public use. 193 void setTitle(String title) { this.title = title; } 194 195 /** 196 * {@inheritDoc} 197 */ 198 public String getAuthors() { return DocRefAuthor.Tools.generateAuthorString(this.authors, true); } 199 200 /** 201 * {@inheritDoc} 202 */ 203 public List<DocRefAuthor> getAuthorList() { return new ArrayList(this.authors); } 204 205 /** 206 * {@inheritDoc} 207 * The string to be checksummed is constructed by concatenating the authors, 208 * title, and location in that order, with no space between. If any values are 209 * null they are substituted with the text "<undef>". 210 * @see CRC64Checksum 211 */ 212 public String getCRC() { 213 StringBuffer sb = new StringBuffer(); 214 sb.append(this.getAuthors()); 215 sb.append((this.title==null || this.title.equals(""))?"<undef>":this.title); 216 sb.append((this.location==null || this.location.equals(""))?"<undef>":this.location); 217 Checksum cs = new CRC64Checksum(); 218 cs.update(sb.toString().getBytes(), 0, sb.length()); 219 return cs.toString(); 220 } 221 222 /** 223 * {@inheritDoc} 224 */ 225 public String getRemark() { return this.remark; } 226 227 /** 228 * {@inheritDoc} 229 */ 230 public CrossRef getCrossref() { return this.crossref; } 231 232 /** 233 * {@inheritDoc} 234 */ 235 public String getLocation() { return this.location; } 236 237 /** 238 * {@inheritDoc} 239 */ 240 public String getTitle() { return this.title; } 241 242 /** 243 * {@inheritDoc} 244 * Document references are compared first by author, then by location, then 245 * by title. If Author and location are equal and this title is null, 246 * and theirs isn't, then this will return -1. 247 * For symmetry if our title is not null and theirs is then we return 1. If 248 * both are null then we return 0. 249 */ 250 public int compareTo(Object o) { 251 if(o == this) return 0; 252 // Hibernate comparison - we haven't been populated yet 253 if (this.authors==null) return -1; 254 // Normal comparison 255 DocRef them = (DocRef)o; 256 if (!this.getAuthors().equals(them.getAuthors())) return this.getAuthors().compareTo(them.getAuthors()); 257 else if (!this.getLocation().equals(them.getLocation())) return this.getLocation().compareTo(them.getLocation()); 258 else if (this.getTitle()==null) { 259 if (them.getTitle()==null) return 0; 260 else return -1; 261 } 262 else if (this.getTitle() != null && them.getTitle() == null) return 1; //other cases are handled above. 263 else return this.getTitle().compareTo(them.getTitle()); 264 } 265 266 /** 267 * {@inheritDoc} 268 * Document references are equal if they have the same author and location and title. 269 */ 270 public boolean equals(Object obj) { 271 if(this == obj) return true; 272 if (obj==null || !(obj instanceof DocRef)) return false; 273 // Hibernate comparison - we haven't been populated yet 274 if (this.authors==null) return false; 275 // Normal comparison 276 DocRef them = (DocRef)obj; 277 return (this.getAuthors().equals(them.getAuthors()) && 278 this.getLocation().equals(them.getLocation()) && 279 ( 280 (this.getTitle()==them.getTitle()) || 281 (this.getTitle()!=null && this.getTitle().equals(them.getTitle())) 282 ) 283 ); 284 } 285 286 /** 287 * {@inheritDoc} 288 */ 289 public int hashCode() { 290 int code = 17; 291 // Hibernate comparison - we haven't been populated yet 292 if (this.authors==null) return code; 293 // Normal comparison 294 code = 37*code + this.getAuthors().hashCode(); 295 code = 37*code + this.location.hashCode(); 296 if (this.title!=null) code = 37*code + this.title.hashCode(); 297 return code; 298 } 299 300 /** 301 * {@inheritDoc} 302 * Form: "authors; location" 303 */ 304 public String toString() { 305 return this.getAuthors()+"; "+this.getLocation(); 306 } 307 308 // Hibernate requirement - not for public use. 309 private Integer id; 310 311 /** 312 * Gets the Hibernate ID. Should be used with caution. 313 * @return the Hibernate ID, if using Hibernate. 314 */ 315 public Integer getId() { return this.id; } 316 317 /** 318 * Sets the Hibernate ID. Should be used with caution. 319 * @param id the Hibernate ID, if using Hibernate. 320 */ 321 public void setId(Integer id) { this.id = id;} 322 323} 324