Skip to content

Commit

Permalink
Provide core logic
Browse files Browse the repository at this point in the history
  • Loading branch information
m-dzianishchyts committed May 28, 2024
1 parent 6938e5e commit c632f13
Show file tree
Hide file tree
Showing 32 changed files with 1,533 additions and 848 deletions.
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> {

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;
}
}

protected interface ValidationAction<N> {

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

0 comments on commit c632f13

Please sign in to comment.