Skip to content

Commit

Permalink
Add 'single' syntax type; update schemas; signal TX before start seg
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeEdgar committed Sep 12, 2019
1 parent b0c3874 commit 9edca99
Show file tree
Hide file tree
Showing 23 changed files with 3,678 additions and 3,033 deletions.
22 changes: 0 additions & 22 deletions src/main/java/io/xlate/edi/internal/schema/Reference.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,6 @@ class Reference implements EDIReference {
this.maxOccurs = maxOccurs;
}

Reference(EDIType referencedType, int minOccurs, int maxOccurs) {
this.refId = referencedType.getId();
this.refTag = null;
this.referencedType = referencedType;
this.minOccurs = minOccurs;
this.maxOccurs = maxOccurs;
}

Reference(EDIReference other) {
this.referencedType = other.getReferencedType();

if (other instanceof Reference) {
this.refId = ((Reference) other).getRefId();
} else {
this.refId = referencedType.getId();
}

this.refTag = null;
this.minOccurs = other.getMinOccurs();
this.maxOccurs = other.getMaxOccurs();
}

@Override
public String toString() {
return "refId: "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class StaEDISchemaFactory extends SchemaFactory {
private static XMLInputFactory factory = XMLInputFactory.newFactory();

private static final String XMLNS = "http://xlate.io/EDISchema/v2";
private static final String REFERR_UNDECLARED = "Type %s references undeclared %s with ref='%s'";
private static final String REFERR_ILLEGAL = "Type '%s' must not be referenced as '%s' in definition of type '%s'";

static final QName QN_SCHEMA = new QName(XMLNS, "schema");
static final QName QN_DESCRIPTION = new QName(XMLNS, "description");
Expand Down Expand Up @@ -440,29 +442,13 @@ void validateReferences(Structure struct, Map<String, EDIType> types) {
EDIType target = types.get(impl.getRefId());

if (target == null) {
StringBuilder excp = new StringBuilder();
excp.append("Type ");
excp.append(struct.getId());
excp.append(" references undeclared ");
excp.append(impl.getRefTag());
excp.append(" with ref='");
excp.append(impl.getRefId());
excp.append('\'');
schemaException(excp.toString());
schemaException(String.format(REFERR_UNDECLARED, struct.getId(), impl.getRefTag(), impl.getRefId()));
}

final EDIType.Type refType = target.getType();

if (refType != refTypeId(impl.getRefTag())) {
StringBuilder excp = new StringBuilder();
excp.append("Type '");
excp.append(impl.getRefId());
excp.append("' must not be referenced as \'");
excp.append(impl.getRefTag());
excp.append("\' in definition of type '");
excp.append(struct.getId());
excp.append('\'');
schemaException(excp.toString());
schemaException(String.format(REFERR_ILLEGAL, impl.getRefId(), impl.getRefTag(), struct.getId()));
}

switch (struct.getType()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,11 @@ public void setControlSchema(Schema schema) {

@Override
public void setTransactionSchema(Schema schema) {
if (getEventType() != EDIStreamEvent.START_TRANSACTION) {
throw new IllegalStateException("message schema set after transaction start");
if (proxy.isTransactionSchemaAllowed()) {
proxy.setTransactionSchema(schema);
} else {
throw new IllegalStateException("Transaction schema can only be set during transaction start");
}

proxy.setTransactionSchema(schema);
}

@Override
Expand Down
24 changes: 7 additions & 17 deletions src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -380,17 +380,15 @@ public EDIStreamWriter writeEmptyElement() throws EDIStreamException {
}

@Override
public EDIStreamWriter writeComponent(CharSequence text)
throws EDIStreamException {
public EDIStreamWriter writeComponent(CharSequence text) throws EDIStreamException {
startComponent();
writeElementData(text);
endComponent();
return this;
}

@Override
public EDIStreamWriter writeComponent(char[] text, int start, int end)
throws EDIStreamException {
public EDIStreamWriter writeComponent(char[] text, int start, int end) throws EDIStreamException {
startComponent();
writeElementData(text, start, end);
endComponent();
Expand All @@ -405,8 +403,7 @@ public EDIStreamWriter writeEmptyComponent() throws EDIStreamException {
}

@Override
public EDIStreamWriter writeElementData(CharSequence text)
throws EDIStreamException {
public EDIStreamWriter writeElementData(CharSequence text) throws EDIStreamException {
ensureLevelAtLeast(LEVEL_ELEMENT);
for (int i = 0, m = text.length(); i < m; i++) {
char curr = text.charAt(i);
Expand All @@ -419,9 +416,7 @@ public EDIStreamWriter writeElementData(CharSequence text)
}

@Override
public EDIStreamWriter writeElementData(char[] text, int start, int end)
throws EDIStreamException {

public EDIStreamWriter writeElementData(char[] text, int start, int end) throws EDIStreamException {
ensureLevelAtLeast(LEVEL_ELEMENT);
ensureArgs(text.length, start, end);

Expand All @@ -437,8 +432,7 @@ public EDIStreamWriter writeElementData(char[] text, int start, int end)
}

@Override
public EDIStreamWriter writeBinaryData(InputStream binaryStream)
throws EDIStreamException {
public EDIStreamWriter writeBinaryData(InputStream binaryStream) throws EDIStreamException {
ensureLevel(LEVEL_ELEMENT);
ensureState(State.ELEMENT_DATA_BINARY);
int input;
Expand All @@ -455,9 +449,7 @@ public EDIStreamWriter writeBinaryData(InputStream binaryStream)
}

@Override
public EDIStreamWriter writeBinaryData(byte[] binary, int start, int end)
throws EDIStreamException {

public EDIStreamWriter writeBinaryData(byte[] binary, int start, int end) throws EDIStreamException {
ensureLevel(LEVEL_ELEMENT);
ensureState(State.ELEMENT_DATA_BINARY);
ensureArgs(binary.length, start, end);
Expand All @@ -470,9 +462,7 @@ public EDIStreamWriter writeBinaryData(byte[] binary, int start, int end)
}

@Override
public EDIStreamWriter writeBinaryData(ByteBuffer binary)
throws EDIStreamException {

public EDIStreamWriter writeBinaryData(ByteBuffer binary) throws EDIStreamException {
ensureLevel(LEVEL_ELEMENT);
ensureState(State.ELEMENT_DATA_BINARY);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public class ProxyEventHandler implements EventHandler {

private Validator transactionValidator;

private boolean transactionSchemaAllowed = false;
private boolean transaction = false;
private boolean transactionNofified = false;

private InputStream binary;
private CharArraySequence segmentHolder = new CharArraySequence();
Expand Down Expand Up @@ -65,6 +65,10 @@ public void setControlSchema(Schema controlSchema) {
controlValidator = controlSchema != null ? new Validator(controlSchema, null) : null;
}

public boolean isTransactionSchemaAllowed() {
return transactionSchemaAllowed;
}

public void setTransactionSchema(Schema transactionSchema) {
transactionValidator = transactionSchema != null ? new Validator(transactionSchema, controlSchema) : null;
}
Expand Down Expand Up @@ -136,7 +140,8 @@ public void interchangeEnd() {
public void loopBegin(CharSequence id) {
if (EDIType.Type.TRANSACTION.toString().equals(id)) {
transaction = true;
transactionNofified = false;
transactionSchemaAllowed = true;
enqueueEvent(EDIStreamEvent.START_TRANSACTION, EDIStreamValidationError.NONE, id, null);
} else if (EDIType.Type.GROUP.toString().equals(id)) {
enqueueEvent(EDIStreamEvent.START_GROUP, EDIStreamValidationError.NONE, id, null);
} else {
Expand All @@ -147,9 +152,8 @@ public void loopBegin(CharSequence id) {
@Override
public void loopEnd(CharSequence id) {
if (EDIType.Type.TRANSACTION.toString().equals(id)) {
if (transaction) {
transaction = false;
}
transaction = false;
enqueueEvent(EDIStreamEvent.END_TRANSACTION, EDIStreamValidationError.NONE, id, null);
} else if (EDIType.Type.GROUP.toString().equals(id)) {
enqueueEvent(EDIStreamEvent.END_GROUP, EDIStreamValidationError.NONE, id, null);
} else {
Expand All @@ -171,15 +175,14 @@ public void segmentBegin(char[] text, int start, int length) {

if (exitTransaction(segmentHolder)) {
transaction = false;
enqueueEvent(EDIStreamEvent.END_TRANSACTION, EDIStreamValidationError.NONE, "TRANSACTION", null);
validator().validateSegment(this, segmentHolder);
}

enqueueEvent(EDIStreamEvent.START_SEGMENT, EDIStreamValidationError.NONE, segmentHolder, null, null);
}

boolean exitTransaction(CharSequence tag) {
if (transaction && transactionNofified && controlSchema != null && controlSchema.containsSegment(tag.toString())) {
if (transaction && !transactionSchemaAllowed && controlSchema != null && controlSchema.containsSegment(tag.toString())) {
return true;
}
return false;
Expand All @@ -192,11 +195,7 @@ public void segmentEnd() {
}

enqueueEvent(EDIStreamEvent.END_SEGMENT, EDIStreamValidationError.NONE, segmentHolder, null, null);

if (transaction && !transactionNofified) {
enqueueEvent(EDIStreamEvent.START_TRANSACTION, EDIStreamValidationError.NONE, "TRANSACTION", null);
transactionNofified = true;
}
transactionSchemaAllowed = false;
}

@Override
Expand Down Expand Up @@ -337,7 +336,8 @@ public void elementError(final EDIStreamEvent event,
}

private Validator validator() {
return transaction ? transactionValidator : controlValidator;
// Do not use the transactionValidator in the period where is may be set/mutated by the user
return transaction && !transactionSchemaAllowed ? transactionValidator : controlValidator;
}

private void enqueueEvent(EDIStreamEvent event,
Expand Down Expand Up @@ -469,10 +469,7 @@ public CharSequence subSequence(@SuppressWarnings("hiding") int start, int end)
}
return ((start == 0) && (end == length))
? this
: new String(
text,
this.start + start,
end - start);
: new String(text, this.start + start, end - start);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@
******************************************************************************/
package io.xlate.edi.internal.stream.validation;

import java.util.List;

import io.xlate.edi.internal.stream.internal.EventHandler;
import io.xlate.edi.schema.EDISyntaxRule;
import io.xlate.edi.stream.EDIStreamEvent;
import io.xlate.edi.stream.EDIStreamValidationError;

class ExclusionSyntaxValidator extends SyntaxValidator {

Expand All @@ -33,25 +29,6 @@ static ExclusionSyntaxValidator getInstance() {
return singleton;
}

static void signalExclusionError(EDISyntaxRule syntax, UsageNode structure, EventHandler handler) {
final List<UsageNode> children = structure.getChildren();
final int limit = children.size() + 1;
int tally = 0;

for (int position : syntax.getPositions()) {
if (position < limit && children.get(position - 1).isUsed() && ++tally > 1) {
final int element = getElementPosition(structure, position);
final int component = getComponentPosition(structure, position);

handler.elementError(EDIStreamEvent.ELEMENT_OCCURRENCE_ERROR,
EDIStreamValidationError.EXCLUSION_CONDITION_VIOLATED,
element,
component,
-1);
}
}
}

@Override
void validate(EDISyntaxRule syntax, UsageNode structure, EventHandler handler) {
SyntaxStatus status = scanSyntax(syntax, structure.getChildren());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright 2017 xlate.io LLC, http://www.xlate.io
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
******************************************************************************/
package io.xlate.edi.internal.stream.validation;

import io.xlate.edi.internal.stream.internal.EventHandler;
import io.xlate.edi.schema.EDISyntaxRule;

class SingleSyntaxValidator extends SyntaxValidator {

private static final SingleSyntaxValidator singleton = new SingleSyntaxValidator();

private SingleSyntaxValidator() {
}

static SingleSyntaxValidator getInstance() {
return singleton;
}

@Override
void validate(EDISyntaxRule syntax, UsageNode structure, EventHandler handler) {
SyntaxStatus status = scanSyntax(syntax, structure.getChildren());

if (status.elementCount > 1) {
signalExclusionError(syntax, structure, handler);
} else if (status.elementCount == 0) {
signalConditionError(syntax, structure, handler);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ static SyntaxValidator getInstance(EDISyntaxRule.Type type) {
return PairedSyntaxValidator.getInstance();
case REQUIRED:
return RequiredSyntaxValidator.getInstance();
case SINGLE:
return SingleSyntaxValidator.getInstance();
default:
throw new IllegalArgumentException("Unexpected syntax restriction type " + type + ".");
}
Expand Down Expand Up @@ -97,6 +99,25 @@ static void signalConditionError(EDISyntaxRule syntax, UsageNode structure, Even
}
}

static void signalExclusionError(EDISyntaxRule syntax, UsageNode structure, EventHandler handler) {
final List<UsageNode> children = structure.getChildren();
final int limit = children.size() + 1;
int tally = 0;

for (int position : syntax.getPositions()) {
if (position < limit && children.get(position - 1).isUsed() && ++tally > 1) {
final int element = getElementPosition(structure, position);
final int component = getComponentPosition(structure, position);

handler.elementError(EDIStreamEvent.ELEMENT_OCCURRENCE_ERROR,
EDIStreamValidationError.EXCLUSION_CONDITION_VIOLATED,
element,
component,
-1);
}
}
}

static int getComponentPosition(UsageNode structure, int position) {
if (structure.getReferencedType().isType(EDIType.Type.COMPOSITE)) {
return position;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ class UsageNode {
this.siblingIndex = siblingIndex;
}

EDIReference getReference() {
return link;
}

EDIType getReferencedType() {
return link.getReferencedType();
}
Expand Down
Loading

0 comments on commit 9edca99

Please sign in to comment.