Skip to content

Commit

Permalink
Merge pull request #457 from RepreZen/task/ZEN-4339
Browse files Browse the repository at this point in the history
[ZEN-4339] Implement optional 2nd phase of validation with KZOP
  • Loading branch information
tfesenko authored Aug 21, 2018
2 parents ccb2eb5 + 461c663 commit b452db3
Show file tree
Hide file tree
Showing 28 changed files with 548 additions and 238 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,18 @@ public void run() {

/*
* This listener is added to the preference store when the editor is initialized. It listens to changes to color
* preferences. Once a color change happens, the editor is re-initialized.
* It also handles changes in validation preferences
* preferences. Once a color change happens, the editor is re-initialized. It also handles changes in validation
* preferences
*/
protected final IPropertyChangeListener preferenceChangeListener = new JsonPreferenceChangeListener();

private JsonContentOutlinePage contentOutline;
private JsonContentOutlinePage contentOutline;

private final IPreferenceStore preferenceStore;

public JsonEditor(JsonDocumentProvider documentProvider, IPreferenceStore preferenceStore) {
super();
this.preferenceStore = preferenceStore;
setDocumentProvider(documentProvider);
}
public JsonEditor(JsonDocumentProvider documentProvider, IPreferenceStore preferenceStore) {
super();
setPreferenceStore(preferenceStore);
setDocumentProvider(documentProvider);
}

@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
Expand All @@ -149,7 +147,7 @@ protected void initializeEditor() {
setSourceViewerConfiguration(createSourceViewerConfiguration());
}

protected abstract YEditSourceViewerConfiguration createSourceViewerConfiguration() ;
protected abstract YEditSourceViewerConfiguration createSourceViewerConfiguration();

@Override
protected void doSetInput(IEditorInput input) throws CoreException {
Expand Down Expand Up @@ -199,13 +197,14 @@ public void createPartControl(Composite parent) {
viewer.doOperation(ProjectionViewer.TOGGLE);

annotationModel = viewer.getProjectionAnnotationModel();
preferenceStore.addPropertyChangeListener(preferenceChangeListener);
getPreferenceStore().addPropertyChangeListener(preferenceChangeListener);
}

@Override
public void dispose() {
// preference store is removed in AbstractTextEditor.dispose()
getPreferenceStore().removePropertyChangeListener(preferenceChangeListener);
super.dispose();
preferenceStore.removePropertyChangeListener(preferenceChangeListener);
}

@Override
Expand Down Expand Up @@ -277,9 +276,9 @@ public boolean canDoOperation(int operation) {
@Override
public void configure(SourceViewerConfiguration configuration) {
super.configure(configuration);

if (configuration instanceof JsonSourceViewerConfiguration) {
JsonSourceViewerConfiguration c = (JsonSourceViewerConfiguration) configuration;
JsonSourceViewerConfiguration c = (JsonSourceViewerConfiguration) configuration;
outlinePresenter = c.getOutlinePresenter(this);

if (outlinePresenter != null) {
Expand Down Expand Up @@ -371,9 +370,11 @@ public void run() {
}
}.schedule();
}

/* Copy of AbstractTextEditor#doSave(IProgressMonitor) which is shadowed by YEdit.
* Saves the file, but does NOT perform any validation. The validation should be done in a workspace job*/

/*
* Copy of AbstractTextEditor#doSave(IProgressMonitor) which is shadowed by YEdit. Saves the file, but does NOT
* perform any validation. The validation should be done in a workspace job
*/
private void hack_AbstractTextEditor_doSave(IProgressMonitor progressMonitor) {

IDocumentProvider p = getDocumentProvider();
Expand Down Expand Up @@ -418,11 +419,11 @@ public IStatus doRunInWorkspace(IProgressMonitor monitor) throws CoreException {
validationOperation.run(monitor);
return Status.OK_STATUS;
}

@Override
public boolean belongsTo(Object family) {
if (family instanceof ValidationOperation) {
return getEditorInput().equals(((ValidationOperation)family).getEditorInput());
return getEditorInput().equals(((ValidationOperation) family).getEditorInput());
}
return false;
}
Expand Down Expand Up @@ -534,11 +535,9 @@ public boolean show(ShowInContext context) {
public ShowInContext getShowInContext() {
return new ShowInContext(getEditorInput(), new StructuredSelection());
}

protected Validator createValidator() {
return new Validator();
}


protected abstract Validator createValidator();

public class JsonPreferenceChangeListener implements IPropertyChangeListener {

private final List<String> colorPreferenceKeys = new ArrayList<>();
Expand Down Expand Up @@ -593,7 +592,7 @@ public class JsonPreferenceChangeListener implements IPropertyChangeListener {
colorPreferenceKeys.add(PreferenceConstants.ITALIC_CONSTANT);
colorPreferenceKeys.add(PreferenceConstants.UNDERLINE_CONSTANT);
}

@Override
public void propertyChange(PropertyChangeEvent event) {
if (colorPreferenceKeys.contains(event.getProperty())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,14 @@
import java.util.Set;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.reprezen.swagedit.core.Activator;
import com.reprezen.swagedit.core.editor.JsonDocument;
import com.reprezen.swagedit.core.model.AbstractNode;
import com.reprezen.swagedit.core.model.Location;
import com.reprezen.swagedit.core.validation.JsonSchemaValidator;
import com.reprezen.swagedit.core.validation.SwaggerError;

/**
Expand All @@ -44,16 +41,16 @@ public class JsonReferenceValidator {

private final JsonReferenceCollector collector;
private final JsonReferenceFactory referenceFactory;
private final JsonSchemaValidator schemaValidator;

protected JsonSchemaFactory factory = null;

public JsonReferenceValidator(JsonReferenceFactory factory) {
public JsonReferenceValidator(JsonSchemaValidator validator, JsonReferenceFactory factory) {
this.referenceFactory = factory;
this.collector = new JsonReferenceCollector(factory);
this.schemaValidator = validator;
}

public void setFactory(JsonSchemaFactory factory) {
this.factory = factory;
protected JsonSchemaValidator getSchemaValidator() {
return schemaValidator;
}

/**
Expand All @@ -79,9 +76,6 @@ protected Collection<? extends SwaggerError> doValidate(URI baseURI, JsonDocumen
Map<JsonReference, List<AbstractNode>> references) {

Set<SwaggerError> errors = Sets.newHashSet();
// Cache of JSON schemas (subsets of the main schema). The key identifies a schema by it's pointer
// in the main schema.
Map<String, JsonSchema> schemas = Maps.newHashMap();

for (JsonReference reference : references.keySet()) {
if (reference instanceof JsonReference.SimpleReference) {
Expand All @@ -96,7 +90,7 @@ protected Collection<? extends SwaggerError> doValidate(URI baseURI, JsonDocumen
errors.addAll(
createReferenceError(SEVERITY_WARNING, error_invalid_reference, references.get(reference)));
} else {
errors.addAll(validateType(doc, baseURI, reference, references.get(reference), schemas));
errors.addAll(validateType(doc, baseURI, reference, references.get(reference)));
}
}

Expand All @@ -120,53 +114,23 @@ protected Collection<? extends SwaggerError> doValidate(URI baseURI, JsonDocumen
* current set of errors
*/
protected Set<SwaggerError> validateType(JsonDocument doc, URI baseURI, JsonReference reference,
Collection<AbstractNode> sources, Map<String, JsonSchema> schemas) {
Collection<AbstractNode> sources) {

Set<SwaggerError> errors = Sets.newHashSet();

JsonNode target = findTarget(doc, baseURI, reference);
// To avoid performing even more cycles, the sources are grouped by their type.
// Validation is done only once for each sources having same type.

Map<String, List<AbstractNode>> sourceTypes = groupSourcesByType(sources);

for (String type : sourceTypes.keySet()) {
JsonSchema jsonSchema = getSchema(doc, type, schemas);
errors.addAll(validate(jsonSchema, target, error_invalid_reference_type, sourceTypes.get(type)));
}

return errors;
}

protected JsonSchema getSchema(JsonDocument doc, String type, Map<String, JsonSchema> schemas) {
JsonSchema schema = schemas.get(type);
if (schema == null) {
try {
schema = factory.getJsonSchema(doc.getSchema().asJson(), type);
schemas.put(type, schema);
} catch (ProcessingException e) {
Activator.getDefault().logError(e.getLocalizedMessage(), e);
}
}
return schema;
}

/*
* Executes JSON schema validation against given target. If the target fails to be recognize as an instance of the
* actual schema, an error is returned with the given message on all sources.
*
*/
protected Set<SwaggerError> validate(JsonSchema schema, JsonNode target, String message,
Collection<AbstractNode> sources) {

Set<SwaggerError> errors = Sets.newHashSet();
try {
ProcessingReport report = schema.validate(target);
ProcessingReport report = schemaValidator.validateSubSchema(target, type);
if (!report.isSuccess()) {
errors = createReferenceError(SEVERITY_WARNING, message, sources);
errors.addAll(createReferenceError(SEVERITY_WARNING, error_invalid_reference_type, sources));
}
} catch (ProcessingException e) {
Activator.getDefault().logError(e.getLocalizedMessage(), e);
}

return errors;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/*******************************************************************************
* Copyright (c) 2016 ModelSolv, Inc. and others.
* 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
*
* Contributors:
* ModelSolv, Inc. - initial API and implementation and/or initial documentation
*******************************************************************************/
package com.reprezen.swagedit.core.schema;

import java.util.HashMap;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright (c) 2016 ModelSolv, Inc. and others.
* 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
*
* Contributors:
* ModelSolv, Inc. - initial API and implementation and/or initial documentation
*******************************************************************************/
package com.reprezen.swagedit.core.validation;

import java.util.Map;
import java.util.Set;

import org.dadacoalition.yedit.YEditLog;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.load.configuration.LoadingConfiguration;
import com.github.fge.jsonschema.core.load.configuration.LoadingConfigurationBuilder;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.google.common.collect.Sets;
import com.reprezen.swagedit.core.Activator;
import com.reprezen.swagedit.core.editor.JsonDocument;

public abstract class JsonSchemaValidator {

private final LoadingConfiguration loadingConfiguration;
private final JsonSchemaFactory factory;
private final JsonNode schema;

public JsonSchemaValidator(JsonNode schema, Map<String, JsonNode> preloadSchemas) {
this.schema = schema;
this.loadingConfiguration = getLoadingConfiguration(preloadSchemas);
this.factory = JsonSchemaFactory.newBuilder() //
.setLoadingConfiguration(loadingConfiguration) //
.freeze();
}

private LoadingConfiguration getLoadingConfiguration(Map<String, JsonNode> preloadSchemas) {
LoadingConfigurationBuilder loadingConfigurationBuilder = LoadingConfiguration.newBuilder();
for (String nextSchemaUri : preloadSchemas.keySet()) {
loadingConfigurationBuilder.preloadSchema(nextSchemaUri, preloadSchemas.get(nextSchemaUri));
}
return loadingConfigurationBuilder.freeze();
}

public Set<SwaggerError> validate(JsonDocument document) {
final ErrorProcessor processor = new ErrorProcessor(document.getYaml(), schema);
final Set<SwaggerError> errors = Sets.newHashSet();

JsonSchema jsonSchema = null;
try {
jsonSchema = factory.getJsonSchema(schema);
} catch (ProcessingException e) {
YEditLog.logException(e);
return errors;
}

try {
errors.addAll(processor.processReport(jsonSchema.validate(document.asJson(), true)));
} catch (ProcessingException e) {
errors.addAll(processor.processMessage(e.getProcessingMessage()));
}

return errors;
}

public ProcessingReport validateSubSchema(JsonNode document, String schemaPointer) {
JsonSchema jsonSchema = null;
try {
jsonSchema = factory.getJsonSchema(schema, schemaPointer);
} catch (ProcessingException e) {
Activator.getDefault().logError(e.getLocalizedMessage(), e);
return null;
}

try {
return jsonSchema.validate(document, true);
} catch (ProcessingException e) {
Activator.getDefault().logError(e.getLocalizedMessage(), e);
return null;
}
}
}
Loading

0 comments on commit b452db3

Please sign in to comment.