package org.jboss.as.patching.installation; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.jboss.as.patching.Constants; import org.jboss.as.patching.PatchingException; import org.jboss.as.patching.logging.PatchLogger; import org.jboss.as.patching.metadata.LayerType; import org.jboss.as.patching.runner.PatchUtils; /** * @author Emanuel Muckenhuber */ abstract class InstallationModificationImpl extends MutableTargetImpl implements InstallationManager.InstallationModification { private final String name; private final InstallationState installationState; private final List<String> allPatches; private final AtomicBoolean done = new AtomicBoolean(); protected InstallationModificationImpl(final PatchableTarget.TargetInfo identity, final String name, final String version, final List<String> allPatches, final InstallationState installationState) { super(identity, version); this.name = name; this.installationState = installationState; this.allPatches = new ArrayList<String>(allPatches); } @Override public InstallationManager.MutablePatchingTarget resolve(String name, LayerType type) { if (type == LayerType.Layer) { return installationState.layers.get(name); } else { return installationState.addOns.get(name); } } @Override public void addInstalledPatch(String patchId) throws PatchingException { if (allPatches.contains(patchId)) { throw PatchLogger.ROOT_LOGGER.alreadyApplied(patchId); } allPatches.add(patchId); } @Override public void removeInstalledPatch(String patchId) throws PatchingException { if (! allPatches.contains(patchId)) { throw PatchLogger.ROOT_LOGGER.cannotRollbackPatch(patchId); } allPatches.remove(patchId); } List<String> getAllPatches() { return allPatches; } @Override public String getName() { return name; } @Override protected void persist() throws IOException { getMutableProperties().put(Constants.ALL_PATCHES, PatchUtils.asString(allPatches)); super.persist(); } boolean setDone() { return done.compareAndSet(false, true); } InstallationState internalComplete() throws Exception { if (!setDone()) { throw new IllegalStateException(); } try { installationState.persist(); } catch (Exception e) { installationState.restore(); throw e; } try { persist(); } catch (Exception e) { installationState.restore(); } return installationState; } static class InstallationState { private final Map<String, MutableTargetImpl> layers = new LinkedHashMap<String, MutableTargetImpl>(); private final Map<String, MutableTargetImpl> addOns = new LinkedHashMap<String, MutableTargetImpl>(); protected void putLayer(final Layer layer) throws IOException { putPatchableTarget(layer.getName(), layer, layers); } protected void putAddOn(final AddOn addOn) throws IOException { putPatchableTarget(addOn.getName(), addOn, addOns); } protected void putPatchableTarget(final String name, final PatchableTarget target, Map<String, MutableTargetImpl> map) throws IOException { final PatchableTarget.TargetInfo info = target.loadTargetInfo(); map.put(name, new MutableTargetImpl(info)); } Map<String, MutableTargetImpl> getLayers() { return layers; } Map<String, MutableTargetImpl> getAddOns() { return addOns; } protected void persist() throws IOException { for (final MutableTargetImpl target : layers.values()) { target.persist(); } for (final MutableTargetImpl target : addOns.values()) { target.persist(); } } private void restore() { for (final MutableTargetImpl target : layers.values()) { try { target.restore(); } catch (IOException e) { PatchLogger.ROOT_LOGGER.debugf(e, "failed to restore original state for layer %s", target); } } for (final MutableTargetImpl target : addOns.values()) { try { target.restore(); } catch (IOException e) { PatchLogger.ROOT_LOGGER.debugf(e, "failed to restore original state for add-on %s", target); } } } } }