Apache Abdera > Documentation > Server Implementation Guide > Support for AtomPub-multipart
Added by David Calavera, last edited by David Calavera on Jul 24, 2008

Abdera includes an implementation of the AtomPub Multipart Media Creation draft.

http://atompub-mulitpart-spec.googlecode.com/svn/trunk/draft-gregorio-atompub-multipart-02.txt

Client Implementation

Abdera Client module allows to send both, the media resource and the media link entry, into a single object packaged as a Multipart/Related file:

Abdera abdera = new Abdera();
Factory factory = abdera.getFactory();

AbderaClient client = new AbderaClient(abdera);

Entry mediaLinkEntry = factory.newEntry();

mediaLinkEntry.setTitle("my image");
mediaLinkEntry.addAuthor("david");
mediaLinkEntry.setId("tag:apache.org,2008:234534344");
mediaLinkEntry.setSummary("multipart test");		
mediaLinkEntry.setContent(new IRI("cid:234234@example.com"), "image/jpg");

InputStream mediaResource = this.getClass().getResourceAsStream("image.jpg");

client.post("http://localhost:9002/media", mediaLinkEntry, mediaResource);

Server implementation

Abdera Server module include some helpful classes in order to parse multipart/related files and to create service documents that show collections that accept multipart/related objects.

The first step to support multipart/related is override the RequestProcessor that writes the service document. We have to change the default RequestProcessor with the provided MultipartRelatedServiceRequestProcessor class:

Provider provider = new DefaultProvider();

Map<TargetType, RequestProcessor> relatedProcessor = new HashMap<TargetType, RequestProcessor>() {
    {put(TargetType.TYPE_SERVICE,new MultipartRelatedServiceRequestProcessor());}
};

provider.addRequestProcessors(relatedProcessor);

Once the provider writes collections that accept multipart objects we have to construct an Adapter that receive these object. Abdera provides an abstract class called AbstractMultipartCollectionAdapter that the custom adapter must override. The custom adapter must implement the method getAlternateAccepts and provide the mime types that support multimedia objects:

class CustomMultipartAdapter extends AbstractMultipartCollectionAdapter {
    public Map<String, String> getAlternateAccepts(RequestContext request) {
        if (accepts == null) {
	    accepts = new HashMap<String, String>() {{
	      put("video/*", null); /* doesn't accept multipart related */	      
	      put("image/png", Constants.LN_ALTERNATE_MULTIPART_RELATED /*multipart-related*/);
	    }};
	}
	return accepts;
    }
}

The abstract class includes a method called getMultipartRelatedData that decodes the multipart stream and gets the media objects once a post method is requested:

class CustomMultipartAdapter extends AbstractMultipartCollectionAdapter {
...

    public ResponseContext postMedia(RequestContext request) {
        try {
	    if (MimeTypeHelper.isMultipart(request.getContentType().toString())) {
	        MultipartRelatedPost post = getMultipartRelatedData(request);
	    }
			
	    return new EmptyResponseContext(201);
	} catch (Exception pe) {			
	     return new EmptyResponseContext(415, pe.getLocalizedMessage());
        }
    }
}

If the multipart stream is well formated the MultipartRelatedPost object will contains the media link entry, the media resource and the headers sent with each one. Thus, we can work with both objects as well as a normal request.