import {Injectable} from '@angular/core'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import {BehaviorSubject, from, Observable, of, Subscriber, throwError, zip} from 'rxjs'; import {AutoCompleteValue} from '../../searchPages/searchUtils/searchHelperClasses.class'; import {EnvProperties} from '../properties/env-properties'; import {catchError, map} from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class ISVocabulariesService { private vocabularies: Map> = new Map>(); private provenanceActionVocabulary: BehaviorSubject<{}> = new BehaviorSubject(null); private subscriptions = []; constructor(private http: HttpClient) {} ngOnDestroy() { this.clearSubscriptions(); } clearSubscriptions() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscriber) { subscription.unsubscribe(); } }); } getVocabularyByType(field: string, entity: string, properties: EnvProperties): Observable { //console.log("getVocabulary field: "+ field + " for entity: "+ entity); var file = ""; var vocabulary = ""; if (field == "lang") { // file="languages.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:languages.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if (field == "type" && (entity == "publication")) { // file = "publicationTypes.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:publication_resource.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if (field == "type" && (entity == "dataset")) { // file = "dnet:dataCite_resource.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:dataCite_resource.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if (field == "type" && (entity == "software" || entity == "other")) { return of([]); } else if (field == "type" && entity == "result" ) { //return Observable.zip(this.getVocabularyFromService("dnet:publication_resource.json", properties),this.getVocabularyFromService("dnet:dataCite_resource.json", properties)); return zip(from(this.getVocabularyFromServiceAsync("dnet:publication_resource.json", properties)),from(this.getVocabularyFromServiceAsync("dnet:dataCite_resource.json", properties))); } else if (field == "access" && (entity == "publication" || entity == "dataset" || entity == "software" || entity == "other" || entity == "result")) { // file= "accessMode.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:access_modes.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if ((field == "type") && (entity == "dataprovider")) { // file = "dataProviderType.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:datasource_typologies.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if (field == "compatibility" && (entity == "dataprovider")) { // file = "dataProviderCompatibility.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:datasourceCompatibilityLevel.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } else if (field == "country") { // file = "countries.json"; // return this.getVocabularyFromFile(file); vocabulary = "dnet:countries.json"; //return this.getVocabularyFromService(vocabulary, properties); return from(this.getVocabularyFromServiceAsync(vocabulary, properties)); } return null; } async getVocabularyFromServiceAsync(vocabularyName: string, properties: EnvProperties): Promise { if(!this.vocabularies.has(vocabularyName)) { await new Promise(resolve => { this.vocabularies.set(vocabularyName, new BehaviorSubject(null)); this.subscriptions.push(this.getVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { this.vocabularies.get(vocabularyName).next(vocabularyRes); resolve(); }, error => { this.vocabularies.get(vocabularyName).next(null); resolve(); } )); }); this.clearSubscriptions(); } return this.vocabularies.get(vocabularyName).getValue(); } getVocabularyFromService(vocabularyName: string, properties: EnvProperties): Observable { let url = properties.vocabulariesAPI + vocabularyName; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) //.map(res => res.json()) .pipe(map(res => res['terms'])) .pipe(map(res => this.parse(res, vocabularyName))) .pipe(catchError(this.handleError)); } parse(data: any, vocabularyName: string): AutoCompleteValue[] { var array: AutoCompleteValue[] = [] for (var i = 0; i < data.length; i++) { var value: AutoCompleteValue = new AutoCompleteValue(); value.id = data[i].englishName;//data[i].code; if (vocabularyName == 'dnet:countries.json') { //use Country code instead of country name value.id = data[i].code; } value.label = data[i].englishName; array.push(value); } return array; } getProvenanceActionVocabulary(properties: EnvProperties): Observable { let vocabulary = "dnet:provenanceActions.json"; return from(this.getProvenanceActionVocabularyFromServiceAsync(vocabulary, properties)); } async getProvenanceActionVocabularyFromServiceAsync (vocabularyName: string, properties: EnvProperties): Promise<{}> { if(!this.provenanceActionVocabulary || !this.provenanceActionVocabulary.getValue()) { await new Promise(resolve => { this.subscriptions.push(this.getProvenanceActionVocabularyFromService(vocabularyName, properties).subscribe( vocabularyRes => { this.provenanceActionVocabulary.next(vocabularyRes); resolve(); }, error => { this.provenanceActionVocabulary.next(null); resolve(); } )); }); this.clearSubscriptions(); } return this.provenanceActionVocabulary.getValue(); } getProvenanceActionVocabularyFromService (vocabularyName: string, properties: EnvProperties): any { let url = properties.vocabulariesAPI+vocabularyName; return this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url) .pipe(map(res => res['terms'])) .pipe(map(res => this.parseProvenanceActionVocabulary(res))); } parseProvenanceActionVocabulary(terms: any) { var provenanceActionVocabulary: {} = {}; for(let term of terms) { provenanceActionVocabulary[term.code] = term.englishName; } return provenanceActionVocabulary; } private handleError(error: HttpErrorResponse) { // in a real world app, we may send the error to some remote logging infrastructure // instead of just logging it to the console console.log(error); return throwError(error || 'Server error'); } }