/*
* Copyright (c) 2016 Fraunhofer IGD
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Fraunhofer IGD <http://www.igd.fraunhofer.de/>
*/
package de.fhg.igd.mapviewer.server.wms.wizard.pages;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import de.fhg.igd.mapviewer.concurrency.Callback;
import de.fhg.igd.mapviewer.concurrency.Concurrency;
import de.fhg.igd.mapviewer.concurrency.IJob;
import de.fhg.igd.mapviewer.concurrency.Job;
import de.fhg.igd.mapviewer.concurrency.Progress;
/**
* Concurrent validator
*
* @author Simon Templer
*/
public class ConcurrentValidator {
/**
* Validation call-back wrapper
*/
private class CallbackWrapper implements Callback<Boolean> {
private final Callback<Boolean> callback;
/**
* Constructor
*
* @param callback the wrapped call-back
*/
public CallbackWrapper(Callback<Boolean> callback) {
this.callback = callback;
}
/**
* @see Callback#done(Object)
*/
@Override
public void done(Boolean result) {
if (result != null) {
stateLock.lock();
valid = result; // set validity value
stateLock.unlock();
callback.done(result);
}
}
/**
* @see Callback#failed(Throwable)
*/
@Override
public void failed(Throwable e) {
stateLock.lock();
valid = false; // set validity value
stateLock.unlock();
callback.failed(e);
}
}
/**
* Validation interface
*/
public interface Validation {
/**
* Validate something
*
* @return if the validation result is valid
* @throws Exception if an error occurs
*/
public boolean validate() throws Exception;
}
private boolean valid;
private final Lock stateLock = new ReentrantLock();
private Validation lastValidation = null;
private final Lock validationLock = new ReentrantLock();
private final Callback<Boolean> callback;
/**
* Constructor
*
* @param callback the call-back for validation updates
* @param valid the initial valid state
*/
public ConcurrentValidator(final Callback<Boolean> callback, boolean valid) {
this.valid = valid;
this.callback = callback;
}
/**
* Determine the valid state
*
* @return the valid state
*/
public boolean isValid() {
stateLock.lock();
try {
return valid;
} finally {
stateLock.unlock();
}
}
/**
* Run a validation
*
* @param validation the validation to run
*/
public void runValidation(final Validation validation) {
validationLock.lock();
try {
lastValidation = validation;
} finally {
validationLock.unlock();
}
IJob<Boolean> job = new Job<Boolean>(Messages.ConcurrentValidator_0,
new CallbackWrapper(callback)) {
@Override
public Boolean work(Progress progress) throws Exception {
try {
Boolean result = validation.validate();
validationLock.lock();
if (lastValidation != validation) {
// ignore this validation result
result = null;
}
validationLock.unlock();
return result;
} catch (Exception e) {
if (lastValidation == validation) {
throw e; // only throw errors that result in state
// changes
}
else
return null;
}
}
};
Concurrency.startJob(job);
}
}