1 /* @source ajdas **************************************************************
2 **
3 ** support for DAS sequence data sources
4 **
5 ** @author Copyright (c) 2009 Mahmut Uludag
6 ** @version $Revision: 1.30 $
7 ** @modified $Date: 2012/12/07 10:20:44 $ by $Author: rice $
8 ** @@
9 **
10 ** This library is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU Lesser General Public
12 ** License as published by the Free Software Foundation; either
13 ** version 2.1 of the License, or (at your option) any later version.
14 **
15 ** This library is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** Lesser General Public License for more details.
19 **
20 ** You should have received a copy of the GNU Lesser General Public
21 ** License along with this library; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 ** MA 02110-1301, USA.
24 ******************************************************************************/
25
26 #include "ajdas.h"
27
28 #include "ajlib.h"
29 #include "ajfileio.h"
30 #include "ajhttp.h"
31 #include "ajsys.h"
32 #include "ajtime.h"
33 #include "ajtextread.h"
34
35 #include "expat.h"
36
37
38
39
40 static void dasRegistryElementstart(void *data, const XML_Char *name,
41 const XML_Char **atts);
42
43 static void dasEntrypointsElementstart(void *data, const XML_Char *name,
44 const XML_Char **atts);
45
46 static AjBool dasQueryParse(AjPFilebuff buff, void* results,
47 XML_StartElementHandler starth,
48 XML_CharacterDataHandler elementh);
49
50 static AjBool dasWriteDBdefinition(AjPFile cachef, const AjPDasSource source,
51 AjBool titleAndURI);
52
53
54
55
56 /* @func ajDasServerNew *******************************************************
57 **
58 ** Returns a new DasServer object
59 **
60 ** @return [AjPDasServer] DAS server object
61 **
62 ** @release 6.4.0
63 ******************************************************************************/
64
ajDasServerNew(void)65 AjPDasServer ajDasServerNew(void)
66 {
67 AjPDasServer ret = NULL;
68
69 AJNEW0(ret);
70
71 ret->host = ajStrNew();
72 ret->path = ajStrNew();
73 ret->port = 80;
74
75 ret->sources = ajListNew();
76
77 return ret;
78 }
79
80
81
82
83 /* @func ajDasServerDel *******************************************************
84 **
85 ** Delete DASserver object
86 **
87 ** @param [u] thys [AjPDasServer*] DASserver object
88 ** @return [void]
89 **
90 ** @release 6.4.0
91 ******************************************************************************/
92
ajDasServerDel(AjPDasServer * thys)93 void ajDasServerDel(AjPDasServer *thys)
94 {
95 AjPDasServer pthis = NULL;
96 AjPDasSource source;
97 AjPDasCoordinate coord;
98 AjIList iter;
99 AjIList iterc;
100
101 if(!thys)
102 return;
103
104 if(!*thys)
105 return;
106
107 pthis = *thys;
108
109 ajStrDel(&pthis->host);
110 ajStrDel(&pthis->path);
111
112 iter = ajListIterNew(pthis->sources);
113
114 while(!ajListIterDone(iter))
115 {
116 source = ajListIterGet(iter);
117 ajStrDel(&source->uri);
118 ajStrDel(&source->title);
119 ajStrDel(&source->description);
120 ajStrDel(&source->sequence_query_uri);
121 ajStrDel(&source->entry_points_uri);
122 ajStrDel(&source->features_query_uri);
123
124 iterc = ajListIterNew(source->coordinates);
125
126 while(!ajListIterDone(iterc))
127 {
128 coord = ajListIterGet(iterc);
129 ajStrDel(&coord->authority);
130 ajStrDel(&coord->source);
131 ajStrDel(&coord->taxid);
132 ajStrDel(&coord->test_range);
133 ajStrDel(&coord->uri);
134 ajStrDel(&coord->version);
135 AJFREE(coord);
136 }
137
138 ajListFree(&source->coordinates);
139 AJFREE(source);
140 ajListIterDel(&iterc);
141 }
142
143 ajListIterDel(&iter);
144 ajListFree(&pthis->sources);
145
146 AJFREE(pthis);
147
148 *thys = NULL;
149
150 return;
151 }
152
153
154
155
156 /* @func ajDasSegmentDel ******************************************************
157 **
158 ** Delete DAS segment objects returned by entry_points queries
159 **
160 ** @param [u] Psegment [AjPDasSegment*] DAS segment object
161 ** @return [void]
162 **
163 ** @release 6.4.0
164 ******************************************************************************/
165
ajDasSegmentDel(AjPDasSegment * Psegment)166 void ajDasSegmentDel(AjPDasSegment* Psegment)
167 {
168 if(Psegment==NULL || *Psegment==NULL)
169 return;
170
171 ajStrDel(&(*Psegment)->id);
172 ajStrDel(&(*Psegment)->type);
173 ajStrDel(&(*Psegment)->orientation);
174
175 AJFREE(*Psegment);
176
177 return;
178 }
179
180
181
182
183 /* @funcstatic dasRegistryElementstart ****************************************
184 **
185 ** Handler for reading DAS registry XML elements
186 **
187 ** @param [u] data [void*] structure for storing results
188 ** @param [r] name [const XML_Char*] XML element name
189 ** @param [r] atts [const XML_Char**] array of element attributes,
190 ** name/value pairs
191 ** @return [void]
192 **
193 ** @release 6.4.0
194 ******************************************************************************/
195
dasRegistryElementstart(void * data,const XML_Char * name,const XML_Char ** atts)196 static void dasRegistryElementstart(void *data, const XML_Char *name,
197 const XML_Char **atts)
198 {
199 AjPList sources = NULL;
200 AjPDasSource source = NULL;
201 const char* key = NULL;
202 const char* value = NULL;
203 const char* type = NULL;
204 const char* query_uri = NULL;
205
206 ajuint i;
207
208 sources = (AjPList) data;
209
210 ajDebug("dasRegistryElementstart: %s\n",name);
211
212 if(ajCharMatchCaseC("SOURCES",name))
213 return;
214
215 if(ajCharMatchCaseC(name,"SOURCE"))
216 {
217 AJNEW0(source);
218 source->coordinates = ajListNew();
219
220 for(i = 0; atts[i]; i += 2)
221 {
222 key = atts[i];
223 value = atts[i+1];
224
225 if(ajCharMatchC(key,"uri"))
226 ajStrAssignC(&source->uri,value);
227 else if(ajCharMatchC(key,"title"))
228 {
229 ajStrAssignC(&source->title,value);
230 ajStrTrimWhite(&source->title);
231 }
232 else if(ajCharMatchC(key,"description"))
233 ajStrAssignC(&source->description,value);
234 }
235
236 ajListPushAppend(sources,source);
237 }
238 else if(ajCharMatchCaseC(name,"CAPABILITY"))
239 {
240 ajListPeekLast(sources,(void**)&source);
241
242 for(i = 0; atts[i]; i += 2)
243 {
244 key = atts[i];
245 value = atts[i+1];
246
247 if(ajCharMatchC(key,"type"))
248 type = value;
249 else
250 query_uri = value;
251 }
252
253 if(ajCharMatchCaseC(type,"das1:features"))
254 {
255 source->features = ajTrue;
256 ajStrAssignC(&source->features_query_uri,query_uri);
257 }
258 else if(ajCharMatchCaseC(type,"das1:sequence"))
259 {
260 source->sequence = ajTrue;
261 ajStrAssignC(&source->sequence_query_uri,query_uri);
262 }
263 else if(ajCharMatchCaseC(type,"das1:entry_points"))
264 {
265 source->entry_points = ajTrue;
266 ajStrAssignC(&source->entry_points_uri,query_uri);
267 }
268 }
269 else if(ajCharMatchCaseC(name,"COORDINATES"))
270 {
271 AjPDasCoordinate coord;
272 AJNEW0(coord);
273 ajListPeekLast(sources,(void**)&source);
274
275 for(i = 0; atts[i]; i += 2)
276 {
277 key = atts[i];
278 value = atts[i+1];
279
280 if(ajCharMatchCaseC(key,"uri"))
281 ajStrAssignC(&coord->uri, value);
282 else if(ajCharMatchCaseC(key,"taxid"))
283 ajStrAssignC(&coord->taxid, value);
284 else if(ajCharMatchCaseC(key,"source"))
285 ajStrAssignC(&coord->source,value);
286 else if(ajCharMatchCaseC(key,"test_range"))
287 ajStrAssignC(&coord->test_range,value);
288 }
289
290 ajListPushAppend(source->coordinates,coord);
291 }
292 else if(!(ajCharMatchC(name,"MAINTAINER") ||
293 ajCharMatchC(name,"VERSION") ||
294 ajCharMatchC(name,"PROP")
295 ))
296 ajDebug("DAS 'sources' request returned an unknown tag: %s",name);
297
298 return;
299 }
300
301
302
303
304 /* @funcstatic dasEntrypointsElementstart *************************************
305 **
306 ** Handler for reading DAS entry-point XML elements
307 **
308 ** @param [u] data [void*] structure for storing results
309 ** @param [r] name [const XML_Char*] XML element name
310 ** @param [r] atts [const XML_Char**] array of name/value pairs
311 ** @return [void]
312 **
313 ** @release 6.4.0
314 ******************************************************************************/
315
dasEntrypointsElementstart(void * data,const XML_Char * name,const XML_Char ** atts)316 static void dasEntrypointsElementstart(void *data, const XML_Char *name,
317 const XML_Char **atts)
318 {
319 const char* key = NULL;
320 AjPStr value = NULL;
321
322 AjPList segments = data;
323 AjPDasSegment segment;
324
325 ajuint i;
326
327
328 ajDebug("dasEntrypointsElementstart: %s\n",name);
329
330 if(ajCharMatchCaseC("DASEP",name) || ajCharMatchCaseC("ENTRY_POINTS",name))
331 {
332 return;
333 }
334
335
336 if(!(ajCharMatchC(name,"SEGMENT")))
337 ajDebug("DAS 'entrypoints' request returned an unknown tag: %s",name);
338
339 {
340
341 AJNEW0(segment);
342
343 for(i = 0; atts[i]; i += 2)
344 {
345 key = atts[i];
346 value = ajStrNewC(atts[i+1]);
347
348 if(ajCharMatchC(key,"id"))
349 ajStrAssignS(&segment->id,value);
350 else if(ajCharMatchC(key,"start"))
351 {
352 ajStrToUint(value, &segment->start);
353 }
354 else if(ajCharMatchC(key,"stop"))
355 {
356 ajStrToUint(value, &segment->stop);
357 }
358 else if(ajCharMatchC(key,"subparts"))
359 {
360 ajStrToBool(value, &segment->subparts);
361 }
362 else if(ajCharMatchC(key,"orientation"))
363 {
364 ajStrAssignS(&segment->orientation,value);
365 }
366 else if(ajCharMatchC(key,"type"))
367 {
368 ajStrAssignS(&segment->type,value);
369 }
370
371 ajStrDel(&value);
372 }
373
374 ajListPushAppend(segments,segment);
375 }
376
377
378 return;
379 }
380
381
382
383
384 /* @func ajDasParseRegistry ***************************************************
385 **
386 ** Parses XML list of DAS sources, either coming from dasregistry.org
387 ** or from individual DAS servers supporting DAS 'sources' command
388 **
389 ** @param [u] buff [AjPFilebuff] XML input stream
390 ** @param [u] sources [AjPList] pointer to the data structure for storing
391 ** parser results of DAS/XML 'source' objects
392 ** @return [AjBool] True on success
393 **
394 ** @release 6.4.0
395 ******************************************************************************/
396
ajDasParseRegistry(AjPFilebuff buff,AjPList sources)397 AjBool ajDasParseRegistry(AjPFilebuff buff, AjPList sources)
398 {
399
400 return dasQueryParse(buff, sources, dasRegistryElementstart, NULL);
401 }
402
403
404
405
406 /* @func ajDasParseEntrypoints ************************************************
407 **
408 ** Parses XML list of DAS entry-points, either coming from dasregistry.org
409 ** or from individual DAS servers supporting DAS 'entry_points' command
410 **
411 ** @param [u] buff [AjPFilebuff] XML input stream
412 ** @param [u] segments [AjPList] pointer to the data structure for storing
413 ** parser results of DAS/XML 'segment' objects
414 ** @return [AjBool] True on success
415 **
416 ** @release 6.4.0
417 ******************************************************************************/
418
ajDasParseEntrypoints(AjPFilebuff buff,AjPList segments)419 AjBool ajDasParseEntrypoints(AjPFilebuff buff, AjPList segments)
420 {
421
422 return dasQueryParse(buff, segments, dasEntrypointsElementstart, NULL);
423 }
424
425
426
427
428 /* @func ajDasServerSethostS **************************************************
429 **
430 ** Set the DAS server host name
431 **
432 ** @param [u] server [AjPDasServer] DASserver object
433 ** @param [r] host [const AjPStr] DAS server host name
434 ** @return [AjBool] True on success
435 **
436 ** @release 6.4.0
437 ******************************************************************************/
438
ajDasServerSethostS(AjPDasServer server,const AjPStr host)439 AjBool ajDasServerSethostS(AjPDasServer server, const AjPStr host)
440 {
441 ajStrAssignS(&server->host, host);
442
443 return ajTrue;
444 }
445
446
447
448
449 /* @func ajDasServerSetpathS **************************************************
450 **
451 ** Set the DAS server URL path
452 **
453 ** @param [u] server [AjPDasServer] DASserver object
454 ** @param [r] path [const AjPStr] DAS server URL path
455 ** @return [AjBool] True on success
456 **
457 ** @release 6.4.0
458 ******************************************************************************/
459
ajDasServerSetpathS(AjPDasServer server,const AjPStr path)460 AjBool ajDasServerSetpathS(AjPDasServer server, const AjPStr path)
461 {
462 ajStrAssignS(&server->path, path);
463
464 return ajTrue;
465 }
466
467
468
469
470 /* @func ajDasServerSetport ***************************************************
471 **
472 ** Set the DAS server port
473 **
474 ** @param [u] server [AjPDasServer] DASserver object
475 ** @param [r] port [ajuint] DAS server port
476 ** @return [AjBool] True on success
477 **
478 ** @release 6.4.0
479 ******************************************************************************/
480
ajDasServerSetport(AjPDasServer server,ajuint port)481 AjBool ajDasServerSetport(AjPDasServer server, ajuint port)
482 {
483 server->port = port;
484
485 return ajTrue;
486 }
487
488
489
490
491 /* @func ajDasServerGetSources ************************************************
492 **
493 ** Makes an http request for getting either list of all DAS sources
494 ** or a particular DAS source on a given DAS server. Http response is parsed
495 ** and results are stored in server object's 'sources' attribute
496 **
497 ** @param [u] server [AjPDasServer] DAS server object
498 ** @param [r] cmd [const AjPStr] DAS 'sources' command, queries either
499 ** all DAS sources or a particular DAS source
500 ** @return [void]
501 **
502 ** @release 6.4.0
503 ******************************************************************************/
504
ajDasServerGetSources(AjPDasServer server,const AjPStr cmd)505 void ajDasServerGetSources(AjPDasServer server, const AjPStr cmd)
506 {
507 AjPStr cmdpath = ajStrNew();
508 AjPStr httpver = ajStrNew();
509 AjPStr dbname = ajStrNew();
510 AjPStr dbproxy = ajStrNew();
511 AjPTextin textin = ajTextinNewDatatype(AJDATATYPE_TEXT);
512
513 if(ajStrGetCharLast(server->path)!='/')
514 ajFmtPrintS(&cmdpath, "%S/%S", server->path, cmd);
515 else
516 ajFmtPrintS(&cmdpath, "%S%S", server->path, cmd);
517
518 ajFilebuffDel(&textin->Filebuff);
519
520 textin->Filebuff = ajHttpRead(httpver, dbname, dbproxy,
521 server->host, server->port, cmdpath);
522
523 if(textin->Filebuff)
524 {
525 ajFilebuffHtmlNoheader(textin->Filebuff);
526 ajDasParseRegistry(textin->Filebuff, server->sources);
527 }
528
529 ajTextinDel(&textin);
530 ajStrDel(&cmdpath);
531 ajStrDel(&httpver);
532 ajStrDel(&dbname);
533 ajStrDel(&dbproxy);
534 }
535
536
537
538
539 /* @func ajDasGetSequenceQueryURI *********************************************
540 **
541 ** Given a DAS server URL, returns sequence query URI for the DAS source
542 ** specified in user query.
543 **
544 ** It first makes a DAS source command/query for the specific DAS source.
545 ** If above fails then makes another query for all DAS sources
546 ** and checks them against the current DAS source.
547 **
548 ** @param [r] qry [const AjPQuery] sequence query object
549 ** @param [r] sourceURIorTitle [const AjPStr] DAS source URI or title
550 ** specified in current query
551 ** @return [AjPStr] sequence-query URI, null if not found
552 **
553 ** @release 6.4.0
554 ******************************************************************************/
555
ajDasGetSequenceQueryURI(const AjPQuery qry,const AjPStr sourceURIorTitle)556 AjPStr ajDasGetSequenceQueryURI(const AjPQuery qry,
557 const AjPStr sourceURIorTitle)
558 {
559 AjPDasServer server = NULL;
560 AjPDasSource source = NULL;
561 AjPStr host = NULL;
562 AjPStr path = NULL;
563 AjPStr cmd = NULL;
564 AjIList iter = NULL;
565
566 AjPStr ret = NULL;
567 ajint port = 80;
568 AjBool validresponse = ajTrue;
569
570 ajDebug("ajDasGetSequenceQueryURI: searching query URI for '%S'",
571 sourceURIorTitle);
572
573 if(!ajHttpQueryUrl(qry, &port, &host, &path))
574 {
575 ajStrDel(&host);
576 ajStrDel(&path);
577 return ajFalse;
578 }
579
580 server = ajDasServerNew();
581
582 ajDasServerSethostS(server,host);
583 ajDasServerSetport(server,port);
584 ajDasServerSetpathS(server,path);
585
586 /* first try direct source command */
587
588 ajFmtPrintS(&cmd, "sources/%S", sourceURIorTitle);
589 ajDasServerGetSources(server, cmd);
590
591 if (ajListGetLength(server->sources)==1)
592 {
593 ajListPeekFirst(server->sources, (void**)&source);
594
595 if(source == NULL || ajListGetLength(source->coordinates)==0)
596 {
597 ajDebug("DAS data source query '%S' didn't return a valid result",
598 cmd);
599 validresponse = ajFalse;
600 }
601 else if(source->sequence == ajFalse)
602 {
603 ajErr("DAS data source (%S,%S) doesn't support sequence queries",
604 source->uri, source->title);
605 ajStrDel(&host);
606 ajStrDel(&path);
607 ajDasServerDel(&server);
608 ajStrDel(&cmd);
609
610 return NULL;
611 }
612
613 if(validresponse && ajStrMatchS(sourceURIorTitle, source->uri))
614 {
615 if(source->sequence_query_uri!=NULL)
616 {
617 ret = ajStrNewRef(source->sequence_query_uri);
618 ajDebug("dasGetSequenceQueryURI: DAS source found "
619 "by direct query '%S'", ret);
620 }
621 else
622 {
623 //TODO: here we can try building the query_uri unless host
624 // is dasregistry.....
625 ajFmtPrintS(&ret, "%S",host);
626 ajWarn("server source description didn't have a query_uri...");
627 }
628 }
629 }
630
631 if(ret==NULL)
632 {
633 ajDebug("dasGetSequenceQueryURI: trying a full 'sources' query");
634 ajStrAssignC(&cmd, "sources");
635 ajDasServerGetSources(server, cmd);
636
637 iter = ajListIterNew(server->sources);
638
639 while(!ajListIterDone(iter))
640 {
641 source = ajListIterGet(iter);
642
643 if((ajStrMatchS(sourceURIorTitle, source->title) ||
644 ajStrMatchS(sourceURIorTitle, source->uri)))
645 {
646 if(source->sequence == ajFalse)
647 {
648 ajErr("DAS data source (%S,%S) doesn't support "
649 "sequence queries", source->uri, source->title);
650 ajStrDel(&host);
651 ajStrDel(&path);
652 ajDasServerDel(&server);
653 ajStrDel(&cmd);
654 ajListIterDel(&iter);
655
656 return NULL;
657 }
658
659 ret = ajStrNewRef(source->sequence_query_uri);
660 ajDebug("ajDasGetSequenceQueryURI: URI found '%S'", ret);
661 break;
662 }
663 }
664
665 ajListIterDel(&iter);
666 }
667
668 ajStrDel(&host);
669 ajStrDel(&path);
670 ajStrDel(&cmd);
671
672 ajDasServerDel(&server);
673
674 return ret;
675 }
676
677
678
679
680 /* @funcstatic dasQueryParse **************************************************
681 **
682 ** Parses DAS query responses
683 **
684 ** @param [u] buff [AjPFilebuff] buffer object holding DAS query response
685 ** @param [u] results [void*] object for storing parser output
686 ** @param [u] starth [XML_StartElementHandler] handler for processing
687 ** XML element attributes
688 ** @param [u] elementh [XML_CharacterDataHandler] handler for processing
689 ** XML element data
690 ** @return [AjBool] True on success
691 **
692 ** @release 6.4.0
693 ******************************************************************************/
694
dasQueryParse(AjPFilebuff buff,void * results,XML_StartElementHandler starth,XML_CharacterDataHandler elementh)695 static AjBool dasQueryParse(AjPFilebuff buff, void* results,
696 XML_StartElementHandler starth,
697 XML_CharacterDataHandler elementh)
698 {
699 XML_Parser parser = NULL;
700 AjPStr line = NULL;
701
702 int done;
703 size_t len;
704
705 if(!buff)
706 return ajFalse;
707
708 line = ajStrNew();
709 parser = XML_ParserCreate(NULL);
710
711 XML_SetElementHandler(parser, starth, NULL);
712
713 if(elementh!=NULL)
714 XML_SetCharacterDataHandler(parser, elementh);
715
716 XML_SetUserData(parser, results);
717
718 done = 0;
719
720 do
721 {
722 ajBuffreadLine(buff,&line);
723 done = ajFilebuffIsEmpty(buff);
724 len = ajStrGetLen(line);
725
726 if(!XML_Parse(parser, line->Ptr, len, done))
727 {
728 ajErr("Failed to parse received DAS response at line %d: '%s'",
729 XML_GetCurrentLineNumber(parser),
730 XML_ErrorString(XML_GetErrorCode(parser)));
731
732 XML_ParserFree(parser);
733 ajStrDel(&line);
734
735 return ajFalse;
736 }
737
738 } while (!done);
739
740 XML_ParserFree(parser);
741 ajStrDel(&line);
742
743 return ajTrue;
744 }
745
746
747
748
749 /* @func ajDasSourceGetDBname *************************************************
750 **
751 ** Returns an EMBOSS DB name for a given DAS source
752 **
753 ** @param [r] source [const AjPDasSource] DAS source object
754 ** @param [r] titleAndURI [AjBool] Include URI in name
755 ** @return [AjPStr] DB name
756 **
757 ** @release 6.4.0
758 ** @@
759 ******************************************************************************/
760
ajDasSourceGetDBname(const AjPDasSource source,AjBool titleAndURI)761 AjPStr ajDasSourceGetDBname(const AjPDasSource source, AjBool titleAndURI)
762 {
763 AjPStr dbname = NULL;
764
765 if (titleAndURI)
766 {
767 dbname = ajStrNewS(source->uri);
768
769 ajStrAppendK(&dbname, '_');
770
771 ajStrAppendS(&dbname, source->title);
772 }
773 else
774 dbname = ajStrNewS(source->title);
775
776 ajStrExchangeSetCC(&dbname, " \":+-()./", "_________");
777
778 ajStrTrimC(&dbname, "_");
779
780 ajStrTrimStartC(&dbname, "0123456789");
781
782 return dbname;
783 }
784
785
786
787
788 /* @func ajDasPrintCachefile **************************************************
789 **
790 ** Prints DB definition for the specified DAS server object
791 **
792 ** @param [r] server [const AjPDasServer] DAS server object
793 ** @param [w] cachef [AjPFile] server cachefile with DB definitions
794 ** @return [void]
795 **
796 ** @release 6.4.0
797 ** @@
798 ******************************************************************************/
799
ajDasPrintCachefile(const AjPDasServer server,AjPFile cachef)800 void ajDasPrintCachefile(const AjPDasServer server, AjPFile cachef)
801 {
802 AjPTime today = NULL;
803 AjIList iter = NULL;
804 AjPStr fname = NULL;
805
806 AjPTable titlecount = NULL;
807 AjPDasSource source = NULL;
808
809 AjPStr title = NULL;
810
811 ajuint* count = NULL;
812
813 titlecount = ajTablestrNewCaseConst(ajListGetLength(server->sources)+20);
814
815 fname = ajStrNewS(ajFileGetPrintnameS(cachef));
816
817 ajFilenameTrimPath(&fname);
818
819 today = ajTimeNewTodayFmt("cachefile");
820
821 ajFmtPrintF(cachef,"# %S %D\n\n", fname, today);
822
823 ajStrDel(&fname);
824 ajTimeDel(&today);
825
826 iter = ajListIterNew(server->sources);
827
828 while(!ajListIterDone(iter))
829 {
830 source = ajListIterGet(iter);
831
832 title = source->title;
833
834 count = ajTableFetchmodS(titlecount,title);
835
836 if (count != NULL)
837 {
838 (*count)++;
839 }
840 else
841 {
842 AJNEW(count);
843 *count = 1;
844 ajTablePut(titlecount, title, (void*)count);
845 }
846
847 }
848
849 ajListIterRewind(iter);
850
851
852 while(!ajListIterDone(iter))
853 {
854 source = ajListIterGet(iter);
855
856 title = source->title;
857
858 count = ajTableFetchmodS(titlecount,title);
859
860 dasWriteDBdefinition(cachef, source, *count>1);
861 }
862
863 ajListIterDel(&iter);
864 ajTableDelValdel(&titlecount, &ajMemFree);
865
866 return;
867 }
868
869
870
871
872 /* @funcstatic dasWriteDBdefinition *******************************************
873 **
874 ** Writes a DAS source DB definition to the specified cache-file
875 **
876 ** @param [u] cachef [AjPFile] cache file
877 ** @param [r] source [const AjPDasSource] DAS source object
878 ** @param [r] titleAndURI [AjBool] Include URI in name
879 ** @return [AjBool] True on success
880 **
881 ** @release 6.4.0
882 ** @@
883 ******************************************************************************/
884
dasWriteDBdefinition(AjPFile cachef,const AjPDasSource source,AjBool titleAndURI)885 static AjBool dasWriteDBdefinition(AjPFile cachef, const AjPDasSource source,
886 AjBool titleAndURI)
887 {
888 AjPStr entry = NULL;
889 ajint ibegin = 0;
890 ajint iend = 0;
891 ajlong i = 0;
892
893 AjPDasCoordinate coord = NULL;
894 AjIList coordsi = NULL;
895
896 AjPStr dbname = NULL;
897 AjPStr comment = NULL;
898 AjPStr type = NULL;
899 AjPStr format = NULL;
900 AjPStr url = NULL;
901 AjPStr example = NULL;
902 AjPStr taxon = NULL;
903 AjPStr fields = NULL;
904
905 if(!source->sequence && !source->features)
906 return ajFalse;
907
908 dbname = ajDasSourceGetDBname(source, titleAndURI);
909 comment = ajStrNewS(source->description);
910
911 ajStrExchangeKK(&comment, '"', '\'');
912 ajStrRemoveWhiteExcess(&comment);
913
914 coordsi = ajListIterNew(source->coordinates);
915
916 type = ajStrNew();
917 format = ajStrNew();
918 url = ajStrNew();
919 taxon = ajStrNew();
920
921 while(!ajListIterDone(coordsi))
922 {
923 coord = ajListIterGet(coordsi);
924
925 example = ajDasTestrangeParse(coord->test_range, &entry,
926 &ibegin, &iend);
927
928 if (source->sequence)
929 {
930 if(ajStrFindCaseC(coord->source, "nucleotide")!=-1 ||
931 ajStrFindCaseC(coord->source, "chromosome")!=-1 ||
932 ajStrFindCaseC(coord->source, "contig")!=-1 ||
933 ajStrFindCaseC(coord->source, "scaffold")!=-1)
934 ajStrAssignC(&type, "Nucleotide");
935 else if(ajStrFindCaseC(coord->source, "Protein")!=-1)
936 ajStrAssignC(&type,"Protein");
937 else
938 ajStrAssignC(&type,"Sequence");
939
940 ajStrAssignC(&format, "das");
941
942 ajStrAssignS(&url, source->sequence_query_uri);
943
944 if(!ajStrPrefixCaseC(url, "http://"))
945 ajStrInsertC(&url, 0, "http://");
946
947 i = ajStrFindlastC(url,"/sequence");
948
949 if(i != -1)
950 ajStrCutEnd(&url,ajStrGetLen(url) - (size_t) i);
951
952 }
953
954 if (source->features)
955 {
956 if(source->sequence)
957 {
958 ajStrAppendC(&type,", ");
959 ajStrAppendC(&format,", ");
960 }
961
962 if(ajStrFindCaseC(coord->source, "nucleotide")!=-1 ||
963 ajStrFindCaseC(coord->source, "chromosome")!=-1 ||
964 ajStrFindCaseC(coord->source, "contig")!=-1 ||
965 ajStrFindCaseC(coord->source, "scaffold")!=-1)
966 ajStrAppendC(&type, "Nucfeatures");
967 else if(ajStrFindCaseC(coord->source, "Protein")!=-1)
968 ajStrAppendC(&type, "Protfeatures");
969 else
970 ajStrAppendC(&type,"Features");
971
972 ajStrAppendC(&format, "dasgff");
973
974 if(ajStrGetLen(url) == 0)
975 {
976 ajStrAssignS(&url, source->features_query_uri);
977
978 if(!ajStrPrefixCaseC(url, "http://"))
979 ajStrInsertC(&url, 0, "http://");
980
981 i = ajStrFindlastC(url,"/features");
982
983 if(i != -1)
984 ajStrCutEnd(&url,ajStrGetLen(url)- (size_t) i);
985
986 }
987
988 fields = ajStrNewC("segment,type,category,categorize,feature_id");
989 }
990 else
991 fields = ajStrNewC("segment");
992
993 if (coord->taxid)
994 ajFmtPrintS(&taxon, " taxon: \"%S\"\n", coord->taxid);
995
996 ajFmtPrintF(cachef,
997 "DBNAME %S [\n"
998 " method: \"das\"\n"
999 " type: \"%S\"\n"
1000 "%S"
1001 " format: \"%S\"\n"
1002 " url: \"%S\"\n"
1003 " example: \"%S\"\n"
1004 " comment: \"%S\"\n"
1005 " hasaccession: \"N\"\n"
1006 " identifier: \"segment\"\n"
1007 " fields: \"%S\"\n"
1008 "]\n\n",
1009 dbname, type,
1010 taxon,
1011 format, url,
1012 example,
1013 comment,
1014 fields);
1015
1016 break; /* TODO: multiple coordinates */
1017 }
1018
1019 ajStrDel(&dbname);
1020 ajStrDel(&comment);
1021 ajStrDel(&type);
1022 ajStrDel(&format);
1023 ajStrDel(&url);
1024 ajStrDel(&url);
1025 ajStrDel(&example);
1026 ajStrDel(&taxon);
1027 ajStrDel(&fields);
1028
1029 ajStrDel(&entry);
1030
1031 ajListIterDel(&coordsi);
1032
1033 return ajTrue;
1034 }
1035
1036
1037
1038
1039 /* @func ajDasTestrangeParse **************************************************
1040 **
1041 ** Parses a DAS test_range attribute and returns sequence identifier, and
1042 ** 'begin' and 'end' positions if any.
1043 **
1044 ** @param [r] testrange [const AjPStr] DAS test_range string
1045 ** @param [w] id [AjPStr*] sequence identifier
1046 ** @param [w] ibegin [ajint*] sequence begin position
1047 ** @param [w] iend [ajint*] sequence end position
1048 ** @return [AjPStr] returns the example query in EMBOSS USA syntax
1049 **
1050 ** @release 6.4.0
1051 ** @@
1052 ******************************************************************************/
1053
ajDasTestrangeParse(const AjPStr testrange,AjPStr * id,ajint * ibegin,ajint * iend)1054 AjPStr ajDasTestrangeParse(const AjPStr testrange, AjPStr* id,
1055 ajint* ibegin, ajint* iend)
1056 {
1057 AjPStr tmp=NULL;
1058 AjPStrTok token;
1059 AjPStr ret = NULL;
1060
1061 *ibegin = 0;
1062 *iend = 0;
1063
1064 /* Parse the test_range string (identifier:begin,end) */
1065
1066 token = ajStrTokenNewC(testrange, ":,");
1067
1068 ret = ajStrNew();
1069
1070 if(!(ajStrTokenNextParseNoskip(token, id)))
1071 {
1072 ajStrTokenDel(&token);
1073 return ret;
1074 }
1075
1076 if(ajStrTokenNextParseNoskip(token, &tmp))
1077 {
1078 ajStrToInt(tmp, ibegin);
1079
1080 if(ajStrTokenNextParseNoskip(token, &tmp))
1081 {
1082 ajStrToInt(tmp, iend);
1083 ajFmtPrintS(&ret,"%S[%d:%d]", *id, *ibegin, *iend);
1084 }
1085 }
1086
1087 if(*iend == 0)
1088 ajStrAssignRef(&ret, *id);
1089
1090 ajStrTokenDel(&token);
1091 ajStrDel(&tmp);
1092
1093 return ret;
1094 }
1095