/* * * * Copyright 2000-2014 JetBrains s.r.o. * * * * 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://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License 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 jetbrains.buildServer.clouds.vmware.connector; import com.vmware.vim25.LocalizedMethodFault; import com.vmware.vim25.TaskInfo; import com.vmware.vim25.TaskInfoState; import com.vmware.vim25.mo.Task; import java.rmi.RemoteException; import java.util.Date; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import jetbrains.buildServer.clouds.base.connector.AsyncCloudTask; import jetbrains.buildServer.clouds.base.connector.CloudTaskResult; import jetbrains.buildServer.util.impl.Lazy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Sergey.Pak * Date: 7/29/2014 * Time: 6:22 PM */ public class VmwareTaskWrapper implements AsyncCloudTask { private static final int FAILURE_COUNT_TRESHOLD = 3; private final Callable<Task> myVmwareTask; private final AtomicBoolean myTaskCancelled; private final Lazy<Future<CloudTaskResult>> myFutureLazy; private final String myTaskName; private volatile long myStartTime; public VmwareTaskWrapper(@NotNull final Callable<Task> vmwareTask, String taskName){ myVmwareTask = vmwareTask; myTaskName = taskName; myTaskCancelled = new AtomicBoolean(false); myFutureLazy = new Lazy<Future<CloudTaskResult>>() { @Nullable @Override protected Future<CloudTaskResult> createValue() { return execute(); } }; } public Future<CloudTaskResult> executeOrGetResultAsync() { return myFutureLazy.getValue(); } @NotNull public String getName() { return myTaskName; } public long getStartTime() { return myStartTime; } private Future<CloudTaskResult> execute() { final Task task; try { task = myVmwareTask.call(); myStartTime = System.currentTimeMillis(); } catch (final Exception e) { return createExceptionFuture(e); } return new Future<CloudTaskResult>() { private final AtomicInteger failureCount = new AtomicInteger(0); private CloudTaskResult myErrorResult = null; public boolean cancel(final boolean mayInterruptIfRunning) { try { task.cancelTask(); myTaskCancelled.set(true); return true; } catch (RemoteException e) { e.printStackTrace(); return false; } } public boolean isCancelled() { return myTaskCancelled.get(); } public boolean isDone() { try { final TaskInfo taskInfo = task.getTaskInfo(); return (taskInfo.getState() == TaskInfoState.success || taskInfo.getState() == TaskInfoState.error); } catch (RemoteException e) { return false; } catch (Exception e) { // wait 3 times, then throw an error: if (failureCount.getAndIncrement() >= FAILURE_COUNT_TRESHOLD){ myErrorResult = new CloudTaskResult(true, e.toString(), e); return true; } return false; } } public CloudTaskResult get() throws InterruptedException, ExecutionException { if (myErrorResult!= null){ return myErrorResult; } try { final String result = task.waitForTask(); TaskInfo taskInfo = task.getTaskInfo(); if (taskInfo.getState() == TaskInfoState.error){ final LocalizedMethodFault error = taskInfo.getError(); return new CloudTaskResult(true, result, new Exception(error== null ? "Unknown error" : error.getLocalizedMessage())); } else { return new CloudTaskResult(result); } } catch (Exception e) { return new CloudTaskResult(true, e.toString(), e); } } public CloudTaskResult get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { final int mss = (int)TimeUnit.MILLISECONDS.convert(timeout, unit); try { final String result = task.waitForTask(mss / 2, mss / 2); TaskInfo taskInfo = task.getTaskInfo(); if (taskInfo.getState() == TaskInfoState.error){ final LocalizedMethodFault error = taskInfo.getError(); return new CloudTaskResult(true, result, new Exception(error== null ? "Unknown error" : error.getLocalizedMessage())); } else { return new CloudTaskResult(result); } } catch (Exception e) { return new CloudTaskResult(true, e.toString(), e); } } }; } private Future<CloudTaskResult> createExceptionFuture(final Exception e) { return new Future<CloudTaskResult>() { public boolean cancel(final boolean mayInterruptIfRunning) { return false; } public boolean isCancelled() { return false; } public boolean isDone() { return true; } public CloudTaskResult get() throws InterruptedException, ExecutionException { throw new ExecutionException (e); } public CloudTaskResult get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { throw new ExecutionException (e); } }; } @Override public String toString() { return "VmwareTaskWrapper{" + "TaskName='" + myTaskName + '\'' + ",StartTime=" + new Date(myStartTime) + '}'; } }