package cz.cuni.mff.d3s.been.swrepository; import static cz.cuni.mff.d3s.been.swrepository.HeaderNames.BPK_IDENTIFIER_HEADER_NAME; import static cz.cuni.mff.d3s.been.swrepository.UrlPaths.*; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.Map; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.protocol.HttpRequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import cz.cuni.mff.d3s.been.bpk.BpkIdentifier; import cz.cuni.mff.d3s.been.datastore.BpkStore; import cz.cuni.mff.d3s.been.datastore.StorePersister; import cz.cuni.mff.d3s.been.datastore.StoreReader; import cz.cuni.mff.d3s.been.swrepository.httpserver.SkeletalRequestHandler; import cz.cuni.mff.d3s.been.util.JSONUtils; import cz.cuni.mff.d3s.been.util.JsonException; /** * {@link HttpRequestHandler} for BPK requests. * * @author darklight */ public class BpkRequestHandler extends SkeletalRequestHandler { private static final Logger log = LoggerFactory.getLogger(BpkRequestHandler.class); private final BpkStore store; private final JSONUtils jsonUtils; /** * Create the request handler over a persistence store. * * @param store * The persistence layer for BPK storage */ public BpkRequestHandler(BpkStore store) { this.store = store; this.jsonUtils = JSONUtils.newInstance(); } @Override public void handleGet(HttpRequest request, HttpResponse response) { if (request.getRequestLine().getUri().equals(BPK_URI)) { handleGetSingleBpk(request, response); return; } if (request.getRequestLine().getUri().equals(BPK_LIST_URI)) { handleListBpks(response); return; } if (request.getRequestLine().getUri().equals(TASK_DESCRIPTOR_LIST_URI)) { handleListTaskDescriptors(request, response); return; } if (request.getRequestLine().getUri().equals(TASK_CONTEXT_DESCRIPTOR_LIST_URI)) { handleListTaskContextDescriptors(request, response); return; } response.setStatusCode(400); log.error("Unknown request"); } private void handleListBpks(HttpResponse response) { List<BpkIdentifier> list = store.listBpks(); StringEntity entity; try { String jsonString = jsonUtils.serialize(list); entity = new StringEntity(jsonString); } catch (UnsupportedEncodingException e) { response.setStatusCode(400); log.error("Cannot create string entity.", e); return; } catch (JsonException e) { response.setStatusCode(400); log.error("Cannot serialize BPK list.", e); return; } response.setEntity(entity); } private void handleGetSingleBpk(HttpRequest request, HttpResponse response) { BpkIdentifier bpkIdentifier; try { bpkIdentifier = jsonUtils.deserialize( request.getFirstHeader(BPK_IDENTIFIER_HEADER_NAME).getValue(), BpkIdentifier.class); } catch (JsonException e) { response.setStatusCode(400); log.error("Could not read BPK identifier from request."); return; } final StoreReader bpkReader = store.getBpkReader(bpkIdentifier); if (bpkReader == null) { replyBadRequest( response, String.format("Could not retrieve reader for BPK identifier %s", bpkIdentifier.toString())); return; } InputStreamEntity bpkEntity = null; try { bpkEntity = new InputStreamEntity(bpkReader.getContentStream(), bpkReader.getContentLength()); } catch (IOException e) { log.error("Failed to open BPK reader {} - {}", bpkReader.toString(), e.getMessage()); } response.setEntity(bpkEntity); } private void handleListTaskDescriptors(HttpRequest request, HttpResponse response) { BpkIdentifier bpkIdentifier; try { bpkIdentifier = jsonUtils.deserialize( request.getFirstHeader(BPK_IDENTIFIER_HEADER_NAME).getValue(), BpkIdentifier.class); } catch (JsonException e) { response.setStatusCode(400); log.error("Could not read BPK identifier from request."); return; } final Map<String, String> descriptors; try { descriptors = store.getTaskDescriptors(bpkIdentifier); } catch (IOException e) { replyBadRequest( response, String.format("Could not convert Task Descriptors from XMLs in BPK file %s", bpkIdentifier.toString())); return; } if (descriptors == null) { replyBadRequest( response, String.format("Could not retrieve descriptors reader for BPK identifier %s", bpkIdentifier.toString())); return; } StringEntity entity; try { String jsonString = jsonUtils.serialize(descriptors); entity = new StringEntity(jsonString); } catch (UnsupportedEncodingException e) { response.setStatusCode(400); log.error("Cannot create string entity.", e); return; } catch (JsonException e) { response.setStatusCode(400); log.error("Cannot serialize TaskDescriptors map.", e); return; } response.setEntity(entity); } private void handleListTaskContextDescriptors(HttpRequest request, HttpResponse response) { BpkIdentifier bpkIdentifier; try { bpkIdentifier = jsonUtils.deserialize( request.getFirstHeader(BPK_IDENTIFIER_HEADER_NAME).getValue(), BpkIdentifier.class); } catch (JsonException e) { response.setStatusCode(400); log.error("Could not read BPK identifier from request."); return; } final Map<String, String> descriptors; try { descriptors = store.getTaskContextDescriptors(bpkIdentifier); } catch (IOException e) { replyBadRequest( response, String.format("Could not convert Task Context Descriptors from XMLs in BPK file %s", bpkIdentifier.toString())); return; } if (descriptors == null) { replyBadRequest( response, String.format("Could not retrieve descriptors reader for BPK identifier %s", bpkIdentifier.toString())); return; } StringEntity entity; try { String jsonString = jsonUtils.serialize(descriptors); entity = new StringEntity(jsonString); } catch (UnsupportedEncodingException e) { response.setStatusCode(400); log.error("Cannot create string entity.", e); return; } catch (JsonException e) { response.setStatusCode(400); log.error("Cannot serialize TaskContextDescriptors map.", e); return; } response.setEntity(entity); } @Override protected void handlePut(HttpRequest request, HttpResponse response) { BpkIdentifier bpkIdentifier; if (!BasicHttpEntityEnclosingRequest.class.isAssignableFrom(request.getClass())) { final String errorMessage = String.format( "Put request %s invalid, because it doesn't contain an entity.", request.toString()); log.error(errorMessage); replyBadRequest(response, errorMessage); return; } BasicHttpEntityEnclosingRequest put = (BasicHttpEntityEnclosingRequest) request; try { bpkIdentifier = jsonUtils.deserialize( request.getFirstHeader(BPK_IDENTIFIER_HEADER_NAME).getValue(), BpkIdentifier.class); } catch (JsonException e) { final String errorMessage = String.format("could not read BPK identifier from request %s.", request.toString()); log.error(errorMessage); replyBadRequest(response, errorMessage); return; } if (!bpkIdentifier.getVersion().endsWith(Versions.SNAPSHOT_SUFFIX)) { if (store.exists(bpkIdentifier)) { final String errorMessage = String.format( "could not upload BPK '%s' - BPK already exists and only *-SNAPSHOT versions are allowed to be reuploaded.", request.toString()); log.error(errorMessage); replyBadRequest(response, errorMessage); return; } } try { final StorePersister bpkPersister = store.getBpkPersister(bpkIdentifier); if (bpkPersister == null) { final String errorMessage = String.format("Could not retrieve persister for BPK %s", bpkIdentifier.toString()); log.error(errorMessage); replyBadRequest(response, errorMessage); return; } final InputStream requestFile = put.getEntity().getContent(); bpkPersister.dump(requestFile); } catch (IOException e) { log.error("Could not persist BPK {} due to I/O error - {}.", bpkIdentifier.toString(), e.getMessage()); } } }