2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26 package org.forester.phylogeny.data;
28 import java.io.IOException;
29 import java.io.Writer;
30 import java.util.ArrayList;
31 import java.util.List;
33 import org.forester.io.parsers.nhx.NHXtags;
34 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
35 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
36 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
37 import org.forester.util.ForesterUtil;
38 import org.forester.util.TaxonomyUtil;
40 public class Taxonomy implements PhylogenyData, MultipleUris, Comparable<Taxonomy> {
42 private String _scientific_name;
43 private String _common_name;
44 private List<String> _synonyms;
45 private String _authority;
46 private Identifier _identifier;
47 private String _taxonomy_code;
49 private List<Uri> _uris;
50 private List<String> _lineage;
57 public StringBuffer asSimpleText() {
62 public Uri getUri( final int index ) {
63 return getUris().get( index );
67 public void addUri( final Uri uri ) {
68 if ( getUris() == null ) {
69 setUris( new ArrayList<Uri>() );
75 public StringBuffer asText() {
76 final StringBuffer sb = new StringBuffer();
77 if ( getIdentifier() != null ) {
79 sb.append( getIdentifier().asSimpleText() );
82 if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
83 if ( sb.length() > 0 ) {
87 sb.append( getTaxonomyCode() );
90 if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
91 if ( sb.length() > 0 ) {
94 sb.append( getScientificName() );
95 if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
97 sb.append( getAuthority() );
101 if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
102 if ( sb.length() > 0 ) {
105 sb.append( getCommonName() );
111 public PhylogenyData copy() {
112 final Taxonomy t = new Taxonomy();
114 t.setTaxonomyCode( getTaxonomyCode() );
116 catch ( final PhyloXmlDataFormatException e ) {
119 t.setScientificName( getScientificName() );
120 t.setCommonName( getCommonName() );
121 t.setAuthority( getAuthority() );
122 for( final String syn : getSynonyms() ) {
123 t.getSynonyms().add( syn );
125 if ( getIdentifier() != null ) {
126 t.setIdentifier( ( Identifier ) getIdentifier().copy() );
129 t.setIdentifier( null );
132 t.setRank( new String( getRank() ) );
134 catch ( final PhyloXmlDataFormatException e ) {
137 if ( getUris() != null ) {
138 t.setUris( new ArrayList<Uri>() );
139 for( final Uri uri : getUris() ) {
141 t.getUris().add( uri );
145 if ( getLineage() != null ) {
146 t.setLineage( new ArrayList<String>() );
147 for( final String l : getLineage() ) {
149 t.getLineage().add( l );
157 public boolean equals( final Object o ) {
161 else if ( o == null ) {
164 else if ( o.getClass() != this.getClass() ) {
165 throw new IllegalArgumentException( "attempt to check [" + this.getClass() + "] equality to " + o + " ["
166 + o.getClass() + "]" );
169 return isEqual( ( Taxonomy ) o );
173 public String getAuthority() {
177 public String getCommonName() {
181 public Identifier getIdentifier() {
185 public String getRank() {
189 public String getScientificName() {
190 return _scientific_name;
193 public List<String> getSynonyms() {
194 if ( _synonyms == null ) {
195 _synonyms = new ArrayList<String>();
200 public String getTaxonomyCode() {
201 return _taxonomy_code;
205 public List<Uri> getUris() {
210 public int hashCode() {
211 if ( ( getIdentifier() != null ) && !ForesterUtil.isEmpty( getIdentifier().getValue() ) ) {
212 return getIdentifier().hashCode();
214 else if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
215 return getTaxonomyCode().hashCode();
217 else if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
218 if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
219 return ( getScientificName().toLowerCase() + getAuthority().toLowerCase() ).hashCode();
221 return getScientificName().toLowerCase().hashCode();
224 return getCommonName().toLowerCase().hashCode();
229 setScientificName( "" );
231 setIdentifier( null );
235 catch ( final PhyloXmlDataFormatException e ) {
239 setTaxonomyCode( "" );
241 catch ( final PhyloXmlDataFormatException e ) {
250 public boolean isEmpty() {
251 return ( ( getIdentifier() == null ) && ForesterUtil.isEmpty( getTaxonomyCode() )
252 && ForesterUtil.isEmpty( getCommonName() ) && ForesterUtil.isEmpty( getScientificName() )
253 && ForesterUtil.isEmpty( _lineage ) );
258 * If this and taxonomy 'data' has an identifier, comparison will be based on that.
259 * Otherwise, if this and taxonomy 'data' has a code, comparison will be based on that.
260 * Otherwise, if Taxonomy 'data' has a scientific name, comparison will be
261 * based on that (case insensitive!).
262 * Otherwise, if Taxonomy 'data' has a common name, comparison will be
263 * based on that (case insensitive!).
264 * (Note. This is important and should not be change without a very good reason.)
268 public boolean isEqual( final PhylogenyData data ) {
269 if ( this == data ) {
272 final Taxonomy tax = ( Taxonomy ) data;
273 if ( ( getIdentifier() != null ) && ( tax.getIdentifier() != null )
274 && !ForesterUtil.isEmpty( getIdentifier().getValue() )
275 && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) {
276 return getIdentifier().isEqual( tax.getIdentifier() );
278 else if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
279 return getTaxonomyCode().equals( tax.getTaxonomyCode() );
281 else if ( !ForesterUtil.isEmpty( getScientificName() ) && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
282 if ( !ForesterUtil.isEmpty( getAuthority() ) && !ForesterUtil.isEmpty( tax.getAuthority() ) ) {
283 return ( getScientificName().equalsIgnoreCase( tax.getScientificName() ) )
284 && ( getAuthority().equalsIgnoreCase( tax.getAuthority() ) );
286 return getScientificName().equalsIgnoreCase( tax.getScientificName() );
288 else if ( !ForesterUtil.isEmpty( getCommonName() ) && !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
289 return getCommonName().equalsIgnoreCase( tax.getCommonName() );
291 //throw new RuntimeException( "comparison not possible with empty fields" );
295 public void setAuthority( final String authority ) {
296 _authority = authority;
299 public void setCommonName( final String common_name ) {
300 _common_name = common_name;
303 public void setIdentifier( final Identifier identifier ) {
304 _identifier = identifier;
307 public void setRank( final String rank ) throws PhyloXmlDataFormatException {
308 if ( !ForesterUtil.isEmpty( rank ) && !TaxonomyUtil.TAXONOMY_RANKS_SET.contains( rank ) ) {
309 throw new PhyloXmlDataFormatException( "illegal rank: [" + rank + "]" );
314 public void setScientificName( final String scientific_name ) {
315 _scientific_name = scientific_name;
318 private void setSynonyms( final List<String> synonyms ) {
319 _synonyms = synonyms;
322 public void setTaxonomyCode( String taxonomy_code ) throws PhyloXmlDataFormatException {
323 if ( !ForesterUtil.isEmpty( taxonomy_code )
324 && !PhyloXmlUtil.TAXOMONY_CODE_PATTERN.matcher( taxonomy_code ).matches() ) {
325 throw new PhyloXmlDataFormatException( "illegal taxonomy code: [" + taxonomy_code + "]" );
327 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328 //TODO FIXME (added on 13-11-18) remove me eventually
329 if ( taxonomy_code.equals( "ACIBL" ) ) {
330 taxonomy_code = "KORVE";
332 else if ( taxonomy_code.equals( "PYRKO" ) ) {
333 taxonomy_code = "THEKO";
335 //TODO FIXME (added on 13-11-18) remove me eventually
336 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337 _taxonomy_code = taxonomy_code;
341 public void setUris( final List<Uri> uris ) {
346 public StringBuffer toNHX() {
347 final StringBuffer sb = new StringBuffer();
348 if ( getIdentifier() != null ) {
349 sb.append( ':' + NHXtags.TAXONOMY_ID );
350 sb.append( ForesterUtil.replaceIllegalNhxCharacters( getIdentifier().getValue() ) );
352 final StringBuffer species = new StringBuffer();
353 if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
354 species.append( ForesterUtil.replaceIllegalNhxCharacters( getTaxonomyCode() ) );
356 if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
357 ForesterUtil.appendSeparatorIfNotEmpty( species, '|' );
358 species.append( ForesterUtil.replaceIllegalNhxCharacters( getScientificName() ) );
360 if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
361 ForesterUtil.appendSeparatorIfNotEmpty( species, '|' );
362 species.append( ForesterUtil.replaceIllegalNhxCharacters( getCommonName() ) );
364 if ( species.length() > 0 ) {
365 sb.append( ':' + NHXtags.SPECIES_NAME );
366 sb.append( species );
372 public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
376 writer.write( ForesterUtil.LINE_SEPARATOR );
377 writer.write( indentation );
378 PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.TAXONOMY );
379 if ( ( getIdentifier() != null ) && !ForesterUtil.isEmpty( getIdentifier().getValue() ) ) {
380 getIdentifier().toPhyloXML( writer, level, indentation );
382 if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
383 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_CODE, getTaxonomyCode(), indentation );
385 if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
386 PhylogenyDataUtil.appendElement( writer,
387 PhyloXmlMapping.TAXONOMY_SCIENTIFIC_NAME,
391 if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
392 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_AUTHORITY, getAuthority(), indentation );
394 if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
395 PhylogenyDataUtil.appendElement( writer,
396 PhyloXmlMapping.TAXONOMY_COMMON_NAME,
400 if ( _synonyms != null ) {
401 for( final String syn : getSynonyms() ) {
402 if ( !ForesterUtil.isEmpty( syn ) ) {
403 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_SYNONYM, syn, indentation );
407 if ( !ForesterUtil.isEmpty( getRank() ) ) {
408 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_RANK, getRank(), indentation );
410 if ( getUris() != null ) {
411 for( final Uri uri : getUris() ) {
413 uri.toPhyloXML( writer, level, indentation );
417 if ( getLineage() != null ) {
418 final StringBuilder sb = new StringBuilder();
419 boolean first = true;
420 for( final String lin : getLineage() ) {
421 if ( !ForesterUtil.isEmpty( lin ) ) {
431 if ( sb.length() > 0 ) {
432 PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_LINEAGE, sb.toString(), indentation );
435 writer.write( ForesterUtil.LINE_SEPARATOR );
436 writer.write( indentation );
437 PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.TAXONOMY );
441 public String toString() {
442 return asText().toString();
446 public int compareTo( final Taxonomy o ) {
450 if ( ( getIdentifier() != null ) && ( o.getIdentifier() != null )
451 && !ForesterUtil.isEmpty( getIdentifier().getValue() )
452 && !ForesterUtil.isEmpty( o.getIdentifier().getValue() ) ) {
453 final int x = getIdentifier().getValuePlusProvider().compareTo( o.getIdentifier().getValuePlusProvider() );
458 if ( !ForesterUtil.isEmpty( getScientificName() ) && !ForesterUtil.isEmpty( o.getScientificName() ) ) {
459 return getScientificName().compareToIgnoreCase( o.getScientificName() );
461 if ( !ForesterUtil.isEmpty( getCommonName() ) && !ForesterUtil.isEmpty( o.getCommonName() ) ) {
462 return getCommonName().compareToIgnoreCase( o.getCommonName() );
464 if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) && !ForesterUtil.isEmpty( o.getTaxonomyCode() ) ) {
465 return getTaxonomyCode().compareToIgnoreCase( o.getTaxonomyCode() );
467 if ( ( getIdentifier() != null ) && ( o.getIdentifier() != null )
468 && !ForesterUtil.isEmpty( getIdentifier().getValue() )
469 && !ForesterUtil.isEmpty( o.getIdentifier().getValue() ) ) {
470 return getIdentifier().getValuePlusProvider().compareTo( o.getIdentifier().getValuePlusProvider() );
475 public void setLineage( final List<String> lineage ) {
479 public List<String> getLineage() {