/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.patching.tool;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jboss.as.patching.Constants;
import org.jboss.as.patching.PatchInfo;
import org.jboss.as.patching.PatchingException;
import org.jboss.as.patching.installation.InstallationManager;
import org.jboss.as.patching.installation.LayersConfig;
import org.jboss.as.patching.logging.PatchLogger;
import org.jboss.as.patching.metadata.MiscContentItem;
import org.jboss.as.patching.runner.PatchToolImpl;
import org.jboss.as.patching.runner.PatchUtils;
import org.jboss.as.version.ProductConfig;
import org.jboss.dmr.ModelNode;
import org.jboss.modules.LocalModuleLoader;
import org.jboss.modules.ModuleLoader;
/**
* The patch tool.
*
* @author Emanuel Muckenhuber
*/
public interface PatchTool {
ContentVerificationPolicy DEFAULT = ContentVerificationPolicy.STRICT;
/**
* Returns a list of patch streams applicable to the current installation.
*
* @return list of patch streams applicable to the current installation
* @throws PatchingException
*/
List<String> getPatchStreams() throws PatchingException;
/**
* Get the patch info for the default patch stream.
*
* @return the patch info
*/
PatchInfo getPatchInfo() throws PatchingException;
/**
* Get the patch info for specific patch stream.
*
* @param streamName patch stream
* @return the patch info
*/
PatchInfo getPatchInfo(String streamName) throws PatchingException;
/**
* Get patching history
*
* @return patching history
*/
PatchingHistory getPatchingHistory() throws PatchingException;
/**
* Get patching history for the default patch stream.
*
* @param streamName patch stream
* @return patching history
*/
PatchingHistory getPatchingHistory(String streamName) throws PatchingException;
/**
* Apply a patch.
*
* @param file the patch file
* @param contentPolicy the content verification policy
* @return the patching result
* @throws PatchingException
*/
PatchingResult applyPatch(File file, ContentVerificationPolicy contentPolicy) throws PatchingException;
/**
* Apply a patch.
*
* @param url the url to retrieve the patch from
* @param contentPolicy the content verification policy
* @return the patching result
* @throws PatchingException
*/
PatchingResult applyPatch(URL url, ContentVerificationPolicy contentPolicy) throws PatchingException;
/**
* Apply a patch.
*
* @param is the content input stream
* @param contentPolicy the content verification policy
* @return the patching result
* @throws PatchingException
*/
PatchingResult applyPatch(InputStream is, ContentVerificationPolicy contentPolicy) throws PatchingException;
/**
* Rollback a patch.
*
* @param patchId the patch id
* @param contentPolicy the content verification policy
* @param rollbackTo rollback all one off patches until the given patch-id
* @param resetConfiguration whether to reset the configuration from the backup
* @return the patching result
* @throws PatchingException
*/
PatchingResult rollback(String patchId, ContentVerificationPolicy contentPolicy, boolean rollbackTo, boolean resetConfiguration) throws PatchingException;
/**
* Rollback a patch.
*
* @param streamName patch stream name
* @param patchId the patch id
* @param contentPolicy the content verification policy
* @param rollbackTo rollback all one off patches until the given patch-id
* @param resetConfiguration whether to reset the configuration from the backup
* @return the patching result
* @throws PatchingException
*/
PatchingResult rollback(String streamName, String patchId, ContentVerificationPolicy contentPolicy, boolean rollbackTo, boolean resetConfiguration) throws PatchingException;
/**
* Rollback the last applied patch.
*
* @param contentPolicy the content verification policy
* @param resetConfiguration whether to reset the configuration from the backup
* @return the patching result
* @throws PatchingException
*/
PatchingResult rollbackLast(ContentVerificationPolicy contentPolicy, boolean resetConfiguration) throws PatchingException;
/**
* Rollback the last applied patch.
*
* @param streamName patch stream name
* @param contentPolicy the content verification policy
* @param resetConfiguration whether to reset the configuration from the backup
* @return the patching result
* @throws PatchingException
*/
PatchingResult rollbackLast(String streamName, ContentVerificationPolicy contentPolicy, boolean resetConfiguration) throws PatchingException;
public class Factory {
private Factory() {
//
}
/**
* Create a new policy builder instance.
*
* @return a content policy builder
*/
public static ContentPolicyBuilder policyBuilder() {
return new ContentPolicyBuilderImpl();
}
/**
* Create a content verification policy from a dmr model
*
* @param operation the model node
* @return the policy
*/
public static ContentVerificationPolicy create(final ModelNode operation) {
final PatchTool.ContentPolicyBuilder builder = policyBuilder();
final boolean overrideModules = operation.get(Constants.OVERRIDE_MODULES).asBoolean(false);
if(overrideModules) {
builder.ignoreModuleChanges();
}
final boolean overrideAll = operation.get(Constants.OVERRIDE_ALL).asBoolean(false);
if(overrideAll) {
builder.overrideAll();
}
if(operation.hasDefined(Constants.OVERRIDE)) {
final ModelNode overrides = operation.get(Constants.OVERRIDE);
for(final ModelNode override : overrides.asList()) {
builder.overrideItem(override.asString());
}
}
if(operation.hasDefined(Constants.PRESERVE)) {
final ModelNode preserves = operation.get(Constants.PRESERVE);
for(final ModelNode preserve : preserves.asList()) {
builder.preserveItem(preserve.asString());
}
}
return builder.createPolicy();
}
/**
* Create an offline local patch tool.
*
* @param jbossHome the distribution root
* @param moduleRoots the module roots
* @param bundleRoots the bundle roots
* @return the patch tool
* @throws IOException
*/
public static PatchTool createLocalTool(final File jbossHome, final List<File> moduleRoots, final List<File> bundleRoots) throws IOException {
final File[] resolvedPath = resolveLayeredModulePath(moduleRoots); // Resolve the patched module root for the module loader
final ModuleLoader loader = new LocalModuleLoader(resolvedPath);
final ProductConfig config = ProductConfig.fromFilesystemSlot(loader, jbossHome.getAbsolutePath(), Collections.emptyMap());
final InstallationManager manager = InstallationManager.load(jbossHome, moduleRoots, bundleRoots, config);
return create(manager);
}
/**
* Create an offline local patch tool.
*
* @param manager the installation manager
* @return the patch tool
*/
public static PatchTool create(final InstallationManager manager) {
return new PatchToolImpl(manager);
}
private static File[] resolveLayeredModulePath(List<File> modulePath) {
boolean foundLayers = false;
List<File> layeredPath = new ArrayList<File>();
for (File file : modulePath) {
// Always add the root, as the user may place modules directly in it
layeredPath.add(file);
LayersConfig layersConfig = getLayersConfig(file);
File layersDir = new File(file, layersConfig.getLayersPath());
if (!layersDir.exists()) {
if (layersConfig.isConfigured()) {
// Bad config from user
throw PatchLogger.ROOT_LOGGER.installationNoLayersConfigFound(layersDir.getAbsolutePath());
}
// else this isn't a root that has layers and add-ons
continue;
}
boolean validLayers = true;
List<File> layerFiles = new ArrayList<File>();
for (String layerName : layersConfig.getLayers()) {
File layer = new File(layersDir, layerName);
if (!layer.exists()) {
if (layersConfig.isConfigured()) {
// Bad config from user
throw PatchLogger.ROOT_LOGGER.installationMissingLayer(layerName, layersDir.getAbsolutePath());
}
// else this isn't a standard layers and add-ons structure
validLayers = false;
break;
}
loadOverlays(layer, layerFiles);
}
if (validLayers) {
foundLayers = true;
layeredPath.addAll(layerFiles);
// Now add-ons
File[] addOns = new File(file, layersConfig.getAddOnsPath()).listFiles();
if (addOns != null) {
for (File addOn : addOns) {
if (addOn.isDirectory()) {
loadOverlays(addOn, layeredPath);
}
}
}
}
}
return foundLayers ? layeredPath.toArray(new File[layeredPath.size()]) : modulePath.toArray(new File[modulePath.size()]);
}
private static LayersConfig getLayersConfig(File repoRoot) {
try {
return LayersConfig.getLayersConfig(repoRoot);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
static void loadOverlays(final File layeringRoot, final List<File> path) {
final File overlays = new File(layeringRoot, Constants.OVERLAYS);
if (overlays.exists()) {
final File refs = new File(overlays, Constants.OVERLAYS);
if (refs.exists()) {
try {
for (final String overlay : PatchUtils.readRefs(refs)) {
final File root = new File(overlays, overlay);
path.add(root);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
path.add(layeringRoot);
}
}
public interface ContentPolicyBuilder {
/**
* Build the resulting policy.
*
* @return the content verification policy
*/
ContentVerificationPolicy createPolicy();
/**
* Ignore all local module changes.
*
* @return the builder
*/
ContentPolicyBuilder ignoreModuleChanges();
/**
* Override all local changes.
*
* @return the builder
*/
ContentPolicyBuilder overrideAll();
/**
* Override a misc content item.
*
* @param item the item to override
* @return the builder
*/
ContentPolicyBuilder overrideItem(MiscContentItem item);
/**
* Override a misc content item.
*
* @param path the path of the item
* @return the builder
*/
ContentPolicyBuilder overrideItem(String path);
/**
* Preserve an existing content item.
*
* @param item the item to preserve
* @return the builder
*/
ContentPolicyBuilder preserveItem(MiscContentItem item);
/**
* Preserve an existing content item.
*
* @param path the path of the item
* @return the builder
*/
ContentPolicyBuilder preserveItem(String path);
}
}