/* * Copyright 2014 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.artificer.server.atom.services; import org.apache.commons.lang.text.StrSubstitutor; import org.artificer.atom.ArtificerAtomConstants; import org.artificer.atom.ArtificerAtomUtils; import org.artificer.atom.err.ArtificerAtomException; import org.artificer.common.ArtificerConfig; import org.artificer.common.MediaType; import org.artificer.common.error.ArtificerServerException; import org.artificer.server.i18n.Messages; import org.jboss.resteasy.plugins.providers.atom.Entry; import org.jboss.resteasy.plugins.providers.atom.Feed; import org.jboss.resteasy.plugins.providers.atom.Link; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.StoredQuery; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import java.net.URI; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; /** * A JAX-RS resource that provides Stored Query support. * * @author Brett Meyer */ @Path("/s-ramp/query") public class StoredQueryResource extends AbstractFeedResource { private static Logger logger = LoggerFactory.getLogger(StoredQueryResource.class); public StoredQueryResource() { } @POST @Consumes(MediaType.APPLICATION_ATOM_XML_ENTRY) @Produces(MediaType.APPLICATION_ATOM_XML_ENTRY) public Entry create(@Context HttpServletRequest request, Entry atomEntry) throws ArtificerServerException { try { String baseUrl = ArtificerConfig.getBaseUrl(request.getRequestURL().toString()); StoredQuery storedQuery = ArtificerAtomUtils.unwrapStoredQuery(atomEntry); storedQuery = queryService.createStoredQuery(storedQuery); return wrapStoredQuery(storedQuery, baseUrl); } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a // unique HTTP response type. throw e; } catch (Exception e) { logError(logger, Messages.i18n.format("ERROR_CREATING_STOREDQUERY"), e); throw new ArtificerAtomException(e); } } @PUT @Path("{queryName}") @Consumes(MediaType.APPLICATION_ATOM_XML_ENTRY) public void update(@PathParam("queryName") String queryName, Entry atomEntry) throws ArtificerServerException { try { StoredQuery storedQuery = ArtificerAtomUtils.unwrapStoredQuery(atomEntry); queryService.updateStoredQuery(queryName, storedQuery); } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a unique // HTTP response type. throw e; } catch (Throwable e) { logError(logger, Messages.i18n.format("ERROR_UPDATING_STOREDQUERY", queryName), e); throw new ArtificerAtomException(e); } } @GET @Path("{queryName}") @Produces(MediaType.APPLICATION_ATOM_XML_ENTRY) public Entry get(@Context HttpServletRequest request, @PathParam("queryName") String queryName) throws ArtificerServerException { try { String baseUrl = ArtificerConfig.getBaseUrl(request.getRequestURL().toString()); StoredQuery storedQuery = queryService.getStoredQuery(queryName); return wrapStoredQuery(storedQuery, baseUrl); } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a unique // HTTP response type. throw e; } catch (Throwable e) { logError(logger, Messages.i18n.format("ERROR_GETTING_STOREDQUERY", queryName), e); throw new ArtificerAtomException(e); } } @GET @Produces(MediaType.APPLICATION_ATOM_XML_FEED) public Feed list(@Context HttpServletRequest request) throws ArtificerAtomException { try { String baseUrl = ArtificerConfig.getBaseUrl(request.getRequestURL().toString()); List<StoredQuery> storedQueries = queryService.getStoredQueries(); Feed feed = new Feed(); feed.setTitle("S-RAMP Stored Queries Feed"); feed.setUpdated(new Date()); for (StoredQuery storedQuery : storedQueries) { feed.getEntries().add(wrapStoredQuery(storedQuery, baseUrl)); } return feed; } catch (Exception e) { logError(logger, Messages.i18n.format("ERROR_GETTING_STOREDQUERIES"), e); throw new ArtificerAtomException(e); } } @GET @Path("{queryName}/results") @Produces(MediaType.APPLICATION_ATOM_XML_FEED) public Feed getResults(@Context HttpServletRequest request, @PathParam("queryName") String queryName, @QueryParam("startPage") Integer startPage, @QueryParam("startIndex") Integer startIndex, @QueryParam("count") Integer count, @QueryParam("orderBy") String orderBy, @QueryParam("ascending") Boolean asc) throws ArtificerServerException { try { String baseUrl = ArtificerConfig.getBaseUrl(request.getRequestURL().toString()); StoredQuery storedQuery = queryService.getStoredQuery(queryName); Map<String, String> params = new HashMap<>(); Enumeration<String> paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); if (!"startPage".equalsIgnoreCase(paramName) && !"startIndex".equalsIgnoreCase(paramName) && !"count".equalsIgnoreCase(paramName) && !"orderBy".equalsIgnoreCase(paramName) && !"ascending".equalsIgnoreCase(paramName)) params.put(paramName, request.getParameter(paramName)); } // Parameter replacement in the query string. Ex: // /s-ramp/core/Document[@uuid = '${uuid}'] // Map: "uuid" -> 12345 // queryString == /s-ramp/core/Document[@uuid = '12345'] String queryString = new StrSubstitutor(params).replace(storedQuery.getQueryExpression()); // TODO: It may be possible to introduce certain optimizations... return createArtifactFeed(queryString, startPage, startIndex, count, orderBy, asc, new HashSet<>(storedQuery.getPropertyName()), baseUrl); } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a unique // HTTP response type. throw e; } catch (Throwable e) { logError(logger, Messages.i18n.format("ERROR_EXECUTING_STOREDQUERY", queryName), e); throw new ArtificerAtomException(e); } } @DELETE @Path("{queryName}") public void delete(@PathParam("queryName") String queryName) throws ArtificerServerException { try { queryService.deleteStoredQuery(queryName); } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a unique // HTTP response type. throw e; } catch (Throwable e) { logError(logger, Messages.i18n.format("ERROR_DELETING_STOREDQUERY", queryName), e); throw new ArtificerAtomException(e); } } private Entry wrapStoredQuery(StoredQuery storedQuery, String baseUrl) throws Exception { Entry entry = ArtificerAtomUtils.wrapStoredQuery(storedQuery); // TODO // entry.setPublished(); // entry.setUpdated(); String atomLink = baseUrl + "/s-ramp/query/" + storedQuery.getQueryName(); // self link Link linkToSelf = new Link(); linkToSelf.setType(MediaType.APPLICATION_ATOM_XML_ENTRY_TYPE); linkToSelf.setRel("self"); linkToSelf.setHref(new URI(atomLink)); entry.getLinks().add(linkToSelf); // edit link Link linkToEdit = new Link(); linkToEdit.setType(MediaType.APPLICATION_ATOM_XML_ENTRY_TYPE); linkToEdit.setRel("edit"); linkToEdit.setHref(new URI(atomLink)); entry.getLinks().add(linkToEdit); // results link // Note: The spec technically requires this for a POST, but it seems useful in other contexts. Link linkToResults = new Link(); linkToResults.setType(MediaType.APPLICATION_ATOM_XML_FEED_TYPE); linkToResults.setRel(ArtificerAtomConstants.X_S_RAMP_QUERY_RESULTS); linkToResults.setHref(new URI(atomLink + "/results")); entry.getLinks().add(linkToResults); return entry; } }