org.wildfly.galleon.plugin.WfInstallPlugin Maven / Gradle / Ivy
/*
* Copyright 2016-2018 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.galleon.plugin;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Stream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
import nu.xom.Serializer;
import org.jboss.galleon.ArtifactCoords;
import org.jboss.galleon.ArtifactException;
import org.jboss.galleon.ArtifactRepositoryManager;
import org.jboss.galleon.Errors;
import org.jboss.galleon.MessageWriter;
import org.jboss.galleon.ProvisioningDescriptionException;
import org.jboss.galleon.ProvisioningException;
import org.jboss.galleon.ProvisioningManager;
import org.jboss.galleon.config.ConfigId;
import org.jboss.galleon.config.ConfigModel;
import org.jboss.galleon.config.FeaturePackConfig;
import org.jboss.galleon.config.ProvisioningConfig;
import org.jboss.galleon.plugin.InstallPlugin;
import org.jboss.galleon.plugin.PluginOption;
import org.jboss.galleon.plugin.ProvisioningPluginWithOptions;
import org.jboss.galleon.runtime.FeaturePackRuntime;
import org.jboss.galleon.runtime.PackageRuntime;
import org.jboss.galleon.runtime.ProvisioningRuntime;
import org.jboss.galleon.util.IoUtils;
import org.jboss.galleon.util.CollectionUtils;
import org.jboss.galleon.util.PropertyUtils;
import org.jboss.galleon.util.ZipUtils;
import org.wildfly.galleon.plugin.config.CopyArtifact;
import org.wildfly.galleon.plugin.config.CopyPath;
import org.wildfly.galleon.plugin.config.DeletePath;
import org.wildfly.galleon.plugin.config.ExampleFpConfigs;
import org.wildfly.galleon.plugin.config.FilePermission;
import org.wildfly.galleon.plugin.config.XslTransform;
import org.wildfly.galleon.plugin.server.CliScriptRunner;
/**
*
* @author Alexey Loubyansky
*/
public class WfInstallPlugin extends ProvisioningPluginWithOptions implements InstallPlugin {
private static final String CONFIG_GEN_METHOD = "generate";
private static final String CONFIG_GEN_PATH = "wildfly/wildfly-config-gen.jar";
private static final String CONFIG_GEN_CLASS = "org.wildfly.galleon.plugin.config.generator.WfConfigGenerator";
private ProvisioningRuntime runtime;
private PropertyResolver versionResolver;
private List installationClassPath = new ArrayList<>();
private Map fpTasksProps = Collections.emptyMap();
private Properties mergedTaskProps = new Properties();
private PropertyResolver mergedTaskPropsResolver;
private boolean thinServer;
private Set schemaGroups = Collections.emptySet();
private final PluginOption mavenDistOption = PluginOption.builder("jboss-maven-dist").hasNoValue().build();
private List finalizingTasks = Collections.emptyList();
private List finalizingTasksPkgs = Collections.emptyList();
private DocumentBuilderFactory docBuilderFactory;
private TransformerFactory xsltFactory;
private Map xslTransformers = Collections.emptyMap();
private Map exampleConfigs = Collections.emptyMap();
@Override
protected List initPluginOptions() {
return Collections.singletonList(mavenDistOption);
}
public ProvisioningRuntime getRuntime() {
return runtime;
}
/* (non-Javadoc)
* @see org.jboss.galleon.util.plugin.ProvisioningPlugin#execute()
*/
@Override
public void postInstall(ProvisioningRuntime runtime) throws ProvisioningException {
final MessageWriter messageWriter = runtime.getMessageWriter();
messageWriter.verbose("WildFly Galleon install plugin");
this.runtime = runtime;
thinServer = runtime.isOptionSet(mavenDistOption);
final Map artifactVersions = new HashMap<>();
for(FeaturePackRuntime fp : runtime.getFeaturePacks()) {
final Path wfRes = fp.getResource(WfConstants.WILDFLY);
if(!Files.exists(wfRes)) {
continue;
}
final Path artifactProps = wfRes.resolve(WfConstants.ARTIFACT_VERSIONS_PROPS);
if(Files.exists(artifactProps)) {
try (Stream lines = Files.lines(artifactProps)) {
final Iterator iterator = lines.iterator();
while (iterator.hasNext()) {
final String line = iterator.next();
final int i = line.indexOf('=');
if (i < 0) {
throw new ProvisioningException("Failed to locate '=' character in " + line);
}
artifactVersions.put(line.substring(0, i), line.substring(i + 1));
}
} catch (IOException e) {
throw new ProvisioningException(Errors.readFile(artifactProps), e);
}
}
final Path tasksPropsPath = wfRes.resolve(WfConstants.WILDFLY_TASKS_PROPS);
if(Files.exists(tasksPropsPath)) {
final Properties fpProps = new Properties();
try(InputStream in = Files.newInputStream(tasksPropsPath)) {
fpProps.load(in);
} catch (IOException e) {
throw new ProvisioningException(Errors.readFile(tasksPropsPath), e);
}
fpTasksProps = CollectionUtils.put(fpTasksProps, fp.getGav(), fpProps);
mergedTaskProps.putAll(fpProps);
}
if(fp.containsPackage(WfConstants.DOCS_SCHEMA)) {
final Path schemaGroupsTxt = fp.getPackage(WfConstants.DOCS_SCHEMA).getResource(
WfConstants.PM, WfConstants.WILDFLY, WfConstants.SCHEMA_GROUPS_TXT);
try(BufferedReader reader = Files.newBufferedReader(schemaGroupsTxt)) {
String line = reader.readLine();
while(line != null) {
schemaGroups = CollectionUtils.add(schemaGroups, line);
line = reader.readLine();
}
} catch (IOException e) {
throw new ProvisioningException(Errors.readFile(schemaGroupsTxt), e);
}
}
}
mergedTaskPropsResolver = new MapPropertyResolver(mergedTaskProps);
versionResolver = new MapPropertyResolver(artifactVersions);
for(FeaturePackRuntime fp : runtime.getFeaturePacks()) {
processPackages(fp);
}
generateConfigs(runtime, messageWriter);
// TODO this needs to be revisited
for(FeaturePackRuntime fp : runtime.getFeaturePacks()) {
final Path finalizeCli = fp.getResource(WfConstants.WILDFLY, WfConstants.SCRIPTS, "finalize.cli");
if(Files.exists(finalizeCli)) {
CliScriptRunner.runCliScript(runtime.getStagedDir(), finalizeCli, messageWriter);
}
}
if(!finalizingTasks.isEmpty()) {
for(int i = 0; i < finalizingTasks.size(); ++i) {
finalizingTasks.get(i).execute(this, finalizingTasksPkgs.get(i));
}
}
if(!exampleConfigs.isEmpty()) {
provisionExampleConfigs();
}
}
private void provisionExampleConfigs() throws ProvisioningException {
final Path examplesTmp = runtime.getTmpPath("example-configs");
final ProvisioningManager pm = ProvisioningManager.builder()
.setInstallationHome(examplesTmp)
.setMessageWriter(runtime.getMessageWriter())
.setArtifactResolver(new ArtifactRepositoryManager() {
@Override
public Path resolve(ArtifactCoords coords) throws ArtifactException {
return runtime.resolveArtifact(coords);
}
@Override
public void install(ArtifactCoords coords, Path artifact) throws ArtifactException {
throw new UnsupportedOperationException();
}
@Override
public void deploy(ArtifactCoords coords, Path artifact) throws ArtifactException {
throw new UnsupportedOperationException();
}
@Override
public String getHighestVersion(ArtifactCoords coords, String range) throws ArtifactException {
throw new UnsupportedOperationException();
}})
.build();
final ProvisioningConfig.Builder configBuilder = ProvisioningConfig.builder();
for(Map.Entry entry : exampleConfigs.entrySet()) {
final FeaturePackConfig.Builder fpBuilder = FeaturePackConfig.builder(entry.getKey())
.setInheritConfigs(false)
.setInheritPackages(false);
for(Map.Entry config : entry.getValue().getConfigs().entrySet()) {
if(config.getValue() != null) {
fpBuilder.addConfig(config.getValue());
} else {
fpBuilder.includeDefaultConfig(config.getKey());
}
}
configBuilder.addFeaturePackDep(fpBuilder.build());
}
try {
runtime.getMessageWriter().verbose("Generating example configs");
ProvisioningConfig config = configBuilder.build();
pm.provision(config, Collections.singletonMap(mavenDistOption.getName(), null));
} catch(ProvisioningException e) {
throw new ProvisioningException("Failed to generate example configs", e);
}
copyExampleConfigs(examplesTmp.resolve(WfConstants.STANDALONE).resolve("configuration"));
copyExampleConfigs(examplesTmp.resolve(WfConstants.DOMAIN).resolve("configuration"));
}
private void copyExampleConfigs(Path configDir) throws ProvisioningException {
if(!Files.exists(configDir)) {
return;
}
try (DirectoryStream stream = Files.newDirectoryStream(configDir)) {
final Iterator i = stream.iterator();
while (i.hasNext()) {
final Path p = i.next();
final String name = p.getFileName().toString();
if (name.endsWith(".xml")) {
Path target = runtime.getStagedDir().resolve(WfConstants.DOCS).resolve("examples").resolve("configs")
.resolve(name);
IoUtils.copy(p, target);
}
}
} catch (IOException e) {
throw new ProvisioningException("Failed to copy example configs", e);
}
}
private void generateConfigs(ProvisioningRuntime runtime, final MessageWriter messageWriter) throws ProvisioningException {
if(!runtime.hasConfigs()) {
return;
}
final Path configGenJar = runtime.getResource(CONFIG_GEN_PATH);
if(!Files.exists(configGenJar)) {
throw new ProvisioningException(Errors.pathDoesNotExist(configGenJar));
}
final List cp = new ArrayList<>();
try {
cp.add(configGenJar.toUri().toURL());
for(Path p : installationClassPath) {
cp.add(p.toUri().toURL());
}
} catch (IOException e) {
throw new ProvisioningException("Failed to init classpath for " + runtime.getStagedDir(), e);
}
final ClassLoader originalCl = Thread.currentThread().getContextClassLoader();
final URLClassLoader configGenCl = new URLClassLoader(cp.toArray(new URL[cp.size()]), originalCl);
Thread.currentThread().setContextClassLoader(configGenCl);
try {
final Class> configHandlerCls = configGenCl.loadClass(CONFIG_GEN_CLASS);
final Constructor> ctor = configHandlerCls.getConstructor();
final Method m = configHandlerCls.getMethod(CONFIG_GEN_METHOD, ProvisioningRuntime.class);
final Object generator = ctor.newInstance();
m.invoke(generator, runtime);
} catch(InvocationTargetException e) {
final Throwable cause = e.getCause();
if(cause instanceof ProvisioningException) {
throw (ProvisioningException)cause;
} else {
throw new ProvisioningException("Failed to invoke config generator " + CONFIG_GEN_CLASS, cause);
}
} catch (Throwable e) {
throw new ProvisioningException("Failed to initialize config generator " + CONFIG_GEN_CLASS, e);
} finally {
Thread.currentThread().setContextClassLoader(originalCl);
try {
configGenCl.close();
} catch (IOException e) {
}
}
}
private void processPackages(final FeaturePackRuntime fp) throws ProvisioningException {
for(PackageRuntime pkg : fp.getPackages()) {
final Path pmWfDir = pkg.getResource(WfConstants.PM, WfConstants.WILDFLY);
if(!Files.exists(pmWfDir)) {
continue;
}
final Path moduleDir = pmWfDir.resolve(WfConstants.MODULE);
if(Files.exists(moduleDir)) {
processModules(fp.getGav(), pkg.getName(), moduleDir);
}
final Path tasksXml = pmWfDir.resolve(WfConstants.TASKS_XML);
if(!Files.exists(tasksXml)) {
continue;
}
final WildFlyPackageTasks pkgTasks = WildFlyPackageTasks.load(tasksXml);
if (pkgTasks.hasTasks()) {
for(WildFlyPackageTask task : pkgTasks.getTasks()) {
if(task.getPhase() == WildFlyPackageTask.Phase.PROCESSING) {
task.execute(this, pkg);
} else {
finalizingTasks = CollectionUtils.add(finalizingTasks, task);
finalizingTasksPkgs = CollectionUtils.add(finalizingTasksPkgs, pkg);
}
}
}
if (pkgTasks.hasMkDirs()) {
mkdirs(pkgTasks, this.runtime.getStagedDir());
}
if (pkgTasks.hasFilePermissions() && !PropertyUtils.isWindows()) {
processFeaturePackFilePermissions(pkgTasks, this.runtime.getStagedDir());
}
}
}
public void xslTransform(FeaturePackRuntime fp, XslTransform xslt, Path pmWfDir) throws ProvisioningException {
final Path src = runtime.getStagedDir().resolve(xslt.getSrc());
if (!Files.exists(src)) {
throw new ProvisioningException(Errors.pathDoesNotExist(src));
}
final Path output = runtime.getStagedDir().resolve(xslt.getOutput());
if (Files.exists(output)) {
throw new ProvisioningException(Errors.pathAlreadyExists(output));
}
try (InputStream srcInput = Files.newInputStream(src); OutputStream outStream = Files.newOutputStream(output)) {
final org.w3c.dom.Document document = getXmlDocumentBuilderFactory().newDocumentBuilder().parse(srcInput);
final Transformer transformer = getXslTransformer(xslt.getStylesheet());
if (xslt.hasParams()) {
for (Map.Entry param : xslt.getParams().entrySet()) {
transformer.setParameter(param.getKey(), param.getValue());
}
}
final Properties taskProps = fpTasksProps.get(fp.getGav());
if (taskProps != null) {
for (Map.Entry
© 2015 - 2025 Weber Informatics LLC | Privacy Policy