/* * Copyright 2010 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.process.internal.worker.child; import org.gradle.api.Action; import org.gradle.api.logging.LogLevel; import org.gradle.internal.UncheckedException; import org.gradle.internal.concurrent.ExecutorFactory; import org.gradle.internal.event.DefaultListenerManager; import org.gradle.internal.event.ListenerManager; import org.gradle.internal.io.ClassLoaderObjectInputStream; import org.gradle.internal.logging.LoggingManagerInternal; import org.gradle.internal.logging.services.LoggingServiceRegistry; import org.gradle.internal.remote.MessagingClient; import org.gradle.internal.remote.ObjectConnection; import org.gradle.internal.remote.internal.inet.MultiChoiceAddress; import org.gradle.internal.remote.internal.inet.MultiChoiceAddressSerializer; import org.gradle.internal.remote.services.MessagingServices; import org.gradle.internal.serialize.Decoder; import org.gradle.internal.serialize.InputStreamBackedDecoder; import org.gradle.internal.service.DefaultServiceRegistry; import org.gradle.internal.service.ServiceRegistry; import org.gradle.process.internal.health.memory.DefaultJvmMemoryInfo; import org.gradle.process.internal.health.memory.DefaultMemoryManager; import org.gradle.process.internal.health.memory.DisabledOsMemoryInfo; import org.gradle.process.internal.health.memory.JvmMemoryInfo; import org.gradle.process.internal.health.memory.JvmMemoryStatus; import org.gradle.process.internal.health.memory.JvmMemoryStatusListener; import org.gradle.process.internal.health.memory.MemoryManager; import org.gradle.process.internal.health.memory.OsMemoryInfo; import org.gradle.process.internal.worker.WorkerLoggingSerializer; import org.gradle.process.internal.worker.WorkerJvmMemoryInfoSerializer; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.ObjectInputStream; import java.util.concurrent.Callable; /** * <p>Stage 2 of the start-up for a worker process with the application classes loaded in the system ClassLoader. Takes * care of deserializing and invoking the worker action.</p> * * <p> Instantiated in the implementation ClassLoader and invoked from {@link org.gradle.process.internal.worker.GradleWorkerMain}. * See {@link ApplicationClassesInSystemClassLoaderWorkerImplementationFactory} for details.</p> */ public class SystemApplicationClassLoaderWorker implements Callable<Void> { private final DataInputStream configInputStream; public SystemApplicationClassLoaderWorker(DataInputStream configInputStream) { this.configInputStream = configInputStream; } public Void call() throws Exception { if (System.getProperty("org.gradle.worker.test.stuck") != null) { // Simulate a stuck worker. There's probably a way to inject this failure... Thread.sleep(30000); return null; } Decoder decoder = new InputStreamBackedDecoder(configInputStream); // Read logging config and setup logging int logLevel = decoder.readSmallInt(); LoggingManagerInternal loggingManager = createLoggingManager(); loggingManager.setLevelInternal(LogLevel.values()[logLevel]).start(); // Read whether process info should be published boolean shouldPublishJvmMemoryInfo = decoder.readBoolean(); // Read server address and start connecting MultiChoiceAddress serverAddress = new MultiChoiceAddressSerializer().read(decoder); MessagingServices messagingServices = new MessagingServices(); WorkerServices workerServices = new WorkerServices(messagingServices); WorkerLogEventListener workerLogEventListener = null; try { // Read serialized worker byte[] serializedWorker = decoder.readBinary(); // Deserialize the worker action Action<WorkerContext> action; try { ObjectInputStream instr = new ClassLoaderObjectInputStream(new ByteArrayInputStream(serializedWorker), getClass().getClassLoader()); action = (Action<WorkerContext>) instr.readObject(); } catch (Exception e) { throw UncheckedException.throwAsUncheckedException(e); } final ObjectConnection connection = messagingServices.get(MessagingClient.class).getConnection(serverAddress); workerLogEventListener = configureLogging(loggingManager, connection); if (shouldPublishJvmMemoryInfo) { configureWorkerJvmMemoryInfoEvents(workerServices, connection); } try { action.execute(new WorkerContext() { public ClassLoader getApplicationClassLoader() { return ClassLoader.getSystemClassLoader(); } @Override public ObjectConnection getServerConnection() { return connection; } }); } finally { connection.stop(); } } finally { if (workerLogEventListener != null) { loggingManager.removeOutputEventListener(workerLogEventListener); } messagingServices.close(); loggingManager.stop(); } return null; } private WorkerLogEventListener configureLogging(LoggingManagerInternal loggingManager, ObjectConnection connection) { connection.useParameterSerializers(WorkerLoggingSerializer.create()); WorkerLoggingProtocol workerLoggingProtocol = connection.addOutgoing(WorkerLoggingProtocol.class); WorkerLogEventListener workerLogEventListener = new WorkerLogEventListener(workerLoggingProtocol); loggingManager.addOutputEventListener(workerLogEventListener); return workerLogEventListener; } private void configureWorkerJvmMemoryInfoEvents(WorkerServices services, ObjectConnection connection) { connection.useParameterSerializers(WorkerJvmMemoryInfoSerializer.create()); final WorkerJvmMemoryInfoProtocol workerJvmMemoryInfoProtocol = connection.addOutgoing(WorkerJvmMemoryInfoProtocol.class); services.get(MemoryManager.class).addListener(new JvmMemoryStatusListener() { @Override public void onJvmMemoryStatus(JvmMemoryStatus jvmMemoryStatus) { workerJvmMemoryInfoProtocol.sendJvmMemoryStatus(jvmMemoryStatus); } }); } LoggingManagerInternal createLoggingManager() { LoggingManagerInternal loggingManagerInternal = LoggingServiceRegistry.newEmbeddableLogging().newInstance(LoggingManagerInternal.class); loggingManagerInternal.captureSystemSources(); return loggingManagerInternal; } private static class WorkerServices extends DefaultServiceRegistry { public WorkerServices(ServiceRegistry parent) { super(parent); } ListenerManager createListenerManager() { return new DefaultListenerManager(); } OsMemoryInfo createOsMemoryInfo() { return new DisabledOsMemoryInfo(); } JvmMemoryInfo createJvmMemoryInfo() { return new DefaultJvmMemoryInfo(); } MemoryManager createMemoryManager(OsMemoryInfo osMemoryInfo, JvmMemoryInfo jvmMemoryInfo, ListenerManager listenerManager, ExecutorFactory executorFactory) { return new DefaultMemoryManager(osMemoryInfo, jvmMemoryInfo, listenerManager, executorFactory); } } }