/** * Create a rollback patch based on the recorded actions. * * @param patchId the new patch id, depending on release or one-off * @param patchType the current patch identity * @return the rollback patch */ protected RollbackPatch createRollbackPatch( final String patchId, final Patch.PatchType patchType) { // Process elements final List<PatchElement> elements = new ArrayList<PatchElement>(); // Process layers for (final PatchEntry entry : getLayers()) { final PatchElement element = createRollbackElement(entry); elements.add(element); } // Process add-ons for (final PatchEntry entry : getAddOns()) { final PatchElement element = createRollbackElement(entry); elements.add(element); } final InstalledIdentity installedIdentity = modification.getUnmodifiedInstallationState(); final String name = installedIdentity.getIdentity().getName(); final IdentityImpl identity = new IdentityImpl(name, modification.getVersion()); if (patchType == Patch.PatchType.CUMULATIVE) { identity.setPatchType(Patch.PatchType.CUMULATIVE); identity.setResultingVersion(installedIdentity.getIdentity().getVersion()); } else if (patchType == Patch.PatchType.ONE_OFF) { identity.setPatchType(Patch.PatchType.ONE_OFF); } final List<ContentModification> modifications = identityEntry.rollbackActions; final Patch delegate = new PatchImpl(patchId, "rollback patch", identity, elements, modifications); return new PatchImpl.RollbackPatchImpl(delegate, installedIdentity); }
/** * Complete the current operation and persist the current state to the disk. This will also * trigger the invalidation of outdated modules. * * @param modification the current modification * @param callback the completion callback */ private void complete( final InstallationManager.InstallationModification modification, final FinalizeCallback callback) { final List<File> processed = new ArrayList<File>(); try { try { // Update the state to invalidate and process module resources if (stateUpdater.compareAndSet(this, State.PREPARED, State.INVALIDATE) && mode == PatchingTaskContext.Mode.APPLY) { // Only invalidate modules when applying patches; on rollback files are immediately // restored for (final File invalidation : moduleInvalidations) { processed.add(invalidation); PatchModuleInvalidationUtils.processFile(invalidation, mode); } } modification.complete(); callback.completed(this); state = State.COMPLETED; } catch (Exception e) { this.moduleInvalidations.clear(); this.moduleInvalidations.addAll(processed); throw new RuntimeException(e); } } finally { if (state != State.COMPLETED) { try { modification.cancel(); } finally { try { undoChanges(); } finally { callback.operationCancelled(this); } } } else { try { if (checkForGarbageOnRestart) { final File cleanupMarker = new File(installedImage.getInstallationMetadata(), "cleanup-patching-dirs"); cleanupMarker.createNewFile(); } } catch (IOException e) { PatchLogger.ROOT_LOGGER.infof(e, "failed to create cleanup marker"); } } } }
IdentityPatchContext( final File backup, final PatchContentProvider contentProvider, final ContentVerificationPolicy contentPolicy, final InstallationManager.InstallationModification modification, final PatchingTaskContext.Mode mode, final InstalledImage installedImage) { this.miscTargetRoot = installedImage.getJbossHome(); this.mode = mode; this.contentProvider = contentProvider; this.contentPolicy = contentPolicy; this.modification = modification; this.installedImage = installedImage; this.history = PatchingHistory.Factory.getHistory(modification.getUnmodifiedInstallationState()); if (backup != null) { this.miscBackup = new File(backup, PatchContentLoader.MISC); this.configBackup = new File(backup, Constants.CONFIGURATION); } else { this.miscBackup = null; // This will trigger a failure when the root is actually needed this.configBackup = null; } this.identityEntry = new PatchEntry(modification, null); }
/** * Get the target entry for a given patch element. * * @param element the patch element * @return the patch entry * @throws PatchingException */ protected PatchEntry resolveForElement(final PatchElement element) throws PatchingException { assert state == State.NEW; final PatchElementProvider provider = element.getProvider(); final String layerName = provider.getName(); final LayerType layerType = provider.getLayerType(); final Map<String, PatchEntry> map; if (layerType == LayerType.Layer) { map = layers; } else { map = addOns; } PatchEntry entry = map.get(layerName); if (entry == null) { final InstallationManager.MutablePatchingTarget target = modification.resolve(layerName, layerType); if (target == null) { throw PatchMessages.MESSAGES.noSuchLayer(layerName); } entry = new PatchEntry(target, element); map.put(layerName, entry); } // Maintain the most recent element entry.updateElement(element); return entry; }
/** * Finalize the patch. * * @param callback the finalize callback * @return the result * @throws Exception */ protected PatchingResult finalize(final FinalizeCallback callback) throws Exception { assert state == State.NEW; final Patch original = callback.getPatch(); final Patch.PatchType patchType = original.getIdentity().getPatchType(); final String patchId; if (patchType == Patch.PatchType.CUMULATIVE) { patchId = modification.getCumulativePatchID(); } else { patchId = original.getPatchId(); } try { // The processed patch, based on the recorded changes final Patch processedPatch = createProcessedPatch(original); // The rollback containing all the recorded rollback actions final RollbackPatch rollbackPatch = createRollbackPatch(patchId, patchType); callback.finishPatch(processedPatch, rollbackPatch, this); } catch (Exception e) { if (undoChanges()) { callback.operationCancelled(this); } throw e; } state = State.PREPARED; return new PatchingResult() { @Override public String getPatchId() { return original.getPatchId(); } @Override public PatchInfo getPatchInfo() { return new PatchInfo() { @Override public String getVersion() { return identityEntry.getResultingVersion(); } @Override public String getCumulativePatchID() { return identityEntry.delegate.getModifiedState().getCumulativePatchID(); } @Override public List<String> getPatchIDs() { return identityEntry.delegate.getModifiedState().getPatchIDs(); } }; } @Override public void commit() { if (state == State.PREPARED) { complete(modification, callback); } else { undoChanges(); throw new IllegalStateException(); } } @Override public void rollback() { if (undoChanges()) { try { callback.operationCancelled(IdentityPatchContext.this); } finally { modification.cancel(); } } } }; }