Removed console outputs and added check for NameInformation response to add taxon...
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / NameCatalogueController.java
1 package eu.etaxonomy.cdm.remote.controller;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.LinkedHashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.UUID;
11
12 import javax.servlet.http.HttpServletRequest;
13 import javax.servlet.http.HttpServletResponse;
14
15 import java.util.Hashtable;
16 import org.springframework.beans.factory.annotation.Autowired;
17 import org.springframework.stereotype.Controller;
18 import org.springframework.web.bind.annotation.RequestMapping;
19 import org.springframework.web.bind.annotation.RequestMethod;
20 import org.springframework.web.bind.annotation.RequestParam;
21 import org.springframework.web.servlet.ModelAndView;
22
23 import eu.etaxonomy.cdm.api.service.IClassificationService;
24 import eu.etaxonomy.cdm.api.service.INameService;
25 import eu.etaxonomy.cdm.api.service.ITaxonService;
26
27 import eu.etaxonomy.cdm.remote.dto.common.ErrorResponse;
28 import eu.etaxonomy.cdm.remote.dto.common.RemoteResponse;
29 import eu.etaxonomy.cdm.remote.dto.namecatalogue.NameInformation;
30 import eu.etaxonomy.cdm.remote.dto.namecatalogue.NameSearch;
31 import eu.etaxonomy.cdm.remote.dto.namecatalogue.TaxonInformation;
32 import eu.etaxonomy.cdm.model.name.NonViralName;
33 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
34 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
35 import eu.etaxonomy.cdm.model.reference.Reference;
36 import eu.etaxonomy.cdm.model.taxon.Synonym;
37 import eu.etaxonomy.cdm.model.taxon.Taxon;
38 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
39 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
40 import eu.etaxonomy.cdm.persistence.query.MatchMode;
41
42 /**
43 * The controller class for the namespace 'name_catalogue'.
44 * This controller provides search mechanisims for searching by taxon name as well as taxon.
45 *
46 * @author c.mathew
47 * @version 1.0
48 * @created 15-Apr-2012
49 */
50
51 @Controller
52 @RequestMapping(value = {"/name_catalogue"})
53 public class NameCatalogueController extends BaseController<TaxonNameBase, INameService> {
54
55 /** Taxon status strings*/
56 public static final String ACCECPTED_NAME_STATUS = "accepted_name";
57 public static final String SYNONYM_STATUS = "synonym";
58
59 /** Flag strings*/
60 public static final String DOUBTFUL_FLAG = "doubtful";
61
62 @Autowired
63 private ITaxonService taxonService;
64
65 @Autowired
66 private IClassificationService classificationService;
67
68 private static final List<String> NAME_SEARCH_INIT_STRATEGY = Arrays.asList(new String []{
69 "combinationAuthorTeam.$",
70 "exCombinationAuthorTeam.$",
71 "basionymAuthorTeam.$",
72 "exBasionymAuthorTeam.$",
73 "taxonBases"
74 });
75
76 private static final List<String> NAME_INFORMATION_INIT_STRATEGY = Arrays.asList(new String []{
77 "taxonBases",
78 "status",
79 "nomenclaturalReference.$",
80 "combinationAuthorTeam.$",
81 "exCombinationAuthorTeam.$",
82 "basionymAuthorTeam.$",
83 "exBasionymAuthorTeam.$",
84 "relationsToThisName.$",
85 "relationsFromThisName.$"
86 });
87
88 private static final List<String> TAXON_INFORMATION_INIT_STRATEGY = Arrays.asList(new String []{
89 "synonymRelations",
90 "taxonNodes",
91 "taxonNodes.classification"
92 });
93
94 private static final List<String> TAXON_NODE_INIT_STRATEGY = Arrays.asList(new String[]{
95 "taxon.sec",
96 "taxon.name",
97 "classification",
98 "classification.reference.$",
99 "classification.reference.authorTeam.$"
100 });
101
102 public NameCatalogueController(){
103 super();
104 setInitializationStrategy(Arrays.asList(new String[]{"$"})); //TODO still needed????
105 }
106
107 /* (non-Javadoc)
108 * @see eu.etaxonomy.cdm.remote.controller.GenericController#setService(eu.etaxonomy.cdm.api.service.IService)
109 */
110 @Autowired
111 @Override
112 public void setService(INameService service) {
113 this.service = service;
114 }
115
116 /**
117 * Returns a list of taxon names matching the <code>{query}</code> string pattern.
118 * Each of these taxon names is accompanied by a list of name uuids and
119 * a list of taxon uuids.
120 * <p>
121 * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>
122 *
123 * @param query
124 * The taxon name pattern(s) to query for. The query can contain wildcard characters ('*').
125 * The query can be performed with no wildcard or with the wildcard at the begin and / or end
126 * depending on the search pattern.
127 * @param request
128 * @param response
129 * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from
130 * {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}
131 * @throws IOException
132 */
133 @RequestMapping(value = {""},
134 method = RequestMethod.GET)
135 public ModelAndView doGetNameSearch(@RequestParam(value = "query", required = true) String[] queries,
136 HttpServletRequest request,
137 HttpServletResponse response) throws IOException {
138 ModelAndView mv = new ModelAndView();
139 List <RemoteResponse> nsList = new ArrayList<RemoteResponse>();
140 for(String query : queries ) {
141
142 String queryWOWildcards = getQueryWithoutWildCards(query);
143 MatchMode mm = getMatchModeFromQuery(query);
144 logger.info("doGetNameSearch()" + request.getServletPath() + " for query \"" + query + "\" without wild cards : " + queryWOWildcards + " and match mode : " + mm);
145 List<NonViralName> nameList = (List<NonViralName>)service.findNamesByTitleCache(queryWOWildcards, mm, NAME_SEARCH_INIT_STRATEGY);
146 if(nameList == null || !nameList.isEmpty()) {
147 NameSearch ns = new NameSearch();
148 ns.setRequest(query);
149
150 for (NonViralName nvn : nameList)
151 {
152 String titleCacheString = nvn.getTitleCache();
153 ns.addToResponseList(titleCacheString, nvn.getUuid().toString(), nvn.getTaxonBases());
154 }
155 nsList.add(ns);
156
157 } else {
158 ErrorResponse er = new ErrorResponse();
159 er.setErrorMessage("No Taxon Name for given query : " + query);
160 nsList.add(er);
161 }
162 }
163 mv.addObject(nsList);
164 return mv;
165 }
166
167 /**
168 * Returns information related to the taxon name matching the given <code>{nameUuid}</code>.
169 * The information includes the name string, relationships, rank, list of related lsids / taxon uuids, etc.
170 * <p>
171 * URI: <b>&#x002F;{datasource-name}&#x002F;name_catalogue</b>
172 *
173 * @param query
174 * The taxon name pattern(s) to query for. The query can contain wildcard characters ('*').
175 * The query can be performed with no wildcard or with the wildcard at the begin and / or end
176 * depending on the search pattern.
177 * @param request
178 * @param response
179 * @return a List of {@link NameSearch} objects each corresponding to a single query. These are built from
180 * {@TaxonNameBase} entities which are in turn initialized using the {@link #NAME_SEARCH_INIT_STRATEGY}
181 * @throws IOException
182 */
183 @RequestMapping(value = {"name"},
184 method = RequestMethod.GET)
185 public ModelAndView doGetNameInformation(@RequestParam(value = "nameUuid", required = true) String[] nameUuids,
186 HttpServletRequest request,
187 HttpServletResponse response) throws IOException {
188 ModelAndView mv = new ModelAndView();
189 List <RemoteResponse> niList = new ArrayList<RemoteResponse>();
190 for(String nameUuid : nameUuids ) {
191 logger.info("doGetNameInformation()" + request.getServletPath() + " for name uuid \"" + nameUuid + "\"");
192 NonViralName nvn = (NonViralName)service.findNameByUuid(UUID.fromString(nameUuid), NAME_INFORMATION_INIT_STRATEGY);
193 if(nvn != null) {
194 NameInformation ni = new NameInformation();
195 ni.setRequest(nameUuid);
196 Reference ref = (Reference) nvn.getNomenclaturalReference();
197 String citation = "";
198 String citation_details = "";
199 if(ref != null) {
200 citation = ref.getTitleCache();
201 }
202 ni.setResponse(nvn.getTitleCache(),
203 nvn.getRank().getTitleCache(),
204 nvn.getStatus(),
205 citation,
206 nvn.getRelationsFromThisName(),
207 nvn.getRelationsToThisName(),
208 nvn.getTaxonBases());
209 niList.add(ni);
210 } else {
211 ErrorResponse re = new ErrorResponse();
212 re.setErrorMessage("No Taxon Name for given UUID : " + nameUuid);
213 niList.add(re);
214 }
215 }
216 mv.addObject(niList);
217 return mv;
218 }
219
220 @RequestMapping(value = {"taxon"},
221 method = RequestMethod.GET)
222 public ModelAndView doGetTaxonInformation(@RequestParam(value = "taxonUuid", required = true) String[] taxonUuids,
223 HttpServletRequest request,
224 HttpServletResponse response) throws IOException {
225 ModelAndView mv = new ModelAndView();
226 List <RemoteResponse> tiList = new ArrayList<RemoteResponse>();
227 for(String taxonUuid : taxonUuids ) {
228 logger.info("doGetTaxonInformation()" + request.getServletPath() + " for taxon uuid \"" + taxonUuid);
229 TaxonBase tb= taxonService.findTaxonByUuid(UUID.fromString(taxonUuid), TAXON_INFORMATION_INIT_STRATEGY);
230 if(tb != null) {
231 TaxonInformation ti = new TaxonInformation();
232 ti.setRequest(taxonUuid);
233
234 if(tb.isInstanceOf(Taxon.class)) {
235 Taxon taxon = (Taxon)tb;
236 ti.setResponseTaxon(tb.getTitleCache(),
237 ACCECPTED_NAME_STATUS,
238 buildFlagMap(tb),
239 buildClassificationMap(taxon));
240 Set<Synonym> synonyms = taxon.getSynonyms();
241 for(Synonym syn: synonyms) {
242 String uuid = syn.getUuid().toString();
243 String name = syn.getTitleCache();
244 String status = SYNONYM_STATUS;
245 ti.addToResponseRelatedTaxa(taxonUuid, name, status, "");
246 }
247 } else if(tb instanceof Synonym) {
248 Synonym synonym = (Synonym)tb;
249 ti.setResponseTaxon(tb.getTitleCache(),
250 SYNONYM_STATUS,
251 buildFlagMap(tb),
252 null);
253 Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();
254 for(Taxon taxon : acceptedTaxa) {
255 String uuid = taxon.getUuid().toString();
256 String name = taxon.getTitleCache();
257 String status = ACCECPTED_NAME_STATUS;
258 ti.addToResponseRelatedTaxa(taxonUuid, name, status, "");
259 }
260 }
261 tiList.add(ti);
262 } else {
263 ErrorResponse re = new ErrorResponse();
264 re.setErrorMessage("No Taxon for given UUID : " + taxonUuid);
265 tiList.add(re);
266 }
267 }
268 mv.addObject(tiList);
269 return mv;
270 }
271
272 private MatchMode getMatchModeFromQuery(String query) {
273 if(query.startsWith("*") && query.endsWith("*")) {
274 return MatchMode.ANYWHERE;
275 } else if(query.startsWith("*")) {
276 return MatchMode.END;
277 } else if(query.endsWith("*")) {
278 return MatchMode.BEGINNING;
279 } else {
280 return MatchMode.EXACT;
281 }
282 }
283
284 private String getQueryWithoutWildCards(String query) {
285
286 String newQuery = query;
287
288 if(query.startsWith("*")) {
289 newQuery = newQuery.substring(1, newQuery.length());
290 }
291
292 if(query.endsWith("*")) {
293 newQuery = newQuery.substring(0, newQuery.length()-1);
294 }
295
296 return newQuery.trim();
297 }
298
299 private Map<String, String> buildFlagMap(TaxonBase tb) {
300 Map<String, String> flags = new Hashtable<String, String>();
301 flags.put(DOUBTFUL_FLAG, Boolean.toString(tb.isDoubtful()));
302 return flags;
303 }
304
305 private Map<String, Map> buildClassificationMap(Taxon taxon) {
306 Map<String, Map> classificationMap = new Hashtable<String, Map>();
307 Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
308
309 for(TaxonNode tn : taxonNodes) {
310 Map<String, String> classification = new LinkedHashMap<String, String>();
311 List<TaxonNode> tnList = classificationService.loadTreeBranchToTaxon(taxon, tn.getClassification(), null, TAXON_NODE_INIT_STRATEGY);
312 for(TaxonNode classificationtn : tnList) {
313
314 classification.put(classificationtn.getTaxon().getName().getRank().getTitleCache(),
315 classificationtn.getTaxon().getName().getTitleCache());
316 }
317
318 String cname = tn.getClassification().getTitleCache();
319 String [] words = cname.split("\\s+");
320 //"\\s+" in regular expression language meaning one or more spaces
321 StringBuilder builder = new StringBuilder();
322 for (String word : words){
323 builder.append(word);
324 }
325 cname = builder.toString();
326 classificationMap.put(cname, classification);
327 }
328 return classificationMap;
329 }
330
331
332 }