3 * Copyright (C) 2009 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.ext
.ipni
;
12 import java
.io
.BufferedReader
;
13 import java
.io
.IOException
;
14 import java
.io
.InputStream
;
15 import java
.io
.InputStreamReader
;
16 import java
.net
.HttpURLConnection
;
17 import java
.net
.MalformedURLException
;
19 import java
.net
.URISyntaxException
;
21 import java
.text
.ParseException
;
22 import java
.util
.ArrayList
;
23 import java
.util
.HashMap
;
24 import java
.util
.List
;
27 import org
.apache
.commons
.lang
.StringUtils
;
28 import org
.apache
.http
.HttpResponse
;
29 import org
.apache
.log4j
.Logger
;
30 import org
.springframework
.stereotype
.Component
;
32 import eu
.etaxonomy
.cdm
.api
.application
.ICdmApplicationConfiguration
;
33 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
34 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
35 import eu
.etaxonomy
.cdm
.common
.UriUtils
;
36 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
37 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
38 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
39 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
40 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
41 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
42 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
43 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
44 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
45 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
46 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
47 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
48 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
49 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
50 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
51 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
52 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
53 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceFactory
;
54 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
55 import eu
.etaxonomy
.cdm
.strategy
.parser
.TimePeriodParser
;
60 * @created Aug 16, 2010
63 * TODO the whole ipni service should be refactored to use UriUtils. I did this for the queryService method only because we ran into timeout
64 * problems in tests. UriUtils handles these problems already.
68 public class IpniService
implements IIpniService
{
69 private static final String EAST_OR_WEST
= "East or west";
71 private static final String NORTH_OR_SOUTH
= "North or south";
73 private static final String LATITUDE_SECONDS
= "Latitude seconds";
75 private static final String LATITUDE_MINUTES
= "Latitude minutes";
77 private static final String LATITUDE_DEGREES
= "Latitude degrees";
79 private static final String COLLECTION_DATE_AS_TEXT
= "Collection date as text";
81 private static final String COLLECTION_DAY1
= "Collection day1";
83 private static final String COLLECTION_MONTH1
= "Collection month1";
85 private static final String COLLECTION_YEAR1
= "Collection year1";
87 private static final String COLLECTION_DAY2
= "Collection day2";
89 private static final String COLLECTION_MONTH2
= "Collection month2";
91 private static final String COLLECTION_YEAR2
= "Collection year2";
93 private static final String COLLECTION_NUMBER
= "Collection number";
95 private static final String COLLECTOR_TEAM_AS_TEXT
= "Collector team as text";
97 private static final String LOCALITY
= "Locality";
99 private static final String TYPE_REMARKS
= "Type remarks";
101 private static final Logger logger
= Logger
.getLogger(IpniService
.class);
104 public static String ID
= "Id";
105 public static String VERSION
= "Version";
106 public static final String REMARKS
= "Remarks";
109 public static final String FULL_NAME_WITHOUT_FAMILY_AND_AUTHORS
= "Full name without family and authors";
110 public static final String AUTHORS
= "Authors";
111 public static final String FAMILY
= "Family";
112 public static final String GENUS
= "Genus";
113 public static final String INFRA_GENUS
= "Infra genus";
114 public static final String SPECIES
= "Species";
115 public static final String INFRA_SPECIFIC
= "Infra species";
116 public static final String RANK
= "Rank";
117 public static final String BASIONYM_AUTHOR
= "Basionym author";
118 public static final String PUBLISHING_AUTHOR
= "Publishing author";
119 public static final String PUBLICATION
= "Publication";
120 public static final String PUBLICATION_YEAR_FULL
= "Publication year full";
121 public static final String NAME_STATUS
= "Name status";
122 public static final String BASIONYM
= "Basionym";
123 public static final String REPLACED_SYNONYM
= "Replaced synonym";
128 public static final String STANDARD_FORM
= "Standard Form";
130 public static final String DEFAULT_AUTHOR_FORENAME
= "Default author forename";
131 public static final String DEFAULT_AUTHOR_SURNAME
= "Default author surname";
132 public static final String TAXON_GROUPS
= "Taxon groups";
133 public static final String DATES
= "Dates";
134 public static final String ALTERNATIVE_NAMES
= "Alternative names";
136 public static final String DEFAULT_AUTHOR_NAME
= "Default author name";
138 public static final String NAME_NOTES
= "Name notes";
139 public static final String NAME_SOURCE
= "Name source";
140 public static final String DATE_TYPE_CODE
= "Date type code";
141 public static final String DATE_TYPE_STRING
= "Date type string";
143 public static final String ALTERNATIVE_ABBREVIATIONS
= "Alternative abbreviations";
144 public static final String EXAMPLE_OF_NAME_PUBLISHED
= "Example of name published";
149 public static final String ABBREVIATION
= "Abbreviation";
150 public static final String TITLE
= "Title";
151 public static final String BPH_NUMBER
= "BPH number";
152 public static final String ISBN
= "ISBN";
153 public static final String ISSN
= "ISSN";
154 public static final String AUTHORS_ROLE
= "Authors role";
155 public static final String EDITION
= "Edition";
156 public static final String DATE
= "Date";
157 public static final String IN_PUBLICATION_FACADE
= "In publication facade";
158 public static final String LC_NUMBER
= "LC number";
159 public static final String PLACE
= "Place";
160 public static final String PUBLICATION_AUTHOR_TEAM
= "Publication author team";
161 public static final String PRECEDED_BY
= "Preceded";
162 public static final String TL2_AUTHOR
= "TL2 author";
163 public static final String TL2_NUMBER
= "TL2 number";
164 public static final String TDWG_ABBREVIATION
= "TDWG abbreviation";
166 private enum ServiceType
{
172 public enum IpniRank
{
174 FAMILIAL ("Familial"),
175 INFRA_FAMILIAL ("Infrafamilial"),
177 INFRA_GENERIC("Infrageneric"),
178 SPECIFIC ("Specific"),
179 INFRA_SPECIFIC("InfraSpecific");
182 IpniRank(String strRank
){
183 this.strRank
= strRank
;
186 public static IpniRank
valueOf(Rank rank
){
189 }else if (rank
.isInfraSpecific()){
190 return INFRA_SPECIFIC
;
191 }else if (rank
.isSpecies()){
193 }else if (rank
.isInfraGeneric()){
194 return INFRA_GENERIC
;
195 }else if (rank
.isGenus()){
197 }else if (rank
.isLower(Rank
.FAMILY())){
198 return INFRA_FAMILIAL
;
199 }else if (rank
.isHigher(Rank
.SUBFAMILY())){
202 logger
.warn("Rank could not be transformed to ipni rank. Use ALL instead");
209 // private URL serviceUrl;
211 // ******************************** CONSTRUCTOR **************************************
213 // ****************************** METHODS ****************************************************/
217 * @see eu.etaxonomy.cdm.ext.ipni.IIpniService#getAuthors(java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration, eu.etaxonomy.cdm.ext.ipni.IpniServiceAuthorConfigurator)
219 public List
<Person
> getAuthors(String abbreviation
, String surname
, String forename
, String isoCountry
, ICdmApplicationConfiguration services
, IpniServiceAuthorConfigurator config
){
222 config
= new IpniServiceAuthorConfigurator();
226 abbreviation
= normalizeParameter(abbreviation
);
227 surname
= normalizeParameter(surname
);
228 isoCountry
= normalizeParameter(isoCountry
);
229 forename
= normalizeParameter(forename
);
231 DelimitedFormat format
= config
.getFormat();
233 String request
= "find_abbreviation=" + abbreviation
+
234 "&find_surname=" + surname
+
235 "&find_isoCountry=" + isoCountry
+
236 "&find_forename=" + forename
+
237 "&output_format=" + format
.parameter
;
239 return (List
)queryService(request
, services
, getServiceUrl(IIpniService
.AUTHOR_SERVICE_URL
), config
, ServiceType
.AUTHOR
);
244 * FIXME rewrote this method to rely on {@link UriUtils}. The whole class should be adjusted to reflect this change.
245 * Also see comments in the class' documentation block.
250 private List
<?
extends IdentifiableEntity
> queryService(String request
, ICdmApplicationConfiguration services
, URL serviceUrl
, IIpniServiceConfigurator config
, ServiceType serviceType
){
252 throw new NullPointerException("Ipni service configurator should not be null");
256 // create the request url
257 URL newUrl
= new URL(serviceUrl
.getProtocol(),
258 serviceUrl
.getHost(),
259 serviceUrl
.getPort(),
264 URI newUri
= newUrl
.toURI();
266 logger
.info("Firing request for URI: " + newUri
);
268 HttpResponse response
= UriUtils
.getResponse(newUri
, null);
270 int responseCode
= response
.getStatusLine().getStatusCode();
272 // get the content at the resource
273 InputStream content
= response
.getEntity().getContent();
275 List
<?
extends IdentifiableEntity
> result
;
276 if (serviceType
.equals(ServiceType
.AUTHOR
)){
277 result
= buildAuthorList(content
, services
, config
);
278 }else if (serviceType
.equals(ServiceType
.NAME
)){
279 result
= buildNameList(content
, services
, config
);
281 result
= buildPublicationList(content
, services
, config
);
283 if(responseCode
== HttpURLConnection
.HTTP_OK
){
286 //TODO error handling
287 logger
.error("No Http_OK");
290 } catch (IOException e
) {
291 logger
.error("No content for request: " + request
);
292 } catch (URISyntaxException e
) {
293 logger
.error("Given URL could not be transformed into URI", e
);
300 private List
<Reference
> buildPublicationList( InputStream content
, ICdmApplicationConfiguration services
, IIpniServiceConfigurator iConfig
) throws IOException
{
301 IpniServicePublicationConfigurator config
= (IpniServicePublicationConfigurator
)iConfig
;
303 List
<Reference
> result
= new ArrayList
<Reference
>();
304 BufferedReader reader
= new BufferedReader (new InputStreamReader(content
));
306 String headerLine
= reader
.readLine();
307 Map
<Integer
, String
> parameterMap
= getParameterMap(headerLine
);
309 String line
= reader
.readLine();
310 while (StringUtils
.isNotBlank(line
)){
311 Reference reference
= getPublicationFromLine(line
, parameterMap
, services
, config
);
312 result
.add(reference
);
313 line
= reader
.readLine();
322 * @param parameterMap
327 private Reference
getPublicationFromLine(String line
, Map
<Integer
, String
> parameterMap
, ICdmApplicationConfiguration appConfig
, IpniServicePublicationConfigurator config
) {
329 String
[] splits
= line
.split("%");
331 Map
<String
, String
> valueMap
= new HashMap
<String
, String
>();
332 for (int i
= 0; i
< splits
.length
; i
++){
333 valueMap
.put(parameterMap
.get(i
), splits
[i
]);
336 //create reference object
337 Reference ref
= ReferenceFactory
.newGeneric();
340 if (config
.isUseAbbreviationAsTitle() == true){
341 ref
.setTitle(valueMap
.get(ABBREVIATION
));
342 //TODO handle title as extension
344 ref
.setTitle(valueMap
.get(TITLE
));
345 //TODO handle abbreviation as extension
347 ref
.setIsbn(valueMap
.get(ISBN
));
348 ref
.setIssn(valueMap
.get(ISSN
));
349 ref
.setEdition(valueMap
.get(EDITION
));
350 ref
.setPlacePublished(valueMap
.get(PLACE
));
352 String author
= valueMap
.get(PUBLICATION_AUTHOR_TEAM
);
353 if (StringUtils
.isNotBlank(author
)){
354 Team team
= Team
.NewTitledInstance(author
, author
);
355 ref
.setAuthorTeam(team
);
359 String remarks
= valueMap
.get(REMARKS
);
360 Annotation annotation
= Annotation
.NewInstance(remarks
, AnnotationType
.EDITORIAL(), Language
.ENGLISH());
361 ref
.addAnnotation(annotation
);
364 String tl2AuthorString
= valueMap
.get(TL2_AUTHOR
);
365 if (ref
.getAuthorTeam() == null){
366 Team tl2Author
= Team
.NewTitledInstance(tl2AuthorString
, null);
367 ref
.setAuthorTeam(tl2Author
);
370 ref
.getAuthorTeam().setTitleCache(tl2AuthorString
, true);
371 ref
.addAnnotation(Annotation
.NewInstance(tl2AuthorString
, AnnotationType
.EDITORIAL(), Language
.ENGLISH()));
376 TimePeriod date
= TimePeriodParser
.parseString(valueMap
.get(DATE
));
377 ref
.setDatePublished(date
);
381 Reference citation
= getIpniCitation(appConfig
);
382 ref
.addSource(OriginalSourceType
.Lineage
, valueMap
.get(ID
), "Publication", citation
, valueMap
.get(VERSION
));
389 In publication facade
400 private List
<BotanicalName
> buildNameList( InputStream content
, ICdmApplicationConfiguration appConfig
, IIpniServiceConfigurator iConfig
) throws IOException
{
401 IpniServiceNamesConfigurator config
= (IpniServiceNamesConfigurator
)iConfig
;
402 List
<BotanicalName
> result
= new ArrayList
<BotanicalName
>();
403 BufferedReader reader
= new BufferedReader (new InputStreamReader(content
));
405 String headerLine
= reader
.readLine();
406 Map
<Integer
, String
> parameterMap
= getParameterMap(headerLine
);
408 String line
= reader
.readLine();
409 while (StringUtils
.isNotBlank(line
)){
410 BotanicalName name
= getNameFromLine(line
,parameterMap
, appConfig
);
412 line
= reader
.readLine();
420 private BotanicalName
getNameFromLine(String line
, Map
<Integer
, String
> parameterMap
, ICdmApplicationConfiguration appConfig
) {
421 //Id%Version%Standard form%Default author forename%Default author surname%Taxon groups%Dates%Alternative names
422 String
[] splits
= line
.split("%");
423 Map
<String
, String
> valueMap
= new HashMap
<String
, String
>();
425 for (int i
= 0; i
< splits
.length
; i
++){
426 valueMap
.put(parameterMap
.get(i
), splits
[i
]);
429 BotanicalName name
= BotanicalName
.NewInstance(null);
432 name
.setNameCache(valueMap
.get(FULL_NAME_WITHOUT_FAMILY_AND_AUTHORS
), true);
433 name
.setAuthorshipCache(valueMap
.get(AUTHORS
), true);
436 name
.setGenusOrUninomial(valueMap
.get(GENUS
));
437 name
.setInfraGenericEpithet(valueMap
.get(INFRA_GENUS
));
438 name
.setSpecificEpithet(valueMap
.get(SPECIES
));
439 name
.setInfraSpecificEpithet(valueMap
.get(INFRA_SPECIFIC
));
443 String rankStr
= nomalizeRank(valueMap
.get(RANK
));
444 name
.setRank(Rank
.getRankByNameOrIdInVoc(rankStr
, NomenclaturalCode
.ICNAFP
, true));
445 } catch (UnknownCdmTypeException e
) {
446 logger
.warn("Rank was unknown");
450 name
.setBasionymAuthorTeam(Team
.NewTitledInstance(valueMap
.get(BASIONYM_AUTHOR
), valueMap
.get(BASIONYM_AUTHOR
)));
451 name
.setCombinationAuthorTeam(Team
.NewTitledInstance(valueMap
.get(PUBLISHING_AUTHOR
), valueMap
.get(PUBLISHING_AUTHOR
)));
454 Reference ref
= ReferenceFactory
.newGeneric();
455 ref
.setTitleCache(valueMap
.get(PUBLICATION
));
456 TimePeriod datePublished
= TimePeriodParser
.parseString(valueMap
.get(PUBLICATION_YEAR_FULL
));
457 name
.setNomenclaturalReference(ref
);
460 NomenclaturalStatusType statusType
= null;
461 String statusString
= valueMap
.get(NAME_STATUS
);
462 if (StringUtils
.isNotBlank(statusString
)){
464 statusType
= NomenclaturalStatusType
.getNomenclaturalStatusTypeByAbbreviation(statusString
);
465 NomenclaturalStatus nomStatus
= NomenclaturalStatus
.NewInstance(statusType
);
466 name
.addStatus(nomStatus
);
467 } catch (UnknownCdmTypeException e
) {
468 logger
.warn("Name status not recognized: " + statusString
);
473 String remarks
= valueMap
.get(REMARKS
);
474 Annotation annotation
= Annotation
.NewInstance(remarks
, AnnotationType
.EDITORIAL(), Language
.ENGLISH());
475 name
.addAnnotation(annotation
);
478 BotanicalName basionym
= BotanicalName
.NewInstance(null);
479 basionym
.setTitleCache(valueMap
.get(BASIONYM
), true);
480 name
.addBasionym(basionym
);
483 BotanicalName replacedSynoynm
= BotanicalName
.NewInstance(null);
484 replacedSynoynm
.setTitleCache(valueMap
.get(REPLACED_SYNONYM
), true);
485 name
.addReplacedSynonym(replacedSynoynm
, null, null, null);
488 DerivedUnitFacade specimen
= DerivedUnitFacade
.NewInstance(SpecimenOrObservationType
.PreservedSpecimen
);
492 String collectionDateAsText
= valueMap
.get(COLLECTION_DATE_AS_TEXT
);
493 TimePeriod gatheringPeriod
= TimePeriodParser
.parseString(collectionDateAsText
);
496 gatheringPeriod
.setStartDay(getIntegerDateValueOrNull(valueMap
, COLLECTION_DAY1
));
497 gatheringPeriod
.setStartMonth(getIntegerDateValueOrNull(valueMap
, COLLECTION_MONTH1
));
498 gatheringPeriod
.setStartYear(getIntegerDateValueOrNull(valueMap
, COLLECTION_YEAR1
));
499 gatheringPeriod
.setEndDay(getIntegerDateValueOrNull(valueMap
, COLLECTION_DAY2
));
500 gatheringPeriod
.setEndMonth(getIntegerDateValueOrNull(valueMap
, COLLECTION_MONTH2
));
501 gatheringPeriod
.setEndYear(getIntegerDateValueOrNull(valueMap
, COLLECTION_YEAR2
));
502 } catch (IndexOutOfBoundsException e
) {
503 logger
.info("Exception occurred when trying to fill gathering period");
505 specimen
.setGatheringPeriod(gatheringPeriod
);
507 specimen
.setFieldNumber(valueMap
.get(COLLECTION_NUMBER
));
510 String team
= valueMap
.get(COLLECTOR_TEAM_AS_TEXT
);
511 Team collectorTeam
= Team
.NewTitledInstance(team
, team
);
512 specimen
.setCollector(collectorTeam
);
514 specimen
.setLocality(valueMap
.get(LOCALITY
));
517 String latDegrees
= CdmUtils
.Nz(valueMap
.get(LATITUDE_DEGREES
));
518 String latMinutes
= CdmUtils
.Nz(valueMap
.get(LATITUDE_MINUTES
));
519 String latSeconds
= CdmUtils
.Nz(valueMap
.get(LATITUDE_SECONDS
));
520 String direction
= CdmUtils
.Nz(valueMap
.get(NORTH_OR_SOUTH
));
521 String latitude
= latDegrees
+ "°" + latMinutes
+ "'" + latSeconds
+ "\"" + direction
;
523 String lonDegrees
= CdmUtils
.Nz(valueMap
.get(LATITUDE_DEGREES
));
524 String lonMinutes
= CdmUtils
.Nz(valueMap
.get(LATITUDE_MINUTES
));
525 String lonSeconds
= CdmUtils
.Nz(valueMap
.get(LATITUDE_SECONDS
));
526 direction
= CdmUtils
.Nz(valueMap
.get(EAST_OR_WEST
));
527 String longitude
= lonDegrees
+ "°" + lonMinutes
+ "'" + lonSeconds
+ "\"" + direction
;
530 specimen
.setExactLocationByParsing(longitude
, latitude
, null, null);
531 } catch (ParseException e
) {
532 logger
.info("Parsing exception occurred when trying to parse type exact location." + e
.getMessage());
533 } catch (Exception e
) {
534 logger
.info("Exception occurred when trying to read type exact location." + e
.getMessage());
539 Annotation typeAnnotation
= Annotation
.NewInstance(TYPE_REMARKS
, AnnotationType
.EDITORIAL(), Language
.DEFAULT());
540 specimen
.addAnnotation(typeAnnotation
);
544 //TODO "Type locations" , eg. holotype CAT ,isotype CAT ,isotype FI
546 //TODO Geographic unit as text
553 Reference citation
= getIpniCitation(appConfig
);
554 name
.addSource(OriginalSourceType
.Lineage
, valueMap
.get(ID
), "Name", citation
, valueMap
.get(VERSION
));
558 //SHORT Family, Infra family, Hybrid genus, Hybrid, Collation, Nomenclatural synonym, Distribution, Citation type
561 * Standardised basionym author flag,
562 * Standardised publishing author flag
564 Full name without family
565 Full name without authors
568 Standardised publication flag
570 publication year note
571 Publication year text
579 Replaced synonym Author team
582 Bibliographic reference
583 Bibliographic type info
586 Original taxon name author team
587 Original replaced synonym
588 Original replaced synonym author team
590 Original basionym author team
591 Original parent citation taxon name author team
592 Original taxon distribution
593 Original hybrid parentage
605 private Integer
getIntegerDateValueOrNull(Map
<String
, String
> valueMap
, String key
) {
607 Integer result
= Integer
.valueOf(valueMap
.get(key
));
612 } catch (NumberFormatException e
) {
613 if (logger
.isDebugEnabled()){
614 logger
.debug("Number Format exception for " + valueMap
.get(key
));
621 private String
nomalizeRank(String string
) {
622 String result
= string
.replace("spec.", "sp.");
627 private List
<Person
> buildAuthorList(InputStream content
, ICdmApplicationConfiguration services
, IIpniServiceConfigurator iConfig
) throws IOException
{
628 IpniServiceAuthorConfigurator config
= (IpniServiceAuthorConfigurator
)iConfig
;
629 List
<Person
> result
= new ArrayList
<Person
>();
630 BufferedReader reader
= new BufferedReader (new InputStreamReader(content
));
632 String headerLine
= reader
.readLine();
633 if (headerLine
!= null){
634 Map
<Integer
, String
> parameterMap
= getParameterMap(headerLine
);
636 String line
= reader
.readLine();
637 while (StringUtils
.isNotBlank(line
)){
638 Person author
= getAuthorFromLine(line
,parameterMap
, services
, config
);
640 line
= reader
.readLine();
649 private Map
<Integer
, String
> getParameterMap(String headerLine
) {
650 Map
<Integer
, String
> result
= new HashMap
<Integer
, String
>();
651 if ( headerLine
!= null ){
652 String
[] splits
= headerLine
.split("%");
653 for (int i
= 0; i
< splits
.length
; i
++){
654 result
.put(i
, splits
[i
]);
661 private Person
getAuthorFromLine(String line
, Map
<Integer
, String
> categoryMap
, ICdmApplicationConfiguration appConfig
, IpniServiceAuthorConfigurator config
) {
662 //Id%Version%Standard form%Default author forename%Default author surname%Taxon groups%Dates%Alternative names
663 String
[] splits
= line
.split("%");
664 Map
<String
, String
> valueMap
= new HashMap
<String
, String
>();
666 for (int i
= 0; i
< splits
.length
; i
++){
667 valueMap
.put(categoryMap
.get(i
), splits
[i
]);
670 Person person
= Person
.NewInstance();
672 person
.setNomenclaturalTitle(valueMap
.get(STANDARD_FORM
));
673 person
.setFirstname(valueMap
.get(DEFAULT_AUTHOR_FORENAME
));
674 person
.setLastname(valueMap
.get(DEFAULT_AUTHOR_SURNAME
));
676 Reference
<?
> citation
= getIpniCitation(appConfig
);
679 person
.addSource(OriginalSourceType
.Lineage
, valueMap
.get(ID
), "Author", citation
, valueMap
.get(VERSION
));
682 TimePeriod lifespan
= TimePeriodParser
.parseString(valueMap
.get(DATES
));
683 person
.setLifespan(lifespan
);
686 String alternativeNames
= valueMap
.get(ALTERNATIVE_NAMES
);
687 if (StringUtils
.isNotBlank(alternativeNames
)){
688 String
[] alternativeNameSplits
= alternativeNames
.split("%");
689 for (String alternativeName
: alternativeNameSplits
){
690 if (alternativeName
.startsWith(">")){
691 alternativeName
= alternativeName
.substring(1);
693 Extension
.NewInstance(person
, alternativeName
, ExtensionType
.INFORMAL_CATEGORY());
703 private Reference
getIpniCitation(ICdmApplicationConfiguration appConfig
) {
704 Reference
<?
> ipniReference
;
705 if (appConfig
!= null){
706 ipniReference
= appConfig
.getReferenceService().find(uuidIpni
);
707 if (ipniReference
== null){
708 ipniReference
= getNewIpniReference();
709 ipniReference
.setUuid(uuidIpni
);
710 appConfig
.getReferenceService().save(ipniReference
);
713 ipniReference
= getNewIpniReference();
715 return ipniReference
;
721 private Reference
getNewIpniReference() {
722 Reference
<?
> ipniReference
;
723 ipniReference
= ReferenceFactory
.newDatabase();
724 ipniReference
.setTitleCache("The International Plant Names Index (IPNI)");
725 return ipniReference
;
732 private String
normalizeParameter(String parameter
) {
733 String result
= CdmUtils
.Nz(parameter
).replace(" ", "+");
737 public List
<BotanicalName
> getNamesAdvanced(String family
, String genus
, String species
, String infraFamily
,
738 String infraGenus
, String infraSpecies
, String authorAbbrev
, Boolean includePublicationAuthors
,
739 Boolean includeBasionymAuthors
,
740 String publicationTitle
,
741 Boolean isAPNIRecord
,
744 Rank rankInRangeToReturn
,
745 Boolean sortByFamily
,
746 IpniServiceNamesConfigurator config
,
747 ICdmApplicationConfiguration services
){
748 IpniRank ipniRank
= IpniRank
.valueOf(rankInRangeToReturn
);
749 return getNamesAdvanced(family
, genus
, species
, infraFamily
, infraGenus
, infraSpecies
, authorAbbrev
, includePublicationAuthors
, includeBasionymAuthors
, publicationTitle
, isAPNIRecord
, isGCIRecord
, isIKRecord
, ipniRank
, sortByFamily
, config
, services
);
752 public List
<BotanicalName
> getNamesAdvanced(String family
, String genus
, String species
, String infraFamily
,
753 String infraGenus
, String infraSpecies
, String authorAbbrev
, Boolean includePublicationAuthors
,
754 Boolean includeBasionymAuthors
,
755 String publicationTitle
,
756 Boolean isAPNIRecord
,
759 IpniRank rankToReturn
,
760 Boolean sortByFamily
,
761 IpniServiceNamesConfigurator config
,
762 ICdmApplicationConfiguration services
) {
764 // find_rankToReturn=all&output_format=normal&find_sortByFamily=on&find_sortByFamily=off&query_type=by_query&back_page=plantsearch
768 config
= new IpniServiceNamesConfigurator();
772 family
= normalizeParameter(family
);
773 genus
= normalizeParameter(genus
);
774 species
= normalizeParameter(species
);
775 infraFamily
= normalizeParameter(infraFamily
);
776 infraGenus
= normalizeParameter(infraGenus
);
777 infraSpecies
= normalizeParameter(infraSpecies
);
778 authorAbbrev
= normalizeParameter(authorAbbrev
);
780 publicationTitle
= normalizeParameter(publicationTitle
);
782 DelimitedFormat format
= config
.getFormat();
785 "find_family=" + family
+
786 "&find_genus=" + genus
+
787 "&find_species=" + species
+
788 "&find_infrafamily=" + infraFamily
+
789 "&find_infragenus=" + infraGenus
+
790 "&find_infraspecies=" + infraSpecies
+
791 "&find_authorAbbrev=" + authorAbbrev
+
792 getBooleanParameter("&find_includePublicationAuthors=", includePublicationAuthors
, "on", "off") +
793 getBooleanParameter("&find_includeBasionymAuthors=", includePublicationAuthors
, "on", "off") +
794 getBooleanParameter("&find_find_isAPNIRecord=", includePublicationAuthors
, "on", "false") +
795 getBooleanParameter("&find_isGCIRecord=", includePublicationAuthors
, "on", "false") +
796 getBooleanParameter("&find_isIKRecord=", includePublicationAuthors
, "on", "false") +
799 "&find_publicationTitle=" + publicationTitle
+
800 "&output_format=" + format
.parameter
;
802 return (List
)queryService(request
, services
, getServiceUrl(IIpniService
.ADVANCED_NAME_SERVICE_URL
), config
, ServiceType
.NAME
);
806 private String
getBooleanParameter(String urlParamString
, Boolean booleanParameter
, String trueString
, String falseString
) {
808 if (booleanParameter
== null){
809 result
= getBooleanParameter(urlParamString
, true, trueString
, falseString
) + getBooleanParameter(urlParamString
, false, trueString
, falseString
);
810 }else if (booleanParameter
== true){
811 result
= urlParamString
+ trueString
;
813 result
= urlParamString
+ falseString
;
820 * @see eu.etaxonomy.cdm.ext.IIpniService#getNamesSimple(java.lang.String, eu.etaxonomy.cdm.ext.IIpniService.DelimitedFormat, eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration)
822 public List
<BotanicalName
> getNamesSimple(String wholeName
, ICdmApplicationConfiguration services
, IpniServiceNamesConfigurator config
){
824 config
= new IpniServiceNamesConfigurator();
828 // query_type=by_query&back_page=query_ipni.html
830 wholeName
= normalizeParameter(wholeName
);
832 DelimitedFormat format
= config
.getFormat();
834 String request
= "find_wholeName=" + wholeName
+
835 "&output_format=" + format
.parameter
;
837 return (List
)queryService(request
, services
, getServiceUrl(IIpniService
.SIMPLE_NAME_SERVICE_URL
), config
, ServiceType
.NAME
);
841 * @see eu.etaxonomy.cdm.ext.IIpniService#getPublications(java.lang.String, java.lang.String, boolean, eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration)
843 public List
<Reference
> getPublications(String title
, String abbreviation
, ICdmApplicationConfiguration services
, IpniServicePublicationConfigurator config
){
844 // http://www.uk.ipni.org/ipni/advPublicationSearch.do?find_title=Spe*plant*&find_abbreviation=&output_format=normal&query_type=by_query&back_page=publicationsearch
845 // http://www.uk.ipni.org/ipni/advPublicationSearch.do?find_title=*Hortus+Britannicus*&find_abbreviation=&output_format=delimited-classic&output_format=delimited
848 config
= new IpniServicePublicationConfigurator();
851 title
= normalizeParameter(title
);
852 abbreviation
= normalizeParameter(abbreviation
);
854 String request
= "find_title=" + title
+
855 "&find_abbreviation=" + abbreviation
+
856 "&output_format=" + DelimitedFormat
.CLASSIC
.parameter
;
858 List
<Reference
> result
= (List
)queryService(request
, services
, getServiceUrl(IIpniService
.PUBLICATION_SERVICE_URL
), config
, ServiceType
.PUBLICATION
);
867 private DelimitedFormat
getDefaultFormat() {
868 return DelimitedFormat
.SHORT
;
875 * @return the serviceUrl
877 public URL
getServiceUrl(String url
) {
880 serviceUrl
= new URL(url
);
881 } catch (MalformedURLException e
) {
882 throw new RuntimeException("This should not happen", e
);