/* * Copyright 2015 the original author or authors. * * 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 org.gradle.tooling.internal.consumer.parameters; import org.gradle.internal.event.ListenerBroadcast; import org.gradle.tooling.Failure; import org.gradle.tooling.events.*; import org.gradle.tooling.events.internal.*; import org.gradle.tooling.events.task.*; import org.gradle.tooling.events.task.internal.*; import org.gradle.tooling.events.test.*; import org.gradle.tooling.events.test.internal.*; import org.gradle.tooling.internal.consumer.DefaultFailure; import org.gradle.tooling.internal.protocol.InternalBuildProgressListener; import org.gradle.tooling.internal.protocol.InternalFailure; import org.gradle.tooling.internal.protocol.events.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Converts progress events sent from the tooling provider to the tooling client to the corresponding event types available on the public Tooling API, and broadcasts the converted events to the * matching progress listeners. This adapter handles all the different incoming progress event types (except the original logging-derived progress listener). */ public class BuildProgressListenerAdapter implements InternalBuildProgressListener { private final ListenerBroadcast<ProgressListener> testProgressListeners = new ListenerBroadcast<ProgressListener>(ProgressListener.class); private final ListenerBroadcast<ProgressListener> taskProgressListeners = new ListenerBroadcast<ProgressListener>(ProgressListener.class); private final ListenerBroadcast<ProgressListener> buildOperationProgressListeners = new ListenerBroadcast<ProgressListener>(ProgressListener.class); private final Map<Object, OperationDescriptor> descriptorCache = new HashMap<Object, OperationDescriptor>(); BuildProgressListenerAdapter(List<ProgressListener> testProgressListeners, List<ProgressListener> taskProgressListeners, List<ProgressListener> buildOperationProgressListeners) { this.testProgressListeners.addAll(testProgressListeners); this.taskProgressListeners.addAll(taskProgressListeners); this.buildOperationProgressListeners.addAll(buildOperationProgressListeners); } @Override public List<String> getSubscribedOperations() { List<String> operations = new ArrayList<String>(); if (!testProgressListeners.isEmpty()) { operations.add(InternalBuildProgressListener.TEST_EXECUTION); } if (!taskProgressListeners.isEmpty()) { operations.add(InternalBuildProgressListener.TASK_EXECUTION); } if (!buildOperationProgressListeners.isEmpty()) { operations.add(InternalBuildProgressListener.BUILD_EXECUTION); } return operations; } @Override public void onEvent(Object event) { doBroadcast(event); } private void doBroadcast(Object event) { if (event instanceof ProgressEvent) { broadcastProgressEvent((ProgressEvent) event); } else if (event instanceof InternalTestProgressEvent) { // Special case for events defined prior to InternalBuildProgressEvent InternalTestProgressEvent progressEvent = (InternalTestProgressEvent) event; broadcastTestProgressEvent(progressEvent); } else if (event instanceof InternalProgressEvent) { InternalProgressEvent progressEvent = (InternalProgressEvent) event; if (progressEvent.getDescriptor() instanceof InternalTaskDescriptor) { broadcastTaskProgressEvent(progressEvent); } else { // Everything else treat as a generic operation broadcastProgressEvent(progressEvent); } } } private void broadcastProgressEvent(ProgressEvent event) { if (event instanceof TestProgressEvent) { testProgressListeners.getSource().statusChanged(event); } else if (event instanceof TaskProgressEvent) { taskProgressListeners.getSource().statusChanged(event); } else { // Everything else treat as a generic operation buildOperationProgressListeners.getSource().statusChanged(event); } } private void broadcastTestProgressEvent(InternalTestProgressEvent event) { TestProgressEvent testProgressEvent = toTestProgressEvent(event); if (testProgressEvent != null) { testProgressListeners.getSource().statusChanged(testProgressEvent); } } private void broadcastTaskProgressEvent(InternalProgressEvent event) { TaskProgressEvent taskProgressEvent = toTaskProgressEvent(event); if (taskProgressEvent != null) { taskProgressListeners.getSource().statusChanged(taskProgressEvent); } } private void broadcastProgressEvent(InternalProgressEvent event) { ProgressEvent progressEvent = toProgressEvent(event); if (progressEvent != null) { buildOperationProgressListeners.getSource().statusChanged(progressEvent); } } private TestProgressEvent toTestProgressEvent(InternalTestProgressEvent event) { if (event instanceof InternalTestStartedProgressEvent) { return testStartedEvent((InternalTestStartedProgressEvent) event); } else if (event instanceof InternalTestFinishedProgressEvent) { return testFinishedEvent((InternalTestFinishedProgressEvent) event); } else { return null; } } private TaskProgressEvent toTaskProgressEvent(InternalProgressEvent event) { if (event instanceof InternalOperationStartedProgressEvent) { return taskStartedEvent((InternalOperationStartedProgressEvent) event); } else if (event instanceof InternalOperationFinishedProgressEvent) { return taskFinishedEvent((InternalOperationFinishedProgressEvent) event); } else { return null; } } private ProgressEvent toProgressEvent(InternalProgressEvent event) { if (event instanceof InternalOperationStartedProgressEvent) { return startedEvent((InternalOperationStartedProgressEvent) event); } else if (event instanceof InternalOperationFinishedProgressEvent) { return finishedEvent((InternalOperationFinishedProgressEvent) event); } else { return null; } } private TestStartEvent testStartedEvent(InternalTestStartedProgressEvent event) { TestOperationDescriptor testDescriptor = addDescriptor(event.getDescriptor(), toTestDescriptor(event.getDescriptor())); return new DefaultTestStartEvent(event.getEventTime(), event.getDisplayName(), testDescriptor); } private TaskStartEvent taskStartedEvent(InternalOperationStartedProgressEvent event) { TaskOperationDescriptor descriptor = addDescriptor(event.getDescriptor(), toTaskDescriptor((InternalTaskDescriptor) event.getDescriptor())); return new DefaultTaskStartEvent(event.getEventTime(), event.getDisplayName(), descriptor); } private StartEvent startedEvent(InternalOperationStartedProgressEvent event) { OperationDescriptor descriptor = addDescriptor(event.getDescriptor(), toDescriptor(event.getDescriptor())); return new DefaultStartEvent(event.getEventTime(), event.getDisplayName(), descriptor); } private TestFinishEvent testFinishedEvent(InternalTestFinishedProgressEvent event) { TestOperationDescriptor descriptor = removeDescriptor(TestOperationDescriptor.class, event.getDescriptor()); return new DefaultTestFinishEvent(event.getEventTime(), event.getDisplayName(), descriptor, toTestResult(event.getResult())); } private TaskFinishEvent taskFinishedEvent(InternalOperationFinishedProgressEvent event) { TaskOperationDescriptor descriptor = removeDescriptor(TaskOperationDescriptor.class, event.getDescriptor()); return new DefaultTaskFinishEvent(event.getEventTime(), event.getDisplayName(), descriptor, toTaskResult((InternalTaskResult) event.getResult())); } private FinishEvent finishedEvent(InternalOperationFinishedProgressEvent event) { OperationDescriptor descriptor = removeDescriptor(OperationDescriptor.class, event.getDescriptor()); return new DefaultFinishEvent(event.getEventTime(), event.getDisplayName(), descriptor, toResult(event.getResult())); } private synchronized <T extends OperationDescriptor> T addDescriptor(InternalOperationDescriptor descriptor, T clientDescriptor) { OperationDescriptor cached = this.descriptorCache.get(descriptor.getId()); if (cached != null) { throw new IllegalStateException(String.format("Operation %s already available.", descriptor)); } descriptorCache.put(descriptor.getId(), clientDescriptor); return clientDescriptor; } private synchronized <T extends OperationDescriptor> T removeDescriptor(Class<T> type, InternalOperationDescriptor descriptor) { OperationDescriptor cachedTestDescriptor = this.descriptorCache.remove(descriptor.getId()); if (cachedTestDescriptor == null) { throw new IllegalStateException(String.format("Operation %s is not available.", descriptor)); } return assertDescriptorType(type, cachedTestDescriptor); } private <T extends OperationDescriptor> T assertDescriptorType(Class<T> type, OperationDescriptor descriptor) { Class<? extends OperationDescriptor> descriptorClass = descriptor.getClass(); if (!type.isAssignableFrom(descriptorClass)) { throw new IllegalStateException(String.format("Unexpected operation type. Required %s but found %s", type.getName(), descriptorClass.getName())); } return (T) descriptor; } private TestOperationDescriptor toTestDescriptor(InternalTestDescriptor descriptor) { OperationDescriptor parent = getParentDescriptor(descriptor.getParentId()); if (descriptor instanceof InternalJvmTestDescriptor) { InternalJvmTestDescriptor jvmTestDescriptor = (InternalJvmTestDescriptor) descriptor; return new DefaultJvmTestOperationDescriptor(jvmTestDescriptor, parent, toJvmTestKind(jvmTestDescriptor.getTestKind()), jvmTestDescriptor.getSuiteName(), jvmTestDescriptor.getClassName(), jvmTestDescriptor.getMethodName()); } else { return new DefaultTestOperationDescriptor(descriptor, parent); } } private static JvmTestKind toJvmTestKind(String testKind) { if (InternalJvmTestDescriptor.KIND_SUITE.equals(testKind)) { return JvmTestKind.SUITE; } else if (InternalJvmTestDescriptor.KIND_ATOMIC.equals(testKind)) { return JvmTestKind.ATOMIC; } else { return JvmTestKind.UNKNOWN; } } private TaskOperationDescriptor toTaskDescriptor(InternalTaskDescriptor descriptor) { OperationDescriptor parent = getParentDescriptor(descriptor.getParentId()); return new DefaultTaskOperationDescriptor(descriptor, descriptor.getTaskPath(), parent); } private OperationDescriptor toDescriptor(InternalOperationDescriptor descriptor) { OperationDescriptor parent = getParentDescriptor(descriptor.getParentId()); return new DefaultOperationDescriptor(descriptor, parent); } private synchronized OperationDescriptor getParentDescriptor(Object parentId) { if (parentId == null) { return null; } else { OperationDescriptor operationDescriptor = descriptorCache.get(parentId); if (operationDescriptor == null) { throw new IllegalStateException(String.format("Parent operation with id %s not available.", parentId)); } else { return operationDescriptor; } } } private TestOperationResult toTestResult(InternalTestResult result) { if (result instanceof InternalTestSuccessResult) { return new DefaultTestSuccessResult(result.getStartTime(), result.getEndTime()); } else if (result instanceof InternalTestSkippedResult) { return new DefaultTestSkippedResult(result.getStartTime(), result.getEndTime()); } else if (result instanceof InternalTestFailureResult) { return new DefaultTestFailureResult(result.getStartTime(), result.getEndTime(), toFailures(result.getFailures())); } else { return null; } } private static TaskOperationResult toTaskResult(InternalTaskResult result) { boolean fromCache = false; if (result instanceof InternalTaskCachedResult) { fromCache = ((InternalTaskCachedResult)result).isFromCache(); } if (result instanceof InternalTaskSuccessResult) { return new DefaultTaskSuccessResult(result.getStartTime(), result.getEndTime(), ((InternalTaskSuccessResult) result).isUpToDate(), fromCache); } else if (result instanceof InternalTaskSkippedResult) { return new DefaultTaskSkippedResult(result.getStartTime(), result.getEndTime(), ((InternalTaskSkippedResult) result).getSkipMessage()); } else if (result instanceof InternalTaskFailureResult) { return new DefaultTaskFailureResult(result.getStartTime(), result.getEndTime(), toFailures(result.getFailures())); } else { return null; } } private static OperationResult toResult(InternalOperationResult result) { if (result instanceof InternalSuccessResult) { return new DefaultOperationSuccessResult(result.getStartTime(), result.getEndTime()); } else if (result instanceof InternalFailureResult) { return new DefaultOperationFailureResult(result.getStartTime(), result.getEndTime(), toFailures(result.getFailures())); } else { return null; } } private static List<Failure> toFailures(List<? extends InternalFailure> causes) { if (causes == null) { return null; } List<Failure> failures = new ArrayList<Failure>(); for (InternalFailure cause : causes) { failures.add(toFailure(cause)); } return failures; } private static Failure toFailure(InternalFailure origFailure) { return origFailure == null ? null : new DefaultFailure( origFailure.getMessage(), origFailure.getDescription(), toFailures(origFailure.getCauses())); } }