Project

General

Profile

1
package eu.dnetlib.parthenos.virtuoso;
2

    
3
import java.io.IOException;
4
import java.io.OutputStream;
5
import java.io.StringWriter;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9

    
10
import com.google.common.collect.Iterators;
11
import com.google.common.collect.Lists;
12
import eu.dnetlib.parthenos.publisher.ParthenosPublisherException;
13
import freemarker.template.Configuration;
14
import freemarker.template.Template;
15
import freemarker.template.TemplateException;
16
import org.apache.commons.io.IOUtils;
17
import org.apache.commons.lang3.StringUtils;
18
import org.apache.commons.logging.Log;
19
import org.apache.commons.logging.LogFactory;
20
import org.apache.http.HttpEntity;
21
import org.apache.http.HttpHeaders;
22
import org.apache.http.NameValuePair;
23
import org.apache.http.client.entity.UrlEncodedFormEntity;
24
import org.apache.http.client.methods.CloseableHttpResponse;
25
import org.apache.http.client.methods.HttpPost;
26
import org.apache.http.impl.client.CloseableHttpClient;
27
import org.apache.http.impl.client.HttpClients;
28
import org.apache.http.message.BasicNameValuePair;
29
import org.apache.http.util.EntityUtils;
30
import org.apache.jena.query.ResultSet;
31
import org.apache.jena.sparql.engine.http.QueryEngineHTTP;
32
import org.springframework.beans.factory.annotation.Autowired;
33
import org.springframework.beans.factory.annotation.Value;
34
import org.springframework.http.HttpStatus;
35
import org.springframework.web.bind.annotation.*;
36

    
37
/**
38
 * Created by Alessia Bardi on 31/01/2018.
39
 * Read-only API for virtuoso.
40
 *
41
 * //TODO: error handling (http://www.springboottutorial.com/spring-boot-exception-handling-for-rest-services)
42
 * //TODO: pagination
43
 * //TODO swagger documentation?
44
 *
45
 * @author Alessia Bardi
46
 */
47
@RestController
48
public class VirtuosoReadAPI {
49

    
50
	private static final Log log = LogFactory.getLog(VirtuosoReadAPI.class);
51

    
52
	@Value("${virtuoso.sparqlurl}")
53
	private String sparqlUrl;
54
	@Value("${virtuoso.pwd}")
55
	private String username;
56
	@Value("${virtuoso.pwd}")
57
	private String password;
58
	@Value("${virtuoso.uri.base.default}")
59
	private String defaultBaseURI;
60
	@Value("${virtuoso.connectionstring")
61
	private String virtuosoConnectionString;
62

    
63
	@Autowired
64
	private Configuration freemarkerConfig;
65

    
66
	@RequestMapping(value = "/virtuoso/apiSubjectsWithType", produces = { "application/json" }, method = RequestMethod.GET)
67
	public List<String> getSubjectsForApiWithType(@RequestParam final String api, @RequestParam final String typeNamespace, @RequestParam final String typeName, @RequestParam final int limit, @RequestParam final int offset){
68
		String fullTypeName = typeNamespace + typeName;
69
		log.debug(String.format("Getting subjects of type %s for API %s limit %d offset %d", fullTypeName, api, limit, offset));
70
		//if I add the ORDER BY the query is too slow: let's hope we are not getting the same subjects over and over again
71
		String queryForSubjectsTemplate = "DEFINE input:inference 'parthenos_rules' SELECT DISTINCT ?s WHERE { GRAPH ?g {?s a <%s> .} . GRAPH dnet:graph {?g dnet:collectedFrom <%s> .}} LIMIT %d OFFSET %d";
72
		String q = String.format(queryForSubjectsTemplate, fullTypeName, defaultBaseURI+api, limit, offset);
73
		log.debug("SPARQL query: "+q);
74
		final QueryEngineHTTP serviceRequest = new QueryEngineHTTP(sparqlUrl, q);
75
		ResultSet subjects = serviceRequest.execSelect();
76
		List<String> res = Lists.newArrayList(Iterators.filter(Iterators.transform(subjects, qs -> qs.getResource("s").getURI()), input -> input.startsWith("http")));
77
		serviceRequest.close();
78
		return res;
79
	}
80

    
81

    
82
	@RequestMapping(value = "/virtuoso/subject", produces = { "application/rdf+xml", "application/xml" }, method = RequestMethod.GET)
83
	@ResponseStatus(value = HttpStatus.OK)
84
	public void getSubject(@RequestParam final String subjectURL, @RequestParam final String typeName, @RequestParam(name="timeout") final String timeoutMs, final OutputStream responseStream)
85
			throws IOException, TemplateException, ParthenosPublisherException {
86

    
87
		sendConstructResponse(generateQuery(subjectURL, typeName), timeoutMs, responseStream);
88
	}
89

    
90
	public String getRDF(final String subjectURL, final String typeName, final String apiId, final String timeoutMs)
91
			throws IOException, TemplateException, ParthenosPublisherException {
92

    
93
		return executeSparqlPost(generateQuery(subjectURL, typeName), timeoutMs);
94
	}
95

    
96
	protected String generateQuery(final String subjectURL, final String typeName) throws IOException, TemplateException {
97
		String templateName = typeName+".sparql";
98
		Template temp = freemarkerConfig.getTemplate(templateName);
99
		Map<String, String> values = new HashMap<>();
100
		values.put("subjectURL", subjectURL);
101

    
102
		StringWriter sw = new StringWriter();
103
		temp.process(values, sw);
104
		String q = sw.toString();
105
		log.debug("Querying for "+subjectURL+" with query "+templateName);
106
		return q;
107
	}
108

    
109

    
110
	protected void sendConstructResponse(final String query, final String timeoutMs, final OutputStream responseStream) throws IOException, ParthenosPublisherException {
111
		String res = executeSparqlPost(query, timeoutMs);
112
		IOUtils.write(res, responseStream);
113
	}
114

    
115
	protected String executeSparqlPost(final String query, final String timeoutMs) throws IOException, ParthenosPublisherException {
116
		try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
117
			HttpPost httpPost = new HttpPost(sparqlUrl);
118
			httpPost.setHeader(HttpHeaders.ACCEPT, "application/rdf+xml");
119
			List<NameValuePair> nvps = Lists.newArrayList();
120
			nvps.add(new BasicNameValuePair("query", query));
121
			if (StringUtils.isNotBlank(timeoutMs)) {
122
				nvps.add(new BasicNameValuePair("timeout", timeoutMs));
123
			}
124
			httpPost.setEntity(new UrlEncodedFormEntity(nvps));
125

    
126

    
127
			try (CloseableHttpResponse response2 = httpclient.execute(httpPost)) {
128
				HttpEntity entity2 = response2.getEntity();
129
				String res = IOUtils.toString(entity2.getContent());
130
				EntityUtils.consume(entity2);
131
				int statusCode = response2.getStatusLine().getStatusCode();
132
				switch(statusCode){
133
				case 200:
134
					return res;
135
				case 504:
136
					String msg = String.format("ERROR 504 on query %s", query);
137
					throw new ParthenosPublisherException(msg);
138
				default:
139
					String errorMessage = String.format("ERROR HTTP STATUS CODE %d, REASON PHRASE: %s\n ERROR BODY: %s", statusCode, response2.getStatusLine(), res);
140
					log.error(errorMessage);
141
					return "";
142
					//throw new ParthenosPublisherException(errorMessage);
143
				}
144
			}
145
		}
146

    
147

    
148
	}
149
	
150

    
151

    
152

    
153

    
154
}
(3-3/3)