/*
* JBoss, Home of Professional Open Source.
* Copyright 2014, 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.validation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import org.jboss.as.patching.installation.InstalledIdentity;
/**
* A validating iterator over the patch history.
*
* @author Alexey Loubyansky
* @author Emanuel Muckenhuber
*/
public interface PatchHistoryIterator {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Retrieve the next patch element without validating the patch nor
* changing the state of the iterator.
*
* @return the next patch
*/
String peek();
/**
* Returns the next validated patch using the default validator
*
* @return the next patch in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
String next();
/**
* Returns the next validated patch.
*
* @param context the validation context which should be used for this node
* @return the next patch in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
String next(PatchingValidationErrorHandler context);
public static final class Builder {
public static Builder create(final InstalledIdentity identity) {
return new Builder(identity);
}
private final InstalledIdentity identity;
private final PatchHistoryValidations.PatchingArtifactStateHandlers handlers = new PatchHistoryValidations.PatchingArtifactStateHandlers();
private PatchingValidationErrorHandler errorHandler = PatchingValidationErrorHandler.DEFAULT;
private Builder(final InstalledIdentity identity) {
this.identity = identity;
}
public void setErrorHandler(PatchingValidationErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public <P extends PatchingArtifact.ArtifactState, S extends PatchingArtifact.ArtifactState> void addStateHandler(PatchingArtifact<P, S> artifact, PatchingArtifactStateHandler<S> handler) {
handlers.put(artifact, handler);
}
public PatchHistoryIterator iterator() {
// Process the patches in from the latest to the oldest
final List<String> patches = new ArrayList<>(identity.getAllInstalledPatches());
Collections.reverse(patches);
final int size = patches.size();
final BasicArtifactProcessor processor = new BasicArtifactProcessor(identity, errorHandler, handlers);
final PatchHistoryIterator iterator = new PatchHistoryIterator() {
int idx = 0;
@Override
public boolean hasNext() {
return idx != size;
}
@Override
public String peek() {
int i = idx + 1;
if (i >= size) {
throw new NoSuchElementException();
}
return patches.get(idx);
}
@Override
public String next() {
return next(errorHandler);
}
@Override
public String next(PatchingValidationErrorHandler context) {
int i = idx;
if (i >= size) {
throw new NoSuchElementException();
}
idx = i + 1;
final String patch = patches.get(i);
final int nextIdx = i + 1;
String nextPatch = null;
if (nextIdx < size) {
nextPatch = patches.get(nextIdx);
}
final PatchingArtifacts.PatchID patchID = new PatchingArtifacts.PatchID(patch, nextPatch);
processor.processRoot(PatchingArtifacts.HISTORY_RECORD, patchID, context);
return patch;
}
};
return iterator;
}
}
}