package org.opennaas.extensions.bod.autobahn.commands; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.getOnlyElement; import static net.geant.autobahn.useraccesspoint.State.CANCELLED; import javax.xml.datatype.XMLGregorianCalendar; import net.geant.autobahn.administration.ReservationType; import net.geant.autobahn.administration.ServiceType; import net.geant.autobahn.useraccesspoint.Priority; import net.geant.autobahn.useraccesspoint.ReservationRequest; import net.geant.autobahn.useraccesspoint.ReservationResponse; import net.geant.autobahn.useraccesspoint.Resiliency; import net.geant.autobahn.useraccesspoint.ServiceRequest; import net.geant.autobahn.useraccesspoint.ServiceResponse; import net.geant.autobahn.useraccesspoint.State; import net.geant.autobahn.useraccesspoint.UserAccessPoint; import net.geant.autobahn.useraccesspoint.UserAccessPointException_Exception; import org.joda.time.DateTime; import org.opennaas.core.resources.action.ActionException; import org.opennaas.core.resources.command.Response; import org.opennaas.extensions.bod.autobahn.model.AutobahnLink; public class CancelServiceCommand extends AutobahnCommand { private final UserAccessPoint userAccessPoint; private final AutobahnLink link; private final String serviceId; private boolean cancelled = false; private boolean undone = false; public CancelServiceCommand(UserAccessPoint userAccessPoint, AutobahnLink link) { this.userAccessPoint = userAccessPoint; this.link = link; this.serviceId = link.getService().getBodID(); setCommandId("cancel"); } @Override public Response execute() { checkState(!cancelled && !undone); try { log.info("Cancelling reservation " + serviceId); userAccessPoint.cancelService(serviceId); cancelled = true; waitUntilOrFailure(CANCELLED); return okResponse("cancelService", "Service " + serviceId + " cancelled"); } catch (ActionException e) { return errorResponse("cancelService", e.getMessage()); } catch (UserAccessPointException_Exception e) { return errorResponse("cancelService", e.getMessage()); } } @Override public Response undo() { checkState(!undone); if (!cancelled) { return okResponse("", "Nothing to undo"); } try { Response response; if (!isBeforeNow(link.getReservation().getEndTime())) { String newServiceId = userAccessPoint.submitService(createServiceRequest()); response = okResponse("submitService", "Restored service " + serviceId + ". " + "New service is " + newServiceId); } else { response = okResponse("submitService", "Did not restore service " + serviceId + "as it has expired already."); } undone = true; return response; } catch (UserAccessPointException_Exception e) { return errorResponse("cancel", e.getMessage()); } } private ServiceRequest createServiceRequest() { ReservationType reservation = link.getReservation(); boolean processNow = isBeforeNow(reservation.getStartTime()); ReservationRequest reservationRequest = new ReservationRequest(); reservationRequest.setStartPort(reservation.getStartPort()); reservationRequest.setEndPort(reservation.getEndPort()); reservationRequest.setStartTime(reservation.getStartTime()); reservationRequest.setEndTime(reservation.getEndTime()); reservationRequest.setDescription(reservation.getDescription()); reservationRequest.setCapacity(reservation.getCapacity()); reservationRequest.setBidirectional(reservation.isBidirectional()); reservationRequest.setPriority(Priority.NORMAL); reservationRequest.setProcessNow(processNow); reservationRequest.setResiliency(Resiliency.NONE); ServiceType service = link.getService(); ServiceRequest serviceRequest = new ServiceRequest(); serviceRequest.setJustification(service.getJustification()); serviceRequest.setUserName(service.getUser().getName()); serviceRequest.getReservations().add(reservationRequest); return serviceRequest; } private boolean isBeforeNow(XMLGregorianCalendar calendar) { /* * We add a 10 second margin to allow the request to be submitted and to allow minor clock skew. */ DateTime time = new DateTime(calendar.toGregorianCalendar()); return time.isBefore(DateTime.now().plusSeconds(10)); } private void waitUntilOrFailure(State state) throws ActionException, UserAccessPointException_Exception { log.debug("Waiting for Service " + serviceId + " to be " + state); State lastState = State.ACCEPTED; while (true) { ReservationResponse reservation = getReservation(); if (!(reservation.getState().equals(lastState))) { lastState = reservation.getState(); log.debug("Service " + serviceId + " state updated to " + lastState); } switch (reservation.getState()) { case CANCELLED: if (state.equals(CANCELLED)) { return; } else { throw new ActionException("Reservation cancelled: " + reservation.getMessage()); } case FAILED: throw new ActionException("Reservation failed: " + reservation.getMessage()); default: break; } if (reservation.getState().ordinal() >= state.ordinal()) { return; } try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { throw new ActionException("Reservation was interrupted", e); } } } private ReservationResponse getReservation() throws UserAccessPointException_Exception { ServiceResponse service = userAccessPoint.queryService(serviceId); return getOnlyElement(service.getReservations()); } }