eu.erasmuswithoutpaper.registryclient.CatalogueFetcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ewp-registry-client Show documentation
Show all versions of ewp-registry-client Show documentation
Allows to run queries on EWP (Erasmus Without Paper) Registry Service.
The newest version!
package eu.erasmuswithoutpaper.registryclient;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.Date;
/**
* Provides a raw <catalogue>
HTTP response, as specified in the
* Registry API.
*
*
* Classes implementing this interface are able to acquire the catalogue response from the Registry
* Service. We provide a default implementation of this interface called
* {@link DefaultCatalogueFetcher}, but sometimes you might want to provide your own implementation,
* for example when running unit tests.
*
*
* @see DefaultCatalogueFetcher
* @see ClientImplOptions#setCatalogueFetcher(CatalogueFetcher)
* @since 1.0.0
*/
public interface CatalogueFetcher {
/**
* Represents a HTTP 200 Registry catalogue response.
*
* @since 1.0.0
*/
class Http200RegistryResponse extends RegistryResponse {
/**
* Thrown by {@link Http200RegistryResponse#deserialize(byte[])} when the raw data could not be
* deserialized into a valid {@link Http200RegistryResponse} object.
*/
static class CouldNotDeserialize extends Exception {
private static final long serialVersionUID = -3124583265761204268L;
}
/**
* Deserialize an object from a raw byte array. (Used for persistent caching of the catalogue
* response.)
*/
static Http200RegistryResponse deserialize(byte[] raw) throws CouldNotDeserialize {
try {
try {
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
int version = in.readInt();
if (version != 1) {
throw new CouldNotDeserialize();
}
Date expires = (Date) in.readObject();
byte[] content = (byte[]) in.readObject();
String etag = (String) in.readObject();
return new Http200RegistryResponse(content, etag, expires);
} catch (StreamCorruptedException | ClassNotFoundException e) {
throw new CouldNotDeserialize();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private final byte[] content;
private final String etag;
/**
* @param content The response body (raw XML data).
* @param etag The value of the HTTP ETag header received with the response, or null if
* no ETag was present.
* @param expires The value of the HTTP Expires header received with the response, or
* null if no Expires header was present. Implementations are allowed to "deduce"
* a proper Expires value from other HTTP headers (i.e. Cache-Control header).
*/
public Http200RegistryResponse(byte[] content, String etag, Date expires) {
super(expires);
this.content = content.clone();
this.etag = etag;
}
byte[] getContent() {
return content;
}
String getETag() {
return etag;
}
/**
* Serialize this object. (Used for persistent caching of the catalogue response.)
*/
byte[] serialize() {
try {
ByteArrayOutputStream data = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(data);
out.writeInt(1); // version
out.writeObject(this.getExpires());
out.writeObject(this.getContent());
out.writeObject(this.getETag());
return data.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Represents a HTTP 304 Registry catalogue response.
*
* @since 1.0.0
*/
class Http304RegistryResponse extends RegistryResponse {
/**
* @param expires value of the HTTP Expires header received with the response.
*/
protected Http304RegistryResponse(Date expires) {
super(expires);
}
}
/**
* A common base for both Registry catalogue responses. ({@link Http200RegistryResponse} and
* {@link Http304RegistryResponse}.)
*
* @since 1.0.0
*/
abstract class RegistryResponse {
private final Date expires;
/**
* @param expires The value of the HTTP Expires header received with the response.
*/
RegistryResponse(Date expires) {
this.expires = expires;
}
/**
* @return as described in {@link #RegistryResponse(Date)}.
*/
Date getExpires() {
if (this.expires != null) {
return new Date(this.expires.getTime());
} else {
return null;
}
}
}
/**
* Fetch the catalogue from the Registry Service, or confirm that it didn't change.
*
*
* Implementations are strongly advised to include the attached ETag value in their
* If-None-Match
HTTP header when making the request to the Registry API.
* {@link ClientImpl} is interested in just two types of Registry API responses:
*
*
*
* - If HTTP 200 is received, then this method must return an {@link Http200RegistryResponse}
* object.
* - If HTTP 304 is received, then this method must return an {@link Http304RegistryResponse}
* object.
* - If any other type of response is received from the Registry API, or the Registry API cannot
* be contacted, then this method must throw an {@link IOException}.
*
*
* @param etag String or null. If not null, then it should contain the ETag value to
* be used in the If-None-Match
request header (the ETag representing the
* version of the catalogue which we currently possess). If null, then this method
* will not use the If-None-Match
header (and will therefore be expected to
* return an {@link Http200RegistryResponse}).
* @return Either {@link Http200RegistryResponse} or {@link Http304RegistryResponse} object.
* @throws IOException if Registry API could not be contacted, or it has responded with a HTTP
* status different than 200 and 304.
*/
RegistryResponse fetchCatalogue(String etag) throws IOException;
}