/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
*/
package gov.redhawk.ui.validation;
import gov.redhawk.ui.RedhawkUiActivator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.ObservableTracker;
import org.eclipse.core.databinding.observable.Observables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.databinding.validation.MultiValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
/**
*
*/
public class EmfValidationStatusProvider extends MultiValidator {
private final Diagnostician diagnostician;
private final EObject eObject;
private final DataBindingContext dataBindingContext;
private final AdapterFactory adapterFactory;
private final IObservableValue<IStatus> validationStatus;
private IObservableValue<IStatus> unmodifiableValidationStatus;
/**
*
*/
public EmfValidationStatusProvider(final EObject objectToValidate, final DataBindingContext context,
final AdapterFactory factory) {
this.eObject = objectToValidate;
this.validationStatus = new WritableValue<IStatus>(Realm.getDefault(), ValidationStatus.ok(), IStatus.class);
this.eObject.eAdapters().add(new EContentAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void notifyChanged(final Notification notification) {
super.notifyChanged(notification);
ObservableTracker.runAndMonitor(new Runnable() {
@Override
public void run() {
try {
IStatus status = validate();
if (status == null) {
status = ValidationStatus.ok();
}
EmfValidationStatusProvider.this.validationStatus.setValue(status);
} catch (final RuntimeException e) { // SUPPRESS CHECKSTYLE Logged Catch all exception
// Usually an NPE as dependencies are
// initialized
EmfValidationStatusProvider.this.validationStatus.setValue(ValidationStatus.error(
e.getMessage(), e));
}
}
}, null, null);
}
});
this.dataBindingContext = context;
this.adapterFactory = factory;
// Subclass the default Diagnostician to customize the String
// representation of each validated EObject
this.diagnostician = new Diagnostician() {
@Override
public String getObjectLabel(final EObject eObject) {
if (!eObject.eIsProxy()) {
final IItemLabelProvider itemLabelProvider = (IItemLabelProvider) getAdapterFactory().adapt(
eObject, IItemLabelProvider.class);
if (itemLabelProvider != null) {
return itemLabelProvider.getText(eObject);
}
}
return super.getObjectLabel(eObject);
}
@Override
protected boolean doValidateContents(final EObject eObject, final DiagnosticChain diagnostics,
final Map<Object, Object> context) {
final Resource eContainerResource = eObject.eResource();
final List<EObject> eContents = eObject.eContents();
if (!eContents.isEmpty()) {
boolean result = true;
for (final Iterator<EObject> i = eContents.iterator(); i.hasNext()
&& (result || diagnostics != null);) {
final EObject child = i.next();
// in case of cross resource containment,
// avoid to validate a child which are not in the
// container resource
final Resource eChildResource = child.eResource();
if (eContainerResource != null && eChildResource == eContainerResource) {
result &= validate(child, diagnostics, context);
}
}
return result;
}
return true;
}
};
}
/**
* @return
*/
protected AdapterFactory getAdapterFactory() {
return this.adapterFactory;
}
/**
* {@inheritDoc}
*/
@Override
protected IStatus validate() {
final IBatchValidator batchValidator = ModelValidationService.getInstance().newValidator(EvaluationMode.BATCH);
batchValidator.setIncludeLiveConstraints(true);
batchValidator.setReportSuccesses(false);
IStatus status;
final Diagnostic diag = this.diagnostician.validate(this.eObject);
status = analyzeDiagnostic(this.dataBindingContext, diag);
if (status.isOK()) {
status = batchValidator.validate(this.eObject);
}
return status;
}
private IStatus analyzeDiagnostic(final DataBindingContext dbc, final Diagnostic diagnostic) {
String message = "";
if (!diagnostic.getChildren().isEmpty()) {
message = diagnostic.getChildren().get(0).getMessage();
}
return new Status(diagnostic.getSeverity(), RedhawkUiActivator.getPluginId(), message, null);
}
/**
* {@inheritDoc}
*/
@Override
public IObservableValue<IStatus> getValidationStatus() {
if (this.unmodifiableValidationStatus == null) {
myRevalidate();
this.unmodifiableValidationStatus = Observables.unmodifiableObservableValue(this.validationStatus);
}
return this.unmodifiableValidationStatus;
}
private void myRevalidate() {
ObservableTracker.runAndMonitor(new Runnable() {
@Override
public void run() {
try {
IStatus status = validate();
if (status == null) {
status = ValidationStatus.ok();
}
EmfValidationStatusProvider.this.validationStatus.setValue(status);
} catch (final RuntimeException e) { // SUPPRESS CHECKSTYLE Logged Catch all exception
// Usually an NPE as dependencies are initialized
EmfValidationStatusProvider.this.validationStatus.setValue(ValidationStatus.error(e.getMessage(), e));
}
}
}, null, null);
}
}