/*
* Copyright 2011 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.artificer.atom.ArtificerAtomUtils;
import org.artificer.atom.err.ArtificerAtomException;
import org.artificer.common.ArtificerConstants;
import org.artificer.common.MediaType;
import org.artificer.common.query.ArtifactSummary;
import org.artificer.repository.query.PagedResult;
import org.artificer.server.QueryServiceImpl;
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.jboss.resteasy.plugins.providers.atom.Person;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
/**
* Base class for all resources that respond with Atom Feeds.
*/
public abstract class AbstractFeedResource extends AbstractResource {
private static Logger logger = LoggerFactory.getLogger(AbstractFeedResource.class);
protected final QueryServiceImpl queryService = new QueryServiceImpl();
/**
* Common method that performs a query for artifacts and returns them in an Atom {@link Feed}.
* @param query the x-path formatted s-ramp query
* @param startIndex which index within the result set to start with (0 indexed)
* @param count the number of items desired
* @param orderBy the property to sort the results by
* @param ascending the sort direction
* @param propNames the set of s-ramp property names - the extra properties that the query should return as part of the {@link Feed}
* @return an Atom {@link Feed}
* @throws org.artificer.atom.err.ArtificerAtomException
*/
protected Feed createArtifactFeed(String query, Integer startPage, Integer startIndex, Integer count, String orderBy,
Boolean ascending, Set<String> propNames, String baseUrl) throws ArtificerAtomException {
if (query == null)
throw new ArtificerAtomException(Messages.i18n.format("MISSING_QUERY_PARAM"));
try {
PagedResult<ArtifactSummary> artifactSet = queryService.query(
query, startPage, startIndex, count, orderBy, ascending);
Feed feed = createFeed(artifactSet, propNames, baseUrl);
addPaginationLinks(feed, artifactSet, baseUrl);
return feed;
} catch (Throwable e) {
logError(logger, Messages.i18n.format("Error trying to create an Artifact Feed."), e);
throw new ArtificerAtomException(e);
}
}
/**
* Creates the Atom {@link Feed} from the given artifact set (query result set).
*
* Note: the Atom feed format allows pagination via the following links:
*
* <pre>
* <link rel="first" href="http://www.example.org/feed"/>
* <link rel="next" href="http://www.example.org/feed?page=4"/>
* <link rel="previous" href="http://www.example.org/feed?page=2"/>
* <link rel="last" href="http://www.example.org/feed?page=147"/>
* </pre>
*
* @param pagedResult
* @param propNames the additional s-ramp properties to return in the {@link Feed}
* @return an Atom {@link Feed}
* @throws Exception
*/
@SuppressWarnings("unchecked")
private Feed createFeed(PagedResult<ArtifactSummary> pagedResult, Set<String> propNames, String baseUrl) throws Exception {
Feed feed = new Feed();
feed.getExtensionAttributes().put(ArtificerConstants.SRAMP_PROVIDER_QNAME, "Artificer");
feed.getExtensionAttributes().put(ArtificerConstants.SRAMP_ITEMS_PER_PAGE_QNAME, String.valueOf(pagedResult.getPageSize()));
feed.getExtensionAttributes().put(ArtificerConstants.SRAMP_START_INDEX_QNAME, String.valueOf(pagedResult.getStartIndex()));
feed.getExtensionAttributes().put(ArtificerConstants.SRAMP_TOTAL_RESULTS_QNAME, String.valueOf(pagedResult.getTotalSize()));
feed.setId(new URI("urn:uuid:" + UUID.randomUUID().toString()));
feed.setTitle("S-RAMP Feed");
feed.setSubtitle("Ad Hoc query feed");
feed.setUpdated(new Date());
feed.getAuthors().add(new Person("anonymous"));
for (ArtifactSummary artifact : pagedResult.getResults()) {
Entry entry = ArtificerAtomUtils.wrapArtifactSummary(artifact);
feed.getEntries().add(entry);
}
return feed;
}
/**
* Add pagination links to the feed.
*
* @param feed
* @param pagedResult
* @param baseUrl
* @throws UnsupportedEncodingException
*/
private void addPaginationLinks(Feed feed, PagedResult<ArtifactSummary> pagedResult, String baseUrl)
throws UnsupportedEncodingException {
long pageSize = pagedResult.getPageSize();
int startIndex = pagedResult.getStartIndex();
String orderBy = pagedResult.getOrderBy();
boolean ascending = pagedResult.isAscending();
String hrefPattern = "%1$s?query=%2$s&startIndex=%3$s&pageSize=%4$s&orderBy=%5$s&ascending=%6$s";
String encodedQuery = URLEncoder.encode(pagedResult.getQuery(), "UTF-8");
String firstHref = String.format(hrefPattern, baseUrl, encodedQuery, 0, String.valueOf(pageSize),
String.valueOf(orderBy), String.valueOf(ascending));
long prevIndex = Math.max(0, startIndex - pageSize);
String prevHref = String.format(hrefPattern, baseUrl, encodedQuery, prevIndex, String.valueOf(pageSize),
String.valueOf(orderBy), String.valueOf(ascending));
String nextHref = String.format(hrefPattern, baseUrl, encodedQuery, startIndex + pageSize, String.valueOf(pageSize),
String.valueOf(orderBy), String.valueOf(ascending));
Link first = new Link("first", firstHref, MediaType.APPLICATION_ATOM_XML_FEED_TYPE);
Link prev = new Link("prev", prevHref, MediaType.APPLICATION_ATOM_XML_FEED_TYPE);
Link next = new Link("next", nextHref, MediaType.APPLICATION_ATOM_XML_FEED_TYPE);
if (startIndex > 0) {
feed.getLinks().add(first);
feed.getLinks().add(prev);
}
if (startIndex + pageSize < pagedResult.getTotalSize()) {
feed.getLinks().add(next);
}
}
}