package org.gcube.lb2pc; import java.net.MalformedURLException; import java.util.List; import java.util.Random; public class Proxy { public HttpResponse onRequest(HttpRequest request) throws Exception { HttpMethod httpMethod = request.getMethod(); switch(httpMethod) { case OPTIONS: return sendSupportedTransactionServiceList(request); case POST: case HEAD: case GET: case PUT: case DELETE: String transactionURI = request.getTransactionURI(request); if(transactionURI!=null) { // Transactional Client return manageTransactionAction(request, transactionURI); }else { // Non-Transactional Client return createMiniTransaction(request); } default: return sendErrorResponseToClient(HttpStatusCode._405, "Unsupported Operation"); } } protected HttpResponse manageTransactionAction(HttpRequest request, String transactionURI) throws Exception { HttpMethod httpMethod = request.getMethod(); String requestURI = request.getRequestURI(); String contentType = request.getContentType(); String lockURI = request.getHeader("X-Lock-URI"); if(lockURI!=null) { // Client already own a lock, verifying and upgrading if needed verifyAndUpgradeLock(httpMethod, contentType, lockURI, transactionURI, requestURI); String shadowResourceURI = getShadowResourceURI(transactionURI, requestURI); logRequest(shadowResourceURI, contentType, httpMethod, null); HttpResponse actionResponse = forwardAction(request); actionResponse.setHeader("X-Lock-URI", lockURI); return createResponse(actionResponse); }else { // Client does not own a lock if(httpMethod != HttpMethod.POST && httpMethod != HttpMethod.PUT && httpMethod != HttpMethod.GET && httpMethod != HttpMethod.HEAD) { // The first action on a resource must be a GET or a CREATE sendErrorResponseToClient(HttpStatusCode._403, "A resource must be read before to be able to modify or delete it."); } HttpResponse actionResponse = null; Lock lock = createLock(httpMethod, transactionURI, requestURI); lockURI = lock.getLockURI(); String resource = null; String shadowResourceURI= null; switch(httpMethod) { case PUT: HttpResponse r = createHttpRequest(HttpMethod.HEAD, null, null, requestURI); if(r.getHttpStatusCode() == HttpStatusCode._204 || (r.getHttpStatusCode().getCode()>=200 && r.getHttpStatusCode().getCode()<300)) { lock.delete(); sendErrorResponseToClient(HttpStatusCode._403, "A resource must be read before to be able to modify or delete it."); }else { // Create with PUT shadowResourceURI = createShadowResource(transactionURI, requestURI, lockURI, contentType, null); logRequest(shadowResourceURI, contentType, httpMethod, request.getContent()); actionResponse = forwardAction(request); } break; case POST: HttpResponse getResponse = getResourceOnEffectiveService(requestURI); resource = getResponse.getContent(); shadowResourceURI = createShadowResource(transactionURI, requestURI, lockURI, contentType, resource); logRequest(shadowResourceURI, contentType, httpMethod, request.getContent()); actionResponse = forwardAction(request); String locationURI = actionResponse.getHeader("Location"); logRequest(shadowResourceURI, contentType, httpMethod, null, locationURI); break; default: HttpResponse response = getResourceOnEffectiveService(requestURI); resource = response.getContent(); shadowResourceURI = createShadowResource(transactionURI, requestURI, lockURI, contentType, resource); // Optimization We don't need any log here // logRequest(shadowResourceURI, contentType, httpMethod, requestURI, request.getContent()); actionResponse = forwardAction(request); break; } actionResponse.setHeader("X-Lock-URI", lockURI); actionResponse.setHeader("X-Transaction-URI", transactionURI); return createResponse(actionResponse); } } private String getShadowResourceURI(String transactionURI, String requestURI) throws MalformedURLException { return ShadowResource.getShadowResourceURI(transactionURI, requestURI); } protected HttpResponse createMiniTransaction(HttpRequest request) throws Exception { String contentType = request.getContentType(); String transactionURI = createTransaction(contentType); HttpResponse actionResponse = manageTransactionAction(request, transactionURI); commitTransation(transactionURI); return actionResponse; } private void commitTransation(String transactionURI) { // TODO } protected String createTransaction(String contentType) { HttpResponse createTransactionResponse = createHttpRequest(HttpMethod.POST, contentType, getOneTransactionServiceURI()); if(createTransactionResponse.getHttpStatusCode() != HttpStatusCode._201) { sendErrorResponseToClient(HttpStatusCode._503, "Please try later"); } return createTransactionResponse.getHeader("Location"); } private String getOneTransactionServiceURI() { List list = getTransactionServiceURIs(); Random random = new Random(); return list.get(random.nextInt(list.size())); } private List getTransactionServiceURIs() { return null; } @SuppressWarnings("unused") private HttpResponse sendSupportedTransactionServiceList(HttpRequest request) { String contentType = request.getContentType(); List list = getTransactionServiceURIs(); // TODO create response with Transaction Services return null; } private static HttpResponse createResponse(HttpResponse actionResponse) { return null; } private static HttpResponse forwardAction(HttpRequest request) { return null; } private HttpResponse getResourceOnEffectiveService(String resourceURI) { return null; } private void logRequest(String shadowResourceURI, String contentType, HttpMethod httpMethod, String resource) throws MalformedURLException { this.logRequest(shadowResourceURI, contentType, httpMethod, resource, null); } private void logRequest(String shadowResourceURI, String contentType, HttpMethod httpMethod, String resource, String locationURI) throws MalformedURLException { Log log = new Log(httpMethod, resource, locationURI); log.create(shadowResourceURI, contentType); } private String createShadowResource(String transactionURI, String requestURI, String lockURI, String contentType, String resource) throws MalformedURLException { ShadowResource shadowResource = new ShadowResource(transactionURI, requestURI, lockURI, contentType); shadowResource.create(); return shadowResource.getURI(); } protected Lock createLock(HttpMethod httpMethod, String transacationURI, String resourceURI) { LockType type = getRequiredType(httpMethod); Lock lock = new Lock(type, transacationURI, resourceURI); lock.create(); return lock; } private LockType getRequiredType(HttpMethod httpMethod) { return null; } protected void verifyAndUpgradeLock(HttpMethod httpMethod, String contentType, String lockURI, String transactionURI, String resourceURI) { Lock lock = retrieveLock(lockURI, contentType); if(lock.getTransactionURI().compareTo(transactionURI) != 0) { // Invalid Lock e.g. the lock does not belong to the transaction or does not exist sendErrorResponseToClient(HttpStatusCode._401, "Provided Lock does belong to provided Transaction"); } if(lock.getResourceURI().compareTo(resourceURI) != 0) { sendErrorResponseToClient(HttpStatusCode._401, "Provided Lock does belong to requested URI"); } if(lock.type == LockType.S) { if(httpMethod != HttpMethod.GET) { upgradeLock(lock, lockURI); // lock.upgrade(); } } } public static HttpResponse sendErrorResponseToClient(HttpStatusCode name, String string) { return null; } /** * GET lock from LockURI * @param lockURI * @return */ private Lock retrieveLock(String lockURI, String contentType) { Lock lock = new Lock(lockURI); lock.read(contentType); return lock; } public static HttpResponse createHttpRequest(HttpMethod get, String contentType, String uri) { return null; } public static HttpResponse createHttpRequest(HttpMethod get, String contentType, String content, String uri) { return null; } protected Lock upgradeLock(Lock lock, String lockURI) { if(lock.getType() == LockType.X) { return lock; } lock.setType(LockType.S); sendLockUpdate(lock, lockURI); return lock; } private void sendLockUpdate(Lock lock, String lockURI) { return; } }