
org.databene.edifatto.parser.AbstractEdiParser Maven / Gradle / Ivy
/*
* Copyright (C) 2013-2015 Volker Bergmann ([email protected]).
* All rights reserved.
*
* 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 org.databene.edifatto.parser;
import java.text.ParsePosition;
import java.util.List;
import java.util.Map;
import org.databene.commons.Assert;
import org.databene.commons.SyntaxError;
import org.databene.edifatto.EdiFormatSymbols;
import org.databene.edifatto.definition.ComponentDefinition;
import org.databene.edifatto.definition.CompositeDefinition;
import org.databene.edifatto.definition.Definition;
import org.databene.edifatto.definition.MessageDefinition;
import org.databene.edifatto.definition.SegmentDefinition;
import org.databene.edifatto.definition.SegmentItemDefinition;
import org.databene.edifatto.model.Component;
import org.databene.edifatto.model.Composite;
import org.databene.edifatto.model.EdiProtocol;
import org.databene.edifatto.model.FunctionalGroup;
import org.databene.edifatto.model.Interchange;
import org.databene.edifatto.model.InterchangeItem;
import org.databene.edifatto.model.Message;
import org.databene.edifatto.model.Segment;
import org.databene.edifatto.model.SegmentGroup;
import org.databene.edifatto.model.SegmentGroupItem;
import org.databene.edifatto.model.SegmentItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Parent class for EDI-style parsers, providing common features
* and the possibility to override aspects.
* Created: 18.10.2013 10:13:28
* @since 1.0
* @author Volker Bergmann
*/
public abstract class AbstractEdiParser {
private final static Logger LOGGER = LoggerFactory.getLogger(AbstractEdiParser.class);
protected final EdiProtocol protocol;
public AbstractEdiParser(EdiProtocol protocol) {
this.protocol = protocol;
}
public Interchange parse(String text) {
EdiFormatSymbols symbols = determineSymbols(text);
SegmentTokenizer tokenizer = new SegmentTokenizer(symbols);
List segments = tokenizer.tokenize(text);
Interchange interchange = parseSegments(segments, symbols);
normalizeInterchange(interchange);
return interchange;
}
protected abstract EdiFormatSymbols determineSymbols(String text);
protected abstract Interchange parseSegments(List segments, EdiFormatSymbols symbols);
protected Interchange parseInterchange(List segments, ParsePosition pos, Interchange interchange, Map context) {
Segment icHeader = parseRequiredSegment(protocol.getInterchangeHeaderTag(), segments, pos);
interchange.addChild(icHeader);
parseFunctionalGroupsOrMessages(segments, pos, interchange, context);
Segment icTrailer = parseRequiredSegment(protocol.getInterchangeTrailerTag(), segments, pos);
interchange.addChild(icTrailer);
return interchange;
}
protected void parseFunctionalGroupsOrMessages(List segments, ParsePosition pos,
Interchange interchange, Map context) {
Segment fgHeader = parseOptionalSegment(protocol.getFunctionalGroupHeaderTag(), segments, pos);
if (fgHeader != null) {
processFunctionalGroupHeader(fgHeader, context);
interchange.addChild(fgHeader);
parseFunctionalGroups(segments, pos, interchange, context);
Segment fgTrailer = parseRequiredSegment(protocol.getFunctionalGroupTrailerTag(), segments, pos);
interchange.addChild(fgTrailer);
} else {
parseMessages(segments, pos, interchange, context);
}
}
protected void processFunctionalGroupHeader(Segment groupHeader, Map context) {
// callback method for child classes
}
private void parseFunctionalGroups(List segments, ParsePosition pos, Interchange interchange, Map context) {
Message message;
while ((message = parseOptionalMessage(segments, pos, context, interchange.getSymbols())) != null)
interchange.addChild(message);
}
private void parseMessages(List segments, ParsePosition pos, Interchange interchange, Map context) {
Message message;
while ((message = parseOptionalMessage(segments, pos, context, interchange.getSymbols())) != null)
interchange.addChild(message);
}
protected Message parseOptionalMessage(List segments, ParsePosition pos, Map context, EdiFormatSymbols symbols) {
String tag = segments.get(pos.getIndex()).getTag();
if (!tag.equals(protocol.getMessageHeaderTag()))
return null;
return parseRequiredMessage(segments, pos, context, symbols);
}
protected abstract Message parseRequiredMessage(List segments, ParsePosition pos, Map context, EdiFormatSymbols symbols);
protected static Segment parseRequiredSegment(String tag, List segments, ParsePosition pos) {
if (pos.getIndex() >= segments.size())
throw new SyntaxError("Expected " + tag + " segment, but no more segment is available", null);
Segment segment = segments.get(pos.getIndex());
requireTag(tag, segment);
pos.setIndex(pos.getIndex() + 1);
return segment;
}
protected static Segment parseOptionalSegment(String tag, List segments, ParsePosition pos) {
Segment segment = segments.get(pos.getIndex());
if (tag.equals(segment.getTag())) {
pos.setIndex(pos.getIndex() + 1);
return segment;
} else {
return null;
}
}
protected static void requireTag(String tag, Segment segment) {
if (!tag.equals(segment.getTag()))
throw new SyntaxError("Expected '" + tag + "' segment but found '" + segment.getTag() + "'", segment.toString());
}
private static void normalizeInterchange(Interchange interchange) {
NormalizationContext context = new NormalizationContext();
MessageDefinition messageDefinition = null;
for (InterchangeItem item : interchange.getChildren()) {
if (item instanceof FunctionalGroup)
normalizeFunctionalGroup((FunctionalGroup) item, context);
else if (item instanceof Message) {
Message message = (Message) item;
messageDefinition = message.getDefinition();
normalizeMessage(message, context);
}
}
for (InterchangeItem item : interchange.getChildren()) {
if (item instanceof Segment) {
Segment segment = (Segment) item;
String tag = segment.getTag();
if (tag.equals(interchange.getType().getServiceStringAdviceTag()))
segment.setDefinition(messageDefinition.getServiceStringAdvice());
else if (tag.equals(interchange.getType().getInterchangeHeaderTag()))
segment.setDefinition(messageDefinition.getInterchangeHeader());
else if (tag.equals(interchange.getType().getInterchangeTrailerTag()))
segment.setDefinition(messageDefinition.getInterchangeTrailer());
normalizeSegment(segment, context);
}
}
}
private static void normalizeFunctionalGroup(FunctionalGroup group, NormalizationContext context) {
for (InterchangeItem item : group.getChildren()) {
if (item instanceof FunctionalGroup)
normalizeFunctionalGroup((FunctionalGroup) item, context);
else if (item instanceof Message)
normalizeMessage((Message) item, context);
else if (item instanceof Segment)
normalizeSegment((Segment) item, context);
else
throw new UnsupportedOperationException("Unexpected type: " + item.getClass().getName());
}
}
private static void normalizeMessage(Message message, NormalizationContext context) {
message.setNo(context.newMessageNo());
for (SegmentGroupItem item : message.getChildren()) {
if (item instanceof SegmentGroup)
normalizeSegmentGroup((SegmentGroup) item, context);
else if (item instanceof Segment)
normalizeSegment((Segment) item, context);
else
throw new UnsupportedOperationException("Unexpected type: " + item.getClass().getName());
}
}
private static void normalizeSegmentGroup(SegmentGroup group, NormalizationContext context) {
group.setNo(context.newSegmentGroupNo());
for (SegmentGroupItem item : group.getChildren()) {
if (item instanceof SegmentGroup)
normalizeSegmentGroup((SegmentGroup) item, context);
else if (item instanceof Segment)
normalizeSegment((Segment) item, context);
else
throw new UnsupportedOperationException("Unexpected type: " + item.getClass().getName());
}
}
private static void normalizeSegment(Segment segment, NormalizationContext context) {
SegmentDefinition definition = segment.getDefinition();
if (definition != null) {
for (int i = 0; i < segment.getChildCount(); i++) {
SegmentItem child = segment.getChild(i);
SegmentItemDefinition childDefinition = definition.getChild(i);
if (child instanceof Composite) {
Composite composite = (Composite) child;
if (childDefinition instanceof CompositeDefinition)
normalizeComposite(composite, (CompositeDefinition) childDefinition);
else // childDefinition instanceof ComponentDefinition
unpackSingleComponent(segment, i);
} else
normalizeComponent((Component) child, (ComponentDefinition) childDefinition);
}
}
}
private static void unpackSingleComponent(Segment segment, int i) {
Composite composite = (Composite) segment.getChild(i);
Component component = composite.getChild(0);
ComponentDefinition definition = (ComponentDefinition) segment.getDefinition().getChild(i);
normalizeComponent(component, definition);
segment.setChild(i, component);
}
private static void normalizeComposite(Composite composite, Definition definition) {
int n = composite.getChildCount();
if (definition instanceof CompositeDefinition) {
CompositeDefinition compositeDef = (CompositeDefinition) definition;
composite.setDefinition(compositeDef);
for (int i = 0; i < n; i++) {
LOGGER.debug("Normalizing child #{} of {}", i, composite);
Component child = composite.getChild(i);
if (i < compositeDef.getChildCount()) {
ComponentDefinition childDef = compositeDef.getChild(i);
normalizeComponent(child, childDef);
} else {
Segment ownerSegment = composite.getSegment();
String errorMessage = "Element '" + composite + "' contains more child elements than allowed thy the specification";
throw new SyntaxError(errorMessage, ownerSegment.toString());
}
}
} else {
Assert.equals(1, n, "Element '" + definition.getName() + "' is expected to have exactly one child, but had " + n + ": "+ composite.toString());
Component component = composite.getChild(0);
normalizeComponent(component, (ComponentDefinition) definition);
}
}
private static void normalizeComponent(Component component, ComponentDefinition definition) {
component.setDefinition(definition);
}
static class NormalizationContext {
int messageCount = 0;
int segmentGroupCount = 0;
public int newMessageNo() {
return ++this.messageCount;
}
public int newSegmentGroupNo() {
return ++this.segmentGroupCount;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy