Package org.wildfly.extension.gravia.service

Source Code of org.wildfly.extension.gravia.service.WildFlyResourceInstaller

/*
* #%L
* Gravia :: Container :: WildFly :: Extension
* %%
* Copyright (C) 2010 - 2014 JBoss by Red Hat
* %%
* 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.
* #L%
*/

package org.wildfly.extension.gravia.service;

import static org.wildfly.extension.gravia.GraviaExtensionLogger.LOGGER;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Executors;

import org.jboss.as.controller.ModelController;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentHelper;
import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentManager;
import org.jboss.as.server.ServerEnvironment;
import org.jboss.as.server.ServerEnvironmentService;
import org.jboss.as.server.Services;
import org.jboss.as.server.moduleservice.ServiceModuleLoader;
import org.jboss.gravia.provision.ResourceHandle;
import org.jboss.gravia.provision.ResourceInstaller;
import org.jboss.gravia.provision.spi.AbstractResourceHandle;
import org.jboss.gravia.provision.spi.AbstractResourceInstaller;
import org.jboss.gravia.provision.spi.RuntimeEnvironment;
import org.jboss.gravia.resource.Capability;
import org.jboss.gravia.resource.IdentityNamespace;
import org.jboss.gravia.resource.Requirement;
import org.jboss.gravia.resource.Resource;
import org.jboss.gravia.resource.ResourceContent;
import org.jboss.gravia.resource.ResourceIdentity;
import org.jboss.gravia.resource.Version;
import org.jboss.gravia.resource.VersionRange;
import org.jboss.gravia.runtime.Module;
import org.jboss.gravia.runtime.ModuleContext;
import org.jboss.gravia.runtime.Runtime;
import org.jboss.gravia.runtime.RuntimeLocator;
import org.jboss.gravia.runtime.ServiceRegistration;
import org.jboss.gravia.runtime.spi.NamedResourceAssociation;
import org.jboss.gravia.utils.IOUtils;
import org.jboss.gravia.utils.IllegalStateAssertion;
import org.jboss.modules.ModuleClassLoader;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.jboss.shrinkwrap.api.ConfigurationBuilder;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.importer.ZipImporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.wildfly.extension.gravia.GraviaConstants;

/**
* Service providing the {@link ResourceInstaller}.
*
* @author Thomas.Diesler@jboss.com
* @since 27-Jun-2013
*/
public class WildFlyResourceInstaller extends AbstractResourceInstaller implements Service<ResourceInstaller> {

    private final InjectedValue<ServerEnvironment> injectedServerEnvironment = new InjectedValue<ServerEnvironment>();
    private final InjectedValue<ServiceModuleLoader> injectedServiceModuleLoader = new InjectedValue<ServiceModuleLoader>();
    private final InjectedValue<ModelController> injectedController = new InjectedValue<ModelController>();
    private final InjectedValue<ModuleContext> injectedModuleContext = new InjectedValue<ModuleContext>();
    private final InjectedValue<RuntimeEnvironment> injectedEnvironment = new InjectedValue<RuntimeEnvironment>();
    private ServerDeploymentManager serverDeploymentManager;
    private ModelControllerClient modelControllerClient;
    private ServiceRegistration<?> registration;

    public ServiceController<ResourceInstaller> install(ServiceTarget serviceTarget, ServiceVerificationHandler verificationHandler) {
        ServiceBuilder<ResourceInstaller> builder = serviceTarget.addService(GraviaConstants.RESOURCE_INSTALLER_SERVICE_NAME, this);
        builder.addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, injectedServerEnvironment);
        builder.addDependency(GraviaConstants.ENVIRONMENT_SERVICE_NAME, RuntimeEnvironment.class, injectedEnvironment);
        builder.addDependency(GraviaConstants.MODULE_CONTEXT_SERVICE_NAME, ModuleContext.class, injectedModuleContext);
        builder.addDependency(Services.JBOSS_SERVICE_MODULE_LOADER, ServiceModuleLoader.class, injectedServiceModuleLoader);
        builder.addDependency(Services.JBOSS_SERVER_CONTROLLER, ModelController.class, injectedController);
        builder.addListener(verificationHandler);
        return builder.install();
    }

    @Override
    public void start(StartContext startContext) throws StartException {
        ModelController modelController = injectedController.getValue();
        modelControllerClient = modelController.createClient(Executors.newCachedThreadPool());
        serverDeploymentManager = ServerDeploymentManager.Factory.create(modelControllerClient);

        ModuleContext syscontext = injectedModuleContext.getValue();
        registration = syscontext.registerService(ResourceInstaller.class, this, null);
    }

    @Override
    public void stop(StopContext context) {
        if (registration != null) {
            registration.unregister();
        }
        try {
            modelControllerClient.close();
        } catch (IOException ex) {
            // ignore
        }
    }

    @Override
    public ResourceInstaller getValue() throws IllegalStateException {
        return this;
    }

    @Override
    public RuntimeEnvironment getEnvironment() {
        return injectedEnvironment.getValue();
    }

    @Override
    public ResourceHandle installResourceProtected(Context context, Resource resource, boolean shared, String runtimeName) throws Exception {
        ResourceHandle handle;
        if (shared) {
            handle = installSharedResourceInternal(context, resource);
        } else {
            handle = installUnsharedResourceInternal(runtimeName, context, resource);
        }
        return handle;
    }

    @SuppressWarnings("deprecation")
    private ResourceHandle installSharedResourceInternal(Context context, Resource resource) throws Exception {
        LOGGER.info("Installing shared resource: {}", resource);

        ResourceIdentity identity = resource.getIdentity();
        String symbolicName = identity.getSymbolicName();
        Version version = identity.getVersion();
        File modulesDir = injectedServerEnvironment.getValue().getModulesDir();
        File moduleDir = new File(modulesDir, symbolicName.replace(".", File.separator) + File.separator + version);
        if (moduleDir.exists())
            throw new IllegalStateException("Module dir already exists: " + moduleDir);

        ResourceContent content = resource.adapt(ResourceContent.class);
        IllegalStateAssertion.assertNotNull(content, "Cannot obtain content from: " + resource);

        // copy resource content
        moduleDir.mkdirs();
        File resFile = new File(moduleDir, symbolicName + "-" + version + ".jar");
        IOUtils.copyStream(content.getContent(), new FileOutputStream(resFile));

        ModuleIdentifier modid = ModuleIdentifier.create(symbolicName, version.toString());

        // generate module.xml
        File xmlFile = new File(moduleDir, "module.xml");
        Map<Requirement, Resource> mapping = context.getResourceMapping();
        String moduleXML = generateModuleXML(resFile, resource, modid, mapping);
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(xmlFile));
        osw.write(moduleXML);
        osw.close();

        // generate the main slot
        File mainDir = new File(moduleDir.getParentFile(), "main");
        if (!mainDir.exists()) {
            mainDir.mkdirs();
            File mainFile = new File(mainDir, "module.xml");
            moduleXML = generateModuleAliasXML(resource, modid);
            osw = new OutputStreamWriter(new FileOutputStream(mainFile));
            osw.write(moduleXML);
            osw.close();
        }

        // Install the resource as module
        ModuleLoader moduleLoader = org.jboss.modules.Module.getBootModuleLoader();
        ModuleClassLoader classLoader = moduleLoader.loadModule(modid).getClassLoader();
        Runtime runtime = RuntimeLocator.getRequiredRuntime();
        Module module = runtime.installModule(classLoader, resource, null);

        // Start the module
        module.start();

        Resource modres = module.adapt(Resource.class);
        return new AbstractResourceHandle(modres, module) {
            @Override
            public void uninstall() {
                LOGGER.info("Cannot uninstall shared resource: {}", getResource());
            }
        };
    }

    private ResourceHandle installUnsharedResourceInternal(String runtimeName, Context context, Resource resource) throws Exception {
        LOGGER.info("Installing unshared resource: {}", resource);

        final ServerDeploymentHelper serverDeployer = new ServerDeploymentHelper(serverDeploymentManager);
        final ResourceWrapper wrapper = getWrappedResourceContent(runtimeName, resource, context.getResourceMapping());

        runtimeName = wrapper.getRuntimeName();
        NamedResourceAssociation.putResource(wrapper.getRuntimeName(), resource);
        try {
            String deploymentName = wrapper.getDeploymentName();
            serverDeployer.deploy(deploymentName, wrapper.getInputStream());
        } finally {
            NamedResourceAssociation.removeResource(runtimeName);
        }

        // Install the resource as module if it has not happend already
        Runtime runtime = RuntimeLocator.getRequiredRuntime();
        Module module = runtime.getModule(resource.getIdentity());
        if (module == null) {
            ModuleLoader moduleLoader = injectedServiceModuleLoader.getValue();
            ModuleIdentifier modid = ModuleIdentifier.create(ServiceModuleLoader.MODULE_PREFIX + runtimeName);
            ClassLoader classLoader = moduleLoader.loadModule(modid).getClassLoader();
            module = runtime.installModule(classLoader, resource, null);
        }

        Resource modres = module != null ? module.adapt(Resource.class) : resource;
        return new AbstractResourceHandle(modres, module) {
            @Override
            public void uninstall() {
                try {
                    String deploymentName = wrapper.getDeploymentName();
                    serverDeployer.undeploy(deploymentName);
                } catch (Throwable th) {
                    LOGGER.warn("Cannot uninstall provisioned resource: " + getResource(), th);
                }
            }
        };
    }

    // Wrap the resource and add a generated jboss-deployment-structure.xml
    private ResourceWrapper getWrappedResourceContent(String runtimeName, Resource resource, Map<Requirement, Resource> mapping) {

        Capability icap = resource.getIdentityCapability();
        if (runtimeName == null) {
            String rtnameAtt = (String) icap.getAttribute(IdentityNamespace.CAPABILITY_RUNTIME_NAME_ATTRIBUTE);
            runtimeName = rtnameAtt != null ? rtnameAtt : resource.getIdentity().getSymbolicName() + ".jar";
        }

        // Do nothing if there is no mapping
        if (mapping == null || mapping.isEmpty()) {
            InputStream content = resource.adapt(ResourceContent.class).getContent();
            return new ResourceWrapper(runtimeName, runtimeName, content);
        }

        // Create content archive
        ConfigurationBuilder config = new ConfigurationBuilder().classLoaders(Collections.singleton(ShrinkWrap.class.getClassLoader()));
        JavaArchive archive = ShrinkWrap.createDomain(config).getArchiveFactory().create(JavaArchive.class, runtimeName);
        archive.as(ZipImporter.class).importFrom(resource.adapt(ResourceContent.class).getContent());

        boolean wrapAsSubdeployment = runtimeName.endsWith(".war");

        // Create wrapper archive
        JavaArchive wrapper;
        Asset structureAsset;
        if (wrapAsSubdeployment) {
            wrapper = ShrinkWrap.createDomain(config).getArchiveFactory().create(JavaArchive.class, "wrapped-" + runtimeName + ".ear");
            structureAsset = new StringAsset(generateSubdeploymentDeploymentStructure(resource, runtimeName, mapping));
        } else {
            wrapper = ShrinkWrap.createDomain(config).getArchiveFactory().create(JavaArchive.class, "wrapped-" + runtimeName);
            structureAsset = new StringAsset(generateDeploymentStructure(resource, runtimeName, mapping));
        }
        wrapper.addAsManifestResource(structureAsset, "jboss-deployment-structure.xml");
        wrapper.add(archive, "/", ZipExporter.class);

        InputStream content = wrapper.as(ZipExporter.class).exportAsInputStream();
        return new ResourceWrapper(wrapper.getName(), runtimeName, content);
    }

    private String generateModuleXML(File resFile, Resource resource, ModuleIdentifier modid, Map<Requirement, Resource> mapping) throws IOException {
        LOGGER.info("Generating dependencies for: {}", resource);
        StringBuffer buffer = new StringBuffer();
        buffer.append("<module xmlns='urn:jboss:module:1.3' name='" + modid.getName() + "' slot='" + modid.getSlot() + "'>");
        buffer.append(" <resources>");
        buffer.append("  <resource-root path='" + resFile.getName() + "'/>");
        buffer.append(" </resources>");
        addModuleDependencies(resource, mapping, buffer);
        buffer.append("</module>");
        return buffer.toString();
    }

    private String generateModuleAliasXML(Resource resource, ModuleIdentifier modid) throws IOException {
        LOGGER.info("Generating main alias for: {}", resource);
        StringBuffer buffer = new StringBuffer();
        buffer.append("<module-alias xmlns='urn:jboss:module:1.3' name='" + modid.getName() + "' target-name='" + modid.getName() + "' target-slot='" + modid.getSlot() + "'/>");
        return buffer.toString();
    }

    private String generateDeploymentStructure(Resource res, String runtimeName, Map<Requirement, Resource> mapping) {
        LOGGER.info("Generating dependencies for: {}", res);
        StringBuffer buffer = new StringBuffer();
        buffer.append("<jboss-deployment-structure xmlns='urn:jboss:deployment-structure:1.2'>");
        buffer.append(" <deployment>");
        buffer.append("  <resources>");
        buffer.append("   <resource-root path='" + runtimeName + "' use-physical-code-source='true'/>");
        buffer.append("  </resources>");
        addModuleDependencies(res, mapping, buffer);
        buffer.append(" </deployment>");
        buffer.append("</jboss-deployment-structure>");
        return buffer.toString();
    }

    private String generateSubdeploymentDeploymentStructure(Resource resource, String runtimeName, Map<Requirement, Resource> mapping) {
        LOGGER.info("Generating dependencies for: {}", resource);
        StringBuffer buffer = new StringBuffer();
        buffer.append("<jboss-deployment-structure xmlns='urn:jboss:deployment-structure:1.2'>");
        buffer.append(" <sub-deployment name='" + runtimeName + "'>");
        buffer.append("  <resources>");
        buffer.append("   <resource-root path='" + runtimeName + "' use-physical-code-source='true'/>");
        buffer.append("  </resources>");
        addModuleDependencies(resource, mapping, buffer);
        buffer.append(" </sub-deployment>");
        buffer.append("</jboss-deployment-structure>");
        return buffer.toString();
    }

    private void addModuleDependencies(Resource resource, Map<Requirement, Resource> mapping, StringBuffer buffer) {
        buffer.append(" <dependencies>");
        for (Requirement req : resource.getRequirements(IdentityNamespace.IDENTITY_NAMESPACE)) {
            Resource depres = mapping != null ? mapping.get(req) : null;
            if (depres != null) {
                ResourceIdentity identity = depres.getIdentity();
                String modname = identity.getSymbolicName();
                Version version = identity.getVersion();
                String slot = version != Version.emptyVersion ? "slot='" + version + "'" : "";
                buffer.append("<module name='" + modname + "' " + slot + "/>");
                LOGGER.info("  {}", identity);
            } else {
                String modname = (String) req.getAttribute(IdentityNamespace.IDENTITY_NAMESPACE);
                VersionRange versionRange = (VersionRange) req.getAttribute(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
                if (versionRange != null) {
                    LOGGER.warn("Cannot find mapping for: {}", req);
                }
                buffer.append("<module name='" + modname + "'/>");
                LOGGER.info("  {}", modname);
            }
        }
        buffer.append(" </dependencies>");
    }

    static class ResourceWrapper {
        private final String deploymentName;
        private final String runtimeName;
        private final InputStream inputStream;
        ResourceWrapper(String deploymentName, String runtimeName, InputStream inputStream) {
            this.deploymentName = deploymentName;
            this.runtimeName = runtimeName;
            this.inputStream = inputStream;
        }
        String getDeploymentName() {
            return deploymentName;
        }
        String getRuntimeName() {
            return runtimeName;
        }
        InputStream getInputStream() {
            return inputStream;
        }
    }
}
TOP

Related Classes of org.wildfly.extension.gravia.service.WildFlyResourceInstaller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.