/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, 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.installation;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jboss.as.patching.Constants;
import org.jboss.as.patching.installation.InstallationManager.InstallationModification;
import org.jboss.as.patching.installation.InstallationManager.ModificationCompletionCallback;
import org.jboss.as.version.ProductConfig;
/**
* Information about the installed identity.
*
* @author Emanuel Muckenhuber
*/
public abstract class InstalledIdentity {
// TODO track this state a better way
private final AtomicBoolean writable = new AtomicBoolean(true);
/**
* Get a list of all installed patches.
*
* @return the list of all installed patches
*/
public abstract List<String> getAllInstalledPatches();
/**
* Get information about the installed identity.
*
* @return the identity
*/
public abstract Identity getIdentity();
/**
* Get a list of available layer names.
*
* @return the available layers
*/
public abstract List<String> getLayerNames();
/**
* Get a layer by name.
*
* @param layerName the layer name
* @return the layer, {@code null} if there is no matching layer
*/
public abstract Layer getLayer(String layerName);
/**
* Get a list of installed layers.
*
* @return the installed layers
*/
public abstract List<Layer> getLayers();
/**
* Get a list of available add-on names.
*
* @return the available add-ons
*/
public abstract Collection<String> getAddOnNames();
/**
* Get an add-on by name.
*
* @param addOnName the add-on name
* @return the add-on, {@code null} if is no matching add-on
*/
public abstract AddOn getAddOn(String addOnName);
/**
* Get a list of installed add-ons.
*
* @return the installed add-ons
*/
public abstract Collection<AddOn> getAddOns();
protected abstract void updateState(final String name, final InstallationModificationImpl modification, final InstallationModificationImpl.InstallationState state);
/**
* Get the installed image.
*
* @return the installed image
*/
public abstract InstalledImage getInstalledImage();
public InstallationModification modifyInstallation(final ModificationCompletionCallback callback) {
if (! writable.compareAndSet(true, false)) {
throw new ConcurrentModificationException();
}
try {
// Load the state
final InstalledIdentity original = copy(this);
final Identity identity = original.getIdentity();
final PatchableTarget.TargetInfo identityInfo = identity.loadTargetInfo();
final InstallationModificationImpl.InstallationState state = load(this);
return new InstallationModificationImpl(identityInfo, identity.getName(), identity.getVersion(), this.getAllInstalledPatches(), state) {
@Override
public InstalledIdentity getUnmodifiedInstallationState() {
return original;
}
@Override
public void complete() {
try {
// Update the state
updateState(identity.getName(), this, internalComplete());
writable.set(true);
} catch (Exception e) {
cancel();
throw new RuntimeException(e);
}
if (callback != null) {
callback.completed();
}
}
@Override
public void cancel() {
try {
if (callback != null) {
callback.canceled();
}
} finally {
writable.set(true);
}
}
};
} catch (Exception e) {
writable.set(true);
throw new RuntimeException(e);
}
}
/**
* Load the installation state based on the identity
*
* @param installedIdentity the installed identity
* @return the installation state
* @throws IOException
*/
protected static InstallationModificationImpl.InstallationState load(final InstalledIdentity installedIdentity) throws IOException {
final InstallationModificationImpl.InstallationState state = new InstallationModificationImpl.InstallationState();
for (final Layer layer : installedIdentity.getLayers()) {
state.putLayer(layer);
}
for (final AddOn addOn : installedIdentity.getAddOns()) {
state.putAddOn(addOn);
}
return state;
}
/**
* Load the layers based on the default setup.
*
* @param jbossHome the jboss home directory
* @param productConfig the product config
* @param repoRoots the repository roots
* @return the available layers
* @throws IOException
*/
public static InstalledIdentity load(final File jbossHome, final ProductConfig productConfig, final File... repoRoots) throws IOException {
final InstalledImage installedImage = installedImage(jbossHome);
return load(installedImage, productConfig, Arrays.<File>asList(repoRoots), Collections.<File>emptyList());
}
/**
* Load the InstalledIdentity configuration based on the module.path
*
* @param installedImage the installed image
* @param productConfig the product config
* @param moduleRoots the module roots
* @param bundleRoots the bundle roots
* @return the available layers
* @throws IOException
*/
public static InstalledIdentity load(final InstalledImage installedImage, final ProductConfig productConfig, List<File> moduleRoots, final List<File> bundleRoots) throws IOException {
return LayersFactory.load(installedImage, productConfig, moduleRoots, bundleRoots);
}
protected static InstalledIdentity copy(InstalledIdentity original) throws IOException {
final InstalledIdentityImpl copy = new InstalledIdentityImpl(original.getIdentity(), original.getAllInstalledPatches(), original.getInstalledImage());
for (final Layer layer : original.getLayers()) {
copy.putLayer(layer.getName(), new LayerInfo(layer.getName(), layer.loadTargetInfo(), layer.getDirectoryStructure()));
}
for (final AddOn addOn : original.getAddOns()) {
copy.putAddOn(addOn.getName(), new LayerInfo(addOn.getName(), addOn.loadTargetInfo(), addOn.getDirectoryStructure()));
}
return copy;
}
static InstalledImage installedImage(final File jbossHome) {
final File appClient = new File(jbossHome, Constants.APP_CLIENT);
final File bundles = new File(jbossHome, Constants.BUNDLES);
final File domain = new File(jbossHome, Constants.DOMAIN);
final File modules = new File(jbossHome, Constants.MODULES);
final File metadata = new File(jbossHome, Constants.INSTALLATION);
final File layersConf = new File(modules, Constants.LAYERS_CONF);
final File standalone = new File(jbossHome, Constants.STANDALONE);
return new InstalledImage() {
@Override
public File getJbossHome() {
return jbossHome;
}
@Override
public File getAppClientDir() {
return appClient;
}
@Override
public File getBundlesDir() {
return bundles;
}
@Override
public File getDomainDir() {
return domain;
}
@Override
public File getInstallationMetadata() {
return metadata;
}
@Override
public File getPatchesDir() {
return new File(getInstallationMetadata(), Constants.PATCHES);
}
@Override
public File getModulesDir() {
return modules;
}
@Override
public File getPatchHistoryDir(String patchId) {
return new File(getPatchesDir(), patchId);
}
@Override
public File getStandaloneDir() {
return standalone;
}
@Override
public File getLayersConf() {
return layersConf;
}
};
}
}