blob: 8865d9e04c47bbca3320d0dd44ba9f8574a64dde [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. The ASF licenses this file to You
* 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.abdera.protocol.server.impl;
import static org.apache.abdera.protocol.server.ProviderHelper.calculateEntityTag;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.abdera.Abdera;
import org.apache.abdera.factory.Factory;
import org.apache.abdera.i18n.text.UrlEncoding;
import org.apache.abdera.model.AtomDate;
import org.apache.abdera.model.Collection;
import org.apache.abdera.model.Document;
import org.apache.abdera.model.Entry;
import org.apache.abdera.model.Feed;
import org.apache.abdera.parser.ParseException;
import org.apache.abdera.parser.Parser;
import org.apache.abdera.protocol.server.CategoriesInfo;
import org.apache.abdera.protocol.server.CollectionAdapter;
import org.apache.abdera.protocol.server.CollectionInfo;
import org.apache.abdera.protocol.server.MediaCollectionAdapter;
import org.apache.abdera.protocol.server.ProviderHelper;
import org.apache.abdera.protocol.server.RequestContext;
import org.apache.abdera.protocol.server.ResponseContext;
import org.apache.abdera.protocol.server.Transactional;
import org.apache.abdera.protocol.server.context.AbstractResponseContext;
import org.apache.abdera.protocol.server.context.BaseResponseContext;
import org.apache.abdera.protocol.server.context.EmptyResponseContext;
import org.apache.abdera.protocol.server.context.ResponseContextException;
import org.apache.abdera.util.EntityTag;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Base CollectionAdapter implementation that provides a number of helper
* utility methods for adapter implementations.
*/
public abstract class AbstractCollectionAdapter
implements CollectionAdapter,
MediaCollectionAdapter,
Transactional,
CollectionInfo {
private final static Log log = LogFactory.getLog(AbstractEntityCollectionAdapter.class);
private String href;
private Map<String,Object> hrefParams = new HashMap<String,Object>();
public AbstractCollectionAdapter() {
super();
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
hrefParams.put("collection", href);
}
public String getHref(RequestContext request) {
return request.urlFor("feed", hrefParams);
}
public void compensate(RequestContext request, Throwable t) {
}
public void end(RequestContext request, ResponseContext response) {
}
public void start(RequestContext request) throws ResponseContextException {
}
public String[] getAccepts(RequestContext request) {
return new String[] { "application/atom+xml;type=entry" };
}
public CategoriesInfo[] getCategoriesInfo(RequestContext request) {
return null;
}
public ResponseContext getCategories(RequestContext request) {
return null;
}
public ResponseContext deleteMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext getMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext headMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext optionsMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext putMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext postMedia(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext headEntry(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public ResponseContext optionsEntry(RequestContext request) {
return ProviderHelper.notsupported(request);
}
public abstract String getAuthor(RequestContext request) throws ResponseContextException;
public abstract String getId(RequestContext request);
/**
* Creates the ResponseContext for a newly created entry. By default, a
* BaseResponseContext is returned. The Location, Content-Location, Etag and
* status are set appropriately.
*/
protected ResponseContext buildCreateEntryResponse(String link, Entry entry) {
BaseResponseContext<Entry> rc = new BaseResponseContext<Entry>(entry);
rc.setLocation(link);
rc.setContentLocation(rc.getLocation().toString());
rc.setEntityTag(calculateEntityTag(entry));
rc.setStatus(201);
return rc;
}
/**
* Creates the ResponseContext for a newly created entry. By default, a
* BaseResponseContext is returned. The Location, Content-Location, Etag and
* status are set appropriately.
*/
protected ResponseContext buildPostMediaEntryResponse(String link, Entry entry) {
return buildCreateEntryResponse(link, entry);
}
/**
* Creates the ResponseContext for a GET entry request. By default, a BaseResponseContext
* is returned. The Entry will contain an appropriate atom:source element
* and the Etag header will be set.
*/
protected ResponseContext buildGetEntryResponse(RequestContext request, Entry entry) throws ResponseContextException {
Feed feed = createFeedBase(request);
entry.setSource(feed.getAsSource());
Document<Entry> entry_doc = entry.getDocument();
AbstractResponseContext rc = new BaseResponseContext<Document<Entry>>(entry_doc);
rc.setEntityTag(calculateEntityTag(entry));
return rc;
}
/**
* Creates the ResponseContext for a HEAD entry request. By default, an EmptyResponseContext
* is returned. The Etag header will be set.
*/
protected ResponseContext buildHeadEntryResponse(RequestContext request,
String id,
Date updated) throws ResponseContextException {
EmptyResponseContext rc = new EmptyResponseContext(200);
rc.setEntityTag(EntityTag.generate(id, AtomDate.format(updated)));
return rc;
}
/**
* Creates the ResponseContext for a GET feed request. By default, a BaseResponseContext
* is returned. The Etag header will be set.
*/
protected ResponseContext buildGetFeedResponse(Feed feed) {
Document<Feed> document = feed.getDocument();
AbstractResponseContext rc = new BaseResponseContext<Document<Feed>>(document);
rc.setEntityTag(calculateEntityTag(document.getRoot()));
return rc;
}
/**
* Create a ResponseContext (or take it from the Exception) for an exception
* that occurred in the application.
*
* @param e
* @return
*/
protected ResponseContext createErrorResponse(ResponseContextException e) {
if (log.isDebugEnabled()) {
log.debug("A ResponseException was thrown.", e);
} else if (e.getResponseContext() instanceof EmptyResponseContext
&& ((EmptyResponseContext)e.getResponseContext()).getStatus() >= 500) {
log.warn("A ResponseException was thrown.", e);
}
return e.getResponseContext();
}
/**
* Create the base feed for the requested collection.
*/
protected Feed createFeedBase(RequestContext request) throws ResponseContextException {
Factory factory = request.getAbdera().getFactory();
Feed feed = factory.newFeed();
feed.setId(getId(request));
feed.setTitle(getTitle(request));
feed.addLink("");
feed.addLink("", "self");
feed.addAuthor(getAuthor(request));
feed.setUpdated(new Date());
return feed;
}
/**
* Retrieves the FOM Entry object from the request payload.
*/
@SuppressWarnings("unchecked")
protected Entry getEntryFromRequest(RequestContext request) throws ResponseContextException {
Abdera abdera = request.getAbdera();
Parser parser = abdera.getParser();
Document<Entry> entry_doc;
try {
entry_doc = (Document<Entry>)request.getDocument(parser).clone();
} catch (ParseException e) {
throw new ResponseContextException(500, e);
} catch (IOException e) {
throw new ResponseContextException(500, e);
}
if (entry_doc == null) {
return null;
}
return entry_doc.getRoot();
}
/**
* Get's the name of the specific resource requested
*/
protected String getResourceName(RequestContext request) {
String path = request.getTargetPath();
int q = path.indexOf("?");
if (q != -1) {
path = path.substring(0, q);
}
String[] segments = path.split("/");
String id = segments[segments.length - 1];
return UrlEncoding.decode(id);
}
public ResponseContext extensionRequest(RequestContext request) {
return ProviderHelper.notallowed(request, getMethods(request));
}
private String[] getMethods(RequestContext request) {
return ProviderHelper.getDefaultMethods(request);
}
public Collection asCollectionElement(RequestContext request) {
Collection collection = request.getAbdera().getFactory().newCollection();
collection.setHref(getHref(request));
collection.setTitle(getTitle(request));
collection.setAccept(getAccepts(request));
for (CategoriesInfo catsinfo : getCategoriesInfo(request)) {
collection.addCategories(catsinfo.asCategoriesElement(request));
}
return collection;
}
}