Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAY-2846 Modeler: Allow to disable some validation rules in the project #617

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,49 @@
import org.apache.cayenne.util.Util;
import org.apache.cayenne.validation.ValidationResult;


/**
* Base validation for all query types
*/
class BaseQueryValidator extends ConfigurationNodeValidator {
public abstract class BaseQueryValidator<T extends QueryDescriptor> extends ConfigurationNodeValidator<T> {
m-dzianishchyts marked this conversation as resolved.
Show resolved Hide resolved

void validateCacheGroup(QueryDescriptor query, ValidationResult validationResult) {
String cacheGroup = query.getProperty(QueryMetadata.CACHE_GROUPS_PROPERTY);
if(cacheGroup != null && cacheGroup.contains(",")) {
addFailure(validationResult, query, "Invalid cache group \"%s\", " +
"multiple groups are deprecated", cacheGroup);
}
/**
* @param validationConfig the config defining the behavior of this validator.
* @since 5.0
*/
public BaseQueryValidator(ValidationConfig validationConfig) {
super(validationConfig);
}

@Override
public void validate(T node, ValidationResult validationResult) {
validateQuery(node, validationResult);
}

protected Performer<T> validateQuery(T query, ValidationResult validationResult) {
return on(query, validationResult)
.performIfEnabled(Inspection.QUERY_NO_NAME, this::checkForName)
.performIfEnabled(Inspection.QUERY_NAME_DUPLICATE, this::checkForNameDuplicates)
.performIfEnabled(Inspection.QUERY_MULTI_CACHE_GROUP, this::checkForMultiCacheGroup);
}

void validateName(QueryDescriptor query, ValidationResult validationResult) {
final String name = query.getName();
void checkForName(T query, ValidationResult validationResult) {

// Must have name
String name = query.getName();
if (Util.isEmptyString(name)) {
addFailure(validationResult, query, "Unnamed " + query.getType());
return;
}
}

void checkForNameDuplicates(T query, ValidationResult validationResult) {
String name = query.getName();
DataMap map = query.getDataMap();
if (map == null) {
if (map == null || Util.isEmptyString(name)) {
return;
}

// check for duplicate names in the parent context
if(hasDuplicateQueryDescriptorInDataMap(query, map)) {
if (hasDuplicateQueryDescriptorInDataMap(query, map)) {
addFailure(validationResult, query, "Duplicate query name: %s", name);
return;
}
Expand All @@ -71,14 +84,21 @@ void validateName(QueryDescriptor query, ValidationResult validationResult) {
}

if (hasDuplicateQueryDescriptorInDataMap(query, nextMap)) {
addFailure(validationResult, query,
"Duplicate %s name in another DataMap: %s",
addFailure(validationResult, query, "Duplicate %s name in another DataMap: %s",
query.getType(), name);
return;
}
}
}

void checkForMultiCacheGroup(T query, ValidationResult validationResult) {
String cacheGroup = query.getProperty(QueryMetadata.CACHE_GROUPS_PROPERTY);
if (cacheGroup != null && cacheGroup.contains(",")) {
addFailure(validationResult, query, "Invalid cache group '%s', multiple groups are deprecated",
cacheGroup);
}
}

private boolean hasDuplicateQueryDescriptorInDataMap(QueryDescriptor queryDescriptor, DataMap dataMap) {
for (final QueryDescriptor otherQuery : dataMap.getQueryDescriptors()) {
if (otherQuery == queryDescriptor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,101 @@
****************************************************************/
package org.apache.cayenne.project.validation;

import org.apache.cayenne.configuration.ConfigurationNode;
import org.apache.cayenne.validation.SimpleValidationFailure;
import org.apache.cayenne.validation.ValidationResult;

import java.util.function.Predicate;

/**
* A base superclass of various node validators.
*
* @since 3.1
*/
public abstract class ConfigurationNodeValidator {
public abstract class ConfigurationNodeValidator<T extends ConfigurationNode> {

protected final ValidationConfig validationConfig;

public void addFailure(
ValidationResult validationResult,
Object source,
String messageFormat,
Object... messageParameters) {
/**
* @param validationConfig the config defining the behavior of this validator.
* @since 5.0
*/
public ConfigurationNodeValidator(ValidationConfig validationConfig) {
this.validationConfig = validationConfig;
}

/**
* @param node the node that needs to be validated.
* @param validationResult the appendable validation result.
* @since 5.0
*/
public abstract void validate(T node, ValidationResult validationResult);

public void addFailure(ValidationResult validationResult, T source, String messageFormat,
Object... messageParameters) {
String message = String.format(messageFormat, messageParameters);
validationResult.addFailure(new SimpleValidationFailure(source, message));
}

public void addFailure(
ValidationResult validationResult,
SimpleValidationFailure failure) {
public void addFailure(ValidationResult validationResult, SimpleValidationFailure failure) {
validationResult.addFailure(failure);
}

protected Performer<T> on(T node, ValidationResult validationResult) {
return new Performer<>(node, validationResult);
}

protected class Performer<N> {

private final N node;
private final ValidationResult validationResult;

protected Performer(N node, ValidationResult validationResult) {
this.node = node;
this.validationResult = validationResult;
}

protected Performer<N> performIfEnabled(Inspection inspection, ValidationAction<N> validationAction) {
if (validationConfig.isEnabled(inspection)) {
validationAction.perform(node, validationResult);
}
return this;
}

protected Performer<N> performIfEnabled(Inspection inspection, Runnable validationAction) {
if (validationConfig.isEnabled(inspection)) {
validationAction.run();
}
return this;
}

protected Performer<N> performIf(Predicate<N> predicate, ValidationAction<N> validationAction) {
if (predicate.test(node)) {
validationAction.perform(node, validationResult);
}
return this;
}

protected Performer<N> performIf(Predicate<N> predicate, Runnable validationAction) {
if (predicate.test(node)) {
validationAction.run();
}
return this;
}

protected Performer<N> perform(ValidationAction<N> validationAction) {
validationAction.perform(node, validationResult);
return this;
}

protected Performer<N> perform(Runnable validationAction) {
validationAction.run();
return this;
}
m-dzianishchyts marked this conversation as resolved.
Show resolved Hide resolved
}

protected interface ValidationAction<N> {
m-dzianishchyts marked this conversation as resolved.
Show resolved Hide resolved

void perform(N node, ValidationResult validationResult);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,23 @@
import org.apache.cayenne.util.Util;
import org.apache.cayenne.validation.ValidationResult;

class DataChannelValidator extends ConfigurationNodeValidator {
public class DataChannelValidator extends ConfigurationNodeValidator<DataChannelDescriptor> {

void validate(DataChannelDescriptor domain, ValidationResult validationResult) {
/**
* @param validationConfig the config defining the behavior of this validator.
* @since 5.0
*/
public DataChannelValidator(ValidationConfig validationConfig) {
super(validationConfig);
}

@Override
public void validate(DataChannelDescriptor node, ValidationResult validationResult) {
on(node, validationResult)
.performIfEnabled(Inspection.DATA_CHANNEL_NO_NAME, this::checkForName);
}

private void checkForName(DataChannelDescriptor domain, ValidationResult validationResult) {
String name = domain.getName();
if (Util.isEmptyString(name)) {
addFailure(validationResult, domain, "Unnamed DataDomain");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,45 +24,36 @@
import org.apache.cayenne.util.Util;
import org.apache.cayenne.validation.ValidationResult;

class DataMapValidator extends ConfigurationNodeValidator {
public class DataMapValidator extends ConfigurationNodeValidator<DataMap> {

void validate(DataMap map, ValidationResult validationResult) {
validateName(map, validationResult);
validateNodeLinks(map, validationResult);
validateJavaPackage(map, validationResult);
/**
* @param validationConfig the config defining the behavior of this validator.
* @since 5.0
*/
public DataMapValidator(ValidationConfig validationConfig) {
super(validationConfig);
}

private void validateNodeLinks(DataMap map, ValidationResult validationResult) {
DataChannelDescriptor domain = map.getDataChannelDescriptor();
if (domain == null) {
return;
}

boolean unlinked = true;
int nodeCount = 0;
for (DataNodeDescriptor node : domain.getNodeDescriptors()) {
nodeCount++;
if (node.getDataMapNames().contains(map.getName())) {
unlinked = false;
break;
}
}

if (unlinked && nodeCount > 0) {
addFailure(validationResult, map, "DataMap is not linked to any DataNodes");
}
@Override
public void validate(DataMap node, ValidationResult validationResult) {
on(node, validationResult)
.performIfEnabled(Inspection.DATA_MAP_NO_NAME, this::checkForName)
.performIfEnabled(Inspection.DATA_MAP_NAME_DUPLICATE, this::checkForNameDuplicates)
.performIfEnabled(Inspection.DATA_MAP_NODE_LINKAGE, this::checkForNodeLinkage)
.performIfEnabled(Inspection.DATA_MAP_JAVA_PACKAGE, this::validateJavaPackage);
}

private void validateName(DataMap map, ValidationResult validationResult) {
private void checkForName(DataMap map, ValidationResult validationResult) {
String name = map.getName();

if (Util.isEmptyString(name)) {
addFailure(validationResult, map, "Unnamed DataMap");
return;
}
}

private void checkForNameDuplicates(DataMap map, ValidationResult validationResult) {
String name = map.getName();
DataChannelDescriptor domain = map.getDataChannelDescriptor();
if (domain == null) {
if (domain == null || Util.isEmptyString(name)) {
return;
}

Expand All @@ -71,25 +62,44 @@ private void validateName(DataMap map, ValidationResult validationResult) {
if (otherMap == map) {
continue;
}

if (name.equals(otherMap.getName())) {
addFailure(validationResult, map, "Duplicate DataMap name: %s", name);
return;
}
}
}

private void checkForNodeLinkage(DataMap map, ValidationResult validationResult) {
DataChannelDescriptor domain = map.getDataChannelDescriptor();
if (domain == null) {
return;
}

boolean linked = false;
int nodeCount = 0;
for (DataNodeDescriptor node : domain.getNodeDescriptors()) {
nodeCount++;
if (node.getDataMapNames().contains(map.getName())) {
linked = true;
break;
}
}

if (!linked && nodeCount > 0) {
addFailure(validationResult, map, "DataMap is not linked to any DataNodes");
}
}

private void validateJavaPackage(DataMap map, ValidationResult validationResult) {
String javaPackage = map.getDefaultPackage();

if(Util.isEmptyString(javaPackage)) {
if (Util.isEmptyString(javaPackage)) {
addFailure(validationResult, map, "Java package is not set in DataMap '%s'", map.getName());
return;
}

NameValidationHelper helper = NameValidationHelper.getInstance();
String invalidChars = helper.invalidCharsInJavaClassName(javaPackage);
if(invalidChars != null) {
if (invalidChars != null) {
addFailure(validationResult, map, "DataMap '%s' Java package '%s' contains invalid characters: %s",
map.getName(), javaPackage, invalidChars);
}
Expand Down
Loading
Loading