/*
* Copyright 2005-2015 by BerryWorks Software, LLC. All rights reserved.
*
* This file is part of EDIReader. You may obtain a license for its use directly from
* BerryWorks Software, and you may also choose to use this software under the terms of the
* GPL version 3. Other products in the EDIReader software suite are available only by licensing
* with BerryWorks. Only those files bearing the GPL statement below are available under the GPL.
*
* EDIReader is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* EDIReader is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with EDIReader. If not,
* see <http://www.gnu.org/licenses/>.
*/
package com.berryworks.edireader;
import java.util.HashMap;
import java.util.Map;
/**
* Data structure that associates leading character sequences with specific parser implementations.
* When an EDI or EDI-like stream of data is to be parsed without pre-knowledge of which particular
* EDI standard is to be used, this parser registry is used to select a parser based on the initial
* characters of data.
* <p>
* The parsers for ANSI X.12 and UN/EDIFACT are included in the registry be default. The classes
* that implement these parsers are provided by the core EDIReader framework.
* <p>
* Parsers for other formats, including HL7, ACH, and NSF, are also listed in the registry.
* The classes that implement these formats are optional modules not included in the core EDIReader framework.
* If an optional parser module is present in the classpath, the registry is therefore able to
* select and load the appropriate parser in response to the leading character sequences in the data.
* <p>
* It is also possible for a developer to implement a parser for an EDI-like data format and register that
* parser along with the leading data characters which signal the instance of an interchange of that format.
* In this way, the EDIReader framework can be extended to parse previously unsupported data formats in the same
* way that it supports X12 and EDIFACT.
*/
public class ParserRegistry {
private static final Map<String, Class> builtinClass = new HashMap<>();
private static final Map<String, String>
registeredClassNames = new HashMap<>();
static {
new ParserRegistry();
}
private ParserRegistry() {
builtinClass.put("ISA", AnsiReader.class);
builtinClass.put("UNA", EdifactReaderWithCONTRL.class);
builtinClass.put("UNB", EdifactReaderWithCONTRL.class);
builtinClass.put("UNH", UNHReader.class);
registeredClassNames.put("UNH",
"com.berryworks.edireader.amadeus.AmadeusReader");
registeredClassNames.put("MSH",
"com.berryworks.edireader.hl7.HL7Reader");
registeredClassNames.put("STX",
"com.berryworks.edireader.tradacoms.TradacomsReader");
registeredClassNames.put("1",
"com.berryworks.edireader.ach.ACHReader");
registeredClassNames.put("AA0",
"com.berryworks.edireader.nsf.NSFReader");
}
/**
* Returns an instance of some EDIReader subclass based on the first
* several chars of data to be parsed.
* <p>
* Parsers for ANSI X12 and UN/EDIFACT are built-in. Other parsers can be registered, including
* custom parsers developed by users. Parsers registered via register() are considered first for
* a match with the incoming data before the built-in parsers are considered, allowing users to
* provide custom implementations of X12 and EDIFACT parsers if needed.
*
* @param firstChars of data to be parsed
* @return subclass of EDIReader that knows how to parse the data, or null if no parser is available
*/
public static EDIReader get(String firstChars) {
EDIReader result = null;
Class parserClass;
// See if a suitable registered class name is recognized by these
// firstChars
String name = (String) getMatch(firstChars, registeredClassNames);
if (name != null) {
try {
parserClass = Class.forName(name);
result = (EDIReader) parserClass.newInstance();
} catch (Exception ignore) {
}
}
// If not, see if there is a builtin class that matches
if (result == null) {
parserClass = (Class) getMatch(firstChars, builtinClass);
if (parserClass != null) {
try {
result = (EDIReader) parserClass.newInstance();
} catch (Exception ignore) {
}
}
}
// If still nothing, return the "catch all" parser if there is one
if (result == null) {
name = registeredClassNames.get("");
if (name != null) {
try {
parserClass = Class.forName(name);
result = (EDIReader) parserClass.newInstance();
} catch (Exception ignore) {
}
}
}
return result;
}
/**
* Registers a parser and associates it with the leading data characters that signal an instance of an interchange
* supported by the parser.
*
* @param firstChars of data to be parsed
* @param className fully qualified classname of an EDIReader subclass
*/
public static void register(String firstChars, String className) {
registeredClassNames.put(firstChars, className);
}
private static Object getMatch(String firstChars, Map map) {
Object result = null;
for (int n = firstChars.length(); result == null && n > 0; firstChars = firstChars.substring(0, --n)) {
result = map.get(firstChars);
}
return result;
}
}