Skip to content

Commit

Permalink
Merge pull request #74 from RepreZen/task/50
Browse files Browse the repository at this point in the history
[#50] Partial fix
  • Loading branch information
andylowry committed Sep 15, 2017
2 parents e9f139f + 698e00d commit 3e4f74a
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@

public interface Link extends OpenApiObject {

// Href
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
String getHref();

@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
void setHref(String href);

// OperationId
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
String getOperationId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ public LinkImpl(String key, JsonOverlay<?> parent) {
super(key, parent);
}

@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
private StringOverlay href = registerField("href", "href", null, new StringOverlay("href", this));

@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
private StringOverlay operationId = registerField("operationId", "operationId", null, new StringOverlay("operationId", this));

Expand All @@ -52,19 +49,6 @@ public LinkImpl(String key, JsonOverlay<?> parent) {
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
private ValMapOverlay<Object,AnyObjectOverlay> extensions = registerField("", "extensions", "x-.+", new ValMapOverlay<Object, AnyObjectOverlay>("", this, AnyObjectOverlay.factory, "x-.+"));

// Href
@Override
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
public String getHref() {
return href.get();
}

@Override
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
public void setHref(String href) {
this.href.set(href);
}

// OperationId
@Override
@Generated("com.reprezen.kaizen.oasparser.jsonoverlay.gen.CodeGenerator")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,9 +399,6 @@ types:

- name: Link
fields:
href:
name: Href
type: String
operationId:
name: OperationId
type: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,140 +12,122 @@

import static com.reprezen.kaizen.oasparser.val.Messages.m;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Map;

import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.reprezen.kaizen.oasparser.model3.Header;
import com.reprezen.kaizen.oasparser.model3.Link;
import com.reprezen.kaizen.oasparser.model3.OpenApi3;
import com.reprezen.kaizen.oasparser.model3.Operation;
import com.reprezen.kaizen.oasparser.model3.Parameter;
import com.reprezen.kaizen.oasparser.model3.Path;
import com.reprezen.kaizen.oasparser.model3.OpenApi3;
import com.reprezen.kaizen.oasparser.val.ObjectValidatorBase;
import com.reprezen.kaizen.oasparser.val.ValidationResults;
import com.reprezen.kaizen.oasparser.val.Validator;

public class LinkValidator extends ObjectValidatorBase<Link> {

@Inject
private Validator<Header> headerValidator;
@Inject
private Validator<Header> headerValidator;

@Override
public void validateObject(Link link, ValidationResults results) {
// no validation for: description
validateUrl(link.getHref(), results, false, "href");
Operation op = checkValidOperation(link, results);
checkParameters(link, op, results);
validateMap(link.getHeaders(), results, false, "headers", Regexes.NOEXT_REGEX, headerValidator);
validateExtensions(link.getExtensions(), results);
}
@Override
public void validateObject(Link link, ValidationResults results) {
// no validation for: description
// TODO: Validate operationRef value (why didn't they must make it a ref object???!)
Operation op = checkValidOperation(link, results);
if (op != null) {
checkParameters(link, op, results);
}
validateMap(link.getHeaders(), results, false, "headers", Regexes.NOEXT_REGEX, headerValidator);
validateExtensions(link.getExtensions(), results);
}

private Operation checkValidOperation(Link link, ValidationResults results) {
String opId = link.getOperationId();
String href = link.getHref();
Operation op = null;
if (opId != null && href != null) {
results.addError(m.msg("OpIdAndHrefInLink|Link may not contain both 'href' and 'operationId' properties"));
}
if (opId != null) {
op = findOperationById(link.getModel(), opId);
if (op == null) {
results.addError(
m.msg("OpIdNotFound|OperationId in Link does not identify an operation in the containing model",
opId),
"operationId");
}
}
String relativePath = getRelativePath(href, results);
if (relativePath != null) {
op = findOperationByPath(link.getModel(), relativePath, results);
if (op == null) {
results.addError(
m.msg("OpPathNotFound|Relative Href in Link does not identify a GET operation in the containing model",
href),
"href");
}
private Operation checkValidOperation(Link link, ValidationResults results) {
String opId = link.getOperationId();
String operationRef = link.getOperationRef();
Operation op = null;
if (opId == null && operationRef == null) {
results.addError(m.msg("NoOpIdNoOpRefInLink|Link must contain eitehr 'operationRef' or 'operationId' properties"));
} else if (opId != null && operationRef != null) {
results.addError(m.msg("OpIdAndOpRefInLink|Link may not contain both 'operationRef' and 'operationId' properties"));
}
if (opId != null) {
op = findOperationById(link.getModel(), opId);
if (op == null) {
results.addError(
m.msg("OpIdNotFound|OperationId in Link does not identify an operation in the containing model",
opId),
"operationId");
}
}
String relativePath = getRelativePath(operationRef, results);
if (relativePath != null) {
op = findOperationByPath(link.getModel(), relativePath, results);
if (op == null) {
results.addError(m.msg(
"OpPathNotFound|Relative OperationRef in Link does not identify a GET operation in the containing model",
operationRef), "operationRef");
}

}
return op;
}
}
return op;
}

private void checkParameters(Link link, Operation op, ValidationResults results) {
// TODO Q: parameter name is not sufficient to identify param in operation; will allow if it's unique, warn if
// it's not
Map<String, Integer> opParamCounts = getParamNameCounts(op.getParameters());
for (String paramName : link.getParameters().keySet()) {
int count = opParamCounts.get(paramName);
if (count == 0) {
results.addError(m.msg("BadLinkParam|Link parameter does not appear in linked operation", paramName),
paramName);
} else if (count > 1) {
results.addWarning(
m.msg("AmbigLinkParam|Link parameter name appears more than once in linked operation",
paramName),
paramName);
}
}
}
private void checkParameters(Link link, Operation op, ValidationResults results) {
// TODO Q: parameter name is not sufficient to identify param in operation; will
// allow if it's unique, warn if
// it's not
Map<String, Integer> opParamCounts = getParamNameCounts(op.getParameters());
for (String paramName : link.getParameters().keySet()) {
int count = opParamCounts.get(paramName);
if (count == 0) {
results.addError(m.msg("BadLinkParam|Link parameter does not appear in linked operation", paramName),
paramName);
} else if (count > 1) {
results.addWarning(
m.msg("AmbigLinkParam|Link parameter name appears more than once in linked operation",
paramName),
paramName);
}
}
}

private Operation findOperationById(OpenApi3 model, String operationId) {
for (Path path : model.getPaths().values()) {
for (Operation op : path.getOperations().values()) {
if (operationId.equals(op.getOperationId())) {
return op;
}
}
}
return null;
}
private Operation findOperationById(OpenApi3 model, String operationId) {
for (Path path : model.getPaths().values()) {
for (Operation op : path.getOperations().values()) {
if (operationId.equals(op.getOperationId())) {
return op;
}
}
}
return null;
}

private Operation findOperationByPath(OpenApi3 model, String relativePath, ValidationResults results) {
Path path = model.getPath(relativePath);
return path != null ? path.getGet() : null;
}
private Operation findOperationByPath(OpenApi3 model, String relativePath, ValidationResults results) {
Path path = model.getPath(relativePath);
return path != null ? path.getGet() : null;
}

private String getRelativePath(String href, ValidationResults results) {
// TODO Q: Assume restricted relative link requirement for href: no "." ".." items, no query string, no
// fragment
// TODO Q: will braces be pct-encoded as required for URIs?
if (href != null) {
try {
URI check = new URI(href);
if (!new URI(href).isAbsolute()) {
String path = check.getPath();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (check.getQuery() != null || check.getFragment() != null || path.matches(".*/\\.\\.?(/.*)?")) {
results.addError(
m.msg("BadRelLinkHref|Relative Link href may not contain a query part, a fragment, or any '.' or '..' path components",
href),
"href");
} else {
return path;
}
}
} catch (URISyntaxException e) {
results.addError(m.msg("BadLinkHref|Link href is not a valid URL", href), "href");
}
}
return null;
}
private String getRelativePath(String operationRef, ValidationResults results) {
// TODO Q: will braces be pct-encoded as required for URIs?
if (operationRef != null) {
results.addWarning("OperationRefUnSupp|Link.operationRef is not yet supported", "operationRef");
}
return null;
}

private Map<String, Integer> getParamNameCounts(Collection<? extends Parameter> parameters) {
Map<String, Integer> counts = Maps.newHashMap();
for (Parameter parameter : parameters) {
String name = parameter.getName();
if (counts.containsKey(name)) {
counts.put(name, 1 + counts.get(name));
} else {
counts.put(name, 1);
}
}
return counts;
}
private Map<String, Integer> getParamNameCounts(Collection<? extends Parameter> parameters) {
Map<String, Integer> counts = Maps.newHashMap();
for (Parameter parameter : parameters) {
String name = parameter.getName();
if (counts.containsKey(name)) {
counts.put(name, 1 + counts.get(name));
} else {
counts.put(name, 1);
}
}
return counts;
}
}

0 comments on commit 3e4f74a

Please sign in to comment.