/** * Copyright 2015-2016 Red Hat, Inc, and individual contributors. * * 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.wildfly.swarm.container.runtime; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; import javax.enterprise.inject.Produces; import javax.inject.Inject; import org.jboss.as.controller.ModelController; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.persistence.ExtensibleConfigurationPersister; import org.jboss.as.server.Bootstrap; import org.jboss.as.server.SelfContainedContainer; import org.jboss.as.server.ServerEnvironment; import org.jboss.as.server.Services; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.ServiceActivator; import org.jboss.msc.service.ServiceContainer; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartException; import org.jboss.msc.service.ValueService; import org.jboss.msc.value.ImmediateValue; import org.jboss.shrinkwrap.api.Archive; import org.wildfly.swarm.bootstrap.performance.Performance; import org.wildfly.swarm.bootstrap.util.TempFileManager; import org.wildfly.swarm.container.internal.Deployer; import org.wildfly.swarm.container.internal.Server; import org.wildfly.swarm.container.runtime.deployments.DefaultDeploymentCreator; import org.wildfly.swarm.container.runtime.marshal.DMRMarshaller; import org.wildfly.swarm.container.runtime.wildfly.ContentRepositoryServiceActivator; import org.wildfly.swarm.container.runtime.wildfly.SwarmContentRepository; import org.wildfly.swarm.container.runtime.wildfly.UUIDFactory; import org.wildfly.swarm.container.runtime.xmlconfig.BootstrapConfiguration; import org.wildfly.swarm.container.runtime.xmlconfig.BootstrapPersister; import org.wildfly.swarm.internal.SwarmMessages; import org.wildfly.swarm.spi.api.ArchivePreparer; import org.wildfly.swarm.spi.api.Customizer; import org.wildfly.swarm.spi.api.UserSpaceExtensionFactory; import org.wildfly.swarm.spi.runtime.annotations.Post; import org.wildfly.swarm.spi.runtime.annotations.Pre; /** * @author Bob McWhirter * @author Ken Finnigan */ @ApplicationScoped public class RuntimeServer implements Server { @Inject @Pre private Instance<Customizer> preCustomizers; @Inject @Post private Instance<Customizer> postCustomizers; @Inject @Any private Instance<ServiceActivator> serviceActivators; @Inject @Any private Instance<Archive> implicitDeployments; @Inject @Any private Instance<ArchivePreparer> archivePreparers; @Inject private DMRMarshaller dmrMarshaller; @Inject private DefaultDeploymentCreator defaultDeploymentCreator; @Inject private SwarmContentRepository contentRepository; @Inject private Instance<RuntimeDeployer> deployer; @Inject @Any private Instance<UserSpaceExtensionFactory> userSpaceExtensionFactories; @Inject private ConfigurableManager configurableManager; public RuntimeServer() { Runtime.getRuntime().addShutdownHook(new Thread(() -> { if (containerStarted) { try { SwarmMessages.MESSAGES.shutdownRequested(); stop(); } catch (Exception e) { throw new RuntimeException(e); } } })); } @Produces @ApplicationScoped ModelControllerClient client() { return this.client; } public Deployer start(boolean eagerOpen) throws Exception { UUID uuid = UUIDFactory.getUUID(); System.setProperty("jboss.server.management.uuid", uuid.toString()); File configurationFile; try { configurationFile = TempFileManager.INSTANCE.newTempFile("swarm-config-", ".xml"); } catch (IOException e) { throw new RuntimeException(e); } List<ModelNode> bootstrapOperations = new ArrayList<>(); BootstrapConfiguration bootstrapConfiguration = () -> bootstrapOperations; this.container = new SelfContainedContainer(new Bootstrap.ConfigurationPersisterFactory() { @Override public ExtensibleConfigurationPersister createConfigurationPersister(ServerEnvironment serverEnvironment, ExecutorService executorService) { return new BootstrapPersister(bootstrapConfiguration, configurationFile); } }); try (AutoCloseable handle = Performance.time("pre-customizers")) { for (Customizer each : this.preCustomizers) { SwarmMessages.MESSAGES.callingPreCustomizer(each); each.customize(); } } try (AutoCloseable handle = Performance.time("post-customizers")) { for (Customizer each : this.postCustomizers) { SwarmMessages.MESSAGES.callingPostCustomizer(each); each.customize(); } } this.archivePreparers.forEach(e -> { // Log it to prevent dead-code elimination. // // This is purely to ensure @Configurables are scanned // prior to logging the configurables. SwarmMessages.MESSAGES.registeredArchivePreparer(e.toString()); }); try (AutoCloseable handle = Performance.time("configurable-manager rescan")) { this.configurableManager.rescan(); this.configurableManager.log(); this.configurableManager.close(); } try (AutoCloseable handle = Performance.time("marshall DMR")) { this.dmrMarshaller.marshal(bootstrapOperations); } SwarmMessages.MESSAGES.wildflyBootstrap(bootstrapOperations.toString()); Thread.currentThread().setContextClassLoader(RuntimeServer.class.getClassLoader()); List<ServiceActivator> activators = new ArrayList<>(); this.serviceActivators.forEach(activators::add); activators.add(new ContentRepositoryServiceActivator(this.contentRepository)); try (AutoCloseable wildflyStart = Performance.time("WildFly start")) { ServiceContainer serviceContainer = null; try (AutoCloseable startWildflyItself = Performance.time("Starting WildFly itself")) { //serviceContainer = this.container.start(bootstrapOperations, this.contentProvider, activators); serviceContainer = this.container.start(bootstrapOperations, null, activators); this.containerStarted = true; } try (AutoCloseable checkFailedServices = Performance.time("Checking for failed services")) { for (ServiceName serviceName : serviceContainer.getServiceNames()) { ServiceController<?> serviceController = serviceContainer.getService(serviceName); StartException exception = serviceController.getStartException(); if (exception != null) { throw exception; } } } ModelController controller = (ModelController) serviceContainer.getService(Services.JBOSS_SERVER_CONTROLLER).getValue(); Executor executor = Executors.newSingleThreadExecutor(); try (AutoCloseable creatingControllerClient = Performance.time("Creating controller client")) { this.client = controller.createClient(executor); } RuntimeDeployer deployer = this.deployer.get(); try (AutoCloseable installDeployer = Performance.time("Installing deployer")) { serviceContainer.addService(ServiceName.of("swarm", "deployer"), new ValueService<>(new ImmediateValue<Deployer>(deployer))).install(); } try (AutoCloseable configUserSpaceExt = Performance.time("Configure user-space extensions")) { configureUserSpaceExtensions(); } try (AutoCloseable deployments = Performance.time("Implicit Deployments")) { for (Archive each : this.implicitDeployments) { if (each != null) { deployer.deploy(each); } } } return deployer; } } private void configureUserSpaceExtensions() { this.userSpaceExtensionFactories.forEach(factory -> { try { factory.configure(); } catch (Exception e) { SwarmMessages.MESSAGES.errorInstallingUserSpaceExtension(factory.getClass().getName()); } }); } public void stop() throws Exception { this.container.stop(); awaitContainerTermination(); this.containerStarted = false; this.container = null; this.client = null; this.deployer = null; } private void awaitContainerTermination() { try { Field field = this.container.getClass().getDeclaredField("executor"); field.setAccessible(true); ExecutorService executor = (ExecutorService) field.get(this.container); executor.awaitTermination(10, TimeUnit.SECONDS); } catch (NoSuchFieldException | IllegalAccessException | InterruptedException e) { SwarmMessages.MESSAGES.errorWaitingForContainerShutdown(e); } } @Override public Deployer deployer() { return this.deployer.get(); } private SelfContainedContainer container; // Container does not expose this state and it's class is final so it cannot be subclassed. private boolean containerStarted; private ModelControllerClient client; }