/* * 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.abdera2.activities.protocol.basic; import java.util.UUID; import java.util.logging.Logger; import javax.activation.MimeType; import org.apache.abdera2.activities.model.ASBase; import org.apache.abdera2.activities.model.ASObject; import org.apache.abdera2.activities.model.Collection; import org.apache.abdera2.activities.model.Collection.CollectionBuilder; import org.apache.abdera2.activities.model.objects.ErrorObject; import org.apache.abdera2.activities.model.objects.PersonObject; import org.apache.abdera2.activities.protocol.ActivitiesResponseContext; import org.apache.abdera2.activities.protocol.managed.FeedConfiguration; import org.apache.abdera2.activities.protocol.managed.ManagedCollectionAdapter; import org.apache.abdera2.common.mediatype.MimeTypeHelper; import org.apache.abdera2.common.protocol.RequestContext; import org.apache.abdera2.common.protocol.ResponseContext; import org.apache.abdera2.common.protocol.Target; import org.apache.abdera2.common.protocol.TargetType; import org.apache.abdera2.common.protocol.RequestContext.Scope; import org.apache.abdera2.common.pusher.ChannelManager; import org.apache.abdera2.common.pusher.Pusher; import org.joda.time.DateTime; import com.google.common.base.Function; import static com.google.common.base.Preconditions.*; import static org.apache.abdera2.common.misc.ExceptionHelper.*; import static org.apache.abdera2.common.protocol.ProviderHelper.*; /** * The BasicAdapter provides a simplistic interface for working with Atompub collections with a restricted set of * options/features. The idea of the basic adapter is to make it easy to provide a minimally capable Atompub server */ @SuppressWarnings("unchecked") public abstract class BasicAdapter extends ManagedCollectionAdapter { public final static Logger logger = Logger.getLogger(BasicAdapter.class.getName()); protected BasicAdapter(FeedConfiguration config) { super(config); putHandler(TargetType.TYPE_COLLECTION,"GET",getItemList()); putHandler(TargetType.TYPE_COLLECTION,"HEAD",getItemList()); putHandler(TargetType.TYPE_COLLECTION,"POST",postItem()); putHandler(TargetType.TYPE_ENTRY,"GET",getItem()); putHandler(TargetType.TYPE_ENTRY,"HEAD",getItem()); putHandler(TargetType.TYPE_ENTRY,"DELETE",deleteItem()); putHandler(TargetType.TYPE_ENTRY,"PUT",putItem()); } public String getProperty(String key) throws Exception { Object val = config.getProperty(key); checkNotNull( val, "Cannot find property in Adapter properties file for feed ", key, config.getFeedId()); checked( val instanceof String, RuntimeException.class); return (String)val; } protected CollectionBuilder createCollection() { return Collection .makeCollection() .id(config.getFeedUri()) .set("title", config.getFeedTitle()) .set("updated", DateTime.now()) .set("author", PersonObject .makePerson() .displayName(config.getFeedAuthor()) .get()); } protected void addEditLinkToObject( ASObject.Builder builder, String id) throws Exception { builder.set("editLink", id); } protected void setObjectId(ASObject.Builder builder) throws Exception { String uuidUri = UUID.randomUUID().toString(); String[] segments = uuidUri.split(":"); String entryId = segments[segments.length - 1]; builder.id(createEntryIdUri(entryId)); } protected String createEntryIdUri(String entryId) throws Exception { return config.getFeedUri() + "/" + entryId; } private void push(RequestContext context, String channel, ASObject.Builder builder) { if (context.getAttribute(Scope.CONTAINER, "AbderaChannelManager") != null) { ChannelManager cm = (ChannelManager) context.getAttribute( Scope.CONTAINER, "AbderaChannelManager"); if (cm != null) { Pusher pusher = cm.getPusher(channel); if (pusher != null) pusher.push(builder.get()); } } } ResponseContext createOrUpdateObject(RequestContext request, boolean createFlag) { try { MimeType mimeType = request.getContentType(); String contentType = mimeType == null ? null : mimeType.toString(); if (contentType != null && !MimeTypeHelper.isJson(contentType)) return notsupported(request); ASBase base = getEntryFromRequest(request); Target target = request.getTarget(); if (base instanceof Collection && createFlag && target.getType() == TargetType.TYPE_COLLECTION) { // only allow multiposts on collections.. these always create, never update Collection coll = (Collection) base; CollectionBuilder retl = Collection.makeCollection(); int c = 0; for (ASObject inputEntry : coll.getItems()) { ASObject.Builder newEntry = createItem(inputEntry,c++); if (newEntry != null) { push(request,target.getParameter(BasicProvider.PARAM_FEED),newEntry); retl.item(newEntry.get()); } else { retl.item( ErrorObject .makeError() .code(-100) .displayName("Error adding object") .get()); } } return new ActivitiesResponseContext>(retl) .setStatus(createFlag?201:200); } else if (base instanceof ASObject){ String entryId = !createFlag ? target.getParameter(BasicProvider.PARAM_ENTRY) : null; ASObject inputEntry = (ASObject) base; ASObject.Builder newEntry = createFlag ? createItem(inputEntry) : updateItem(entryId, inputEntry); if (newEntry != null) { push(request,target.getParameter(BasicProvider.PARAM_FEED),newEntry); String loc = newEntry.get().getProperty("editLink"); return new ActivitiesResponseContext(newEntry) .setStatus(createFlag?201:200) .setLocation(loc); } else return notfound(request); } else return notallowed(request); } catch (Exception e) { return servererror(request, e.getMessage(), e); } } private Function postItem() { return new Function() { public ResponseContext apply(RequestContext input) { return createOrUpdateObject(input,true); } }; } private Function deleteItem() { return new Function() { public ResponseContext apply(RequestContext input) { Target target = input.getTarget(); String entryId = target.getParameter(BasicProvider.PARAM_ENTRY); try { return deleteItem(entryId) ? nocontent() : notfound(input); } catch (Exception e) { return servererror( input, e.getMessage(), e); } } }; } private Function putItem() { return new Function() { public ResponseContext apply(RequestContext input) { return createOrUpdateObject(input,false); } }; } private Function getItem() { return new Function() { public ResponseContext apply(RequestContext input) { Target target = input.getTarget(); String entryId = target.getParameter(BasicProvider.PARAM_ENTRY); try { ASObject.Builder object = getItem(entryId); if (object != null) { return new ActivitiesResponseContext(object) .setStatus(200); } else return notfound(input); } catch (Exception e) { return servererror(input, e.getMessage(), e); } } }; } public Function getItemList() { return new Function() { public ResponseContext apply(RequestContext input) { try { CollectionBuilder collection = getCollection(); if (collection != null) { return new ActivitiesResponseContext>(collection) .setStatus(200); } else return notfound(input); } catch (Exception e) { return servererror(input, e.getMessage(), e); } } }; } public abstract CollectionBuilder getCollection() throws Exception; public abstract ASObject.Builder getItem(Object objectId) throws Exception; public abstract ASObject.Builder createItem(ASObject object) throws Exception; public abstract ASObject.Builder createItem(ASObject object, int c) throws Exception; public abstract ASObject.Builder updateItem(Object objectId, ASObject object) throws Exception; public abstract boolean deleteItem(Object objectId) throws Exception; }