/* * Copyright 2007-2008 Amazon Technologies, Inc. * * Licensed 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://aws.amazon.com/apache2.0 * * This file 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. */ package com.amazonaws.mturk.service.axis; import org.apache.log4j.Logger; import com.amazonaws.mturk.addon.BatchItemCallback; import com.amazonaws.mturk.requester.Assignment; import com.amazonaws.mturk.requester.AssignmentStatus; import com.amazonaws.mturk.requester.HIT; import com.amazonaws.mturk.requester.HITStatus; import com.amazonaws.mturk.service.exception.InternalServiceException; import com.amazonaws.mturk.service.exception.ServiceException; import com.amazonaws.mturk.util.ClientConfig; /** * Attempts to "delete" a HIT */ class DeleteHITCommand implements AsyncCallback { private int hitIndex = -1; private String hitId; private boolean approve; private boolean expire; private RequesterService service; private boolean deleted = false; private AsyncReply reply = null; private BatchItemCallback callback = null; private static Logger log = Logger.getLogger(DeleteHITCommand.class); /** * Attempts to delete a HIT by disposing it. If exceptions occur, additional API calls are being invoked * on the same thread to load the hit, expire it or approve its assignments prior to trying to dispose it * again. * * @param index Zero-based index of the hit to delete (e.g. the row in an input file) * @param hitId The ID of the HIT to delete * @param approve If true, allows the command to approve any submitted assignments for the HIT prior to disposing it * @param expire If true, allows the command to expire the hit prior to disposing it * @param service The requester service to use for the API methods the command invokes. */ public DeleteHITCommand(int index, String hitId, boolean approve, boolean expire, RequesterService service, BatchItemCallback callback) { this.hitId = hitId; this.approve = approve; this.expire = expire; this.service = service; this.hitIndex = index; this.callback = callback; } private void logInfo(String msg) { if (callback == null) { log.info("[" + hitId + "] " + msg + ((hitIndex == -1) ? "" : " (Index: "+hitIndex+")")); } else { callback.processItemResult(hitId, true, msg, null); } } private void logFailure(Exception e) { if (callback == null) { log.error("[" + hitId + "] FAILURE Deleting HIT (" + e.getLocalizedMessage() + ")" + ((hitIndex == -1) ? "" : " (Index: "+hitIndex+")")); } else { callback.processItemResult(hitId, false, null, e); } } private void logSuccess() { deleted=true; logInfo("Successfully deleted HIT"); } private void disposeHit() { service.disposeHIT(hitId); logSuccess(); } public void execute() { reply = service.disposeHITAsync(hitId, this); } public boolean hasSucceeded() throws ServiceException { if (reply == null) { throw new ServiceException("execute() not called prior to retrieving the result of the operation"); } try { reply.getResult(); } catch (ServiceException e) { // exception was handled in callback } return deleted; } /** * Handles/logs throttling errors in the sandbox environment * @param ex */ private void handleException(Exception ex) throws InternalServiceException { if (ex instanceof InternalServiceException && service.getConfig().getServiceURL().equalsIgnoreCase(ClientConfig.SANDBOX_SERVICE_URL)) { logFailure(ex); throw (InternalServiceException)ex; } } /** * Callback for errors on the initial disposeHIT call. */ public void processFailure(Object axisRequestMessage, Exception axisFailure) { // Tries to dispose a HIT by going through a sequence of // getHIT/forceExpireHIT/get/approveAssignments // If throttling errors occur, this sequence is aborted HIT hit = null; try { try { hit = service.getHIT(hitId); } catch (Exception e2) { handleException(e2); } if (hit == null) { logFailure(new ServiceException("HIT not found. The hitId may be invalid.")); return; } else if (hit.getHITStatus() != null && hit.getHITStatus().equals(HITStatus.Disposed)) { logInfo("HIT already deleted. Skipping HIT"); deleted = true; } else if (expire) { // Try to expire the HIT if we've been given permission // then redispose of it try { service.forceExpireHIT(hitId); } catch (Exception e2) { handleException(e2); } try { disposeHit(); } catch (Exception e2) { handleException(e2); } } if (!deleted) { if (approve) { // we've been given permission to approve all the assignments try { Assignment[] assigns = service.getAllSubmittedAssignmentsForHIT(hitId); for (int j = 0; assigns != null && j < assigns.length; j++) { try { if (assigns[j] != null && assigns[j].getAssignmentStatus().equals(AssignmentStatus.Submitted)) { String assignsId = assigns[j].getAssignmentId(); service.approveAssignment(assignsId, null); // null for RequesterFeedback } } catch (Exception e3) { // Gobble these up, although if they happen then (in theory) we won't be able to dispose. } } } catch (Exception e2) { // Don't sweat this. } try { // Now re-try disposing it disposeHit(); } catch (Exception e2) { if (hit.getHITStatus().equals(HITStatus.Unassignable)) { logFailure(new ServiceException("HIT still being worked on. Not deleted.")); } else { logFailure(e2); } } } else { // We weren't given permission to approve, so just fail. if (hit.getHITStatus().equals(HITStatus.Unassignable)) { logFailure(new ServiceException("HIT still being worked on. Not deleted.")); } else { logFailure(axisFailure); } } } } catch (InternalServiceException svcEx) { // do nothing: throttling error occurred in command sequence // and was already handled and logged } } public void processResult(Object axisRequestMessage, Object axisResult) { logSuccess(); } }