package edu.asu.spring.quadriga.qstore.impl; import java.io.StringWriter; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import org.apache.commons.codec.binary.Base64; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import edu.asu.spring.quadriga.domain.factories.IRestVelocityFactory; import edu.asu.spring.quadriga.exceptions.QStoreStorageException; import edu.asu.spring.quadriga.exceptions.QuadrigaException; import edu.asu.spring.quadriga.qstore.IQStoreConnector; import edu.asu.spring.quadriga.velocity.impl.VelocityBuilder; @Service @PropertySource(value = "classpath:/settings.properties") public class QStoreConnector implements IQStoreConnector { private static final Logger logger = LoggerFactory .getLogger(QStoreConnector.class); @Autowired @Qualifier("qStoreURL") private String qStoreURL; @Autowired @Qualifier("qStoreURL_Add") private String qStoreURL_Add; @Autowired @Qualifier("qStoreURL_Search") private String qStoreUrl_search; @Autowired @Qualifier("restTemplate") RestTemplate restTemplate; @Autowired @Qualifier("qStoreURL_Get_POST") private String qStoreURL_Get_POST; @Autowired @Qualifier("qStoreURL_Get") private String qStoreURL_Get; @Autowired @Qualifier("jaxbMarshaller") private Jaxb2Marshaller jaxbMarshaller; @Autowired private IRestVelocityFactory restVelocityFactory; // TODO: we need to replace all restVelocityFactory uses with this builder @Autowired private VelocityBuilder velocityBuilder; @Autowired private Environment env; /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#getQStoreAddURL() */ @Override public String getQStoreAddURL() { return qStoreURL + qStoreURL_Add; } /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#getQStoreGetURL() */ @Override public String getQStoreGetURL() { return qStoreURL + qStoreURL_Get; } /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#getQStoreGetPOSTURL() */ @Override public String getQStoreGetPOSTURL() { return qStoreURL + qStoreURL_Get_POST; } protected String getQStoreSearchUrl() { return qStoreURL + qStoreUrl_search; } @PostConstruct public void init() { List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); messageConverters.add(new StringHttpMessageConverter()); messageConverters.add(new MarshallingHttpMessageConverter( jaxbMarshaller, jaxbMarshaller)); restTemplate.setMessageConverters(messageConverters); } /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#getCreationEvent(java.lang.String) */ @Override @Cacheable(value="creationEvent") public String getCreationEvent(String id) throws QStoreStorageException { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_XML); // set media types List<MediaType> mediaTypes = new ArrayList<MediaType>(); mediaTypes.add(MediaType.APPLICATION_XML); headers.setAccept(mediaTypes); String authHeader = getAuthHeader(); headers.set("Authorization", authHeader); ResponseEntity<String> response = null; logger.debug("URL : " + getQStoreGetURL() + id); // Get the XML from QStore try { logger.debug("Requesting: " + getQStoreGetURL() + id); response = restTemplate .exchange(getQStoreGetURL() + id, HttpMethod.GET, new HttpEntity<String[]>(headers), String.class); } catch (RestClientException ex) { throw new QStoreStorageException(ex); } return response.getBody().toString(); } /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#store(java.lang.String) */ @Override public String store(String xml) throws QStoreStorageException { String res = ""; // add message converters List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = buildRestHeader(messageConverters, restTemplate); HttpEntity<String> request = new HttpEntity<String>(xml, headers); try { // add xml in QStore String url = getQStoreAddURL(); res = restTemplate.postForObject(url, request, String.class); } catch (Exception e) { throw new QStoreStorageException(e); } return res; } /* (non-Javadoc) * @see edu.asu.spring.quadriga.service.qstore.impl.IQStoreConnector#getStatements(java.lang.String) */ @Override @Cacheable(value="statements") public String getStatements(String xml) { String res = ""; // Add message converters for JAxb List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = buildRestHeader(messageConverters, restTemplate); HttpEntity<String> request = new HttpEntity<String>(xml, headers); try { // Get complete network xml from QStore res = restTemplate.postForObject(getQStoreGetPOSTURL(), request, String.class); } catch (Exception e) { logger.error("QStore not accepting the xml, please check with the server logs.", e); // res = e.getMessage(); return res; } return res; } @Override @Cacheable(value="appellationEvents") public String getAppellationEventsByConceptAndText(String conceptUri, String textUri) throws QuadrigaException { List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = buildRestHeader(messageConverters, restTemplate); Map<String, Object> props = new HashMap<String, Object>(); props.put("conceptUri", conceptUri); props.put("textUri", textUri); String payload; try { payload = velocityBuilder.getRenderedTemplate("velocitytemplates/searchQStore/searchAppEvents.vm", props); } catch (ResourceNotFoundException e1) { throw new QuadrigaException(e1); } catch (ParseErrorException e1) { throw new QuadrigaException(e1); } catch (Exception e1) { // the velocity engine actually throws 'Exception' throw new QuadrigaException(e1); } HttpEntity<String> request = new HttpEntity<String>(payload, headers); String res = ""; try { logger.debug("Search Qstore for " + conceptUri + " and " + textUri); res = restTemplate.postForObject(getQStoreSearchUrl(), request, String.class); } catch (Exception e) { throw new QStoreStorageException(e); } return res; } @Override @Cacheable(value="conceptSearch") public String searchNodesByConcept(String conceptId) throws Exception { List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = buildRestHeader(messageConverters, restTemplate); VelocityEngine engine = restVelocityFactory.getVelocityEngine(); engine.init(); Template template = engine.getTemplate("velocitytemplates/searchQStore/requestNodes.vm"); VelocityContext context = new VelocityContext(); context.put("conceptId", conceptId); StringWriter writer = new StringWriter(); template.merge(context, writer); HttpEntity<String> request = new HttpEntity<String>(writer.toString(), headers); String res = ""; try { // Get complete network xml from QStore res = restTemplate.postForObject(getQStoreSearchUrl(), request, String.class); } catch (Exception e) { logger.error("QStore not accepting the xml, please check with the server logs.", e); // res = e.getMessage(); return res; } return res; } protected HttpHeaders buildRestHeader(List<HttpMessageConverter<?>> messageConverters, RestTemplate restTemplate) { List<MediaType> mediaTypes = new ArrayList<MediaType>(); mediaTypes.add(MediaType.APPLICATION_XML); messageConverters.add(new FormHttpMessageConverter()); messageConverters.add(new StringHttpMessageConverter()); restTemplate.setMessageConverters(messageConverters); // Add http header HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_XML); headers.setAccept(mediaTypes); String authHeader = getAuthHeader(); headers.set("Authorization", authHeader); return headers; } private String getAuthHeader() { String auth = env.getProperty("qstore.admin.username") + ":" + env.getProperty("qstore.admin.password"); byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset .forName("US-ASCII"))); return "Basic " + new String(encodedAuth); } }