├── README ├── nucleus8583-core ├── src │ ├── test │ │ ├── resources │ │ │ └── META-INF │ │ │ │ ├── test.zz │ │ │ │ └── nucleus8583 │ │ │ │ └── nucleus8583.types │ │ └── java │ │ │ └── org │ │ │ └── nucleus8583 │ │ │ └── core │ │ │ ├── field │ │ │ └── types │ │ │ │ ├── DummyField3.java │ │ │ │ ├── DummyField.java │ │ │ │ ├── Iso8583StringLTest.java │ │ │ │ └── CustomFieldTypeTest.java │ │ │ ├── xml │ │ │ ├── Iso8583MessageDefinitionTest.java │ │ │ └── Iso8583FieldAlignmentsTest.java │ │ │ ├── charset │ │ │ └── spi │ │ │ │ ├── Utf8ProviderTest.java │ │ │ │ ├── AsciiProviderTest.java │ │ │ │ ├── AsciiDecoderTest.java │ │ │ │ └── AsciEncoderTest.java │ │ │ ├── Iso8583MessageSerializer192Test.java │ │ │ ├── WritePerformanceTest.java │ │ │ ├── util │ │ │ ├── ResourcesUtilsTest.java │ │ │ ├── FastStringReaderTest.java │ │ │ └── FastIntegerTest.java │ │ │ ├── ReadPerformanceTest.java │ │ │ ├── Iso8583MessageSerializerTest.java │ │ │ └── PackUnpackTest.java │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── nucleus8583 │ │ │ ├── nucleus8583.charsets │ │ │ └── nucleus8583.types │ │ └── java │ │ └── org │ │ └── nucleus8583 │ │ └── core │ │ ├── charset │ │ ├── spi │ │ │ ├── CharsetProvider.java │ │ │ ├── Utf8Provider.java │ │ │ ├── AsciiProvider.java │ │ │ ├── AsciiDecoder.java │ │ │ ├── AsciiEncoder.java │ │ │ └── Utf8Encoder.java │ │ └── Charsets.java │ │ ├── util │ │ ├── ReaderUtils.java │ │ ├── FastStringReader.java │ │ ├── StringUtils.java │ │ ├── FastInteger.java │ │ └── ResourceUtils.java │ │ ├── field │ │ └── type │ │ │ ├── Iso8583UnicodeLVarStringFieldType.java │ │ │ ├── Iso8583UnicodeLLVarStringFieldType.java │ │ │ ├── Iso8583UnicodeLLLVarStringFieldType.java │ │ │ ├── Iso8583AbstractStringFieldType.java │ │ │ ├── Iso8583FieldType.java │ │ │ ├── Iso8583BinaryFieldType.java │ │ │ ├── Iso8583UnicodeVarStringFieldType.java │ │ │ ├── Iso8583StringFieldType.java │ │ │ ├── Iso8583AbstractBinaryFieldType.java │ │ │ └── Iso8583FieldTypes.java │ │ ├── xml │ │ ├── Iso8583MessageDefinition.java │ │ ├── Iso8583FieldAlignments.java │ │ └── Iso8583FieldDefinition.java │ │ ├── iso-message.xsd │ │ └── Iso8583MessageFactory.java ├── .settings │ ├── org.maven.ide.eclipse.prefs │ └── org.eclipse.jdt.core.prefs ├── .project ├── faq.txt ├── .classpath └── pom.xml ├── .gitignore ├── nucleus8583-oim ├── src │ ├── main │ │ └── java │ │ │ └── org │ │ │ └── nucleus8583 │ │ │ └── oim │ │ │ ├── type │ │ │ ├── spi │ │ │ │ ├── DataTypeFactory.java │ │ │ │ └── DataType.java │ │ │ └── DataTypes.java │ │ │ ├── language │ │ │ ├── spi │ │ │ │ ├── Language.java │ │ │ │ ├── CompiledExpression.java │ │ │ │ ├── MvelLanguage.java │ │ │ │ ├── OgnlLanguage.java │ │ │ │ └── LiteralLanguage.java │ │ │ └── Languages.java │ │ │ ├── EntityDefinition.java │ │ │ ├── DataStructureDefinition.java │ │ │ ├── component │ │ │ ├── HasFieldsComponent.java │ │ │ ├── SkipComponent.java │ │ │ ├── BaseComponent.java │ │ │ ├── Iso8583MessageComponent.java │ │ │ ├── ArrayComponent.java │ │ │ └── DataStructureComponent.java │ │ │ ├── OimDefinition.java │ │ │ ├── converter │ │ │ ├── BinaryConverter.java │ │ │ ├── StringConverter.java │ │ │ ├── ULongConverter.java │ │ │ ├── UIntConverter.java │ │ │ ├── DecimalConverter.java │ │ │ ├── TypeConverter.java │ │ │ └── DateTimeConverter.java │ │ │ ├── util │ │ │ ├── BeanUtil.java │ │ │ ├── StringUtil.java │ │ │ ├── FastStringReader.java │ │ │ ├── JAXBUtils.java │ │ │ └── ElExpression.java │ │ │ ├── xml │ │ │ ├── SkipComponentFactory.java │ │ │ ├── CollectionComponentFactory.java │ │ │ ├── DataStructureComponentFactory.java │ │ │ ├── Iso8583MessagesFactory.java │ │ │ ├── TransientComponentFactory.java │ │ │ ├── BasicComponentFactory.java │ │ │ └── Iso8583MessageComponentFactory.java │ │ │ └── Iso8583MessageManager.java │ └── test │ │ ├── java │ │ └── org │ │ │ └── nucleus8583 │ │ │ └── oim │ │ │ └── metadata │ │ │ ├── Ipm1Detail.java │ │ │ ├── Ipm1.java │ │ │ └── MessageManagerTest.java │ │ └── resources │ │ └── META-INF │ │ ├── oim-types.xml │ │ └── oim-sample.xml └── pom.xml └── wiki ├── Source.wiki ├── Sidebar.wiki ├── Downloads.wiki ├── Introduction.wiki ├── PerformanceBenchmark.wiki ├── Benchmarking.wiki ├── BenchmarkCodeJPos.wiki └── BenchmarkCodeNucleus8583.wiki /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/resources/META-INF/test.zz: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | temp 4 | .classpath 5 | .project 6 | .settings 7 | 8 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/field/types/DummyField3.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.types; 2 | 3 | public class DummyField3 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/resources/META-INF/nucleus8583/nucleus8583.charsets: -------------------------------------------------------------------------------- 1 | ASCII=org.nucleus8583.core.charset.spi.AsciiProvider 2 | UTF-8=org.nucleus8583.core.charset.spi.Utf8Provider 3 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/type/spi/DataTypeFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.type.spi; 2 | 3 | public interface DataTypeFactory { 4 | DataType createDataType(String query) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/spi/Language.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language.spi; 2 | 3 | public interface Language { 4 | CompiledExpression compile(String expression) throws Exception; 5 | } 6 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/test/java/org/nucleus8583/oim/metadata/Ipm1Detail.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.metadata; 2 | 3 | public class Ipm1Detail { 4 | @SuppressWarnings("unused") 5 | private String customerName = "abcdefhg"; 6 | } 7 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/resources/META-INF/nucleus8583/nucleus8583.types: -------------------------------------------------------------------------------- 1 | dummy=org.nucleus8583.core.field.types.DummyField 2 | dummy2=org.nucleus8583.core.field.types.DummyField2 3 | dummy3=org.nucleus8583.core.field.types.DummyField3 4 | -------------------------------------------------------------------------------- /wiki/Source.wiki: -------------------------------------------------------------------------------- 1 | Source can be downloaded via Git repository: 2 | 3 | {{{ 4 | git clone git://github.com/robbik/nucleus8583.git 5 | }}} 6 | 7 | or 8 | 9 | {{{ 10 | git clone http://github.com/robbik/nucleus8583.git 11 | }}} -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/EntityDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim; 2 | 3 | import javax.xml.bind.annotation.XmlRootElement; 4 | 5 | @XmlRootElement(name = "entity") 6 | public class EntityDefinition { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/DataStructureDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim; 2 | 3 | import javax.xml.bind.annotation.XmlRootElement; 4 | 5 | @XmlRootElement(name = "data-structure") 6 | public class DataStructureDefinition { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/spi/CompiledExpression.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language.spi; 2 | 3 | public interface CompiledExpression { 4 | Object eval(Object root) throws Exception; 5 | 6 | T eval(Object root, Class resultType) throws Exception; 7 | } 8 | -------------------------------------------------------------------------------- /wiki/Sidebar.wiki: -------------------------------------------------------------------------------- 1 | * [Introduction Introduction] 2 | * [Quickstart Quickstart] 3 | * [Manual Manual Documentation] 4 | * Performance Benchmarking 5 | * [PerformanceBenchmark Introduction and result] 6 | * [BenchmarkCodeNucleus8583 nucleus8583 benchmark code] 7 | * [BenchmarkCodeJPos jPOS benchmark code] -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/HasFieldsComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.Map; 5 | 6 | public interface HasFieldsComponent { 7 | Field getField(String name); 8 | 9 | Map getFields(); 10 | } 11 | -------------------------------------------------------------------------------- /nucleus8583-core/.settings/org.maven.ide.eclipse.prefs: -------------------------------------------------------------------------------- 1 | #Thu Mar 24 09:37:52 WIT 2011 2 | activeProfiles= 3 | eclipse.preferences.version=1 4 | fullBuildGoals=process-test-resources 5 | includeModules=false 6 | resolveWorkspaceProjects=true 7 | resourceFilterGoals=process-resources resources\:testResources 8 | skipCompilerPlugin=true 9 | version=1 10 | -------------------------------------------------------------------------------- /wiki/Downloads.wiki: -------------------------------------------------------------------------------- 1 | = Downloads = 2 | You can download via maven central repositories by specifying below dependency to your pom.xml file. 3 | 4 | {{{ 5 | 6 | ... 7 | 8 | org.nucleus8583 9 | nucleus8583-core 10 | 2.3.0 11 | 12 | ... 13 | 14 | }}} -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/CharsetProvider.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.io.Reader; 7 | import java.io.Writer; 8 | 9 | public interface CharsetProvider { 10 | Reader createDecoder(InputStream in) throws IOException; 11 | 12 | Writer createEncoder(OutputStream out) throws IOException; 13 | } 14 | -------------------------------------------------------------------------------- /nucleus8583-core/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Thu Mar 24 09:38:53 WIT 2011 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 8 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 9 | org.eclipse.jdt.core.compiler.source=1.6 10 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/OimDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlElementRef; 8 | import javax.xml.bind.annotation.XmlRootElement; 9 | 10 | @XmlRootElement(name = "oim") 11 | @XmlAccessorType(XmlAccessType.FIELD) 12 | public class OimDefinition { 13 | @XmlElementRef 14 | private List entities; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/Utf8Provider.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.io.Reader; 7 | import java.io.Writer; 8 | 9 | 10 | public class Utf8Provider implements CharsetProvider { 11 | 12 | public Writer createEncoder(OutputStream out) throws IOException { 13 | return new Utf8Encoder(out); 14 | } 15 | 16 | public Reader createDecoder(InputStream in) throws IOException { 17 | return new Utf8Decoder(in); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/AsciiProvider.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.io.Reader; 7 | import java.io.Writer; 8 | 9 | 10 | public class AsciiProvider implements CharsetProvider { 11 | 12 | public Writer createEncoder(OutputStream out) throws IOException { 13 | return new AsciiEncoder(out); 14 | } 15 | 16 | public Reader createDecoder(InputStream in) throws IOException { 17 | return new AsciiDecoder(in); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/BinaryConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import java.util.BitSet; 4 | 5 | public final class BinaryConverter extends TypeConverter { 6 | 7 | @Override 8 | public BitSet convertToIsoBinary(Object value) { 9 | return (BitSet) value; 10 | } 11 | 12 | @Override 13 | public Object convertToJavaObject(BitSet value) { 14 | return value; 15 | } 16 | 17 | @Override 18 | public Character getDefaultAlignment() { 19 | return ALIGN_NONE; 20 | } 21 | 22 | @Override 23 | public Character getDefaultPadWith() { 24 | return PAD_SPACE; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /nucleus8583-core/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nucleus8583 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.maven.ide.eclipse.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.maven.ide.eclipse.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /nucleus8583-core/faq.txt: -------------------------------------------------------------------------------- 1 | Q: how to release the artifact? 2 | A: > mvn clean source:jar javadoc:jar deploy -P releases -DrepositoryId=oss-sonatype-releases 3 | 4 | Q: how to deploy the artifact's snapshot? 5 | A: > mvn clean source:jar javadoc:jar deploy -P snaphosts -DrepositoryId=oss-sonatype-snapshots 6 | 7 | Q: maven settings? 8 | A: 9 | oss-sonatype-snapshots 10 | robbi.kurniawan 11 | 12 | 13 | 14 | oss-sonatype-releases 15 | robbi.kurniawan 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/util/ReaderUtils.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | 7 | public abstract class ReaderUtils { 8 | 9 | public static void readFully(Reader reader, char[] cbuf, int length) throws IOException { 10 | int cbufWriteIndex = 0; 11 | int remaining = length; 12 | 13 | int nbread; 14 | 15 | while (remaining > 0) { 16 | nbread = reader.read(cbuf, cbufWriteIndex, remaining); 17 | if (nbread == -1) { 18 | throw new EOFException(); 19 | } 20 | 21 | remaining -= nbread; 22 | cbufWriteIndex += nbread; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583UnicodeLVarStringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 4 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 5 | 6 | public final class Iso8583UnicodeLVarStringFieldType extends Iso8583UnicodeVarStringFieldType { 7 | private static final long serialVersionUID = -5615324004502124085L; 8 | 9 | public Iso8583UnicodeLVarStringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 10 | String defaultPadWith, String defaultEmptyValue) { 11 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue, 1, 9); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/util/BeanUtil.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.util; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.Map; 5 | 6 | public final class BeanUtil { 7 | public static void collectFields(Class _class, Map fields) { 8 | Class current = _class; 9 | 10 | while ((current != null) && (current != Object.class)) { 11 | Field[] arrFields = current.getDeclaredFields(); 12 | 13 | for (int i = arrFields.length - 1; i >= 0; --i) { 14 | Field f = arrFields[i]; 15 | f.setAccessible(true); 16 | 17 | fields.put(f.getName(), f); 18 | } 19 | 20 | current = current.getSuperclass(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583UnicodeLLVarStringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 4 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 5 | 6 | public final class Iso8583UnicodeLLVarStringFieldType extends Iso8583UnicodeVarStringFieldType { 7 | private static final long serialVersionUID = -5615324004502124085L; 8 | 9 | public Iso8583UnicodeLLVarStringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 10 | String defaultPadWith, String defaultEmptyValue) { 11 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue, 2, 99); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583UnicodeLLLVarStringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 4 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 5 | 6 | public final class Iso8583UnicodeLLLVarStringFieldType extends Iso8583UnicodeVarStringFieldType { 7 | private static final long serialVersionUID = -5615324004502124085L; 8 | 9 | public Iso8583UnicodeLLLVarStringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 10 | String defaultPadWith, String defaultEmptyValue) { 11 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue, 3, 999); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /nucleus8583-core/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.util; 2 | 3 | public final class StringUtil { 4 | private StringUtil() { 5 | // do nothing 6 | } 7 | 8 | public static boolean hasText(String str) { 9 | if (str == null) { 10 | return false; 11 | } 12 | 13 | return str.trim().length() > 0; 14 | } 15 | 16 | public static boolean hasText(String str, boolean trimmed) { 17 | if (str == null) { 18 | return false; 19 | } 20 | 21 | if (trimmed) { 22 | str = str.trim(); 23 | } 24 | 25 | return str.length() > 0; 26 | } 27 | 28 | public static boolean nullOrEmpty(String str, boolean trimmed) { 29 | if (str == null) { 30 | return true; 31 | } 32 | 33 | if (trimmed) { 34 | str = str.trim(); 35 | } 36 | 37 | return str.length() == 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/StringConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | public class StringConverter extends TypeConverter { 4 | @Override 5 | public Object convertToJavaObject(char[] value, int off, int len) { 6 | if (len == 0) { 7 | return EMPTY; 8 | } 9 | 10 | return new String(value, off, off + len); 11 | } 12 | 13 | @Override 14 | public Object convertToJavaObject(String value) { 15 | return value; 16 | } 17 | 18 | @Override 19 | public String convertToIsoString(Object value) { 20 | if (value == null) { 21 | return EMPTY; 22 | } 23 | 24 | return (String) value; 25 | } 26 | 27 | @Override 28 | public Character getDefaultAlignment() { 29 | return ALIGN_LEFT; 30 | } 31 | 32 | @Override 33 | public Character getDefaultPadWith() { 34 | return PAD_SPACE; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/test/java/org/nucleus8583/oim/metadata/Ipm1.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.metadata; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | 6 | @SuppressWarnings("unused") 7 | public class Ipm1 { 8 | private String cardNumber = "31254"; 9 | 10 | private String stan = "2"; 11 | 12 | private Date transactionDate = new Date(); 13 | 14 | private Date transactionTime = new Date(); 15 | 16 | private BigDecimal charge = BigDecimal.valueOf(1500); 17 | 18 | private String rrn = "1762745214"; 19 | 20 | private String responseCode = ""; 21 | 22 | private Ipm1Detail[] details; 23 | 24 | public Ipm1() { 25 | // details = new Vector(); 26 | // details.add(new Ipm1Detail()); 27 | 28 | details = new Ipm1Detail[] { new Ipm1Detail() }; 29 | } 30 | 31 | public Ipm1Detail[] getDetails() { 32 | return details; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/spi/MvelLanguage.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language.spi; 2 | 3 | import org.mvel2.MVEL; 4 | 5 | public class MvelLanguage implements Language { 6 | 7 | public CompiledExpression compile(String expression) throws Exception { 8 | return new MvelCompiledExpression(expression); 9 | } 10 | 11 | private static class MvelCompiledExpression implements CompiledExpression { 12 | private Object compiled; 13 | 14 | public MvelCompiledExpression(String expression) { 15 | compiled = MVEL.compileExpression(expression); 16 | } 17 | 18 | public Object eval(Object root) throws Exception { 19 | return MVEL.executeExpression(compiled, root); 20 | } 21 | 22 | public T eval(Object root, Class resultType) 23 | throws Exception { 24 | return MVEL.executeExpression(compiled, root, resultType); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/xml/Iso8583MessageDefinitionTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.xml; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import javax.xml.bind.JAXBContext; 6 | import javax.xml.bind.Unmarshaller; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.nucleus8583.core.util.ResourceUtils; 11 | 12 | public class Iso8583MessageDefinitionTest { 13 | private Iso8583MessageDefinition def; 14 | 15 | @Before 16 | public void before() throws Exception { 17 | JAXBContext ctx = JAXBContext.newInstance(Iso8583MessageDefinition.class); 18 | Unmarshaller unmarshaller = ctx.createUnmarshaller(); 19 | 20 | def = (Iso8583MessageDefinition) unmarshaller.unmarshal(ResourceUtils.getURL("file:src/test/resources/META-INF/codec8583.xml")); 21 | } 22 | 23 | @Test 24 | public void testGetEncoding() { 25 | assertEquals("ASCII", def.getEncoding()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/xml/Iso8583MessageDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.xml; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlAttribute; 8 | import javax.xml.bind.annotation.XmlElementRef; 9 | import javax.xml.bind.annotation.XmlRootElement; 10 | 11 | @XmlRootElement(name = "iso-message", namespace = "http://www.nucleus8583.org/schema/iso-message") 12 | @XmlAccessorType(XmlAccessType.FIELD) 13 | public class Iso8583MessageDefinition { 14 | 15 | @XmlAttribute(name = "encoding", required = true) 16 | private String encoding; 17 | 18 | @XmlElementRef 19 | private List fields; 20 | 21 | public String getEncoding() { 22 | return encoding; 23 | } 24 | 25 | public List getFields() { 26 | return fields; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/charset/spi/Utf8ProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import static org.junit.Assert.assertNotNull; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.Reader; 9 | import java.io.Writer; 10 | 11 | import org.junit.Test; 12 | 13 | public class Utf8ProviderTest { 14 | 15 | @Test 16 | public void testEncoder() throws Exception { 17 | Writer writer = new Utf8Provider() 18 | .createEncoder(new ByteArrayOutputStream()); 19 | 20 | assertNotNull(writer); 21 | assertTrue(writer instanceof Utf8Encoder); 22 | } 23 | 24 | @Test 25 | public void testDecoder() throws Exception { 26 | Reader reader = new Utf8Provider() 27 | .createDecoder(new ByteArrayInputStream(new byte[0])); 28 | 29 | assertNotNull(reader); 30 | assertTrue(reader instanceof Utf8Decoder); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/xml/Iso8583FieldAlignments.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.xml; 2 | 3 | import javax.xml.bind.annotation.XmlEnum; 4 | import javax.xml.bind.annotation.XmlEnumValue; 5 | import javax.xml.bind.annotation.XmlType; 6 | 7 | @XmlType 8 | @XmlEnum(String.class) 9 | public enum Iso8583FieldAlignments { 10 | @XmlEnumValue("left") LEFT, 11 | @XmlEnumValue("right") RIGHT, 12 | @XmlEnumValue("none") NONE; 13 | 14 | public char symbolicValue() { 15 | if (this == LEFT) { 16 | return 'l'; 17 | } 18 | if (this == RIGHT) { 19 | return 'r'; 20 | } 21 | return 'n'; 22 | } 23 | 24 | public static Iso8583FieldAlignments enumValueOf(String str) { 25 | if ("left".equalsIgnoreCase(str)) { 26 | return LEFT; 27 | } 28 | 29 | if ("right".equalsIgnoreCase(str)) { 30 | return RIGHT; 31 | } 32 | 33 | if ("none".equalsIgnoreCase(str)) { 34 | return NONE; 35 | } 36 | 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/charset/spi/AsciiProviderTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import static org.junit.Assert.assertNotNull; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.Reader; 9 | import java.io.Writer; 10 | 11 | import org.junit.Test; 12 | 13 | public class AsciiProviderTest { 14 | 15 | @Test 16 | public void testEncoder() throws Exception { 17 | Writer writer = new AsciiProvider() 18 | .createEncoder(new ByteArrayOutputStream()); 19 | 20 | assertNotNull(writer); 21 | assertTrue(writer instanceof AsciiEncoder); 22 | } 23 | 24 | @Test 25 | public void testDecoder() throws Exception { 26 | Reader reader = new AsciiProvider() 27 | .createDecoder(new ByteArrayInputStream(new byte[0])); 28 | 29 | assertNotNull(reader); 30 | assertTrue(reader instanceof AsciiDecoder); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/spi/OgnlLanguage.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language.spi; 2 | 3 | import ognl.Ognl; 4 | import ognl.OgnlContext; 5 | 6 | 7 | public class OgnlLanguage implements Language { 8 | private static final Object EMPTY = new Object(); 9 | 10 | public CompiledExpression compile(String expression) throws Exception { 11 | return new OgnlCompiledExpression(expression); 12 | } 13 | 14 | private static class OgnlCompiledExpression implements CompiledExpression { 15 | private Object compiled; 16 | 17 | public OgnlCompiledExpression(String expression) throws Exception { 18 | compiled = Ognl.compileExpression(new OgnlContext(), EMPTY, 19 | expression); 20 | } 21 | 22 | public Object eval(Object root) throws Exception { 23 | return Ognl.getValue(compiled, root); 24 | } 25 | 26 | public T eval(Object root, Class resultType) 27 | throws Exception { 28 | return resultType.cast(Ognl.getValue(compiled, root, resultType)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/AsciiDecoder.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.Reader; 6 | 7 | public class AsciiDecoder extends Reader { 8 | private final InputStream in; 9 | 10 | public AsciiDecoder(InputStream in) { 11 | this.in = in; 12 | } 13 | 14 | public void close() throws IOException { 15 | in.close(); 16 | } 17 | 18 | @Override 19 | public int read() throws IOException { 20 | int ubyte = in.read(); 21 | if (ubyte < 0) { 22 | return -1; 23 | } 24 | 25 | return ubyte & 0x7F; 26 | } 27 | 28 | public int read(char[] cbuf, int off, int len) throws IOException { 29 | int ubyte; 30 | int total = 0; 31 | 32 | for (int i = 0, j = off; i < len; ++i, ++j) { 33 | ubyte = in.read(); 34 | if (ubyte < 0) { 35 | if (total == 0) { 36 | total = -1; 37 | } 38 | 39 | break; 40 | } 41 | 42 | cbuf[j] = (char) (ubyte & 0x7F); 43 | ++total; 44 | } 45 | 46 | return total; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/ULongConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import org.nucleus8583.util.FastInteger; 4 | 5 | public class IntegerConverter extends TypeConverter { 6 | private static final Long ZERO = Long.valueOf(0); 7 | 8 | @Override 9 | public Object convertToJavaObject(char[] value, int off, int len) { 10 | if (len == 0) { 11 | return ZERO; 12 | } 13 | 14 | return FastLong.parseUlong(value, off, len); 15 | } 16 | 17 | @Override 18 | public Object convertToJavaObject(String value) { 19 | int vlen = value.length(); 20 | if (vlen == 0) { 21 | return ZERO; 22 | } 23 | 24 | return FastLong.parseULong(value, vlen); 25 | } 26 | 27 | @Override 28 | public String convertToIsoString(Object value) { 29 | if (value == null) { 30 | return EMPTY; 31 | } 32 | 33 | return ((Long) value).toString(); 34 | } 35 | 36 | @Override 37 | public Character getDefaultAlignment() { 38 | return ALIGN_RIGHT; 39 | } 40 | 41 | @Override 42 | public Character getDefaultPadWith() { 43 | return PAD_ZERO; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/UIntConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import org.nucleus8583.util.FastInteger; 4 | 5 | public class IntegerConverter extends TypeConverter { 6 | private static final Integer ZERO = Integer.valueOf(0); 7 | 8 | @Override 9 | public Object convertToJavaObject(char[] value, int off, int len) { 10 | if (len == 0) { 11 | return ZERO; 12 | } 13 | 14 | return FastInteger.parseUint(value, off, len); 15 | } 16 | 17 | @Override 18 | public Object convertToJavaObject(String value) { 19 | int vlen = value.length(); 20 | if (vlen == 0) { 21 | return ZERO; 22 | } 23 | 24 | return FastInteger.parseUint(value, vlen); 25 | } 26 | 27 | @Override 28 | public String convertToIsoString(Object value) { 29 | if (value == null) { 30 | return EMPTY; 31 | } 32 | 33 | return ((Integer) value).toString(); 34 | } 35 | 36 | @Override 37 | public Character getDefaultAlignment() { 38 | return ALIGN_RIGHT; 39 | } 40 | 41 | @Override 42 | public Character getDefaultPadWith() { 43 | return PAD_ZERO; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/test/resources/META-INF/oim-types.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 11 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583AbstractStringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Writer; 6 | import java.util.BitSet; 7 | 8 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 9 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 10 | 11 | public abstract class Iso8583AbstractStringFieldType extends Iso8583FieldType { 12 | private static final long serialVersionUID = -5615324004502124085L; 13 | 14 | public Iso8583AbstractStringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 15 | String defaultPadWith, String defaultEmptyValue) { 16 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 17 | } 18 | 19 | public boolean isBinary() { 20 | return false; 21 | } 22 | 23 | public void read(Reader reader, BitSet bits) throws IOException { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | public BitSet readBinary(Reader reader) throws IOException { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | public void write(Writer writer, BitSet value) throws IOException { 32 | throw new UnsupportedOperationException(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583FieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Serializable; 6 | import java.io.Writer; 7 | import java.util.BitSet; 8 | 9 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 10 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 11 | 12 | public abstract class Iso8583FieldType implements Serializable { 13 | private static final long serialVersionUID = -1162912563090715434L; 14 | 15 | protected final int id; 16 | 17 | public Iso8583FieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 18 | String defaultPadWith, String defaultEmptyValue) { 19 | this.id = def.getId(); 20 | } 21 | 22 | public int getId() { 23 | return id; 24 | } 25 | 26 | public abstract boolean isBinary(); 27 | 28 | public abstract void write(Writer writer, String value) throws IOException; 29 | 30 | public abstract void write(Writer writer, BitSet value) throws IOException; 31 | 32 | public abstract void read(Reader reader, BitSet bits) throws IOException; 33 | 34 | public abstract BitSet readBinary(Reader reader) throws IOException; 35 | 36 | public abstract String readString(Reader reader) throws IOException; 37 | } 38 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/test/resources/META-INF/oim-sample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583BinaryFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Writer; 6 | import java.util.BitSet; 7 | 8 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 9 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 10 | 11 | public final class Iso8583BinaryFieldType extends Iso8583AbstractBinaryFieldType { 12 | private static final long serialVersionUID = -5615324004502124085L; 13 | 14 | private final int length; 15 | 16 | public Iso8583BinaryFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 17 | String defaultPadWith, String defaultEmptyValue) { 18 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 19 | 20 | if (def.getLength() <= 0) { 21 | throw new IllegalArgumentException("length must be greater than zero"); 22 | } 23 | 24 | this.length = def.getLength() << 1; 25 | } 26 | 27 | public void read(Reader reader, BitSet bits) throws IOException { 28 | super.read(reader, bits, length); 29 | } 30 | 31 | public BitSet readBinary(Reader reader) throws IOException { 32 | BitSet bits = new BitSet(); 33 | super.read(reader, bits, length); 34 | 35 | return bits; 36 | } 37 | 38 | public void write(Writer writer, BitSet value) throws IOException { 39 | super.write(writer, value, length); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/xml/Iso8583FieldAlignmentsTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.xml; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class Iso8583FieldAlignmentsTest { 8 | 9 | @Test 10 | public void symbolicValueTest() { 11 | assertEquals('l', Iso8583FieldAlignments.LEFT.symbolicValue()); 12 | assertEquals('r', Iso8583FieldAlignments.RIGHT.symbolicValue()); 13 | assertEquals('n', Iso8583FieldAlignments.NONE.symbolicValue()); 14 | } 15 | 16 | @Test 17 | public void enumValueOfTest() { 18 | assertEquals(Iso8583FieldAlignments.LEFT, Iso8583FieldAlignments.enumValueOf("left")); 19 | assertEquals(Iso8583FieldAlignments.LEFT, Iso8583FieldAlignments.enumValueOf("lefT")); 20 | 21 | assertEquals(Iso8583FieldAlignments.RIGHT, Iso8583FieldAlignments.enumValueOf("right")); 22 | assertEquals(Iso8583FieldAlignments.RIGHT, Iso8583FieldAlignments.enumValueOf("rIgHt")); 23 | 24 | assertEquals(Iso8583FieldAlignments.NONE, Iso8583FieldAlignments.enumValueOf("none")); 25 | assertEquals(Iso8583FieldAlignments.NONE, Iso8583FieldAlignments.enumValueOf("nOnE")); 26 | 27 | assertEquals(null, Iso8583FieldAlignments.enumValueOf("l3ft")); 28 | assertEquals(null, Iso8583FieldAlignments.enumValueOf("")); 29 | assertEquals(null, Iso8583FieldAlignments.enumValueOf(null)); 30 | assertEquals(null, Iso8583FieldAlignments.enumValueOf("zzz")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/type/spi/DataType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.type.spi; 2 | 3 | import java.util.BitSet; 4 | 5 | public abstract class DataType { 6 | protected static final Character ALIGN_LEFT = Character.valueOf('l'); 7 | 8 | protected static final Character ALIGN_RIGHT = Character.valueOf('r'); 9 | 10 | protected static final Character ALIGN_NONE = Character.valueOf('l'); 11 | 12 | protected static final Character PAD_SPACE = Character.valueOf(' '); 13 | 14 | protected static final Character PAD_ZERO = Character.valueOf('0'); 15 | 16 | protected static final String EMPTY = "".intern(); 17 | 18 | public String writeObjectAsString(Object value) { 19 | throw new UnsupportedOperationException(); 20 | } 21 | 22 | public BitSet writeObjectAsBinary(Object value) { 23 | throw new UnsupportedOperationException(); 24 | } 25 | 26 | public Object readObject(char[] value, int off, int len) { 27 | return readObject(new String(value, off, len)); 28 | } 29 | 30 | public Object readObject(String value) { 31 | throw new UnsupportedOperationException(); 32 | } 33 | 34 | public Object readObject(BitSet value) { 35 | throw new UnsupportedOperationException(); 36 | } 37 | 38 | public Character getDefaultAlignment() { 39 | return null; 40 | } 41 | 42 | public Character getDefaultPadWith() { 43 | return null; 44 | } 45 | 46 | public Integer getDefaultLength() { 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/SkipComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | import java.util.Map; 7 | 8 | public final class SkipComponent extends BaseComponent { 9 | private final String filler; 10 | 11 | private final int length; 12 | 13 | public SkipComponent(String filler, int length) { 14 | this.filler = filler; 15 | this.length = length; 16 | } 17 | 18 | private void skip(Reader reader, int length) throws IOException { 19 | int crem = length; 20 | int dcrem; 21 | 22 | while (crem > 0) { 23 | dcrem = (int) reader.skip(length); 24 | if (dcrem <= 0) { 25 | throw new EOFException(); 26 | } 27 | 28 | crem -= dcrem; 29 | } 30 | } 31 | 32 | @Override 33 | public boolean isBinary() { 34 | return false; 35 | } 36 | 37 | @Override 38 | public void encode(StringBuilder sb, Object pojo, 39 | Map session) { 40 | sb.append(filler); 41 | } 42 | 43 | @Override 44 | public String encodeToString(Object pojo, Map session) { 45 | return filler; 46 | } 47 | 48 | @Override 49 | public void decode(String value, Object pojo, Map session) { 50 | // do nothing 51 | } 52 | 53 | @Override 54 | public void decode(Reader reader, Object pojo, Map session) 55 | throws IOException { 56 | skip(reader, length); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/Iso8583MessageSerializer192Test.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.StringWriter; 6 | import java.util.BitSet; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | public class Iso8583MessageSerializer192Test { 12 | private Iso8583MessageSerializer serializer; 13 | 14 | private String packed; 15 | 16 | private Iso8583Message unpacked; 17 | 18 | @Before 19 | public void initialize() throws Exception { 20 | serializer = new Iso8583MessageSerializer("classpath:META-INF/codec8583L.xml"); 21 | 22 | packed = "0200C0000000000100008000000000000000060300000049998000000001000000400000000000000003301002000000000000000000000"; 23 | 24 | unpacked = new Iso8583Message(); 25 | unpacked.setMti("0200"); 26 | unpacked.set(2, "030000"); 27 | unpacked.set(48, "9998"); 28 | unpacked.set(164, "301"); 29 | 30 | BitSet bs = new BitSet(); 31 | bs.set(10, true); 32 | unpacked.set(190, bs); 33 | } 34 | 35 | @Test 36 | public void testRead() throws Exception { 37 | Iso8583Message unpacked = new Iso8583Message(); 38 | 39 | serializer.read(packed, unpacked); 40 | assertEquals(this.unpacked, unpacked); 41 | } 42 | 43 | @Test 44 | public void testWrite() throws Exception { 45 | StringWriter sw = new StringWriter(); 46 | 47 | serializer.write(unpacked, sw); 48 | assertEquals(packed, sw.toString()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/DecimalConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class DecimalConverter extends TypeConverter { 6 | private final int precision; 7 | 8 | public DecimalConverter(int precision) { 9 | this.precision = precision; 10 | } 11 | 12 | @Override 13 | public Object convertToJavaObject(char[] value, int off, int len) { 14 | if (len == 0) { 15 | return BigDecimal.ZERO; 16 | } 17 | 18 | BigDecimal result = new BigDecimal(new String(value, off, len)); 19 | 20 | if (precision > 0) { 21 | return result.movePointLeft(precision); 22 | } 23 | 24 | return result; 25 | } 26 | 27 | @Override 28 | public Object convertToJavaObject(String value) { 29 | if (value.length() == 0) { 30 | return BigDecimal.ZERO; 31 | } 32 | 33 | BigDecimal result = new BigDecimal(value); 34 | 35 | if (precision > 0) { 36 | return result.movePointLeft(precision); 37 | } 38 | 39 | return result; 40 | } 41 | 42 | @Override 43 | public String convertToIsoString(Object value) { 44 | if (value == null) { 45 | return EMPTY; 46 | } 47 | 48 | if (precision > 0) { 49 | return ((BigDecimal) value).movePointRight(precision) 50 | .toPlainString(); 51 | } 52 | 53 | return ((BigDecimal) value).toPlainString(); 54 | } 55 | 56 | @Override 57 | public Character getDefaultAlignment() { 58 | return ALIGN_RIGHT; 59 | } 60 | 61 | @Override 62 | public Character getDefaultPadWith() { 63 | return PAD_ZERO; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/xml/Iso8583FieldDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.xml; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlAttribute; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement(name = "iso-field", namespace = "http://www.nucleus8583.org/schema/iso-message") 9 | @XmlAccessorType(XmlAccessType.FIELD) 10 | public class Iso8583FieldDefinition { 11 | @XmlAttribute(name = "id", required = true) 12 | private int id; 13 | 14 | @XmlAttribute(name = "type", required = true) 15 | private String type; 16 | 17 | @XmlAttribute(name = "length") 18 | private final int length; 19 | 20 | @XmlAttribute(name = "align") 21 | private final Iso8583FieldAlignments align; 22 | 23 | @XmlAttribute(name = "pad-with") 24 | private final String padWith; 25 | 26 | @XmlAttribute(name = "empty-value") 27 | private final String emptyValue; 28 | 29 | public Iso8583FieldDefinition() { 30 | length = 0; 31 | 32 | align = null; 33 | padWith = null; 34 | 35 | emptyValue = null; 36 | } 37 | 38 | public int getId() { 39 | return id; 40 | } 41 | 42 | public String getType() { 43 | return type; 44 | } 45 | 46 | public int getLength() { 47 | return length; 48 | } 49 | 50 | public Iso8583FieldAlignments getAlign() { 51 | return align; 52 | } 53 | 54 | public String getPadWith() { 55 | return padWith; 56 | } 57 | 58 | public String getEmptyValue() { 59 | return emptyValue; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/SkipComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.util.Arrays; 4 | import java.util.regex.Pattern; 5 | 6 | import org.nucleus8583.oim.component.SkipComponent; 7 | import org.nucleus8583.oim.util.StringUtil; 8 | import org.w3c.dom.Element; 9 | 10 | public abstract class SkipComponentFactory { 11 | private static final Pattern digits = Pattern.compile("^[0-9]+$"); 12 | 13 | public static SkipComponent parse(Element node) { 14 | String sFillWith = node.getAttribute("fill-with"); 15 | String sLength = node.getAttribute("length"); 16 | 17 | int length; 18 | 19 | // length 20 | if (StringUtil.nullOrEmpty(sLength, true)) { 21 | throw new NullPointerException("length is required"); 22 | } else { 23 | sLength = sLength.trim(); 24 | if (!digits.matcher(sLength).matches()) { 25 | throw new IllegalArgumentException( 26 | "length must be numeric only"); 27 | } 28 | 29 | length = Integer.parseInt(sLength, 10); 30 | if (length <= 0) { 31 | throw new IllegalArgumentException( 32 | "length must be more than zero"); 33 | } 34 | } 35 | 36 | // fill-with 37 | if (StringUtil.nullOrEmpty(sFillWith, false)) { 38 | throw new IllegalArgumentException("fill-with is required"); 39 | } 40 | if (sFillWith.length() != 1) { 41 | throw new IllegalArgumentException( 42 | "fill-with value must be one character only, given '" 43 | + sFillWith + "'"); 44 | } 45 | 46 | char[] cbuf = new char[length]; 47 | Arrays.fill(cbuf, sFillWith.charAt(0)); 48 | 49 | return new SkipComponent(new String(cbuf), length); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/TypeConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import java.util.BitSet; 4 | 5 | public abstract class TypeConverter { 6 | protected static final Character ALIGN_LEFT = Character.valueOf('l'); 7 | 8 | protected static final Character ALIGN_RIGHT = Character.valueOf('r'); 9 | 10 | protected static final Character ALIGN_NONE = Character.valueOf('l'); 11 | 12 | protected static final Character PAD_SPACE = Character.valueOf(' '); 13 | 14 | protected static final Character PAD_ZERO = Character.valueOf('0'); 15 | 16 | protected static final String EMPTY = "".intern(); 17 | 18 | protected String name; 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public String convertToIsoString(Object value) { 29 | throw new UnsupportedOperationException(); 30 | } 31 | 32 | public BitSet convertToIsoBinary(Object value) { 33 | throw new UnsupportedOperationException(); 34 | } 35 | 36 | public Object convertToJavaObject(char[] value, int off, int len) { 37 | return convertToJavaObject(new String(value, off, len)); 38 | } 39 | 40 | public Object convertToJavaObject(String value) { 41 | throw new UnsupportedOperationException(); 42 | } 43 | 44 | public Object convertToJavaObject(BitSet value) { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | public Character getDefaultAlignment() { 49 | return null; 50 | } 51 | 52 | public Character getDefaultPadWith() { 53 | return null; 54 | } 55 | 56 | public Integer getDefaultLength() { 57 | return null; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/Charsets.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset; 2 | 3 | import java.io.InputStream; 4 | import java.net.URL; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Properties; 8 | 9 | import org.nucleus8583.core.charset.spi.CharsetProvider; 10 | import org.nucleus8583.core.util.ResourceUtils; 11 | 12 | public abstract class Charsets { 13 | private static final Map providers; 14 | 15 | static { 16 | providers = new HashMap(); 17 | 18 | URL[] urls = ResourceUtils 19 | .getURLs("classpath:META-INF/nucleus8583/nucleus8583.charsets"); 20 | 21 | for (int i = 0; i < urls.length; ++i) { 22 | load(urls[i]); 23 | } 24 | } 25 | 26 | private static void load(URL url) { 27 | InputStream in = null; 28 | Properties prop = new Properties(); 29 | 30 | try { 31 | in = url.openStream(); 32 | prop.load(in); 33 | } catch (Throwable t) { 34 | // do nothing 35 | } finally { 36 | if (in != null) { 37 | try { 38 | in.close(); 39 | } catch (Throwable t) { 40 | // do nothing 41 | } 42 | } 43 | } 44 | 45 | for (Map.Entry entry : prop.entrySet()) { 46 | try { 47 | Class cla = Class.forName((String) entry.getValue(), true, 48 | Thread.currentThread().getContextClassLoader()); 49 | 50 | providers.put(((String) entry.getKey()).toUpperCase(), 51 | (CharsetProvider) cla.newInstance()); 52 | } catch (Throwable t) { 53 | // do nothing 54 | } 55 | } 56 | } 57 | 58 | public static CharsetProvider getProvider(String encoding) { 59 | return providers.get(encoding.toUpperCase()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/WritePerformanceTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | import org.junit.Before; 7 | import org.junit.Ignore; 8 | import org.junit.Test; 9 | 10 | @Ignore 11 | public class WritePerformanceTest { 12 | private Iso8583MessageSerializer serializer; 13 | 14 | private OutputStream nullOut; 15 | 16 | @Before 17 | public void initialize() throws Exception { 18 | serializer = new Iso8583MessageSerializer("classpath:META-INF/codec8583.xml"); 19 | 20 | nullOut = new OutputStream() { 21 | public void write(int b) throws IOException { 22 | // do nothing 23 | } 24 | }; 25 | } 26 | 27 | private long measure(int loops) throws Exception { 28 | long startDate = System.currentTimeMillis(); 29 | 30 | for (int i = loops - 1; i >= 0; --i) { 31 | Iso8583Message msg = new Iso8583Message(); 32 | 33 | msg.setMti("0200"); 34 | msg.set(2, "3125"); 35 | msg.set(7, "0104132431"); 36 | msg.set(11, "1"); 37 | msg.set(12, "132431"); 38 | msg.set(13, "0104"); 39 | msg.set(29, "C01000000"); 40 | msg.set(37, "1762745214"); 41 | msg.set(39, "00"); 42 | msg.set(48, "01000abcdefghijkl "); 43 | 44 | serializer.write(msg, nullOut); 45 | } 46 | long endDate = System.currentTimeMillis(); 47 | 48 | return endDate - startDate; 49 | } 50 | 51 | @Test 52 | public void shouldVeryFast() throws Exception { 53 | int loops = 1000000; 54 | 55 | for (int i = 0; i < 1; ++i) { 56 | long elapsed = measure(loops); 57 | 58 | System.out.println("[write] loops / sec = " + (loops * 1000 / elapsed)); 59 | Thread.yield(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/AsciiEncoder.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.io.Writer; 6 | 7 | public class AsciiEncoder extends Writer { 8 | private final OutputStream out; 9 | 10 | public AsciiEncoder(OutputStream out) { 11 | this.out = out; 12 | } 13 | 14 | public void close() throws IOException { 15 | out.close(); 16 | } 17 | 18 | public void flush() throws IOException { 19 | out.flush(); 20 | } 21 | 22 | @Override 23 | public void write(String str) throws IOException { 24 | int len = str.length(); 25 | for (int i = 0; i < len; ++i) { 26 | out.write(str.charAt(i) & 0x7F); 27 | } 28 | } 29 | 30 | @Override 31 | public void write(String str, int off, int len) throws IOException { 32 | if (off == 0) { 33 | for (int i = 0; i < len; ++i) { 34 | out.write(str.charAt(i) & 0x7F); 35 | } 36 | } else { 37 | for (int i = 0, j = off; i < len; ++i) { 38 | out.write(str.charAt(j++) & 0x7F); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public void write(int ichar) throws IOException { 45 | out.write(ichar & 0x7F); 46 | } 47 | 48 | @Override 49 | public void write(char[] cbuf) throws IOException { 50 | int len = cbuf.length; 51 | for (int i = 0; i < len; ++i) { 52 | out.write(cbuf[i] & 0x7F); 53 | } 54 | } 55 | 56 | public void write(char[] cbuf, int off, int len) throws IOException { 57 | if (off == 0) { 58 | for (int i = 0; i < len; ++i) { 59 | out.write(cbuf[i] & 0x7F); 60 | } 61 | } else { 62 | for (int i = 0, j = off; i < len; ++i, ++j) { 63 | out.write(cbuf[j] & 0x7F); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/BaseComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.util.BitSet; 6 | import java.util.Map; 7 | 8 | public abstract class BaseComponent { 9 | public boolean isBinary() { 10 | throw new UnsupportedOperationException(); 11 | } 12 | 13 | public void decode(Reader reader, Object pojo, Map session) 14 | throws IOException { 15 | throw new UnsupportedOperationException(); 16 | } 17 | 18 | public Object decode(Reader reader, Map session) 19 | throws IOException { 20 | throw new UnsupportedOperationException(); 21 | } 22 | 23 | public void decode(String value, Object pojo, Map session) { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | public Object decode(String value, Map session) { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | public void decode(BitSet value, Object pojo, Map session) { 32 | throw new UnsupportedOperationException(); 33 | } 34 | 35 | public BitSet decode(BitSet value, Map session) { 36 | throw new UnsupportedOperationException(); 37 | } 38 | 39 | public void encode(StringBuilder sb, Object pojo, 40 | Map session) { 41 | throw new UnsupportedOperationException(); 42 | } 43 | 44 | public String encodeToString(Object pojo, Map session) { 45 | StringBuilder sb = new StringBuilder(); 46 | encode(sb, pojo, session); 47 | 48 | return sb.toString(); 49 | } 50 | 51 | public BitSet encodeToBinary(Object pojo, Map session) { 52 | throw new UnsupportedOperationException(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /wiki/Introduction.wiki: -------------------------------------------------------------------------------- 1 | = Introduction = 2 | nucleus8583 is java based, OSGi compliant implementation of the ISO-8583 standard protocol. 3 | 4 | nucleus8583 provides very simple read and write operations to and from ISO-8583 message. With its simplicity, nucleus8583 has very small footprint and memory usage. This is supported by its ability to reuse instantiated object so the object instantiation can be minimized. 5 | 6 | Although nucleus8583 is very small and very simple, nucleus8583 has very extreme performance. In our testing mechanism, nucleus8583 can perform up to 4x compared to other Java based implementations (open source and commercial-based) under light and heavy loads. 7 | 8 | In the configuration, nucleus8583 has XML-based configuration with standard ISO-8583's data element for its field type. nucleus8583 use "a", "an", "a..", etc for the field type instead of class name. 9 | 10 | == Features == 11 | # OSGi compliant 12 | # Maven-based component 13 | # Very small footprint 14 | # Extreme performance, 4x faster than top ISO-8583 java-based implementation 15 | # Very simple API 16 | # Minimum memory usage 17 | # Library only, no additional feature 18 | 19 | == Changes == 20 | === From 1.x === 21 | # Iso8583Message and Iso8583Codec moved from package org.nucleus8583.codec to org.nucleus8583 22 | # Iso8583Message.toString() returns value in XML format 23 | # Change Iso8583Message constructor to non-public modifier, restricting access 24 | # Add javadoc documentation to Iso8583Message and Iso8583Codec 25 | 26 | === From 2.0.x === 27 | # drop char[] as acceptable value type 28 | # add support to UTF-8 encoding 29 | # replace thrown Exception into java.io.IOException and RuntimeException 30 | 31 | == Supported Encoding == 32 | === Version 2.0.x === 33 | # ASCII 34 | === Version 2.1.x === 35 | # ASCII 36 | # UTF-8 -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/iso-message.xsd: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/field/types/DummyField.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.types; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Writer; 6 | import java.util.BitSet; 7 | 8 | import org.nucleus8583.core.field.type.Iso8583FieldType; 9 | import org.nucleus8583.core.util.ReaderUtils; 10 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 11 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 12 | 13 | public class DummyField extends Iso8583FieldType { 14 | private static final long serialVersionUID = 3050266879047299109L; 15 | 16 | public DummyField(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 17 | String defaultPadWith, String defaultEmptyValue) { 18 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 19 | } 20 | 21 | public boolean isBinary() { 22 | return false; 23 | } 24 | 25 | public void write(Writer writer, String value) throws IOException { 26 | if (value == null) { 27 | writer.write("xx"); 28 | } else { 29 | int vlen = value.length(); 30 | switch (vlen) { 31 | case 0: 32 | writer.write("xx"); 33 | break; 34 | case 1: 35 | writer.write("x"); 36 | writer.write(value); 37 | break; 38 | case 2: 39 | writer.write(value); 40 | break; 41 | default: 42 | writer.write(value.substring(0, 2)); 43 | break; 44 | } 45 | } 46 | } 47 | 48 | public void write(Writer writer, BitSet value) throws IOException { 49 | throw new UnsupportedOperationException(); 50 | } 51 | 52 | public void read(Reader reader, BitSet bits) throws IOException { 53 | throw new UnsupportedOperationException(); 54 | } 55 | 56 | public BitSet readBinary(Reader reader) throws IOException { 57 | throw new UnsupportedOperationException(); 58 | } 59 | 60 | public String readString(Reader reader) throws IOException { 61 | char[] cbuf = new char[2]; 62 | ReaderUtils.readFully(reader, cbuf, 2); 63 | 64 | return new String(cbuf); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583UnicodeVarStringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Writer; 6 | 7 | import org.nucleus8583.core.util.FastInteger; 8 | import org.nucleus8583.core.util.ReaderUtils; 9 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 10 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 11 | 12 | public abstract class Iso8583UnicodeVarStringFieldType extends Iso8583AbstractStringFieldType { 13 | private static final long serialVersionUID = -5615324004502124085L; 14 | 15 | private final int lcount; 16 | 17 | private final int length; 18 | 19 | private final String emptyValue; 20 | 21 | public Iso8583UnicodeVarStringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 22 | String defaultPadWith, String defaultEmptyValue, int lcount, int length) { 23 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 24 | 25 | this.lcount = lcount; 26 | this.length = length; 27 | 28 | if (def.getEmptyValue() == null) { 29 | if (defaultEmptyValue == null) { 30 | this.emptyValue = ""; 31 | } else { 32 | this.emptyValue = defaultEmptyValue; 33 | } 34 | } else { 35 | this.emptyValue = def.getEmptyValue(); 36 | } 37 | } 38 | 39 | public String readString(Reader reader) throws IOException { 40 | int vlen = FastInteger.readUint(reader, lcount); 41 | 42 | if (vlen == 0) { 43 | return emptyValue; 44 | } 45 | 46 | char[] cbuf = new char[vlen]; 47 | ReaderUtils.readFully(reader, cbuf, vlen); 48 | 49 | return new String(cbuf); 50 | } 51 | 52 | public void write(Writer writer, String value) throws IOException { 53 | int vlen = value.length(); 54 | if (vlen > length) { 55 | throw new IllegalArgumentException("value of field #" + id + " is too long, expected 0-" + length + " but actual is " + vlen); 56 | } 57 | 58 | FastInteger.writeUint(writer, vlen, lcount); 59 | writer.write(value, 0, vlen); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/Iso8583MessageManager.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import org.nucleus8583.Iso8583Message; 9 | import org.nucleus8583.oim.component.Iso8583MessageComponent; 10 | import org.nucleus8583.oim.xml.Iso8583MessagesFactory; 11 | 12 | public final class Iso8583MessageManager { 13 | private final Iso8583MessagesFactory xmlFactory; 14 | 15 | private final Map messageComponents; 16 | 17 | public Iso8583MessageManager(List pathname) throws IOException { 18 | this(pathname.toArray(new String[0])); 19 | } 20 | 21 | public Iso8583MessageManager(String... locations) throws IOException { 22 | xmlFactory = new Iso8583MessagesFactory(locations); 23 | messageComponents = new HashMap(); 24 | 25 | for (Map.Entry entry : xmlFactory 26 | .getMessages().entrySet()) { 27 | messageComponents.put(entry.getKey(), entry.getValue()); 28 | } 29 | } 30 | 31 | private Iso8583MessageComponent findMessageComponent(String messageName) { 32 | Iso8583MessageComponent found = messageComponents.get(messageName); 33 | if (found == null) { 34 | throw new RuntimeException("unable to find message " + messageName); 35 | } 36 | 37 | return found; 38 | } 39 | 40 | public Object convert(String messageName, Iso8583Message msg) { 41 | return findMessageComponent(messageName).decode(msg, 42 | new HashMap()); 43 | } 44 | 45 | /** 46 | * convert from java plain object obj to ISO-8583 message. 47 | * 48 | * @param messageName 49 | * message name 50 | * @param obj 51 | * plain old java object 52 | * @param msg 53 | * ISO-8583 message 54 | */ 55 | public void convert(String messageName, Object obj, Iso8583Message msg) { 56 | findMessageComponent(messageName).encode(msg, obj, 57 | new HashMap()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/spi/LiteralLanguage.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language.spi; 2 | 3 | 4 | public class LiteralLanguage implements Language { 5 | 6 | public CompiledExpression compile(String expression) throws Exception { 7 | return new LiteralCompiledExpression(expression); 8 | } 9 | 10 | private static class LiteralCompiledExpression implements 11 | CompiledExpression { 12 | private String compiled; 13 | 14 | public LiteralCompiledExpression(String expression) { 15 | compiled = expression; 16 | } 17 | 18 | public Object eval(Object root) throws Exception { 19 | return compiled; 20 | } 21 | 22 | public T eval(Object root, Class resultType) 23 | throws Exception { 24 | Object transformed; 25 | 26 | if (Boolean.class.equals(resultType)) { 27 | transformed = Boolean.valueOf(compiled); 28 | } else if (boolean.class.equals(resultType)) { 29 | transformed = Boolean.parseBoolean(compiled); 30 | } else if (Integer.class.equals(resultType)) { 31 | transformed = Integer.valueOf(compiled); 32 | } else if (int.class.equals(resultType)) { 33 | transformed = Integer.parseInt(compiled); 34 | } else if (Long.class.equals(resultType)) { 35 | transformed = Long.valueOf(compiled); 36 | } else if (long.class.equals(resultType)) { 37 | transformed = Long.parseLong(compiled); 38 | } else if (Float.class.equals(resultType)) { 39 | transformed = Float.valueOf(compiled); 40 | } else if (float.class.equals(resultType)) { 41 | transformed = Float.parseFloat(compiled); 42 | } else if (Double.class.equals(resultType)) { 43 | transformed = Double.valueOf(compiled); 44 | } else if (double.class.equals(resultType)) { 45 | transformed = Double.parseDouble(compiled); 46 | } else if (byte[].class.equals(resultType)) { 47 | transformed = compiled.getBytes(); 48 | } else if (char[].class.equals(resultType)) { 49 | transformed = compiled.toCharArray(); 50 | } else { 51 | transformed = compiled; 52 | } 53 | 54 | return resultType.cast(transformed); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/util/FastStringReader.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.util; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | 6 | public class FastStringReader extends Reader { 7 | private final String value; 8 | 9 | private final int vlen; 10 | 11 | private int readIndex; 12 | 13 | private int remaining; 14 | 15 | public FastStringReader(String value) { 16 | this.value = value; 17 | this.vlen = StringUtil.nullOrEmpty(value, false) ? 0 : value.length(); 18 | 19 | this.readIndex = 0; 20 | this.remaining = this.vlen; 21 | } 22 | 23 | public int read(char[] cbuf, int off, int len) throws IOException { 24 | if (remaining == 0) { 25 | return -1; 26 | } 27 | 28 | int actualLen = Math.min(len, remaining); 29 | if (actualLen > 0) { 30 | value.getChars(readIndex, readIndex + actualLen, cbuf, off); 31 | 32 | readIndex += actualLen; 33 | remaining -= actualLen; 34 | } 35 | 36 | return actualLen; 37 | } 38 | 39 | @Override 40 | public int read() throws IOException { 41 | if (remaining <= 0) { 42 | return -1; 43 | } 44 | 45 | char cc = value.charAt(readIndex); 46 | 47 | ++readIndex; 48 | --remaining; 49 | 50 | return cc; 51 | } 52 | 53 | @Override 54 | public int read(char[] cbuf) throws IOException { 55 | return read(cbuf, 0, cbuf.length); 56 | } 57 | 58 | @Override 59 | public long skip(long n) throws IOException { 60 | int actualN = Math.min(remaining, (int) n); 61 | 62 | readIndex += actualN; 63 | remaining -= actualN; 64 | 65 | return actualN; 66 | } 67 | 68 | @Override 69 | public boolean ready() throws IOException { 70 | return remaining > 0; 71 | } 72 | 73 | @Override 74 | public boolean markSupported() { 75 | return false; 76 | } 77 | 78 | @Override 79 | public void mark(int readAheadLimit) throws IOException { 80 | throw new IOException(); 81 | } 82 | 83 | @Override 84 | public void reset() throws IOException { 85 | this.readIndex = 0; 86 | this.remaining = this.vlen; 87 | } 88 | 89 | public void close() throws IOException { 90 | this.readIndex = 0; 91 | this.remaining = this.vlen; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/util/FastStringReader.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | 6 | public class FastStringReader extends Reader { 7 | private String value; 8 | 9 | private int vlen; 10 | 11 | private int readIndex; 12 | 13 | private int remaining; 14 | 15 | public FastStringReader(String value) { 16 | this.value = value; 17 | this.vlen = value == null ? 0 : value.length(); 18 | 19 | this.readIndex = 0; 20 | this.remaining = this.vlen; 21 | } 22 | 23 | public int read(char[] cbuf, int off, int len) throws IOException { 24 | if (remaining == 0) { 25 | return -1; 26 | } 27 | 28 | int actualLen = Math.min(len, remaining); 29 | if (actualLen > 0) { 30 | value.getChars(readIndex, readIndex + actualLen, cbuf, off); 31 | 32 | readIndex += actualLen; 33 | remaining -= actualLen; 34 | } 35 | 36 | return actualLen; 37 | } 38 | 39 | @Override 40 | public int read() throws IOException { 41 | if (remaining <= 0) { 42 | return -1; 43 | } 44 | 45 | char cc = value.charAt(readIndex); 46 | 47 | ++readIndex; 48 | --remaining; 49 | 50 | return cc; 51 | } 52 | 53 | @Override 54 | public int read(char[] cbuf) throws IOException { 55 | return read(cbuf, 0, cbuf.length); 56 | } 57 | 58 | @Override 59 | public long skip(long n) throws IOException { 60 | int actualN = Math.min(remaining, (int) n); 61 | 62 | readIndex += actualN; 63 | remaining -= actualN; 64 | 65 | return actualN; 66 | } 67 | 68 | @Override 69 | public boolean ready() throws IOException { 70 | return remaining > 0; 71 | } 72 | 73 | @Override 74 | public boolean markSupported() { 75 | return false; 76 | } 77 | 78 | @Override 79 | public void mark(int readAheadLimit) throws IOException { 80 | throw new IOException(); 81 | } 82 | 83 | @Override 84 | public void reset() throws IOException { 85 | this.readIndex = 0; 86 | this.remaining = this.vlen; 87 | } 88 | 89 | public void close() throws IOException { 90 | this.readIndex = 0; 91 | this.remaining = 0; 92 | 93 | this.value = null; 94 | this.vlen = 0; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/charset/spi/AsciiDecoderTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import org.junit.Test; 12 | 13 | public class AsciiDecoderTest { 14 | 15 | @Test 16 | public void testClose() throws Exception { 17 | final AtomicBoolean closed = new AtomicBoolean(false); 18 | 19 | InputStream is = new InputStream() { 20 | public int read() throws IOException { 21 | return 0; 22 | } 23 | 24 | @Override 25 | public void close() throws IOException { 26 | closed.set(true); 27 | } 28 | }; 29 | 30 | AsciiDecoder decoder = new AsciiDecoder(is); 31 | decoder.close(); 32 | 33 | assertTrue(closed.get()); 34 | } 35 | 36 | @Test 37 | public void testEof() throws Exception { 38 | AsciiDecoder decoder = new AsciiDecoder(new ByteArrayInputStream( 39 | new byte[0])); 40 | 41 | assertEquals(-1, decoder.read()); 42 | } 43 | 44 | @Test 45 | public void testRead() throws Exception { 46 | AsciiDecoder decoder = new AsciiDecoder(new ByteArrayInputStream( 47 | "abcde".getBytes())); 48 | 49 | assertEquals('a', decoder.read()); 50 | } 51 | 52 | @Test 53 | public void testPartialBulkRead() throws Exception { 54 | AsciiDecoder decoder; 55 | char[] cbuf = new char[10]; 56 | 57 | decoder = new AsciiDecoder(new ByteArrayInputStream("abcde".getBytes())); 58 | assertEquals(5, decoder.read(cbuf, 0, cbuf.length)); 59 | assertEquals("abcde", new String(cbuf, 0, 5)); 60 | 61 | decoder = new AsciiDecoder(new ByteArrayInputStream("abcde".getBytes())); 62 | assertEquals(5, decoder.read(cbuf, 1, cbuf.length - 1)); 63 | assertEquals("aabcd", new String(cbuf, 0, 5)); 64 | } 65 | 66 | @Test 67 | public void testNoBulkRead() throws Exception { 68 | AsciiDecoder decoder = new AsciiDecoder(new ByteArrayInputStream( 69 | new byte[0])); 70 | 71 | char[] cbuf = new char[10]; 72 | 73 | assertEquals(-1, decoder.read(cbuf, 0, cbuf.length)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /wiki/PerformanceBenchmark.wiki: -------------------------------------------------------------------------------- 1 | = Performance Benchmarking = 2 | 3 | For performance benchmarking, we use standard desktop PC with specifications: 4 | # Hardware 5 | * Processor : Intel Dual Core 2.66GHz 32-bit 6 | * Memory : 2 GB 7 | # Software 8 | * Operating System : Microsoft Windows XP Service Pack 2 9 | * Java Virtual Machine : Sun Java VM 1.6.0 Update 10 (32-bit) 10 | 11 | In our small testing program which you can download [BenchmarkCodeNucleus8583 here] for nucleus8583 or [BenchmarkCodeJPos here] for jPOS, we do `N` `write`/`pack` operations and `read`/`unpack` operations and measure its average performance, average CPU, and average memory usage. In this benchmark we use jPOS 1.7.1 as our comparison. 12 | 13 | == Test Case == 14 | We use following data for our benchmarking process: 15 | {{{ 16 | '0200423800080A010000133125 01041324310000011324310104C010000001762745214 0003701000abcdefghijkl ' 17 | }}} 18 | 19 | or if we want to breakdown into details: 20 | || *iso bit number* || *value* || 21 | || `0` || `'0200'` || 22 | || `1` || `'423800080A01000013'` || 23 | || `2` || `'3125 '` || 24 | || `7` || `'0104132431'` || 25 | || `11` || `'000001'` || 26 | || `12` || `'132431'` || 27 | || `13` || `'0104'` || 28 | || `29` || `'C01000000'` || 29 | || `37` || `'1762745214 '` || 30 | || `39` || `'00'` || 31 | || `48` || `'01000abcdefghijkl '` || 32 | 33 | == Benchmarking Result == 34 | Performance measured how many operations can be done in one second. 35 | 36 | === Read/Unpack === 37 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 38 | || 10,000 || 128,205 || 58,139 || 39 | || 100,000 || 120,772 || 54,704 || 40 | || 1,000,000 || 119,846 || 53,837 || 41 | || 10,000,000 || 116,808 || 53,551 || 42 | 43 | === Write/Pack === 44 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 45 | || 10,000 || 128,205 || 26,666 || 46 | || 100,000 || 118,483 || 26,123 || 47 | || 1,000,000 || 115,727 || 25,827 || 48 | || 10,000,000 || 117,172 || 25,948 || 49 | 50 | === Conclusion === 51 | As you can see in two tables above, nucleus8583 significantly faster than jPOS in any test case. The data tells us that nucleus8583 performs 5 times compared to jPOS in write/pack operation and performs 2 times compared to jPOS in read/unpack operation. -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/language/Languages.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.language; 2 | 3 | import java.io.InputStreamReader; 4 | import java.io.Reader; 5 | import java.net.URL; 6 | import java.util.Map; 7 | import java.util.Properties; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import org.nucleus8583.oim.language.spi.CompiledExpression; 11 | import org.nucleus8583.oim.language.spi.Language; 12 | import org.nucleus8583.util.ResourceUtils; 13 | 14 | public abstract class Languages { 15 | private static ConcurrentHashMap map = new ConcurrentHashMap(); 16 | 17 | static { 18 | URL[] urls = ResourceUtils 19 | .getURLs("classpath:META-INF/nucleus8583/nucleus8583.languages"); 20 | 21 | if (urls.length > 0) { 22 | for (int i = 0; i < urls.length; ++i) { 23 | addLanguages(urls[i]); 24 | } 25 | } 26 | } 27 | 28 | public static void addLanguages(URL url) { 29 | Reader reader = null; 30 | Properties prop = new Properties(); 31 | 32 | try { 33 | reader = new InputStreamReader(url.openStream()); 34 | prop.load(reader); 35 | } catch (Throwable t) { 36 | // do nothing 37 | } finally { 38 | if (reader != null) { 39 | try { 40 | reader.close(); 41 | } catch (Throwable t) { 42 | // do nothing 43 | } 44 | } 45 | } 46 | 47 | for (Map.Entry entry : prop.entrySet()) { 48 | try { 49 | Class cla = Class.forName((String) entry.getValue(), true, 50 | Thread.currentThread().getContextClassLoader()); 51 | 52 | addLanguage((String) entry.getKey(), 53 | (Language) cla.newInstance()); 54 | } catch (Throwable t) { 55 | // do nothing 56 | } 57 | } 58 | } 59 | 60 | public static void addLanguage(String name, Language lang) { 61 | if (map.putIfAbsent(name, lang) != null) { 62 | throw new IllegalArgumentException("language name " + name 63 | + " already exists"); 64 | } 65 | } 66 | 67 | public static void removeLanguage(String name) { 68 | map.remove(name); 69 | } 70 | 71 | public static CompiledExpression compile(String name, String expression) 72 | throws Exception { 73 | Language lang = map.get(name); 74 | if (lang == null) { 75 | throw new IllegalArgumentException("unsupported language " + name); 76 | } 77 | 78 | return lang.compile(expression); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/converter/DateTimeConverter.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.converter; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | public class DateTimeConverter extends TypeConverter { 8 | private final String pattern; 9 | 10 | private final Integer length; 11 | 12 | private final ThreadLocal formatter; 13 | 14 | public DateTimeConverter(String pattern) { 15 | this.pattern = pattern; 16 | this.length = Integer.valueOf(pattern.length()); 17 | 18 | this.formatter = new ThreadLocal(); 19 | } 20 | 21 | private String format(Date value) { 22 | SimpleDateFormat fmt = formatter.get(); 23 | if (fmt == null) { 24 | fmt = new SimpleDateFormat(pattern); 25 | formatter.set(fmt); 26 | } 27 | 28 | return fmt.format(value); 29 | } 30 | 31 | private Date parse(String value) throws ParseException { 32 | SimpleDateFormat fmt = formatter.get(); 33 | if (fmt == null) { 34 | fmt = new SimpleDateFormat(pattern); 35 | formatter.set(fmt); 36 | } 37 | 38 | return fmt.parse(value); 39 | } 40 | 41 | @Override 42 | public Object convertToJavaObject(char[] value, int off, int len) { 43 | if (len == 0) { 44 | return null; 45 | } 46 | 47 | try { 48 | return parse(new String(value, off, off + len)); 49 | } catch (ParseException ex) { 50 | throw new RuntimeException("unable to parse date/time string " 51 | + new String(value, off, off + len) + ", pattern used is " 52 | + pattern); 53 | } 54 | } 55 | 56 | @Override 57 | public Object convertToJavaObject(String value) { 58 | if (value.length() == 0) { 59 | return null; 60 | } 61 | 62 | try { 63 | return parse(value); 64 | } catch (ParseException ex) { 65 | throw new RuntimeException("unable to parse date/time string " 66 | + value + ", pattern used is " + pattern); 67 | } 68 | } 69 | 70 | @Override 71 | public String convertToIsoString(Object value) { 72 | if (value == null) { 73 | return EMPTY; 74 | } 75 | 76 | return format((Date) value); 77 | } 78 | 79 | @Override 80 | public Character getDefaultAlignment() { 81 | return ALIGN_LEFT; 82 | } 83 | 84 | @Override 85 | public Integer getDefaultLength() { 86 | return length; 87 | } 88 | 89 | @Override 90 | public Character getDefaultPadWith() { 91 | return PAD_SPACE; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/util/ResourcesUtilsTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.net.URL; 9 | 10 | import org.junit.Test; 11 | 12 | public class ResourcesUtilsTest { 13 | 14 | @Test 15 | public void testGetURLsClasspath() throws Exception { 16 | URL[] urls = ResourceUtils.getURLs("classpath:META-INF/test.zz"); 17 | 18 | assertNotNull(urls); 19 | assertTrue(urls.length == 1); 20 | 21 | assertEquals('a', urls[0].openStream().read()); 22 | } 23 | 24 | @Test 25 | public void testGetURLsClasspathNotFound() throws Exception { 26 | URL[] urls = ResourceUtils.getURLs("classpath:META-INF/test.zz2"); 27 | 28 | assertNotNull(urls); 29 | assertTrue(urls.length == 0); 30 | } 31 | 32 | @Test 33 | public void testGetURLsFile() throws Exception { 34 | URL[] urls = ResourceUtils 35 | .getURLs("file:src/test/resources/META-INF/test.zz"); 36 | 37 | assertNotNull(urls); 38 | assertTrue(urls.length == 1); 39 | 40 | assertEquals('a', urls[0].openStream().read()); 41 | } 42 | 43 | @Test 44 | public void testGetURLsFileNoScheme() throws Exception { 45 | URL[] urls = ResourceUtils 46 | .getURLs("src/test/resources/META-INF/test.zz"); 47 | 48 | assertNotNull(urls); 49 | assertTrue(urls.length == 1); 50 | 51 | assertEquals('a', urls[0].openStream().read()); 52 | } 53 | 54 | @Test 55 | public void testGetURLClasspath() throws Exception { 56 | URL url = ResourceUtils.getURL("classpath:META-INF/test.zz"); 57 | 58 | assertNotNull(url); 59 | assertEquals('a', url.openStream().read()); 60 | } 61 | 62 | @Test 63 | public void testGetURLClasspathNotFound() throws Exception { 64 | URL url = ResourceUtils.getURL("classpath:META-INF/test.zz2"); 65 | 66 | assertNull(url); 67 | } 68 | 69 | @Test 70 | public void testGetURLFile() throws Exception { 71 | URL url = ResourceUtils 72 | .getURL("file:src/test/resources/META-INF/test.zz"); 73 | 74 | assertNotNull(url); 75 | assertEquals('a', url.openStream().read()); 76 | } 77 | 78 | @Test 79 | public void testGetURLFileNoScheme() throws Exception { 80 | URL url = ResourceUtils.getURL("src/test/resources/META-INF/test.zz"); 81 | 82 | assertNotNull(url); 83 | assertEquals('a', url.openStream().read()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/test/java/org/nucleus8583/oim/metadata/MessageManagerTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.metadata; 2 | 3 | import java.io.StringReader; 4 | 5 | import org.junit.Before; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.nucleus8583.Iso8583Message; 9 | import org.nucleus8583.Iso8583MessageFactory; 10 | import org.nucleus8583.oim.Iso8583MessageManager; 11 | 12 | @Ignore 13 | public class MessageManagerTest { 14 | private Iso8583MessageFactory factory; 15 | 16 | private Iso8583MessageManager manager; 17 | 18 | private Iso8583Message msg; 19 | 20 | @Before 21 | public void initialize() throws Exception { 22 | factory = new Iso8583MessageFactory( 23 | "file:src/test/resources/META-INF/nucleus8583.xml"); 24 | 25 | manager = new Iso8583MessageManager( 26 | "file:src/test/resources/META-INF/oim-types.xml", 27 | "file:src/test/resources/META-INF/oim-sample.xml"); 28 | 29 | msg = factory.createMessage(); 30 | } 31 | 32 | @Test 33 | public void packShouldFast() throws Exception { 34 | Ipm1 ipm1 = new Ipm1(); 35 | int loops = 1000000; 36 | 37 | long start = System.currentTimeMillis(); 38 | for (int i = loops; i > 0; --i) { 39 | manager.convert("ipm1", ipm1, msg); 40 | } 41 | long elapsed = System.currentTimeMillis() - start; 42 | 43 | long memoryUsage = (Runtime.getRuntime().totalMemory() - Runtime 44 | .getRuntime().freeMemory()); 45 | 46 | System.out.println("[pack] loops / sec: " + (loops * 1000 / elapsed)); 47 | System.out.println("[pack] memory: " + memoryUsage); 48 | 49 | System.out.println("[pack] iso unpacked data:\n" + msg); 50 | System.out 51 | .println("[pack] iso packed data:\n" + new String(msg.pack())); 52 | } 53 | 54 | @Test 55 | public void unpackShouldFast() throws Exception { 56 | String packed = "0200403800080A0100001331254 0000021806160117C001800001762745214 03701000abcdefhgijklmn "; 57 | int loops = 1000000; 58 | 59 | msg.unpack(new StringReader(packed)); 60 | 61 | Object pojo = null; 62 | 63 | long start = System.currentTimeMillis(); 64 | for (int i = loops; i > 0; --i) { 65 | pojo = manager.convert("ipm1", msg); 66 | } 67 | long elapsed = System.currentTimeMillis() - start; 68 | 69 | long memoryUsage = (Runtime.getRuntime().totalMemory() - Runtime 70 | .getRuntime().freeMemory()); 71 | 72 | System.out.println("[unpack] loops / sec: " + (loops * 1000 / elapsed)); 73 | System.out.println("[unpack] memory: " + memoryUsage); 74 | System.out.println("[unpack] pojo:" + pojo); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/util/FastStringReaderTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertFalse; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.io.IOException; 8 | 9 | import org.junit.Test; 10 | 11 | public class FastStringReaderTest { 12 | 13 | @Test 14 | public void markSupportedTest() throws Exception { 15 | FastStringReader reader = new FastStringReader("ance"); 16 | assertFalse(reader.markSupported()); 17 | } 18 | 19 | @Test(expected = IOException.class) 20 | public void markTest() throws Exception { 21 | FastStringReader reader = new FastStringReader("ance"); 22 | reader.mark(0); 23 | } 24 | 25 | @Test 26 | public void testNull() throws Exception { 27 | FastStringReader reader = new FastStringReader(null); 28 | assertFalse(reader.ready()); 29 | assertEquals(-1, reader.read()); 30 | assertEquals(0, reader.skip(1)); 31 | } 32 | 33 | @Test 34 | public void testEmptyString() throws Exception { 35 | FastStringReader reader = new FastStringReader(""); 36 | assertFalse(reader.ready()); 37 | assertEquals(-1, reader.read()); 38 | assertEquals(0, reader.skip(1)); 39 | } 40 | 41 | @Test 42 | public void testReset() throws Exception { 43 | FastStringReader reader = new FastStringReader("abcd"); 44 | 45 | assertTrue(reader.ready()); 46 | assertEquals('a', reader.read()); 47 | 48 | reader.reset(); 49 | assertEquals('a', reader.read()); 50 | } 51 | 52 | @Test 53 | public void testClose() throws Exception { 54 | FastStringReader reader = new FastStringReader("abcd"); 55 | assertTrue(reader.ready()); 56 | 57 | reader.close(); 58 | assertFalse(reader.ready()); 59 | } 60 | 61 | @Test 62 | public void testSkip() throws Exception { 63 | FastStringReader reader = new FastStringReader("abcd"); 64 | 65 | reader.skip(1); 66 | assertEquals('b', reader.read()); 67 | 68 | reader.skip(7); 69 | assertEquals(-1, reader.read()); 70 | 71 | reader.reset(); 72 | reader.skip(2); 73 | 74 | char[] cbuf = new char[20]; 75 | 76 | int readb = reader.read(cbuf); 77 | assertEquals(2, readb); 78 | 79 | assertEquals("cd", new String(cbuf, 0, readb)); 80 | } 81 | 82 | @Test 83 | public void testRead() throws Exception { 84 | FastStringReader reader = new FastStringReader("abcd"); 85 | char[] cbuf = new char[20]; 86 | 87 | int readb = reader.read(cbuf); 88 | assertEquals(4, readb); 89 | assertEquals("abcd", new String(cbuf, 0, readb)); 90 | 91 | reader.reset(); 92 | 93 | readb = reader.read(cbuf, 0, 0); 94 | assertEquals(0, readb); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/ReadPerformanceTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | import org.junit.Before; 7 | import org.junit.Ignore; 8 | import org.junit.Test; 9 | 10 | @Ignore 11 | public class ReadPerformanceTest { 12 | private Iso8583MessageSerializer serializer; 13 | 14 | private InputStream ipacked; 15 | 16 | @Before 17 | public void initialize() throws Exception { 18 | serializer = new Iso8583MessageSerializer("classpath:META-INF/codec8583.xml"); 19 | 20 | final byte[] bpacked = "0200423800080A010000000000000000000004312501041324311 1324310104C010000001762745214 0003701000abcdefghijkl ".getBytes(); 21 | 22 | ipacked = new InputStream() { 23 | private int readerIndex = 0; 24 | 25 | private int remaining = bpacked.length; 26 | 27 | public int read() throws IOException { 28 | if (remaining == 0) { 29 | return -1; 30 | } 31 | 32 | int readb = bpacked[readerIndex] & 0xFF; 33 | 34 | ++readerIndex; 35 | --remaining; 36 | 37 | return readb; 38 | } 39 | 40 | @Override 41 | public int read(byte b[], int off, int len) throws IOException { 42 | if (remaining == 0) { 43 | return -1; 44 | } 45 | 46 | if (remaining >= len) { 47 | System.arraycopy(bpacked, readerIndex, b, off, len); 48 | 49 | readerIndex += len; 50 | remaining -= len; 51 | 52 | return len; 53 | } 54 | 55 | try { 56 | System.arraycopy(bpacked, readerIndex, b, off, remaining); 57 | } catch (Throwable e) { 58 | System.err.println("error: " + "bpacked.length = " 59 | + bpacked.length + ", readerIndex = "); 60 | } 61 | 62 | remaining = 0; 63 | readerIndex = bpacked.length; 64 | 65 | return len; 66 | } 67 | 68 | public void close() throws IOException { 69 | readerIndex = 0; 70 | remaining = bpacked.length; 71 | } 72 | }; 73 | } 74 | 75 | private long measure(int loops) throws Exception { 76 | Iso8583Message msg = new Iso8583Message(); 77 | 78 | long startDate = System.currentTimeMillis(); 79 | for (int i = 0; i < loops; ++i) { 80 | serializer.read(ipacked, msg); 81 | ipacked.close(); 82 | } 83 | long endDate = System.currentTimeMillis(); 84 | 85 | return endDate - startDate; 86 | } 87 | 88 | @Test 89 | public void shouldVeryFast() throws Exception { 90 | int loops = 1000000; 91 | 92 | for (int i = 0; i < 1; ++i) { 93 | long elapsed = measure(loops); 94 | 95 | System.out.println("[read] loops/ms = " + (loops * 1000 / elapsed)); 96 | Thread.yield(); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/util/JAXBUtils.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.io.PrintWriter; 6 | import java.io.StringWriter; 7 | import java.net.URL; 8 | import java.util.Collections; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | import javax.xml.bind.JAXBContext; 13 | import javax.xml.bind.JAXBException; 14 | 15 | import org.cheetah.core.ServiceContextDefinition; 16 | import org.cheetah.core.ServiceDefinition; 17 | 18 | public abstract class JAXBUtils { 19 | private static JAXBContext ctx; 20 | 21 | private static Set> classes; 22 | 23 | static { 24 | classes = Collections.synchronizedSet(new HashSet>()); 25 | 26 | classes.add(ServiceContextDefinition.class); 27 | classes.add(ServiceDefinition.class); 28 | 29 | URL[] urls = ResourceUtils 30 | .getURLs("classpath:META-INF/cheetah/cheetah.actions"); 31 | 32 | if (urls.length > 0) { 33 | for (int i = 0; i < urls.length; ++i) { 34 | addClasses(urls[i]); 35 | } 36 | } 37 | } 38 | 39 | public static void addClass(Class _class) { 40 | classes.add(_class); 41 | } 42 | 43 | public static void addClasses(URL url) { 44 | BufferedReader reader = null; 45 | 46 | String line; 47 | ClassLoader cl = Thread.currentThread().getContextClassLoader(); 48 | 49 | try { 50 | reader = new BufferedReader(new InputStreamReader(url.openStream())); 51 | 52 | while ((line = reader.readLine()) != null) { 53 | line = line.trim(); 54 | 55 | if ((line.length() == 0) || line.startsWith(";")) { 56 | continue; 57 | } 58 | 59 | try { 60 | classes.add(Class.forName(line, true, cl)); 61 | } catch (Throwable t) { 62 | // do nothing 63 | } 64 | } 65 | } catch (Throwable t) { 66 | // do nothing 67 | } finally { 68 | if (reader != null) { 69 | try { 70 | reader.close(); 71 | } catch (Throwable t) { 72 | // do nothing 73 | } 74 | } 75 | } 76 | } 77 | 78 | private static synchronized void createContext() { 79 | if (ctx == null) { 80 | try { 81 | ctx = JAXBContext.newInstance(classes.toArray(new Class[0])); 82 | } catch (JAXBException e) { 83 | StringWriter sw = new StringWriter(); 84 | 85 | PrintWriter w = new PrintWriter(sw); 86 | e.printStackTrace(w); 87 | 88 | w.flush(); 89 | 90 | throw new InternalError(sw.toString()); 91 | } 92 | } 93 | } 94 | 95 | public static Object unmarshal(URL url) throws JAXBException { 96 | createContext(); 97 | 98 | return ctx.createUnmarshaller().unmarshal(url); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/field/types/Iso8583StringLTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.types; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.EOFException; 7 | import java.io.StringReader; 8 | import java.io.StringWriter; 9 | import java.util.BitSet; 10 | 11 | import javax.xml.bind.JAXBContext; 12 | import javax.xml.bind.Unmarshaller; 13 | 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.nucleus8583.core.field.type.Iso8583FieldType; 17 | import org.nucleus8583.core.field.type.Iso8583FieldTypes; 18 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 19 | 20 | public class Iso8583StringLTest { 21 | private Iso8583FieldType stringField; 22 | 23 | @Before 24 | public void before() throws Exception { 25 | Unmarshaller unmarshaller = JAXBContext.newInstance( 26 | Iso8583FieldDefinition.class).createUnmarshaller(); 27 | 28 | stringField = Iso8583FieldTypes.getType((Iso8583FieldDefinition) unmarshaller 29 | .unmarshal(new ByteArrayInputStream( 30 | ("").getBytes()))); 31 | } 32 | 33 | @Test(expected = UnsupportedOperationException.class) 34 | public void packBinary() throws Exception { 35 | stringField.write(new StringWriter(), new BitSet()); 36 | } 37 | 38 | @Test 39 | public void packString() throws Exception { 40 | StringWriter sw = new StringWriter(); 41 | stringField.write(sw, "20"); 42 | assertEquals("220", sw.toString()); 43 | } 44 | 45 | @Test 46 | public void packEmptyString() throws Exception { 47 | StringWriter sw = new StringWriter(); 48 | stringField.write(sw, ""); 49 | assertEquals("0", sw.toString()); 50 | } 51 | 52 | @Test(expected = IllegalArgumentException.class) 53 | public void packStringOverflow() throws Exception { 54 | StringWriter sw = new StringWriter(); 55 | stringField.write(sw, "abcdefghji"); 56 | } 57 | 58 | @Test(expected = UnsupportedOperationException.class) 59 | public void unpackBinary1() throws Exception { 60 | stringField.read(new StringReader("a"), new BitSet()); 61 | } 62 | 63 | @Test(expected = UnsupportedOperationException.class) 64 | public void unpackBinary2() throws Exception { 65 | stringField.readBinary(new StringReader("a")); 66 | } 67 | 68 | @Test 69 | public void unpackString() throws Exception { 70 | assertEquals("20", stringField.readString(new StringReader("220"))); 71 | } 72 | 73 | @Test 74 | public void unpackEmptyString() throws Exception { 75 | assertEquals("", stringField.readString(new StringReader("0"))); 76 | } 77 | 78 | @Test(expected = EOFException.class) 79 | public void unpackStringUnpadOverflow() throws Exception { 80 | stringField.readString(new StringReader("5ab")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/util/FastIntegerTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.EOFException; 6 | import java.io.IOException; 7 | import java.io.StringReader; 8 | import java.io.StringWriter; 9 | import java.util.Random; 10 | 11 | import org.junit.Test; 12 | 13 | public class FastIntegerTest { 14 | 15 | @Test 16 | public void smokeTestUintToString() { 17 | Random rnd = new Random(); 18 | 19 | for (int i = 1; i < 1000; ++i) { 20 | int z = rnd.nextInt(Integer.MAX_VALUE - 100); 21 | String sz = FastInteger.uintToString(z, 10); 22 | 23 | assertEquals(sz, z, Integer.parseInt(sz)); 24 | } 25 | } 26 | 27 | @Test 28 | public void smokeTestWriteUint() throws IOException { 29 | Random rnd = new Random(); 30 | 31 | for (int i = 1; i < 1000; ++i) { 32 | StringWriter sw = new StringWriter(); 33 | 34 | int z = rnd.nextInt(Integer.MAX_VALUE - 100); 35 | FastInteger.writeUint(sw, z, 10); 36 | 37 | String sz = sw.toString(); 38 | assertEquals(sz, z, Integer.parseInt(sz)); 39 | } 40 | } 41 | 42 | @Test 43 | public void smokeTestParseUint() { 44 | Random rnd = new Random(); 45 | 46 | for (int i = 1; i < 1000; ++i) { 47 | int z = rnd.nextInt(Integer.MAX_VALUE - 100); 48 | String sz = String.valueOf(z); 49 | 50 | assertEquals(sz, z, FastInteger.parseUint(sz)); 51 | } 52 | } 53 | 54 | @Test 55 | public void smokeTestParseUintCharArray() { 56 | Random rnd = new Random(); 57 | 58 | for (int i = 1; i < 1000; ++i) { 59 | int z = rnd.nextInt(Integer.MAX_VALUE - 100); 60 | String sz = String.valueOf(z); 61 | 62 | assertEquals(sz, z, FastInteger.parseUint(sz.toCharArray())); 63 | } 64 | } 65 | 66 | @Test 67 | public void smokeTestReadUint() throws IOException { 68 | Random rnd = new Random(); 69 | 70 | for (int i = 1; i < 1000; ++i) { 71 | int z = rnd.nextInt(Integer.MAX_VALUE - 100); 72 | String sz = String.valueOf(z); 73 | 74 | assertEquals(sz, z, FastInteger.readUint(new StringReader(sz), sz 75 | .length())); 76 | } 77 | } 78 | 79 | @Test(expected = NumberFormatException.class) 80 | public void parseUintShouldThrowNumberFormatException() { 81 | FastInteger.parseUint("a"); 82 | } 83 | 84 | @Test(expected = NumberFormatException.class) 85 | public void parseUintCharArrayShouldThrowNumberFormatException() { 86 | FastInteger.parseUint("a".toCharArray()); 87 | } 88 | 89 | @Test(expected = NumberFormatException.class) 90 | public void readUintShouldThrowNumberFormatException() throws IOException { 91 | FastInteger.readUint(new StringReader("a"), 1); 92 | } 93 | 94 | @Test(expected = EOFException.class) 95 | public void readUintShouldThrowEOFException() throws IOException { 96 | FastInteger.readUint(new StringReader("1"), 2); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /wiki/Benchmarking.wiki: -------------------------------------------------------------------------------- 1 | = Benchmarking = 2 | 3 | For benchmarking, we use standard desktop PC with specifications: 4 | # Hardware 5 | * Processor : Intel Dual Core 2.6GHz 32-bit 6 | * Memory : 2 GB 7 | * Hard disk : 80 GB 8 | # Software 9 | * Operating System : Ubuntu 8.1 10 | * Java Virtual Machine : Sun Java VM 1.6.10 (32-bit) 11 | 12 | In our small testing program which you can download [BenchmarkingCode here], we do `N` `write`/`pack` operations and `read`/`unpack` operations and measure its average performance, average CPU, and average memory usage. In this benchmark we use jPOS 1.7.1 as our comparison. 13 | 14 | == Test Case == 15 | We use following data for our benchmarking process: 16 | {{{ 17 | '0200423800080A010000133125 01041324310000011324310104C010000001762745214 0003701000abcdefghijkl ' 18 | }}} 19 | 20 | or if we want to breakdown into details: 21 | || *iso bit number* || *value* || 22 | || `0` || `'0200'` || 23 | || `1` || `'423800080A01000013'` || 24 | || `2` || `'3125 '` || 25 | || `7` || `'0104132431'` || 26 | || `11` || `'000001'` || 27 | || `12` || `'132431'` || 28 | || `13` || `'0104'` || 29 | || `29` || `'C01000000'` || 30 | || `37` || `'1762745214 '` || 31 | || `39` || `'00'` || 32 | || `48` || `'01000abcdefghijkl '` || 33 | 34 | == Benchmarking Result == 35 | === Performance === 36 | Performance measured how many operations can be done in one second. 37 | 38 | === Read/Unpack === 39 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 40 | || 1000 || in progress || in progress || 41 | || 10,000 || in progress || in progress || 42 | || 100,000 || in progress || in progress || 43 | || 1,000,000 || in progress || in progress || 44 | || 10,000,000 || in progress || in progress || 45 | 46 | === Write/Pack === 47 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 48 | || 1000 || in progress || in progress || 49 | || 10,000 || in progress || in progress || 50 | || 100,000 || in progress || in progress || 51 | || 1,000,000 || in progress || in progress || 52 | || 10,000,000 || in progress || in progress || 53 | 54 | === CPU Usage === 55 | CPU usage measured how many CPU usage (in percent) during benchmarking process. 56 | 57 | === Read/Unpack === 58 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 59 | || 1000 || 99% || in progress || 60 | || 10,000 || 99% || in progress || 61 | || 100,000 || 99% || in progress || 62 | || 1,000,000 || 99% || in progress || 63 | || 10,000,000 || 99% || in progress || 64 | 65 | === Write/Pack === 66 | || *total operations count (N)* || *nucleus8583* || *jPOS* || 67 | || 1000 || 99% || in progress || 68 | || 10,000 || 99% || in progress || 69 | || 100,000 || 99% || in progress || 70 | || 1,000,000 || 99% || in progress || 71 | || 10,000,000 || 99% || in progress || -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583StringFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.io.Writer; 6 | import java.util.Arrays; 7 | 8 | import org.nucleus8583.core.util.ReaderUtils; 9 | import org.nucleus8583.core.util.StringUtils; 10 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 11 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 12 | 13 | public final class Iso8583StringFieldType extends Iso8583AbstractStringFieldType { 14 | private static final long serialVersionUID = -5615324004502124085L; 15 | 16 | private final int length; 17 | 18 | private final char align; 19 | 20 | private final char padWith; 21 | 22 | private final char[] padder; 23 | 24 | private final char[] emptyValue; 25 | 26 | public Iso8583StringFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 27 | String defaultPadWith, String defaultEmptyValue) { 28 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 29 | 30 | if (def.getLength() <= 0) { 31 | throw new IllegalArgumentException("length must be greater than zero"); 32 | } 33 | 34 | this.length = def.getLength(); 35 | 36 | if (def.getAlign() == null) { 37 | if (defaultAlign == null) { 38 | throw new IllegalArgumentException("alignment required"); 39 | } 40 | 41 | this.align = defaultAlign.symbolicValue(); 42 | } else { 43 | this.align = def.getAlign().symbolicValue(); 44 | } 45 | 46 | if (this.align == 'n') { 47 | this.padWith = ' '; 48 | } else { 49 | if (StringUtils.isEmpty(def.getPadWith(), false)) { 50 | if (StringUtils.isEmpty(defaultPadWith, false)) { 51 | throw new IllegalArgumentException("pad-with required"); 52 | } 53 | 54 | this.padWith = defaultPadWith.charAt(0); 55 | } else { 56 | this.padWith = def.getPadWith().charAt(0); 57 | } 58 | } 59 | 60 | this.padder = new char[this.length]; 61 | 62 | Arrays.fill(this.padder, this.padWith); 63 | 64 | if (def.getEmptyValue() == null) { 65 | if (defaultEmptyValue == null) { 66 | this.emptyValue = new char[0]; 67 | } else { 68 | this.emptyValue = defaultEmptyValue.toCharArray(); 69 | } 70 | } else { 71 | this.emptyValue = def.getEmptyValue().toCharArray(); 72 | } 73 | } 74 | 75 | public String readString(Reader reader) throws IOException { 76 | char[] cbuf = new char[length]; 77 | ReaderUtils.readFully(reader, cbuf, length); 78 | 79 | return new String(StringUtils.unpad(cbuf, length, align, padWith, emptyValue)); 80 | } 81 | 82 | public void write(Writer writer, String value) throws IOException { 83 | int vlen = value.length(); 84 | if (vlen > length) { 85 | throw new IllegalArgumentException("value of field #" + id + " is too long, expected " + length + " but actual is " + vlen); 86 | } 87 | 88 | StringUtils.pad(writer, value, vlen, length, align, padder); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/CollectionComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.regex.Pattern; 5 | 6 | import org.nucleus8583.oim.component.ArrayComponent; 7 | import org.nucleus8583.oim.component.BaseComponent; 8 | import org.nucleus8583.oim.component.DataStructureComponent; 9 | import org.nucleus8583.oim.component.HasFieldsComponent; 10 | import org.nucleus8583.oim.component.ListComponent; 11 | import org.nucleus8583.oim.util.StringUtil; 12 | import org.w3c.dom.Element; 13 | import org.w3c.dom.NodeList; 14 | 15 | public abstract class CollectionComponentFactory { 16 | private static final Pattern digits = Pattern.compile("^[0-9]+$"); 17 | 18 | public static BaseComponent parse(Iso8583MessagesFactory factory, 19 | HasFieldsComponent parent, Element node) { 20 | String s_no = node.getAttribute("no"); 21 | String s_name = node.getAttribute("name"); 22 | String s_size = node.getAttribute("size"); 23 | String s_dsRef = node.getAttribute("data-structure-ref"); 24 | 25 | // no 26 | int no; 27 | 28 | if (StringUtil.hasText(s_no, true)) { 29 | s_no = s_no.trim(); 30 | 31 | if (!digits.matcher(s_no).matches()) { 32 | throw new IllegalArgumentException("no must be numeric only"); 33 | } 34 | 35 | no = Integer.parseInt(s_no, 10); 36 | } else { 37 | no = -1; 38 | } 39 | 40 | // name 41 | String name; 42 | 43 | if (!StringUtil.hasText(s_name)) { 44 | throw new IllegalArgumentException("name is required"); 45 | } 46 | 47 | name = s_name.trim(); 48 | 49 | // size 50 | String size; 51 | 52 | if (StringUtil.hasText(s_size)) { 53 | s_size = s_size.trim(); 54 | 55 | if (!s_size.startsWith("transient:") 56 | && !s_size.startsWith("basic:")) { 57 | throw new IllegalArgumentException( 58 | "prefix 'transient:' or 'basic:' required"); 59 | } 60 | 61 | size = s_size; 62 | } else { 63 | size = null; 64 | } 65 | 66 | // append 67 | boolean append = "true".equalsIgnoreCase(node.getAttribute("append")); 68 | 69 | // data-structure 70 | DataStructureComponent dscomp; 71 | 72 | if (StringUtil.hasText(s_dsRef)) { 73 | dscomp = factory.findDataStructure(s_dsRef.trim()); 74 | 75 | if (dscomp == null) { 76 | throw new IllegalArgumentException( 77 | "unable to find data-structure " + s_dsRef); 78 | } 79 | } else { 80 | NodeList children = node.getElementsByTagName("data-structure"); 81 | int count = children.getLength(); 82 | 83 | if (count == 0) { 84 | throw new IllegalArgumentException("data-structure is required"); 85 | } 86 | 87 | dscomp = DataStructureComponentFactory.parse(factory, parent, true, 88 | (Element) children.item(0)); 89 | } 90 | 91 | Field field = parent.getField(name); 92 | if (field.getType().isArray()) { 93 | return new ArrayComponent(parent, no, name, size, dscomp); 94 | } 95 | 96 | return new ListComponent(parent, no, name, size, append, dscomp); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/field/types/CustomFieldTypeTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.types; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertTrue; 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.StringWriter; 9 | 10 | import javax.xml.bind.JAXBContext; 11 | import javax.xml.bind.Unmarshaller; 12 | 13 | import org.junit.Test; 14 | import org.nucleus8583.core.field.type.Iso8583FieldType; 15 | import org.nucleus8583.core.field.type.Iso8583FieldTypes; 16 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 17 | 18 | public class CustomFieldTypeTest { 19 | 20 | @Test 21 | public void testDummyField() throws Exception { 22 | Unmarshaller unmarshaller = JAXBContext.newInstance( 23 | Iso8583FieldDefinition.class).createUnmarshaller(); 24 | 25 | Object x = unmarshaller 26 | .unmarshal(new ByteArrayInputStream( 27 | ("") 28 | .getBytes())); 29 | 30 | assertNotNull(x); 31 | assertTrue(x instanceof Iso8583FieldDefinition); 32 | 33 | Iso8583FieldType f = Iso8583FieldTypes.getType((Iso8583FieldDefinition) x); 34 | 35 | assertNotNull(f); 36 | assertTrue(f instanceof DummyField); 37 | 38 | StringWriter sw = new StringWriter(); 39 | ((DummyField) f).write(sw, "abcdefg"); 40 | assertEquals("ab", sw.toString()); 41 | 42 | sw = new StringWriter(); 43 | ((DummyField) f).write(sw, "a"); 44 | assertEquals("xa", sw.toString()); 45 | 46 | sw = new StringWriter(); 47 | ((DummyField) f).write(sw, ""); 48 | assertEquals("xx", sw.toString()); 49 | 50 | sw = new StringWriter(); 51 | ((DummyField) f).write(sw, (String) null); 52 | assertEquals("xx", sw.toString()); 53 | } 54 | 55 | @Test(expected = RuntimeException.class) 56 | public void testDummyField2() throws Exception { 57 | Unmarshaller unmarshaller = JAXBContext.newInstance( 58 | Iso8583FieldDefinition.class).createUnmarshaller(); 59 | 60 | Object x = unmarshaller 61 | .unmarshal(new ByteArrayInputStream( 62 | ("") 63 | .getBytes())); 64 | 65 | assertNotNull(x); 66 | assertTrue(x instanceof Iso8583FieldDefinition); 67 | 68 | Iso8583FieldTypes.getType((Iso8583FieldDefinition) x); 69 | } 70 | 71 | @Test(expected = RuntimeException.class) 72 | public void testDummyField3() throws Exception { 73 | Unmarshaller unmarshaller = JAXBContext.newInstance( 74 | Iso8583FieldDefinition.class).createUnmarshaller(); 75 | 76 | Object x = unmarshaller 77 | .unmarshal(new ByteArrayInputStream( 78 | ("") 79 | .getBytes())); 80 | 81 | assertNotNull(x); 82 | assertTrue(x instanceof Iso8583FieldDefinition); 83 | 84 | Iso8583FieldTypes.getType((Iso8583FieldDefinition) x); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/type/DataTypes.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.type; 2 | 3 | import java.io.InputStreamReader; 4 | import java.io.Reader; 5 | import java.net.URL; 6 | import java.util.Map; 7 | import java.util.Properties; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import org.nucleus8583.oim.language.spi.CompiledExpression; 11 | import org.nucleus8583.oim.type.spi.DataType; 12 | import org.nucleus8583.oim.type.spi.DataTypeFactory; 13 | import org.nucleus8583.util.ResourceUtils; 14 | 15 | public abstract class DataTypes { 16 | private static ConcurrentHashMap map = new ConcurrentHashMap(); 17 | 18 | static { 19 | URL[] urls = ResourceUtils 20 | .getURLs("classpath:META-INF/nucleus8583/nucleus8583.types"); 21 | 22 | if (urls.length > 0) { 23 | for (int i = 0; i < urls.length; ++i) { 24 | addDataType(urls[i]); 25 | } 26 | } 27 | } 28 | 29 | private static String substring(String s, int start, char untilBefore) { 30 | int end = s.indexOf(untilBefore, start); 31 | if (end < 0) { 32 | return s.substring(start); 33 | } 34 | return s.substring(start, end); 35 | } 36 | 37 | private static String substring(String s, char startAfter) { 38 | int start = s.indexOf(startAfter); 39 | if (start < 0) { 40 | return ""; 41 | } 42 | return s.substring(start + 1); 43 | } 44 | 45 | public static void addDataType(URL url) { 46 | Reader reader = null; 47 | Properties prop = new Properties(); 48 | 49 | try { 50 | reader = new InputStreamReader(url.openStream()); 51 | prop.load(reader); 52 | } catch (Throwable t) { 53 | // do nothing 54 | } finally { 55 | if (reader != null) { 56 | try { 57 | reader.close(); 58 | } catch (Throwable t) { 59 | // do nothing 60 | } 61 | } 62 | } 63 | 64 | for (Map.Entry entry : prop.entrySet()) { 65 | String entryValue = (String) entry.getValue(); 66 | 67 | try { 68 | Class cla = Class.forName(substring(entryValue, 0, '?'), 69 | true, Thread.currentThread().getContextClassLoader()); 70 | 71 | DataTypeFactory factory = (DataTypeFactory) cla.newInstance(); 72 | 73 | addDataType((String) entry.getKey(), 74 | factory.createDataType(substring(entryValue, '?'))); 75 | } catch (Throwable t) { 76 | // do nothing 77 | } 78 | } 79 | } 80 | 81 | public static void addDataType(String name, DataType lang) { 82 | if (map.putIfAbsent(name, lang) != null) { 83 | throw new IllegalArgumentException("language name " + name 84 | + " already exists"); 85 | } 86 | } 87 | 88 | public static void removeDataType(String name) { 89 | map.remove(name); 90 | } 91 | 92 | public static DataType compile(String name, String expression) 93 | throws Exception { 94 | DataType lang = map.get(name); 95 | if (lang == null) { 96 | throw new IllegalArgumentException("unsupported language " + name); 97 | } 98 | 99 | return lang.compile(expression); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | public abstract class StringUtils { 7 | 8 | public static boolean isNull(String value) { 9 | return value == null; 10 | } 11 | 12 | public static boolean isEmpty(String value, boolean trimmed) { 13 | if (value == null) { 14 | return true; 15 | } 16 | 17 | if (trimmed) { 18 | value = value.trim(); 19 | } 20 | 21 | return value.length() == 0; 22 | } 23 | 24 | public static String defaultIfNull(String value, String defaultValue) { 25 | if (value == null) { 26 | return defaultValue; 27 | } 28 | 29 | return value; 30 | } 31 | 32 | public static String defaultIfEmpty(String value, boolean trimmed, String defaultValue) { 33 | if (isEmpty(value, trimmed)) { 34 | return defaultValue; 35 | } 36 | 37 | return value; 38 | } 39 | 40 | public static void pad(Writer writer, String value, int valueLength, int expectedLength, char align, char[] padder) throws IOException { 41 | if (valueLength == 0) { 42 | writer.write(padder, 0, expectedLength); 43 | } else if (valueLength == expectedLength) { 44 | writer.write(value, 0, valueLength); 45 | } else { 46 | switch (align) { 47 | case 'l': 48 | writer.write(value, 0, valueLength); 49 | writer.write(padder, 0, expectedLength - valueLength); 50 | 51 | break; 52 | case 'r': 53 | writer.write(padder, 0, expectedLength - valueLength); 54 | writer.write(value, 0, valueLength); 55 | 56 | break; 57 | default: // 'n' 58 | writer.write(value, 0, valueLength); 59 | writer.write(padder, 0, expectedLength - valueLength); 60 | 61 | break; 62 | } 63 | } 64 | } 65 | 66 | public static char[] unpad(char[] value, int valueLength, char align, char padder, char[] defaultValue) { 67 | char[] cbuf; 68 | int cbufLength; 69 | 70 | switch (align) { 71 | case 'l': 72 | cbufLength = 0; 73 | 74 | for (int i = valueLength - 1; i >= 0; --i) { 75 | if (value[i] != padder) { 76 | cbufLength = i + 1; 77 | break; 78 | } 79 | } 80 | 81 | if (cbufLength == 0) { 82 | cbuf = defaultValue; 83 | } else if (cbufLength == valueLength) { 84 | cbuf = value; 85 | } else { 86 | cbuf = new char[cbufLength]; 87 | System.arraycopy(value, 0, cbuf, 0, cbufLength); 88 | } 89 | 90 | break; 91 | case 'r': 92 | int padLength = valueLength; 93 | 94 | for (int i = 0; i < valueLength; ++i) { 95 | if (value[i] != padder) { 96 | padLength = i; 97 | break; 98 | } 99 | } 100 | 101 | if (padLength == 0) { 102 | cbuf = value; 103 | } else if (padLength == valueLength) { 104 | cbuf = defaultValue; 105 | } else { 106 | cbufLength = valueLength - padLength; 107 | 108 | cbuf = new char[cbufLength]; 109 | System.arraycopy(value, padLength, cbuf, 0, cbufLength); 110 | } 111 | 112 | break; 113 | default: // 'n' 114 | cbuf = value; 115 | break; 116 | } 117 | 118 | return cbuf; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /nucleus8583-oim/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | org.nucleus8583 8 | nucleus8583-oim 9 | 2.3.0 10 | 11 | nucleus8583-oim 12 | bundle 13 | 14 | 15 | 16 | opensymphony 17 | OpenSymphony Maven Repository 18 | scp://maven2.opensymphony.com/opt/repository/maven2 19 | 20 | 21 | repository.codehaus.org 22 | http://repository.codehaus.org/ 23 | 24 | false 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.apache.maven.plugins 33 | maven-compiler-plugin 34 | 2.0.2 35 | 36 | 1.6 37 | 1.6 38 | 39 | 40 | 41 | 42 | org.apache.felix 43 | maven-bundle-plugin 44 | 2.1.0 45 | true 46 | 47 | 48 | 49 | org.nucleus8583.*, 50 | ognl, 51 | org.mvel2, 52 | javax.xml.parsers.*, 53 | org.w3c.dom.*, 54 | org.xml.sax.* 55 | 56 | org.nucleus8583.oim 57 | 58 | org.nucleus8583.oim.component.*, 59 | org.nucleus8583.oim.converter.*, 60 | 61 | org.nucleus8583.oim.xml.*, 62 | org.nucleus8583.oim.util.*, 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.nucleus8583 73 | nucleus8583-core 74 | 2.3.0 75 | 76 | 77 | 78 | org.mvel 79 | mvel2 80 | 2.0.19 81 | 82 | 83 | 84 | ognl 85 | ognl 86 | 3.0 87 | 88 | 89 | javassist 90 | javassist 91 | 3.12.1.GA 92 | 93 | 94 | 95 | junit 96 | junit 97 | 4.8.1 98 | test 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/util/FastInteger.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | import java.io.Writer; 7 | 8 | public abstract class FastInteger { 9 | private static final int[][] digitsToInt; 10 | 11 | private static final char[] intToDigits; 12 | 13 | private static final int MAX_DIGIT = 10; 14 | 15 | static { 16 | digitsToInt = new int[Character.MAX_VALUE][MAX_DIGIT]; 17 | 18 | for (int i = 0; i < digitsToInt.length; ++i) { 19 | if ((i >= '0') && (i <= '9')) { 20 | int tens = 1; 21 | int digit = i - '0'; 22 | 23 | for (int j = 0; j < MAX_DIGIT; ++j) { 24 | digitsToInt[i][j] = digit * tens; 25 | tens *= 10; 26 | } 27 | } else { 28 | for (int j = 0; j < MAX_DIGIT; ++j) { 29 | digitsToInt[i][j] = -1; 30 | } 31 | } 32 | } 33 | 34 | intToDigits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', 35 | '9' }; 36 | } 37 | 38 | public static String uintToString(int ivalue, int len) { 39 | int rem = ivalue; 40 | char[] cc = new char[len]; 41 | 42 | for (int i = len - 1; i >= 0; --i) { 43 | cc[i] = intToDigits[rem % 10]; 44 | rem = rem / 10; 45 | } 46 | 47 | return new String(cc); 48 | } 49 | 50 | public static void writeUint(Writer writer, int ivalue, int len) 51 | throws IOException { 52 | int rem = ivalue; 53 | char[] cc = new char[len]; 54 | 55 | for (int i = len - 1; i >= 0; --i) { 56 | cc[i] = intToDigits[rem % 10]; 57 | rem = rem / 10; 58 | } 59 | 60 | writer.write(cc, 0, len); 61 | } 62 | 63 | public static int readUint(Reader reader, int len) throws IOException { 64 | int ivalue = 0; 65 | int ichar; 66 | 67 | for (int i = len - 1; i >= 0; --i) { 68 | ichar = reader.read(); 69 | if (ichar < 0) { 70 | throw new EOFException(); 71 | } 72 | 73 | int digitInt = digitsToInt[ichar][i]; 74 | if (digitInt < 0) { 75 | throw new NumberFormatException((char) ichar 76 | + " is not a number."); 77 | } 78 | 79 | ivalue += digitInt; 80 | } 81 | 82 | return ivalue; 83 | } 84 | 85 | public static int parseUint(char[] s, int start, int len) { 86 | int ivalue = 0; 87 | 88 | for (int i = len - 1, j = start; i >= 0; --i, ++j) { 89 | int digitInt = digitsToInt[(int) s[j]][i]; 90 | if (digitInt < 0) { 91 | throw new NumberFormatException(s[j] + " is not a number."); 92 | } 93 | 94 | ivalue += digitInt; 95 | } 96 | 97 | return ivalue; 98 | } 99 | 100 | public static int parseUint(char[] s) { 101 | return parseUint(s, 0, s.length); 102 | } 103 | 104 | public static int parseUint(CharSequence s, int len) { 105 | int ivalue = 0; 106 | 107 | for (int i = len - 1, j = 0; i >= 0; --i, ++j) { 108 | int digitInt = digitsToInt[(int) s.charAt(j)][i]; 109 | if (digitInt < 0) { 110 | throw new NumberFormatException(s.charAt(j) 111 | + " is not a number."); 112 | } 113 | 114 | ivalue += digitInt; 115 | } 116 | 117 | return ivalue; 118 | } 119 | 120 | public static int parseUint(CharSequence s) { 121 | return parseUint(s, s.length()); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/Iso8583MessageFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import java.io.InputStream; 4 | 5 | import org.w3c.dom.Node; 6 | 7 | /** 8 | * Entry point to create {@link Iso8583Message}. Creating this class requires 9 | * configuration. 10 | * 11 | * @author Robbi Kurniawan 12 | * @deprecated please use {@link Iso8583MessageSerializer} instead 13 | */ 14 | @Deprecated 15 | public final class Iso8583MessageFactory { 16 | private final Iso8583MessageSerializer wrapped; 17 | 18 | /** 19 | * create a new instance of {@link Iso8583MessageFactory} using given 20 | * configuration. 21 | * 22 | * For example, if you want to load "nucleus8583.xml" from "META-INF" 23 | * located in classpath, the location should be 24 | * classpath:META-INF/nucleus8583.xml. 25 | * 26 | * If you want to load "nucleus8583.xml" from "conf" directory, the location 27 | * should be file:conf/nucleus8583.xml or just 28 | * conf/nucleus8583.xml. 29 | * 30 | * @param location 31 | * configuration location (in URI) 32 | */ 33 | public Iso8583MessageFactory(String location) { 34 | wrapped = new Iso8583MessageSerializer(location); 35 | } 36 | 37 | /** 38 | * create a new instance of {@link Iso8583MessageFactory} using given 39 | * configuration 40 | * 41 | * @param in 42 | * input stream 43 | */ 44 | public Iso8583MessageFactory(InputStream in) { 45 | wrapped = new Iso8583MessageSerializer(in); 46 | } 47 | 48 | /** 49 | * create a new instance of {@link Iso8583MessageFactory} using given 50 | * configuration 51 | * 52 | * @param node 53 | * an DOM node where the entire XML start from 54 | */ 55 | public Iso8583MessageFactory(Node node) { 56 | wrapped = new Iso8583MessageSerializer(node); 57 | } 58 | 59 | /** 60 | * same as 61 | * return new Iso8583MessageFactory(location); 62 | * 63 | * 64 | * @param location 65 | * @return a new instance of Iso8583MessageFactory. 66 | */ 67 | public static Iso8583MessageFactory create(String location) { 68 | return new Iso8583MessageFactory(location); 69 | } 70 | 71 | /** 72 | * same as 73 | * return new Iso8583MessageFactory(in); 74 | * 75 | * 76 | * @param in 77 | * @return a new instance of Iso8583MessageFactory. 78 | */ 79 | public static Iso8583MessageFactory create(InputStream in) { 80 | return new Iso8583MessageFactory(in); 81 | } 82 | 83 | /** 84 | * same as 85 | * return new Iso8583MessageFactory(node); 86 | * 87 | * 88 | * @param node 89 | * @return a new instance of Iso8583MessageFactory. 90 | */ 91 | public static Iso8583MessageFactory create(Node node) { 92 | return new Iso8583MessageFactory(node); 93 | } 94 | 95 | /** 96 | * create a new instance of {@link Iso8583Message} 97 | * 98 | * @return the new instance of {@link Iso8583Message} 99 | */ 100 | public Iso8583Message createMessage() { 101 | Iso8583Message instance = new Iso8583Message(); 102 | instance.attach(this); 103 | 104 | return instance; 105 | } 106 | 107 | /** 108 | * retrieve encoding used by this instance 109 | * 110 | * @return used encoding 111 | */ 112 | public String getEncoding() { 113 | return wrapped.getEncoding(); 114 | } 115 | 116 | /** 117 | * DO NOT use this method directly 118 | */ 119 | Iso8583MessageSerializer getWrappedObject() { 120 | return wrapped; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/Iso8583MessageComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.BitSet; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import org.nucleus8583.Iso8583Message; 9 | import org.nucleus8583.oim.util.BeanUtil; 10 | 11 | public final class Iso8583MessageComponent implements HasFieldsComponent { 12 | private final String name; 13 | 14 | private final Class _class; 15 | 16 | private final Map fields; 17 | 18 | private final int[] isoFieldsNumber; 19 | 20 | private final BaseComponent[] isoFieldsComponent; 21 | 22 | private final int isoFieldsCount; 23 | 24 | public Iso8583MessageComponent(String name, Class _class, 25 | BaseComponent[] isoFieldsComponent, int[] isoFieldsNumber, 26 | int isoFieldsCount) { 27 | this.name = name; 28 | this._class = _class; 29 | 30 | this.isoFieldsComponent = isoFieldsComponent; 31 | this.isoFieldsNumber = isoFieldsNumber; 32 | this.isoFieldsCount = isoFieldsCount; 33 | 34 | fields = new HashMap(); 35 | BeanUtil.collectFields(_class, fields); 36 | } 37 | 38 | public void encode(Iso8583Message msg, Object pojo, 39 | Map session) { 40 | BaseComponent component; 41 | int isoNo; 42 | 43 | for (int i = 0; i < isoFieldsCount; ++i) { 44 | component = isoFieldsComponent[i]; 45 | isoNo = isoFieldsNumber[i]; 46 | 47 | if (isoNo == 0) { 48 | String value = component.encodeToString(pojo, session); 49 | if (value == null) { 50 | msg.unsetMti(); 51 | } else { 52 | msg.setMti(value); 53 | } 54 | } else { 55 | if (component.isBinary()) { 56 | BitSet value = component.encodeToBinary(pojo, session); 57 | if (value == null) { 58 | msg.unsafeUnset(isoNo); 59 | } else { 60 | msg.unsafeSet(isoNo, value); 61 | } 62 | } else { 63 | String value = component.encodeToString(pojo, session); 64 | if (value == null) { 65 | msg.unsafeUnset(isoNo); 66 | } else { 67 | msg.unsafeSet(isoNo, value); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | public void decode(Iso8583Message msg, Object pojo, 75 | Map session) { 76 | BaseComponent component; 77 | int isoNo; 78 | 79 | for (int i = 0; i < isoFieldsCount; ++i) { 80 | component = isoFieldsComponent[i]; 81 | isoNo = isoFieldsNumber[i]; 82 | 83 | if (isoNo == 0) { 84 | component.decode(msg.getMti(), pojo, session); 85 | } else { 86 | if (component.isBinary()) { 87 | BitSet value = msg.unsafeGetBinary(isoNo); 88 | if (value != null) { 89 | component.decode(value, pojo, session); 90 | } 91 | } else { 92 | String value = msg.unsafeGetString(isoNo); 93 | if (value != null) { 94 | component.decode(value, pojo, session); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | public Object decode(Iso8583Message msg, Map session) { 102 | Object pojo; 103 | 104 | try { 105 | pojo = _class.newInstance(); 106 | } catch (InstantiationException e) { 107 | throw new RuntimeException(e); 108 | } catch (IllegalAccessException e) { 109 | throw new RuntimeException(e); 110 | } 111 | 112 | decode(msg, pojo, session); 113 | return pojo; 114 | } 115 | 116 | public String getName() { 117 | return name; 118 | } 119 | 120 | public Field getField(String name) { 121 | return fields.get(name); 122 | } 123 | 124 | public Map getFields() { 125 | return fields; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/util/ResourceUtils.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.util; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | import java.util.ArrayList; 9 | import java.util.Enumeration; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | 14 | public abstract class ResourceUtils { 15 | private static final String LOCATION_PREFIX_FILE = "file:"; 16 | private static final String LOCATION_PREFIX_CLASSPATH = "classpath:"; 17 | 18 | private static void addResources(List resolved, 19 | Set doubleChecker, ClassLoader cl, String name) { 20 | Enumeration en; 21 | 22 | try { 23 | if (cl == null) { 24 | en = ClassLoader.getSystemResources(name); 25 | } else { 26 | en = cl.getResources(name); 27 | } 28 | } catch (IOException e) { 29 | en = null; 30 | } 31 | 32 | if (en != null) { 33 | while (en.hasMoreElements()) { 34 | URL el = en.nextElement(); 35 | String strEl = el.toString(); 36 | 37 | if (!doubleChecker.contains(strEl)) { 38 | resolved.add(el); 39 | doubleChecker.add(strEl); 40 | } 41 | } 42 | } 43 | } 44 | 45 | public static URL[] getURLs(String location) { 46 | List resolved = new ArrayList(); 47 | Set doubleChecker = new HashSet(); 48 | 49 | if (location.startsWith(LOCATION_PREFIX_CLASSPATH)) { 50 | location = location.substring(10); 51 | 52 | addResources(resolved, doubleChecker, Thread.currentThread() 53 | .getContextClassLoader(), location); 54 | addResources(resolved, doubleChecker, 55 | ResourceUtils.class.getClassLoader(), location); 56 | addResources(resolved, doubleChecker, 57 | ClassLoader.getSystemClassLoader(), location); 58 | addResources(resolved, doubleChecker, null, location); 59 | } else { 60 | URL resolved1; 61 | 62 | try { 63 | resolved1 = new URL(location); 64 | } catch (MalformedURLException ex) { 65 | if (location.startsWith(LOCATION_PREFIX_FILE)) 66 | location = location.substring(5); 67 | 68 | try { 69 | resolved1 = new File(location).toURI().toURL(); 70 | } catch (MalformedURLException ex2) { 71 | throw new RuntimeException(new FileNotFoundException( 72 | "unable to find " + location)); 73 | } 74 | } 75 | 76 | if (resolved1 != null) { 77 | resolved.add(resolved1); 78 | } 79 | } 80 | 81 | return resolved.toArray(new URL[0]); 82 | } 83 | 84 | public static URL getURL(String location) { 85 | URL resolved; 86 | 87 | if (location.startsWith(LOCATION_PREFIX_CLASSPATH)) { 88 | location = location.substring(10); 89 | 90 | resolved = Thread.currentThread().getContextClassLoader() 91 | .getResource(location); 92 | if (resolved == null) { 93 | resolved = ResourceUtils.class.getResource(location); 94 | } 95 | if (resolved == null) { 96 | resolved = ClassLoader.getSystemClassLoader().getResource( 97 | location); 98 | } 99 | if (resolved == null) { 100 | resolved = ClassLoader.getSystemResource(location); 101 | } 102 | } else { 103 | try { 104 | resolved = new URL(location); 105 | } catch (MalformedURLException ex) { 106 | if (location.startsWith(LOCATION_PREFIX_FILE)) 107 | location = location.substring(5); 108 | 109 | try { 110 | resolved = new File(location).toURI().toURL(); 111 | } catch (MalformedURLException ex2) { 112 | throw new RuntimeException(new FileNotFoundException( 113 | "unable to find " + location)); 114 | } 115 | } 116 | } 117 | 118 | return resolved; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/charset/spi/Utf8Encoder.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.io.Writer; 6 | 7 | public class Utf8Encoder extends Writer { 8 | private final OutputStream out; 9 | 10 | public Utf8Encoder(OutputStream out) { 11 | this.out = out; 12 | } 13 | 14 | public void close() throws IOException { 15 | out.close(); 16 | } 17 | 18 | public void flush() throws IOException { 19 | out.flush(); 20 | } 21 | 22 | @Override 23 | public void write(int ichar) throws IOException { 24 | if (ichar < 0) { 25 | throw new IOException("data contains value " + ((long) ichar & 0xFFFFFFFFL) 26 | + " which is not compatible with UTF-8 encoding"); 27 | } 28 | 29 | if (ichar <= 0x7F) { 30 | out.write(ichar); // 0xxxxxxx 31 | } else if (ichar <= 0x7FF) { 32 | out.write(0xC0 | (ichar >> 6)); // 110xxxxx 33 | out.write(0x80 | (ichar & 0x3F)); // 10xxxxxx 34 | } else if (ichar <= 0xFFFF) { 35 | out.write(0xE0 | (ichar >> 12)); // 1110xxxx 36 | out.write(0x80 | ((ichar >> 6) & 0x3F)); // 10xxxxxx 37 | out.write(0x80 | (ichar & 0x3F)); // 10xxxxxx 38 | } else if (ichar <= 0x1FFFFF) { 39 | out.write(0xF0 | (ichar >> 18)); // 11110xxx 40 | out.write(0x80 | ((ichar >> 12) & 0x3F)); // 10xxxxxx 41 | out.write(0x80 | ((ichar >> 6) & 0x3F)); // 10xxxxxx 42 | out.write(0x80 | (ichar & 0x3F)); // 10xxxxxx 43 | } else if (ichar <= 0x3FFFFFF) { 44 | out.write(0xF8 | (ichar >> 24)); // 111110xx 45 | out.write(0x80 | ((ichar >> 18) & 0x3F)); // 10xxxxxx 46 | out.write(0x80 | ((ichar >> 12) & 0x3F)); // 10xxxxxx 47 | out.write(0x80 | ((ichar >> 6) & 0x3F)); // 10xxxxxx 48 | out.write(0x80 | (ichar & 0x3F)); // 10xxxxxx 49 | } else { 50 | out.write(0xFC | (ichar >> 30)); // 1111110x 51 | out.write(0x80 | ((ichar >> 24) & 0x3F)); // 10xxxxxx 52 | out.write(0x80 | ((ichar >> 18) & 0x3F)); // 10xxxxxx 53 | out.write(0x80 | ((ichar >> 12) & 0x3F)); // 10xxxxxx 54 | out.write(0x80 | ((ichar >> 6) & 0x3F)); // 10xxxxxx 55 | out.write(0x80 | (ichar & 0x3F)); // 10xxxxxx 56 | } 57 | } 58 | 59 | @Override 60 | public void write(char[] cbuf) throws IOException { 61 | int len = cbuf.length; 62 | for (int i = 0; i < len;) { 63 | write((int) cbuf[i++]); 64 | } 65 | } 66 | 67 | public void write(char[] cbuf, int off, int len) throws IOException { 68 | if (off == 0) { 69 | for (int i = 0; i < len;) { 70 | write((int) cbuf[i++]); 71 | } 72 | } else { 73 | for (int i = 0, j = off; i < len; ++i) { 74 | write((int) cbuf[j++]); 75 | } 76 | } 77 | } 78 | 79 | @Override 80 | public void write(String str) throws IOException { 81 | int len = str.length(); 82 | 83 | for (int i = 0; i < len;) { 84 | write(str.charAt(i++) & 0x7F); 85 | } 86 | } 87 | 88 | @Override 89 | public void write(String str, int off, int len) throws IOException { 90 | if (off == 0) { 91 | for (int i = 0; i < len;) { 92 | write((int) str.charAt(i++)); 93 | } 94 | } else { 95 | for (int i = 0, j = off; i < len; ++i) { 96 | write((int) str.charAt(j++)); 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/Iso8583MessageSerializerTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.io.StringWriter; 11 | import java.util.BitSet; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | public class Iso8583MessageSerializerTest { 17 | private Iso8583MessageSerializer serializer; 18 | 19 | private String packed; 20 | 21 | private Iso8583Message unpacked; 22 | 23 | @Before 24 | public void initialize() throws Exception { 25 | serializer = new Iso8583MessageSerializer("classpath:META-INF/codec8583.xml"); 26 | 27 | packed = "0200C00000000001000104000000000000000603000000499980000000000000000301"; 28 | 29 | unpacked = new Iso8583Message(); 30 | unpacked.setMti("0200"); 31 | unpacked.set(2, "030000"); 32 | unpacked.set(48, "9998"); 33 | unpacked.set(64, new BitSet()); 34 | unpacked.set(70, "301"); 35 | } 36 | 37 | @Test(expected = RuntimeException.class) 38 | public void testCreateNewInstanceIfEncodingIsUnsupported() { 39 | Iso8583MessageSerializer.create("classpath:META-INF/error8583.xml"); 40 | } 41 | 42 | @Test 43 | public void testCreateNewInstanceIfNoF28Defined() throws Exception { 44 | String errorMsg = null; 45 | 46 | try { 47 | Iso8583MessageSerializer.create("classpath:META-INF/codec8583-4.xml"); 48 | } catch (IllegalArgumentException ex) { 49 | errorMsg = ex.getMessage(); 50 | } 51 | 52 | assertEquals("field #28 is not defined", errorMsg); 53 | } 54 | 55 | @Test 56 | public void testReadFromBytes() throws Exception { 57 | Iso8583Message unpacked = new Iso8583Message(); 58 | serializer.read(packed.getBytes(), unpacked); 59 | 60 | assertEquals(this.unpacked, unpacked); 61 | } 62 | 63 | @Test 64 | public void testReadFromString() throws Exception { 65 | Iso8583Message unpacked = new Iso8583Message(); 66 | serializer.read(packed, unpacked); 67 | 68 | assertEquals(this.unpacked, unpacked); 69 | } 70 | 71 | @Test(expected = IOException.class) 72 | public void testReadFromEmptyString() throws Exception { 73 | serializer.read("", unpacked); 74 | } 75 | 76 | @Test 77 | public void testReadAfterSerialized() throws Exception { 78 | Iso8583Message unpacked = new Iso8583Message(); 79 | 80 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 81 | new ObjectOutputStream(out).writeObject(unpacked); 82 | 83 | unpacked = (Iso8583Message) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject(); 84 | serializer.read(packed, unpacked); 85 | 86 | assertEquals(this.unpacked, unpacked); 87 | } 88 | 89 | @Test 90 | public void testWriteToWriter() throws Exception { 91 | StringWriter sw = new StringWriter(); 92 | 93 | serializer.write(unpacked, sw); 94 | assertEquals(packed, sw.toString()); 95 | } 96 | 97 | @Test 98 | public void testWriteToOutputStream() throws Exception { 99 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 100 | 101 | serializer.write(unpacked, baos); 102 | assertEquals(packed, new String(baos.toByteArray())); 103 | } 104 | 105 | @Test 106 | public void packTestAfterSerialized() throws Exception { 107 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 108 | new ObjectOutputStream(out).writeObject(unpacked); 109 | 110 | unpacked = (Iso8583Message) new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject(); 111 | 112 | StringWriter sw = new StringWriter(); 113 | serializer.write(unpacked, sw); 114 | assertEquals(this.packed, sw.toString()); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/charset/spi/AsciEncoderTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.charset.spi; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | import org.junit.Test; 12 | 13 | public class AsciEncoderTest { 14 | 15 | @Test 16 | public void testClose() throws Exception { 17 | final AtomicBoolean closed = new AtomicBoolean(false); 18 | 19 | OutputStream is = new OutputStream() { 20 | 21 | public void write(int b) throws IOException { 22 | // do nothing 23 | } 24 | 25 | @Override 26 | public void close() throws IOException { 27 | closed.set(true); 28 | } 29 | }; 30 | 31 | AsciiEncoder encoder = new AsciiEncoder(is); 32 | encoder.close(); 33 | 34 | assertTrue(closed.get()); 35 | } 36 | 37 | @Test 38 | public void testFlush() throws Exception { 39 | final AtomicBoolean flushed = new AtomicBoolean(false); 40 | 41 | OutputStream is = new OutputStream() { 42 | 43 | public void write(int b) throws IOException { 44 | // do nothing 45 | } 46 | 47 | @Override 48 | public void flush() throws IOException { 49 | flushed.set(true); 50 | } 51 | }; 52 | 53 | AsciiEncoder encoder = new AsciiEncoder(is); 54 | encoder.flush(); 55 | 56 | assertTrue(flushed.get()); 57 | } 58 | 59 | @Test 60 | public void testWriteString() throws Exception { 61 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 62 | AsciiEncoder encoder = new AsciiEncoder(out); 63 | 64 | encoder.write("abcde"); 65 | encoder.flush(); 66 | 67 | assertEquals("abcde", new String(out.toByteArray())); 68 | } 69 | 70 | @Test 71 | public void testWriteString2() throws Exception { 72 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 73 | AsciiEncoder encoder = new AsciiEncoder(out); 74 | 75 | encoder.write("abcde", 1, 3); 76 | encoder.flush(); 77 | 78 | assertEquals("bcd", new String(out.toByteArray())); 79 | } 80 | 81 | @Test 82 | public void testWriteString3() throws Exception { 83 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 84 | AsciiEncoder encoder = new AsciiEncoder(out); 85 | 86 | encoder.write("abcde", 0, 3); 87 | encoder.flush(); 88 | 89 | assertEquals("abc", new String(out.toByteArray())); 90 | } 91 | 92 | @Test 93 | public void testWriteChar() throws Exception { 94 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 95 | AsciiEncoder encoder = new AsciiEncoder(out); 96 | 97 | encoder.write('a'); 98 | encoder.flush(); 99 | 100 | assertEquals("a", new String(out.toByteArray())); 101 | } 102 | 103 | @Test 104 | public void testWriteCharArray() throws Exception { 105 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 106 | AsciiEncoder encoder = new AsciiEncoder(out); 107 | 108 | encoder.write("abcde".toCharArray()); 109 | encoder.flush(); 110 | 111 | assertEquals("abcde", new String(out.toByteArray())); 112 | } 113 | 114 | @Test 115 | public void testWriteCharArray2() throws Exception { 116 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 117 | AsciiEncoder encoder = new AsciiEncoder(out); 118 | 119 | encoder.write("abcde".toCharArray(), 1, 3); 120 | encoder.flush(); 121 | 122 | assertEquals("bcd", new String(out.toByteArray())); 123 | } 124 | 125 | @Test 126 | public void testWriteCharArray3() throws Exception { 127 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 128 | AsciiEncoder encoder = new AsciiEncoder(out); 129 | 130 | encoder.write("abcde".toCharArray(), 0, 3); 131 | encoder.flush(); 132 | 133 | assertEquals("abc", new String(out.toByteArray())); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583AbstractBinaryFieldType.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | import java.io.Writer; 7 | import java.util.BitSet; 8 | 9 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 10 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 11 | 12 | public abstract class Iso8583AbstractBinaryFieldType extends Iso8583FieldType { 13 | private static final long serialVersionUID = 3977789121124596289L; 14 | 15 | private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 16 | 17 | public Iso8583AbstractBinaryFieldType(Iso8583FieldDefinition def, Iso8583FieldAlignments defaultAlign, 18 | String defaultPadWith, String defaultEmptyValue) { 19 | super(def, defaultAlign, defaultPadWith, defaultEmptyValue); 20 | } 21 | 22 | public boolean isBinary() { 23 | return true; 24 | } 25 | 26 | public String readString(Reader packed) throws IOException { 27 | throw new UnsupportedOperationException(); 28 | } 29 | 30 | public void write(Writer writer, String value) throws IOException { 31 | throw new UnsupportedOperationException(); 32 | } 33 | 34 | protected void read(Reader reader, BitSet bits, int length) throws IOException { 35 | int bitsIndex = 0; 36 | int ichar; 37 | 38 | bits.clear(); 39 | 40 | for (int i = 0; i < length; ++i, bitsIndex += 4) { 41 | ichar = reader.read(); 42 | if (ichar < 0) { 43 | throw new EOFException(); 44 | } 45 | 46 | switch ((char) ichar) { 47 | case '0': 48 | break; 49 | case '1': 50 | // 0001 51 | bits.set(bitsIndex + 3); 52 | break; 53 | case '2': 54 | // 0010 55 | bits.set(bitsIndex + 2); 56 | break; 57 | case '3': 58 | // 0011 59 | bits.set(bitsIndex + 2); 60 | bits.set(bitsIndex + 3); 61 | break; 62 | case '4': 63 | // 0100 64 | bits.set(bitsIndex + 1); 65 | break; 66 | case '5': 67 | // 0101 68 | bits.set(bitsIndex + 1); 69 | bits.set(bitsIndex + 3); 70 | break; 71 | case '6': 72 | // 0110 73 | bits.set(bitsIndex + 1); 74 | bits.set(bitsIndex + 2); 75 | break; 76 | case '7': 77 | // 0111 78 | bits.set(bitsIndex + 1); 79 | bits.set(bitsIndex + 2); 80 | bits.set(bitsIndex + 3); 81 | break; 82 | case '8': 83 | // 1000 84 | bits.set(bitsIndex); 85 | break; 86 | case '9': 87 | // 1001 88 | bits.set(bitsIndex); 89 | bits.set(bitsIndex + 3); 90 | break; 91 | case 'A': 92 | // 1010 93 | bits.set(bitsIndex); 94 | bits.set(bitsIndex + 2); 95 | break; 96 | case 'B': 97 | // 1011 98 | bits.set(bitsIndex); 99 | bits.set(bitsIndex + 2); 100 | bits.set(bitsIndex + 3); 101 | break; 102 | case 'C': 103 | // 1100 104 | bits.set(bitsIndex); 105 | bits.set(bitsIndex + 1); 106 | break; 107 | case 'D': 108 | // 1101 109 | bits.set(bitsIndex); 110 | bits.set(bitsIndex + 1); 111 | bits.set(bitsIndex + 3); 112 | break; 113 | case 'E': 114 | // 1110 115 | bits.set(bitsIndex); 116 | bits.set(bitsIndex + 1); 117 | bits.set(bitsIndex + 2); 118 | break; 119 | case 'F': 120 | // 1111 121 | bits.set(bitsIndex); 122 | bits.set(bitsIndex + 1); 123 | bits.set(bitsIndex + 2); 124 | bits.set(bitsIndex + 3); 125 | break; 126 | } 127 | } 128 | } 129 | 130 | protected void write(Writer writer, BitSet value, int length) throws IOException { 131 | int bitsIndex = 0; 132 | int ivalue; 133 | 134 | for (int i = 0; i < length; ++i) { 135 | ivalue = 0; 136 | 137 | if (value.get(bitsIndex++)) { 138 | ivalue |= 8; 139 | } 140 | if (value.get(bitsIndex++)) { 141 | ivalue |= 4; 142 | } 143 | if (value.get(bitsIndex++)) { 144 | ivalue |= 2; 145 | } 146 | if (value.get(bitsIndex++)) { 147 | ivalue |= 1; 148 | } 149 | 150 | writer.write(HEX[ivalue]); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/DataStructureComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import org.nucleus8583.oim.component.BaseComponent; 6 | import org.nucleus8583.oim.component.BasicComponent; 7 | import org.nucleus8583.oim.component.DataStructureComponent; 8 | import org.nucleus8583.oim.component.HasFieldsComponent; 9 | import org.nucleus8583.oim.component.TransientComponent; 10 | import org.nucleus8583.oim.util.StringUtil; 11 | import org.w3c.dom.Element; 12 | import org.w3c.dom.Node; 13 | import org.w3c.dom.NodeList; 14 | 15 | public abstract class DataStructureComponentFactory { 16 | private static final Pattern digits = Pattern.compile("^[0-9]+$"); 17 | 18 | public static DataStructureComponent parse(Iso8583MessagesFactory factory, 19 | HasFieldsComponent parent, boolean ignoreField, Element node) { 20 | 21 | String s_no = node.getAttribute("no"); 22 | String s_name = node.getAttribute("name"); 23 | String s_className = node.getAttribute("class"); 24 | 25 | // no 26 | int no; 27 | 28 | if (StringUtil.hasText(s_no)) { 29 | s_no = s_no.trim(); 30 | 31 | if (!digits.matcher(s_no).matches()) { 32 | throw new IllegalArgumentException( 33 | "no value must be numeric only"); 34 | } 35 | 36 | no = Integer.parseInt(s_no, 10); 37 | } else { 38 | no = -1; 39 | } 40 | 41 | // name 42 | String name; 43 | 44 | if (StringUtil.hasText(s_name)) { 45 | name = s_name.trim(); 46 | } else { 47 | name = null; 48 | } 49 | 50 | // class 51 | String className; 52 | 53 | if (StringUtil.hasText(s_className)) { 54 | className = s_className.trim(); 55 | } else { 56 | if (parent == null) { 57 | throw new IllegalArgumentException("class is required"); 58 | } 59 | 60 | className = null; 61 | } 62 | 63 | // child components 64 | NodeList children = node.getChildNodes(); 65 | int count = children.getLength(); 66 | 67 | int realCount = 0; 68 | for (int i = 0; i < count; ++i) { 69 | if (Element.class.isInstance(children.item(i))) { 70 | ++realCount; 71 | } 72 | } 73 | 74 | BaseComponent[] childComponents = new BaseComponent[realCount]; 75 | 76 | DataStructureComponent instance = new DataStructureComponent(parent, 77 | no, className, name, childComponents, ignoreField); 78 | boolean nextIgnoreField = !instance.hasField(); 79 | 80 | for (int i = 0, j = 0; i < count; ++i) { 81 | Node child = children.item(i); 82 | if (!Element.class.isInstance(child)) { 83 | continue; 84 | } 85 | 86 | Element el = (Element) child; 87 | String tagName = el.getTagName(); 88 | 89 | if ("skip".equals(tagName)) { 90 | childComponents[j] = SkipComponentFactory.parse(el); 91 | } else if ("basic".equals(tagName)) { 92 | childComponents[j] = validate(BasicComponentFactory.parse( 93 | factory, instance, el)); 94 | } else if ("transient".equals(tagName)) { 95 | childComponents[j] = validate(TransientComponentFactory.parse( 96 | factory, el)); 97 | } else if ("data-structure".equals(tagName)) { 98 | childComponents[j] = DataStructureComponentFactory.parse( 99 | factory, instance, nextIgnoreField, el); 100 | } else if ("list".equals(tagName)) { 101 | childComponents[j] = CollectionComponentFactory.parse(factory, 102 | instance, el); 103 | } else { 104 | throw new IllegalArgumentException("unsupported tag " + tagName); 105 | } 106 | 107 | ++j; 108 | } 109 | 110 | return instance; 111 | } 112 | 113 | private static BasicComponent validate(BasicComponent component) { 114 | if (component.isBinary()) { 115 | throw new RuntimeException( 116 | "data-structure cannot contains binary value"); 117 | } 118 | 119 | return component; 120 | } 121 | 122 | private static TransientComponent validate(TransientComponent component) { 123 | if (component.isBinary()) { 124 | throw new RuntimeException( 125 | "data-structure cannot contains binary value"); 126 | } 127 | 128 | return component; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /wiki/BenchmarkCodeJPos.wiki: -------------------------------------------------------------------------------- 1 | = Benchmark Code = 2 | Small unit test for JPos performance measurement. 3 | 4 | == Read / Pack == 5 | {{{ 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStream; 9 | 10 | import org.jpos.iso.ISOMsg; 11 | import org.jpos.iso.packager.GenericPackager; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | public class PackStressTest { 17 | private GenericPackager jposPackager; 18 | 19 | private OutputStream nullOut; 20 | 21 | @Before 22 | public void initialize() throws Exception { 23 | jposPackager = new GenericPackager("src/test/resources/META-INF/jpos.xml"); 24 | 25 | nullOut = new OutputStream() { 26 | public void write(int b) throws IOException { 27 | // do nothing 28 | } 29 | }; 30 | } 31 | 32 | private long measureJPos(int loops) throws Exception { 33 | long startDate = System.currentTimeMillis(); 34 | for (int i = loops - 1; i >= 0; --i) { 35 | ISOMsg msg = new ISOMsg(); 36 | msg.setPackager(jposPackager); 37 | 38 | msg.setMTI("0200"); 39 | msg.set(2, "3125"); 40 | msg.set(7, "0104132431"); 41 | msg.set(11, "1"); 42 | msg.set(12, "132431"); 43 | msg.set(13, "0104"); 44 | msg.set(29, "C01000000"); 45 | msg.set(37, "1762745214"); 46 | msg.set(39, "00"); 47 | msg.set(48, "01000abcdefghijkl "); 48 | 49 | msg.pack(nullOut); 50 | } 51 | long endDate = System.currentTimeMillis(); 52 | 53 | return endDate - startDate; 54 | } 55 | 56 | @Test 57 | public void shouldVeryFast() throws Exception { 58 | int loops = 10000; // changed to 10000, 100000, 1000000, 10000000 59 | 60 | long elapsedJPos = measureJPos(loops); 61 | System.out.println("[pack] [jpos] loops / sec = " 62 | + ((long)loops * 1000L / elapsedJPos)); 63 | } 64 | } 65 | }}} 66 | 67 | == Write / Unpack == 68 | {{{ 69 | import java.io.FileInputStream; 70 | import java.io.IOException; 71 | import java.io.InputStream; 72 | 73 | import org.jpos.iso.ISOMsg; 74 | import org.jpos.iso.packager.GenericPackager; 75 | 76 | import org.junit.Before; 77 | import org.junit.Test; 78 | 79 | public class UnpackStressTest { 80 | private GenericPackager jposPackager; 81 | 82 | private InputStream ipacked; 83 | 84 | @Before 85 | public void initialize() throws Exception { 86 | jposPackager = new GenericPackager("src/test/resources/META-INF/jpos.xml"); 87 | 88 | final byte[] bpacked = "0200423800080A010000133125 01041324310000011324310104C010000001762745214 0003701000abcdefghijkl " 89 | .getBytes(); 90 | 91 | ipacked = new InputStream() { 92 | private int readerIndex = 0; 93 | 94 | private int remaining = bpacked.length; 95 | 96 | public int read() throws IOException { 97 | if (remaining == 0) { 98 | return -1; 99 | } 100 | 101 | int readb = bpacked[readerIndex] & 0xFF; 102 | 103 | ++readerIndex; 104 | --remaining; 105 | 106 | return readb; 107 | } 108 | 109 | @Override 110 | public int read(byte b[], int off, int len) throws IOException { 111 | if (remaining == 0) { 112 | return -1; 113 | } 114 | 115 | if (remaining >= len) { 116 | System.arraycopy(bpacked, readerIndex, b, off, len); 117 | 118 | readerIndex += len; 119 | remaining -= len; 120 | 121 | return len; 122 | } 123 | 124 | try { 125 | System.arraycopy(bpacked, readerIndex, b, off, remaining); 126 | } catch (Throwable e) { 127 | System.err.println("error: " + "bpacked.length = " 128 | + bpacked.length + ", readerIndex = "); 129 | } 130 | 131 | remaining = 0; 132 | readerIndex = bpacked.length; 133 | 134 | return len; 135 | } 136 | 137 | public void close() throws IOException { 138 | readerIndex = 0; 139 | remaining = bpacked.length; 140 | } 141 | }; 142 | } 143 | 144 | private long measureJPos(int loops) throws Exception { 145 | long startDate = System.currentTimeMillis(); 146 | for (int i = 0; i < loops; ++i) { 147 | ISOMsg msg = new ISOMsg(); 148 | msg.setPackager(jposPackager); 149 | 150 | msg.unpack(ipacked); 151 | 152 | ipacked.close(); 153 | } 154 | long endDate = System.currentTimeMillis(); 155 | 156 | return endDate - startDate; 157 | } 158 | 159 | @Test 160 | public void shouldVeryFast() throws Exception { 161 | int loops = 10000; // to be changed 162 | 163 | long elapsedJPos = measureJPos(loops); 164 | 165 | System.out.println("[unpack] [jpos] loops / sec = " 166 | + ((long)loops * 1000L / elapsedJPos)); 167 | } 168 | } 169 | }}} -------------------------------------------------------------------------------- /wiki/BenchmarkCodeNucleus8583.wiki: -------------------------------------------------------------------------------- 1 | = Benchmark Code = 2 | Small unit test for nucleus8583 performance measurement. 3 | 4 | == Read / Pack == 5 | {{{ 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | 9 | import org.nucleus8583.core.Iso8583MessageFactory; 10 | import org.nucleus8583.core.Iso8583Message; 11 | 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | 15 | public class PackStressTest { 16 | private Iso8583MessageFactory factory; 17 | 18 | private OutputStream nullOut; 19 | 20 | @Before 21 | public void initialize() throws Exception { 22 | factory = new Iso8583MessageFactory("src/test/resources/META-INF/codec8583.xml"); 23 | 24 | nullOut = new OutputStream() { 25 | public void write(int b) throws IOException { 26 | // do nothing 27 | } 28 | }; 29 | } 30 | 31 | private long measureNucleus8583(int loops) throws Exception { 32 | long startDate = System.currentTimeMillis(); 33 | for (int i = loops - 1; i >= 0; --i) { 34 | Iso8583Message msg = factory.createMessage(); 35 | 36 | msg.setMti("0200"); 37 | msg.set(2, "3125"); 38 | msg.set(7, "0104132431"); 39 | msg.set(11, "1"); 40 | msg.set(12, "132431"); 41 | msg.set(13, "0104"); 42 | msg.set(29, "C01000000"); 43 | msg.set(37, "1762745214"); 44 | msg.set(39, "00"); 45 | msg.set(48, "01000abcdefghijkl "); 46 | 47 | msg.pack(nullOut); 48 | } 49 | long endDate = System.currentTimeMillis(); 50 | 51 | return endDate - startDate; 52 | } 53 | 54 | @Test 55 | public void shouldVeryFast() throws Exception { 56 | int loops = 10000; // changed to 10000, 100000, 1000000, 10000000 57 | 58 | long elapsedNucleus8583 = measureNucleus8583(loops); 59 | System.out.println("[pack] [nucleus8583] loops / sec = " 60 | + ((long)loops * 1000L / elapsedNucleus8583)); 61 | } 62 | } 63 | }}} 64 | 65 | == Write / Unpack == 66 | {{{ 67 | import java.io.IOException; 68 | import java.io.InputStream; 69 | 70 | import org.nucleus8583.core.Iso8583MessageFactory; 71 | import org.nucleus8583.core.Iso8583Message; 72 | 73 | import org.junit.Before; 74 | import org.junit.Test; 75 | 76 | public class UnpackStressTest { 77 | private Iso8583MessageFactory factory; 78 | 79 | private InputStream ipacked; 80 | 81 | @Before 82 | public void initialize() throws Exception { 83 | factory = new Iso8583MessageFactory("src/test/resources/META-INF/codec8583.xml"); 84 | 85 | final byte[] bpacked = "0200423800080A010000133125 01041324310000011324310104C010000001762745214 0003701000abcdefghijkl " 86 | .getBytes(); 87 | 88 | ipacked = new InputStream() { 89 | private int readerIndex = 0; 90 | 91 | private int remaining = bpacked.length; 92 | 93 | public int read() throws IOException { 94 | if (remaining == 0) { 95 | return -1; 96 | } 97 | 98 | int readb = bpacked[readerIndex] & 0xFF; 99 | 100 | ++readerIndex; 101 | --remaining; 102 | 103 | return readb; 104 | } 105 | 106 | @Override 107 | public int read(byte b[], int off, int len) throws IOException { 108 | if (remaining == 0) { 109 | return -1; 110 | } 111 | 112 | if (remaining >= len) { 113 | System.arraycopy(bpacked, readerIndex, b, off, len); 114 | 115 | readerIndex += len; 116 | remaining -= len; 117 | 118 | return len; 119 | } 120 | 121 | try { 122 | System.arraycopy(bpacked, readerIndex, b, off, remaining); 123 | } catch (Throwable e) { 124 | System.err.println("error: " + "bpacked.length = " 125 | + bpacked.length + ", readerIndex = "); 126 | } 127 | 128 | remaining = 0; 129 | readerIndex = bpacked.length; 130 | 131 | return len; 132 | } 133 | 134 | public void close() throws IOException { 135 | readerIndex = 0; 136 | remaining = bpacked.length; 137 | } 138 | }; 139 | } 140 | 141 | private long measureNucleus8583(int loops) throws Exception { 142 | long startDate = System.currentTimeMillis(); 143 | for (int i = 0; i < loops; ++i) { 144 | Iso8583Message msg = factory.createMessage(); 145 | msg.unpack(ipacked); 146 | 147 | ipacked.close(); 148 | } 149 | long endDate = System.currentTimeMillis(); 150 | 151 | return endDate - startDate; 152 | } 153 | 154 | @Test 155 | public void shouldVeryFast() throws Exception { 156 | int loops = 10000; // to be changed 157 | 158 | long elapsedNucleus8583 = measureNucleus8583(loops); 159 | 160 | System.out.println("[unpack] [nucleus8583] loops / sec = " 161 | + ((long)loops * 1000L / elapsedNucleus8583)); 162 | } 163 | } 164 | }}} -------------------------------------------------------------------------------- /nucleus8583-core/src/main/java/org/nucleus8583/core/field/type/Iso8583FieldTypes.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core.field.type; 2 | 3 | import java.io.InputStream; 4 | import java.lang.reflect.Constructor; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.net.URL; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Properties; 12 | 13 | import org.nucleus8583.core.util.ResourceUtils; 14 | import org.nucleus8583.core.xml.Iso8583FieldAlignments; 15 | import org.nucleus8583.core.xml.Iso8583FieldDefinition; 16 | 17 | public abstract class Iso8583FieldTypes { 18 | 19 | private static final class Entry { 20 | 21 | public Class clazz; 22 | 23 | public Iso8583FieldAlignments align; 24 | 25 | public String padWith; 26 | 27 | public String emptyValue; 28 | } 29 | 30 | private static final Map types; 31 | 32 | static { 33 | types = new HashMap(); 34 | 35 | URL[] urls = ResourceUtils.getURLs("classpath:META-INF/nucleus8583/nucleus8583.types"); 36 | 37 | for (int i = 0; i < urls.length; ++i) { 38 | load(urls[i]); 39 | } 40 | } 41 | 42 | private static Entry createEntry(List lines) { 43 | int size = lines.size(); 44 | if (size == 0) { 45 | return null; 46 | } 47 | 48 | Entry entry = new Entry(); 49 | 50 | try { 51 | entry.clazz = Class.forName(lines.get(0), true, Thread.currentThread().getContextClassLoader()); 52 | } catch (Throwable t) { 53 | return null; 54 | } 55 | 56 | for (int i = 1; i < size; ++i) { 57 | String line = lines.get(i); 58 | int eqidx = line.indexOf('='); 59 | 60 | if (eqidx >= 0) { 61 | String name = line.substring(0, eqidx); 62 | String value = line.substring(eqidx + 1); 63 | 64 | if ("align".equals(name)) { 65 | entry.align = Iso8583FieldAlignments.enumValueOf(value); 66 | } else if ("pad-with".equals(name)) { 67 | entry.padWith = value; 68 | } else if ("empty-value".equals(name)) { 69 | entry.emptyValue = value; 70 | } 71 | } 72 | } 73 | 74 | return entry; 75 | } 76 | 77 | private static Entry createEntry(String rawdef) { 78 | boolean escaped = false; 79 | 80 | StringBuilder sb = new StringBuilder(); 81 | 82 | char[] craw = rawdef.toCharArray(); 83 | int size = craw.length; 84 | 85 | ArrayList lines = new ArrayList(); 86 | 87 | for (int i = 0; i < size; ++i) { 88 | char cc = craw[i]; 89 | 90 | if ((cc == '\\') && !escaped) { 91 | escaped = true; 92 | } else { 93 | if ((cc == ',') && !escaped) { 94 | if (sb.length() > 0) { 95 | lines.add(sb.toString()); 96 | sb.setLength(0); 97 | } 98 | } else { 99 | sb.append(cc); 100 | } 101 | 102 | escaped = false; 103 | } 104 | } 105 | 106 | if (escaped) { 107 | sb.append('\\'); 108 | } 109 | if (sb.length() > 0) { 110 | lines.add(sb.toString()); 111 | } 112 | 113 | return createEntry(lines); 114 | } 115 | 116 | private static void load(URL url) { 117 | InputStream in = null; 118 | Properties prop = new Properties(); 119 | 120 | try { 121 | in = url.openStream(); 122 | prop.load(in); 123 | } catch (Throwable t) { 124 | // do nothing 125 | } finally { 126 | if (in != null) { 127 | try { 128 | in.close(); 129 | } catch (Throwable t) { 130 | // do nothing 131 | } 132 | } 133 | } 134 | 135 | for (Map.Entry entry : prop.entrySet()) { 136 | Entry obj = createEntry((String) entry.getValue()); 137 | 138 | if (obj != null) { 139 | types.put(((String) entry.getKey()).toUpperCase(), obj); 140 | } 141 | } 142 | } 143 | 144 | public static Iso8583FieldType getType(Iso8583FieldDefinition def) { 145 | Entry entry = types.get(def.getType().toUpperCase()); 146 | if (entry == null) { 147 | throw new RuntimeException("an error occured while retrieving type " + def.getType() + ", type not found."); 148 | } 149 | 150 | try { 151 | Constructor ctor = entry.clazz.getConstructor(Iso8583FieldDefinition.class, Iso8583FieldAlignments.class, String.class, String.class); 152 | 153 | return (Iso8583FieldType) ctor.newInstance(def, entry.align, entry.padWith, entry.emptyValue); 154 | } catch (InvocationTargetException ex) { 155 | Throwable t = ex.getCause(); 156 | 157 | if (t instanceof RuntimeException) { 158 | throw (RuntimeException) t; 159 | } 160 | throw new RuntimeException("an error occured while retrieving type " + def.getType() + ", unable to instantiate class " + entry.clazz + ".", t); 161 | } catch (RuntimeException ex) { 162 | throw ex; 163 | } catch (Throwable t) { 164 | throw new RuntimeException("an error occured while retrieving type " + def.getType() + ", unable to instantiate class " + entry.clazz + ".", t); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/Iso8583MessagesFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.io.IOException; 4 | import java.net.URISyntaxException; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.xml.parsers.DocumentBuilderFactory; 9 | import javax.xml.parsers.ParserConfigurationException; 10 | 11 | import org.nucleus8583.oim.component.DataStructureComponent; 12 | import org.nucleus8583.oim.component.Iso8583MessageComponent; 13 | import org.nucleus8583.oim.converter.TypeConverter; 14 | import org.nucleus8583.util.ResourceUtils; 15 | import org.w3c.dom.Document; 16 | import org.w3c.dom.Element; 17 | import org.w3c.dom.Node; 18 | import org.w3c.dom.NodeList; 19 | import org.xml.sax.SAXException; 20 | 21 | public final class Iso8583MessagesFactory { 22 | private final Map types; 23 | 24 | private final Map dataStructures; 25 | 26 | private final Map messages; 27 | 28 | public Iso8583MessagesFactory(String... locations) throws IOException { 29 | types = new HashMap(); 30 | dataStructures = new HashMap(); 31 | messages = new HashMap(); 32 | 33 | int count = locations.length; 34 | 35 | for (int i = 0; i < count; ++i) { 36 | readType(locations[i]); 37 | } 38 | for (int i = 0; i < count; ++i) { 39 | readDataStructure(locations[i]); 40 | } 41 | for (int i = 0; i < count; ++i) { 42 | readEntity(locations[i]); 43 | } 44 | } 45 | 46 | private Document read(String location) throws IOException { 47 | Document doc; 48 | try { 49 | doc = DocumentBuilderFactory 50 | .newInstance() 51 | .newDocumentBuilder() 52 | .parse(ResourceUtils.getURL(location).toURI() 53 | .toASCIIString()); 54 | } catch (SAXException e) { 55 | throw new RuntimeException("unable to parse configuration file", e); 56 | } catch (ParserConfigurationException e) { 57 | throw new RuntimeException("unable to parse configuration file", e); 58 | } catch (URISyntaxException e) { 59 | throw new RuntimeException("unable to parse configuration file", e); 60 | } 61 | 62 | return doc; 63 | } 64 | 65 | private void readType(String location) throws IOException { 66 | Element root = read(location).getDocumentElement(); 67 | 68 | NodeList children = root.getChildNodes(); 69 | int count = children.getLength(); 70 | 71 | for (int i = 0; i < count; ++i) { 72 | Node childNode = children.item(i); 73 | if (!Element.class.isInstance(childNode)) { 74 | continue; 75 | } 76 | 77 | Element childEl = (Element) childNode; 78 | 79 | if ("type".equals(childEl.getTagName())) { 80 | TypeConverter converter = TypeConverterFactory.parse(childEl); 81 | types.put(converter.getName(), converter); 82 | } 83 | } 84 | } 85 | 86 | private void readDataStructure(String location) throws IOException { 87 | Element root = read(location).getDocumentElement(); 88 | 89 | NodeList children = root.getChildNodes(); 90 | int count = children.getLength(); 91 | 92 | for (int i = 0; i < count; ++i) { 93 | Node childNode = children.item(i); 94 | if (!Element.class.isInstance(childNode)) { 95 | continue; 96 | } 97 | 98 | Element el = (Element) childNode; 99 | 100 | if ("data-structure".equals(el.getTagName())) { 101 | DataStructureComponent comp = DataStructureComponentFactory 102 | .parse(this, null, false, el); 103 | 104 | dataStructures.put(comp.getName(), comp); 105 | } 106 | } 107 | } 108 | 109 | private void readEntity(String location) throws IOException { 110 | Element root = read(location).getDocumentElement(); 111 | 112 | NodeList list = root.getChildNodes(); 113 | int count = list.getLength(); 114 | 115 | for (int i = 0; i < count; ++i) { 116 | Object node = list.item(i); 117 | if (!Element.class.isInstance(node)) { 118 | continue; 119 | } 120 | 121 | Element el = (Element) node; 122 | String tagName = el.getTagName(); 123 | 124 | if ("message".equals(tagName)) { 125 | Iso8583MessageComponent comp = Iso8583MessageComponentFactory 126 | .parse(this, el); 127 | messages.put(comp.getName(), comp); 128 | } 129 | } 130 | } 131 | 132 | public Map getMessages() { 133 | return messages; 134 | } 135 | 136 | public Iso8583MessageComponent findMessage(String name) { 137 | return messages.containsKey(name) ? messages.get(name) : null; 138 | } 139 | 140 | public DataStructureComponent findDataStructure(String name) { 141 | return dataStructures.containsKey(name) ? dataStructures.get(name) 142 | : null; 143 | } 144 | 145 | public TypeConverter findTypeConverter(String name) { 146 | return types.containsKey(name) ? types.get(name) : null; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /nucleus8583-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 4.0.0 8 | 9 | org.nucleus8583 10 | nucleus8583-core 11 | 12 | bundle 13 | 14 | nucleus8583 Core 15 | 2.4.0 16 | 17 | OSGi bundle for ISO-8583 message standard implementation. 18 | http://code.google.com/p/nucleus8583/ 19 | 20 | 21 | UTF-8 22 | 23 | 24 | 25 | 26 | The Apache Software License, Version 2.0 27 | http://www.apache.org/licenses/LICENSE-2.0.txt 28 | repo 29 | 30 | 31 | 32 | 33 | http://code.google.com/p/nucleus8583/issues/ 34 | 35 | 36 | 37 | git@github.com:robbik/nucleus8583.git 38 | scm:git:git@github.com:robbik/nucleus8583.git 39 | scm:git:git@github.com:robbik/nucleus8583.git 40 | 41 | 42 | 43 | 44 | robbi.kurniawan 45 | Robbi Kurniawan 46 | robbi.kurniawan@gmail.com 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-compiler-plugin 55 | 2.0.2 56 | 57 | 1.5 58 | 1.5 59 | 60 | 61 | 62 | 63 | org.apache.felix 64 | maven-bundle-plugin 65 | true 66 | 2.1.0 67 | 68 | 69 | ${project.url} 70 | * 71 | * 72 | org.nucleus8583.core.* 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | snapshots 83 | 84 | 85 | 86 | oss-sonatype-snapshots 87 | https://oss.sonatype.org/content/repositories/snapshots/ 88 | 89 | 90 | 91 | 92 | 93 | releases 94 | 95 | 96 | 97 | 98 | org.apache.maven.plugins 99 | maven-gpg-plugin 100 | 1.1 101 | 102 | 103 | sign-artifacts 104 | package 105 | 106 | sign 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | oss-sonatype-releases 117 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 118 | 119 | 120 | 121 | 122 | 123 | jdk15 124 | 125 | 126 | 1.5 127 | 128 | 129 | 130 | 131 | javax.xml.bind 132 | jaxb-api 133 | 2.2.2 134 | provided 135 | 136 | 137 | com.sun.xml.bind 138 | jaxb-impl 139 | 2.2.2 140 | provided 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | junit 149 | junit 150 | 4.8.1 151 | test 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/TransientComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import org.nucleus8583.oim.component.TransientComponent; 6 | import org.nucleus8583.oim.converter.TypeConverter; 7 | import org.nucleus8583.oim.util.ElExpression; 8 | import org.nucleus8583.oim.util.StringUtil; 9 | import org.w3c.dom.Element; 10 | 11 | public abstract class TransientComponentFactory { 12 | private static final Pattern digits = Pattern.compile("^[0-9]+$"); 13 | 14 | public static TransientComponent parse(Iso8583MessagesFactory factory, 15 | Element node) { 16 | String s_no = node.getAttribute("no"); 17 | String s_name = node.getAttribute("name"); 18 | String s_type = node.getAttribute("type"); 19 | String s_precision = node.getAttribute("precision"); 20 | String s_align = node.getAttribute("align"); 21 | String s_padWith = node.getAttribute("pad-with"); 22 | String s_length = node.getAttribute("length"); 23 | String s_generatedValue = node.getAttribute("generated-value"); 24 | 25 | // no 26 | int no; 27 | 28 | if (StringUtil.hasText(s_no)) { 29 | s_no = s_no.trim(); 30 | 31 | if (!digits.matcher(s_no).matches()) { 32 | throw new IllegalArgumentException( 33 | "transient: no must be numeric"); 34 | } 35 | 36 | no = Integer.parseInt(s_no, 10); 37 | } else { 38 | no = -1; 39 | } 40 | 41 | // name 42 | String name; 43 | 44 | if (!StringUtil.hasText(s_name)) { 45 | throw new IllegalArgumentException("transient: name is required"); 46 | } 47 | 48 | name = s_name.trim(); 49 | 50 | // type and precision 51 | TypeConverter converter; 52 | 53 | if (!StringUtil.hasText(s_type)) { 54 | throw new IllegalArgumentException("transient: type is required"); 55 | } 56 | 57 | if (StringUtil.hasText(s_precision)) { 58 | s_precision = s_precision.trim(); 59 | 60 | if (!digits.matcher(s_precision).matches()) { 61 | throw new IllegalArgumentException( 62 | "transient: precision must be numeric"); 63 | } 64 | } else { 65 | s_precision = null; 66 | } 67 | 68 | if (s_precision == null) { 69 | s_type = s_type.trim(); 70 | } else { 71 | s_type = s_type.trim() + ";precision=" + s_precision; 72 | } 73 | 74 | converter = factory.findTypeConverter(s_type); 75 | if (converter == null) { 76 | throw new IllegalArgumentException( 77 | "transient: unable to find type " + s_type); 78 | } 79 | 80 | // align 81 | char align; 82 | 83 | if (StringUtil.hasText(s_align)) { 84 | s_align = s_align.trim(); 85 | 86 | if ("left".equalsIgnoreCase(s_align) 87 | || "l".equalsIgnoreCase(s_align)) { 88 | align = 'l'; 89 | } else if ("right".equalsIgnoreCase(s_align) 90 | || "r".equalsIgnoreCase(s_align)) { 91 | align = 'r'; 92 | } else if ("none".equalsIgnoreCase(s_align) 93 | || "n".equalsIgnoreCase(s_align)) { 94 | align = 'n'; 95 | } else { 96 | throw new IllegalArgumentException( 97 | "transient: unknown alignment " + s_align); 98 | } 99 | } else { 100 | Character def = converter.getDefaultAlignment(); 101 | 102 | if (def != null) { 103 | align = def.charValue(); 104 | } else { 105 | align = 'n'; 106 | } 107 | } 108 | 109 | // pad-with 110 | char padWith; 111 | 112 | if (StringUtil.hasText(s_padWith)) { 113 | if (s_padWith.length() != 1) { 114 | throw new IllegalArgumentException( 115 | "transient: pad-with must be one character length, given " 116 | + s_padWith.length() + " character(s) length"); 117 | } 118 | 119 | padWith = s_padWith.charAt(0); 120 | } else { 121 | Character def = converter.getDefaultPadWith(); 122 | 123 | if (def != null) { 124 | padWith = def.charValue(); 125 | } else { 126 | padWith = ' '; 127 | } 128 | } 129 | 130 | // length 131 | int length; 132 | 133 | if (StringUtil.hasText(s_length)) { 134 | s_length = s_length.trim(); 135 | if (!digits.matcher(s_length).matches()) { 136 | throw new IllegalArgumentException( 137 | "transient: length must be numeric"); 138 | } 139 | 140 | length = Integer.parseInt(s_length, 10); 141 | if (length <= 0) { 142 | throw new IllegalArgumentException( 143 | "transient: length must be more than zero"); 144 | } 145 | } else { 146 | Integer def = converter.getDefaultLength(); 147 | 148 | if (def != null) { 149 | length = def.intValue(); 150 | } else { 151 | throw new IllegalArgumentException( 152 | "transient: length must be defined"); 153 | } 154 | } 155 | 156 | // generated-value 157 | ElExpression generatedValue; 158 | 159 | if (StringUtil.hasText(s_generatedValue, false)) { 160 | generatedValue = new ElExpression(s_generatedValue); 161 | } else { 162 | generatedValue = null; 163 | } 164 | 165 | return new TransientComponent(no, name, converter, align, padWith, 166 | length, generatedValue); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/util/ElExpression.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.util; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import ognl.Ognl; 7 | import ognl.OgnlContext; 8 | 9 | import org.mvel2.MVEL; 10 | 11 | public class ElExpression { 12 | private static final int EL_TYPE_MVEL = 1; 13 | 14 | private static final int EL_TYPE_MVEL_CONST = 2; 15 | 16 | private static final int EL_TYPE_OGNL = 3; 17 | 18 | private static final int EL_TYPE_OGNL_CONST = 4; 19 | 20 | private static final int EL_TYPE_LITERAL = 5; 21 | 22 | private static final Object EMPTY = new Object(); 23 | 24 | private final String expression; 25 | 26 | private final Object compiled; 27 | 28 | private final int type; 29 | 30 | public static Object eval(String expression, Map vars) { 31 | return new ElExpression(expression).eval(vars); 32 | } 33 | 34 | public static Object eval(String expression) { 35 | return new ElExpression(expression).eval(Collections 36 | . emptyMap()); 37 | } 38 | 39 | public ElExpression(String expression) { 40 | if (expression.startsWith("mvel:const:")) { 41 | this.expression = expression.substring(11); 42 | 43 | try { 44 | compiled = MVEL.eval(this.expression); 45 | } catch (RuntimeException e) { 46 | throw new RuntimeException( 47 | "unable to evaluate mvel expression " + this.expression, 48 | e); 49 | } 50 | 51 | type = EL_TYPE_MVEL_CONST; 52 | } else if (expression.startsWith("mvel:")) { 53 | this.expression = expression.substring(5); 54 | 55 | try { 56 | compiled = MVEL.compileExpression(this.expression); 57 | } catch (RuntimeException e) { 58 | throw new RuntimeException("unable to compile mvel expression " 59 | + this.expression, e); 60 | } 61 | 62 | type = EL_TYPE_MVEL; 63 | } else if (expression.startsWith("ognl:const:")) { 64 | this.expression = expression.substring(11); 65 | 66 | try { 67 | compiled = Ognl.getValue(this.expression, new Object()); 68 | } catch (Throwable e) { 69 | throw new RuntimeException( 70 | "unable to evaluate ognl expression " + this.expression, 71 | e); 72 | } 73 | 74 | type = EL_TYPE_OGNL_CONST; 75 | } else if (expression.startsWith("ognl:")) { 76 | this.expression = expression.substring(5); 77 | 78 | try { 79 | compiled = Ognl.compileExpression(new OgnlContext(), EMPTY, 80 | this.expression); 81 | } catch (Throwable e) { 82 | throw new RuntimeException("unable to compile ognl expression " 83 | + this.expression, e); 84 | } 85 | 86 | type = EL_TYPE_OGNL; 87 | } else if (expression.startsWith("literal:")) { 88 | this.expression = expression.substring(8); 89 | 90 | compiled = null; 91 | type = EL_TYPE_LITERAL; 92 | } else { 93 | this.expression = expression; 94 | 95 | compiled = null; 96 | type = EL_TYPE_LITERAL; 97 | } 98 | } 99 | 100 | public Object eval(Map vars) { 101 | switch (type) { 102 | case EL_TYPE_MVEL_CONST: 103 | return compiled; 104 | case EL_TYPE_MVEL: 105 | try { 106 | return MVEL.executeExpression(compiled, vars); 107 | } catch (Throwable e) { 108 | throw new RuntimeException( 109 | "unable to evaluate compiled mvel expression " 110 | + expression, e); 111 | } 112 | case EL_TYPE_OGNL_CONST: 113 | return compiled; 114 | case EL_TYPE_OGNL: 115 | try { 116 | return Ognl.getValue(compiled, vars); 117 | } catch (Throwable e) { 118 | throw new RuntimeException( 119 | "unable to evaluate compiled ognl expression " 120 | + expression, e); 121 | } 122 | case EL_TYPE_LITERAL: 123 | return expression; 124 | default: 125 | return null; 126 | } 127 | } 128 | 129 | public Object eval(Object root) { 130 | switch (type) { 131 | case EL_TYPE_MVEL_CONST: 132 | return compiled; 133 | case EL_TYPE_MVEL: 134 | try { 135 | return MVEL.executeExpression(compiled, root); 136 | } catch (Throwable e) { 137 | throw new RuntimeException( 138 | "unable to evaluate compiled mvel expression " 139 | + expression, e); 140 | } 141 | case EL_TYPE_OGNL_CONST: 142 | return compiled; 143 | case EL_TYPE_OGNL: 144 | try { 145 | return Ognl.getValue(compiled, root); 146 | } catch (Throwable e) { 147 | throw new RuntimeException( 148 | "unable to evaluate compiled ognl expression " 149 | + expression, e); 150 | } 151 | case EL_TYPE_LITERAL: 152 | return expression; 153 | default: 154 | return null; 155 | } 156 | } 157 | 158 | public boolean isConstant() { 159 | switch (type) { 160 | case EL_TYPE_MVEL_CONST: 161 | return true; 162 | case EL_TYPE_MVEL: 163 | return false; 164 | case EL_TYPE_OGNL_CONST: 165 | return true; 166 | case EL_TYPE_OGNL: 167 | return false; 168 | case EL_TYPE_LITERAL: 169 | return true; 170 | default: 171 | return false; 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /nucleus8583-core/src/main/resources/META-INF/nucleus8583/nucleus8583.types: -------------------------------------------------------------------------------- 1 | a=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 2 | a\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 3 | a\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 4 | a\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 5 | a.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 6 | a..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 7 | a...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 8 | 9 | n=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=right,pad-with\=0,empty-value\=0 10 | n\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\=0 11 | n\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\=0 12 | n\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\=0 13 | n.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\=0 14 | n..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\=0 15 | n...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\=0 16 | 17 | s=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 18 | s\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 19 | s\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 20 | s\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 21 | s.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 22 | s..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 23 | s...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 24 | 25 | an=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 26 | an\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 27 | an\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 28 | an\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 29 | an.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 30 | an..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 31 | an...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 32 | 33 | as=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 34 | as\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 35 | as\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 36 | as\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 37 | as.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 38 | as..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 39 | as...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 40 | 41 | ns=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 42 | ns\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 43 | ns\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 44 | ns\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 45 | ns.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 46 | ns..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 47 | ns...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 48 | 49 | ans=org.nucleus8583.core.field.type.Iso8583StringFieldType,align\=left,pad-with\= ,empty-value\= 50 | ans\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 51 | ans\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 52 | ans\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 53 | ans.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 54 | ans..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 55 | ans...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 56 | 57 | custom=org.nucleus8583.core.field.type.Iso8583StringFieldType 58 | custom\ .=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 59 | custom\ ..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 60 | custom\ ...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 61 | custom.=org.nucleus8583.core.field.type.Iso8583UnicodeLVarStringFieldType,empty-value\= 62 | custom..=org.nucleus8583.core.field.type.Iso8583UnicodeLLVarStringFieldType,empty-value\= 63 | custom...=org.nucleus8583.core.field.type.Iso8583UnicodeLLLVarStringFieldType,empty-value\= 64 | 65 | b=org.nucleus8583.core.field.type.Iso8583BinaryFieldType 66 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/BasicComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import org.nucleus8583.oim.component.BasicComponent; 6 | import org.nucleus8583.oim.component.HasFieldsComponent; 7 | import org.nucleus8583.oim.converter.TypeConverter; 8 | import org.nucleus8583.oim.util.ElExpression; 9 | import org.nucleus8583.oim.util.StringUtil; 10 | import org.w3c.dom.Element; 11 | 12 | public abstract class BasicComponentFactory { 13 | private static final Pattern digits = Pattern.compile("^[0-9]+$"); 14 | 15 | public static BasicComponent parse(Iso8583MessagesFactory factory, 16 | HasFieldsComponent parent, Element node) { 17 | String s_no = node.getAttribute("no"); 18 | String s_name = node.getAttribute("name"); 19 | String s_type = node.getAttribute("type"); 20 | String s_precision = node.getAttribute("precision"); 21 | String s_align = node.getAttribute("align"); 22 | String s_padWith = node.getAttribute("pad-with"); 23 | String s_length = node.getAttribute("length"); 24 | String s_generatedValue = node.getAttribute("generated-value"); 25 | 26 | // no 27 | int no; 28 | 29 | if (StringUtil.hasText(s_no)) { 30 | s_no = s_no.trim(); 31 | 32 | if (!digits.matcher(s_no).matches()) { 33 | throw new IllegalArgumentException("basic: no must be numeric"); 34 | } 35 | 36 | no = Integer.parseInt(s_no, 10); 37 | } else { 38 | no = -1; 39 | } 40 | 41 | // name 42 | String name; 43 | 44 | if (StringUtil.hasText(s_name)) { 45 | name = s_name.trim(); 46 | } else { 47 | name = null; 48 | } 49 | 50 | // type and precision 51 | TypeConverter converter; 52 | 53 | if (!StringUtil.hasText(s_type)) { 54 | throw new IllegalArgumentException("basic: type is required"); 55 | } 56 | 57 | if (StringUtil.hasText(s_precision)) { 58 | s_precision = s_precision.trim(); 59 | if (!digits.matcher(s_precision).matches()) { 60 | throw new IllegalArgumentException( 61 | "basic: precision must be numeric"); 62 | } 63 | } else { 64 | s_precision = null; 65 | } 66 | 67 | if (s_precision == null) { 68 | s_type = s_type.trim(); 69 | } else { 70 | s_type = s_type.trim() + ";precision=" + s_precision; 71 | } 72 | 73 | converter = factory.findTypeConverter(s_type); 74 | if (converter == null) { 75 | throw new IllegalArgumentException("basic: unable to found type " 76 | + s_type); 77 | } 78 | 79 | // align 80 | char align; 81 | 82 | if (StringUtil.hasText(s_align)) { 83 | s_align = s_align.trim(); 84 | 85 | if ("left".equalsIgnoreCase(s_align) 86 | || "l".equalsIgnoreCase(s_align)) { 87 | align = 'l'; 88 | } else if ("right".equalsIgnoreCase(s_align) 89 | || "r".equalsIgnoreCase(s_align)) { 90 | align = 'r'; 91 | } else if ("none".equalsIgnoreCase(s_align) 92 | || "n".equalsIgnoreCase(s_align)) { 93 | align = 'n'; 94 | } else { 95 | throw new IllegalArgumentException("basic: unknown alignment " 96 | + s_align); 97 | } 98 | } else { 99 | Character def = converter.getDefaultAlignment(); 100 | 101 | if (def != null) { 102 | align = def.charValue(); 103 | } else { 104 | align = 'n'; 105 | } 106 | } 107 | 108 | // pad-with 109 | char padWith; 110 | 111 | if (StringUtil.hasText(s_padWith)) { 112 | if (s_padWith.length() != 1) { 113 | throw new IllegalArgumentException( 114 | "basic: pad-with must be one character length, given " 115 | + s_padWith.length() + " character(s) length"); 116 | } 117 | 118 | padWith = s_padWith.charAt(0); 119 | } else { 120 | Character def = converter.getDefaultPadWith(); 121 | 122 | if (def != null) { 123 | padWith = def.charValue(); 124 | } else { 125 | padWith = ' '; 126 | } 127 | } 128 | 129 | // length 130 | int length; 131 | 132 | if (StringUtil.hasText(s_length)) { 133 | s_length = s_length.trim(); 134 | if (!digits.matcher(s_length).matches()) { 135 | throw new IllegalArgumentException( 136 | "basic: length must be numeric"); 137 | } 138 | 139 | length = Integer.parseInt(s_length, 10); 140 | if (length <= 0) { 141 | throw new IllegalArgumentException( 142 | "basic: length must be more than zero"); 143 | } 144 | } else { 145 | Integer def = converter.getDefaultLength(); 146 | 147 | if (def != null) { 148 | length = def.intValue(); 149 | } else { 150 | throw new IllegalArgumentException( 151 | "basic: length must be defined"); 152 | } 153 | } 154 | 155 | // generated-value 156 | ElExpression generatedValue; 157 | 158 | if (StringUtil.hasText(s_generatedValue, false)) { 159 | generatedValue = new ElExpression(s_generatedValue); 160 | } else { 161 | generatedValue = null; 162 | } 163 | 164 | // consistency check 165 | if ((generatedValue != null) && (name != null)) { 166 | throw new IllegalArgumentException( 167 | "basic: generated-value cannot be used together with name"); 168 | } 169 | 170 | return new BasicComponent(parent, no, name, converter, align, padWith, 171 | length, generatedValue); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/ArrayComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.lang.reflect.Array; 6 | import java.lang.reflect.Field; 7 | import java.util.Map; 8 | 9 | import org.nucleus8583.oim.util.FastStringReader; 10 | 11 | public final class ArrayComponent extends BaseComponent { 12 | private final int no; 13 | 14 | private final String name; 15 | 16 | private final Field field; 17 | 18 | private final Class componentType; 19 | 20 | private final Field sizeBasic; 21 | 22 | private final String sizeTransient; 23 | 24 | private final DataStructureComponent dataStructure; 25 | 26 | public ArrayComponent(HasFieldsComponent parent, int no, String name, 27 | String size, DataStructureComponent dscomp) { 28 | this.no = no; 29 | this.name = name; 30 | 31 | field = parent.getField(name); 32 | componentType = field.getType().getComponentType(); 33 | 34 | if (size == null) { 35 | sizeBasic = null; 36 | sizeTransient = null; 37 | } else if (size.startsWith("transient:")) { 38 | sizeBasic = null; 39 | sizeTransient = size.substring(10); 40 | } else { 41 | // basic: 42 | size = size.substring(6); 43 | 44 | sizeBasic = parent.getField(size.substring(10)); 45 | if (sizeBasic == null) { 46 | throw new IllegalArgumentException("field " + size 47 | + " cannot be found"); 48 | } 49 | sizeTransient = null; 50 | } 51 | 52 | dataStructure = dscomp; 53 | } 54 | 55 | public int getNo() { 56 | return no; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | @Override 64 | public boolean isBinary() { 65 | return false; 66 | } 67 | 68 | @Override 69 | public void encode(StringBuilder sb, Object pojo, 70 | Map session) { 71 | Object array; 72 | 73 | try { 74 | array = field.get(pojo); 75 | } catch (IllegalAccessException e) { 76 | throw new RuntimeException(e); 77 | } 78 | 79 | if (array == null) { 80 | return; 81 | } 82 | 83 | int count; 84 | 85 | if (sizeTransient != null) { 86 | count = ((Integer) session.get(sizeTransient)).intValue(); 87 | } else if (sizeBasic != null) { 88 | try { 89 | count = sizeBasic.getInt(pojo); 90 | } catch (IllegalAccessException e) { 91 | throw new RuntimeException(e); 92 | } 93 | } else { 94 | count = Array.getLength(array); 95 | } 96 | 97 | for (int i = 0; i < count; ++i) { 98 | dataStructure.encode(sb, Array.get(array, i), session); 99 | } 100 | } 101 | 102 | @Override 103 | public String encodeToString(Object pojo, Map session) { 104 | Object array; 105 | 106 | try { 107 | array = field.get(pojo); 108 | } catch (IllegalAccessException e) { 109 | throw new RuntimeException(e); 110 | } 111 | 112 | if (array == null) { 113 | return null; 114 | } 115 | 116 | StringBuilder sb = new StringBuilder(); 117 | int count; 118 | 119 | if (sizeTransient != null) { 120 | count = ((Integer) session.get(sizeTransient)).intValue(); 121 | } else if (sizeBasic != null) { 122 | try { 123 | count = sizeBasic.getInt(pojo); 124 | } catch (IllegalAccessException e) { 125 | throw new RuntimeException(e); 126 | } 127 | } else { 128 | count = Array.getLength(array); 129 | } 130 | 131 | for (int i = 0; i < count; ++i) { 132 | dataStructure.encode(sb, Array.get(array, i), session); 133 | } 134 | 135 | return sb.toString(); 136 | } 137 | 138 | @Override 139 | public void decode(String value, Object pojo, Map session) { 140 | Reader reader = new FastStringReader(value); 141 | int count; 142 | 143 | if (sizeTransient != null) { 144 | count = ((Integer) session.get(sizeTransient)).intValue(); 145 | } else if (sizeBasic != null) { 146 | try { 147 | count = sizeBasic.getInt(pojo); 148 | } catch (IllegalAccessException e) { 149 | throw new RuntimeException(e); 150 | } 151 | } else { 152 | throw new IllegalStateException("please set size attribute value"); 153 | } 154 | 155 | Object array = Array.newInstance(componentType, count); 156 | try { 157 | for (int i = 0; i < count; ++i) { 158 | Array.set(array, i, dataStructure.decode(reader, session)); 159 | } 160 | } catch (IOException ex) { 161 | throw new RuntimeException("internal error", ex); 162 | } 163 | 164 | try { 165 | field.set(pojo, array); 166 | } catch (IllegalAccessException e) { 167 | throw new RuntimeException(e); 168 | } 169 | } 170 | 171 | @Override 172 | public void decode(Reader reader, Object pojo, Map session) 173 | throws IOException { 174 | int count; 175 | 176 | if (sizeTransient != null) { 177 | count = ((Integer) session.get(sizeTransient)).intValue(); 178 | } else if (sizeBasic != null) { 179 | try { 180 | count = sizeBasic.getInt(pojo); 181 | } catch (IllegalAccessException e) { 182 | throw new RuntimeException(e); 183 | } 184 | } else { 185 | throw new IllegalStateException("please set size attribute value"); 186 | } 187 | 188 | Object array = Array.newInstance(componentType, count); 189 | for (int i = 0; i < count; ++i) { 190 | Array.set(array, i, dataStructure.decode(reader, session)); 191 | } 192 | 193 | try { 194 | field.set(pojo, array); 195 | } catch (IllegalAccessException e) { 196 | throw new RuntimeException(e); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/xml/Iso8583MessageComponentFactory.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.xml; 2 | 3 | import org.nucleus8583.oim.component.ArrayComponent; 4 | import org.nucleus8583.oim.component.BaseComponent; 5 | import org.nucleus8583.oim.component.BasicComponent; 6 | import org.nucleus8583.oim.component.DataStructureComponent; 7 | import org.nucleus8583.oim.component.Iso8583MessageComponent; 8 | import org.nucleus8583.oim.component.ListComponent; 9 | import org.nucleus8583.oim.component.TransientComponent; 10 | import org.nucleus8583.oim.util.StringUtil; 11 | import org.w3c.dom.Element; 12 | import org.w3c.dom.Node; 13 | import org.w3c.dom.NodeList; 14 | 15 | public abstract class Iso8583MessageComponentFactory { 16 | private static BasicComponent validate(BasicComponent comp) { 17 | if (comp.getNo() < 0) { 18 | throw new IllegalArgumentException( 19 | "no attribute is required for basic " + comp.getName()); 20 | } 21 | 22 | return comp; 23 | } 24 | 25 | private static TransientComponent validate(TransientComponent comp) { 26 | if (comp.getNo() < 0) { 27 | throw new IllegalArgumentException( 28 | "no attribute is required for transient " + comp.getName()); 29 | } 30 | 31 | return comp; 32 | } 33 | 34 | private static DataStructureComponent validate(DataStructureComponent comp) { 35 | if (comp.getNo() < 0) { 36 | throw new IllegalArgumentException( 37 | "no attribute is required for data structure " 38 | + comp.getName()); 39 | } 40 | 41 | return comp; 42 | } 43 | 44 | private static BaseComponent validate(BaseComponent base) { 45 | if (ArrayComponent.class.isInstance(base)) { 46 | ArrayComponent comp = (ArrayComponent) base; 47 | 48 | if (comp.getNo() < 0) { 49 | throw new IllegalArgumentException( 50 | "no attribute is required for list " + comp.getName()); 51 | } 52 | } else if (ListComponent.class.isInstance(base)) { 53 | ListComponent comp = (ListComponent) base; 54 | 55 | if (comp.getNo() < 0) { 56 | throw new IllegalArgumentException( 57 | "no attribute is required for list " + comp.getName()); 58 | } 59 | } 60 | 61 | return base; 62 | } 63 | 64 | public static Iso8583MessageComponent parse(Iso8583MessagesFactory factory, 65 | Element node) { 66 | String s_name = node.getAttribute("name"); 67 | String s_className = node.getAttribute("class"); 68 | 69 | // name 70 | String name; 71 | 72 | if (StringUtil.nullOrEmpty(s_name, true)) { 73 | throw new IllegalArgumentException("name is required"); 74 | } 75 | 76 | name = s_name.trim(); 77 | 78 | // class 79 | Class _class; 80 | 81 | if (StringUtil.nullOrEmpty(s_className, true)) { 82 | throw new IllegalArgumentException("class is required"); 83 | } 84 | 85 | s_className = s_className.trim(); 86 | 87 | try { 88 | _class = Class.forName(s_className, true, Thread.currentThread() 89 | .getContextClassLoader()); 90 | } catch (ClassNotFoundException e) { 91 | throw new RuntimeException("unable to find class " + s_className); 92 | } 93 | 94 | // children 95 | NodeList children = node.getChildNodes(); 96 | int count = children.getLength(); 97 | 98 | int realCount = 0; 99 | for (int i = 0; i < count; ++i) { 100 | Node child = children.item(i); 101 | 102 | if (!Element.class.isInstance(child)) { 103 | continue; 104 | } 105 | 106 | Element el = (Element) child; 107 | String elTagName = el.getTagName(); 108 | 109 | if ("basic".equals(elTagName)) { 110 | ++realCount; 111 | } else if ("transient".equals(elTagName)) { 112 | ++realCount; 113 | } else if ("data-structure".equals(elTagName)) { 114 | ++realCount; 115 | } else if ("list".equals(elTagName)) { 116 | ++realCount; 117 | } 118 | } 119 | 120 | if (realCount == 0) { 121 | throw new NullPointerException( 122 | "at least one child component required"); 123 | } 124 | 125 | BaseComponent[] isoFields = new BaseComponent[realCount]; 126 | int[] isoNumbers = new int[realCount]; 127 | 128 | // create instance 129 | Iso8583MessageComponent instance = new Iso8583MessageComponent(name, 130 | _class, isoFields, isoNumbers, realCount); 131 | 132 | for (int i = 0, j = 0; i < count; ++i) { 133 | Node child = children.item(i); 134 | if (!Element.class.isInstance(child)) { 135 | continue; 136 | } 137 | 138 | Element el = (Element) child; 139 | String elTagName = el.getTagName(); 140 | 141 | if ("basic".equals(elTagName)) { 142 | BasicComponent comp = validate(BasicComponentFactory.parse( 143 | factory, instance, el)); 144 | 145 | isoFields[j] = comp; 146 | isoNumbers[j++] = comp.getNo(); 147 | } else if ("transient".equals(elTagName)) { 148 | TransientComponent comp = validate(TransientComponentFactory 149 | .parse(factory, el)); 150 | 151 | isoFields[j] = comp; 152 | isoNumbers[j++] = comp.getNo(); 153 | } else if ("data-structure".equals(elTagName)) { 154 | DataStructureComponent comp = validate(DataStructureComponentFactory 155 | .parse(factory, instance, false, el)); 156 | 157 | isoFields[j] = comp; 158 | isoNumbers[j++] = comp.getNo(); 159 | } else if ("list".equals(elTagName)) { 160 | BaseComponent comp = validate(CollectionComponentFactory.parse( 161 | factory, instance, el)); 162 | 163 | isoFields[j] = comp; 164 | 165 | if (ArrayComponent.class.isInstance(comp)) { 166 | isoNumbers[j++] = ((ArrayComponent) comp).getNo(); 167 | } else { 168 | isoNumbers[j++] = ((ListComponent) comp).getNo(); 169 | } 170 | } 171 | } 172 | 173 | return instance; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /nucleus8583-oim/src/main/java/org/nucleus8583/oim/component/DataStructureComponent.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.oim.component; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | import java.lang.reflect.Field; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.nucleus8583.oim.util.BeanUtil; 10 | import org.nucleus8583.oim.util.FastStringReader; 11 | import org.nucleus8583.oim.util.StringUtil; 12 | 13 | public final class DataStructureComponent extends BaseComponent implements 14 | HasFieldsComponent { 15 | private final int no; 16 | 17 | private final String name; 18 | 19 | private final Field field; 20 | 21 | private final Class _class; 22 | 23 | private final Map fields; 24 | 25 | private final BaseComponent[] childComponents; 26 | 27 | private final int childrenCount; 28 | 29 | public DataStructureComponent(HasFieldsComponent parent, int no, 30 | String className, String name, BaseComponent[] childComponents, 31 | boolean ignoreField) { 32 | 33 | this.no = no; 34 | 35 | if (StringUtil.hasText(className)) { 36 | try { 37 | _class = Class.forName(className, true, Thread.currentThread() 38 | .getContextClassLoader()); 39 | } catch (ClassNotFoundException e) { 40 | throw new IllegalArgumentException("unable to find class " 41 | + className); 42 | } 43 | 44 | fields = new HashMap(); 45 | BeanUtil.collectFields(_class, fields); 46 | } else { 47 | _class = null; 48 | fields = parent.getFields(); 49 | } 50 | 51 | this.name = name; 52 | 53 | if (ignoreField || (name == null)) { 54 | field = null; 55 | } else { 56 | field = fields.get(name); 57 | } 58 | 59 | this.childComponents = childComponents; 60 | childrenCount = childComponents == null ? 0 : childComponents.length; 61 | } 62 | 63 | public int getNo() { 64 | return no; 65 | } 66 | 67 | public String getName() { 68 | return name; 69 | } 70 | 71 | public boolean hasField() { 72 | return field != null; 73 | } 74 | 75 | @Override 76 | public boolean isBinary() { 77 | return false; 78 | } 79 | 80 | @Override 81 | public void encode(StringBuilder sb, Object pojo, 82 | Map session) { 83 | if (field != null) { 84 | try { 85 | pojo = field.get(pojo); 86 | } catch (IllegalAccessException e) { 87 | throw new RuntimeException(e); 88 | } 89 | } 90 | 91 | for (int i = 0; i < childrenCount; ++i) { 92 | childComponents[i].encode(sb, pojo, session); 93 | } 94 | } 95 | 96 | @Override 97 | public String encodeToString(Object pojo, Map session) { 98 | StringBuilder sb = new StringBuilder(); 99 | encode(sb, pojo, session); 100 | 101 | return sb.toString(); 102 | } 103 | 104 | @Override 105 | public void decode(Reader reader, Object pojo, Map session) 106 | throws IOException { 107 | if ((field != null) && (_class != null)) { 108 | Object newpojo; 109 | 110 | try { 111 | newpojo = _class.newInstance(); 112 | field.set(pojo, newpojo); 113 | } catch (InstantiationException e) { 114 | throw new RuntimeException(e); 115 | } catch (IllegalAccessException e) { 116 | throw new RuntimeException(e); 117 | } 118 | 119 | pojo = newpojo; 120 | } 121 | 122 | for (int i = 0; i < childrenCount; ++i) { 123 | childComponents[i].decode(reader, pojo, session); 124 | } 125 | } 126 | 127 | @Override 128 | public Object decode(Reader reader, Map session) 129 | throws IOException { 130 | if (_class == null) { 131 | return null; 132 | } 133 | 134 | Object pojo; 135 | 136 | try { 137 | pojo = _class.newInstance(); 138 | } catch (InstantiationException e) { 139 | throw new RuntimeException(e); 140 | } catch (IllegalAccessException e) { 141 | throw new RuntimeException(e); 142 | } 143 | 144 | for (int i = 0; i < childrenCount; ++i) { 145 | childComponents[i].decode(reader, pojo, session); 146 | } 147 | 148 | return pojo; 149 | } 150 | 151 | @Override 152 | public void decode(String value, Object pojo, Map session) { 153 | if ((field != null) && (_class != null)) { 154 | Object newpojo; 155 | 156 | try { 157 | newpojo = _class.newInstance(); 158 | field.set(pojo, newpojo); 159 | } catch (InstantiationException e) { 160 | throw new RuntimeException(e); 161 | } catch (IllegalAccessException e) { 162 | throw new RuntimeException(e); 163 | } 164 | 165 | pojo = newpojo; 166 | } 167 | 168 | Reader reader = new FastStringReader(value); 169 | 170 | try { 171 | for (int i = 0; i < childrenCount; ++i) { 172 | childComponents[i].decode(reader, pojo, session); 173 | } 174 | } catch (IOException e) { 175 | throw new RuntimeException("internal error", e); 176 | } 177 | } 178 | 179 | @Override 180 | public Object decode(String value, Map session) { 181 | if (_class == null) { 182 | return null; 183 | } 184 | 185 | Reader reader = new FastStringReader(value); 186 | Object pojo; 187 | 188 | try { 189 | pojo = _class.newInstance(); 190 | } catch (InstantiationException e) { 191 | throw new RuntimeException(e); 192 | } catch (IllegalAccessException e) { 193 | throw new RuntimeException(e); 194 | } 195 | 196 | try { 197 | for (int i = 0; i < childrenCount; ++i) { 198 | childComponents[i].decode(reader, pojo, session); 199 | } 200 | } catch (IOException e) { 201 | throw new RuntimeException("internal error", e); 202 | } 203 | 204 | return pojo; 205 | } 206 | 207 | public Field getField(String name) { 208 | return fields.get(name); 209 | } 210 | 211 | public Map getFields() { 212 | return fields; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /nucleus8583-core/src/test/java/org/nucleus8583/core/PackUnpackTest.java: -------------------------------------------------------------------------------- 1 | package org.nucleus8583.core; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.util.BitSet; 11 | 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | 15 | @SuppressWarnings("deprecation") 16 | public class PackUnpackTest { 17 | private Iso8583MessageFactory messageFactory; 18 | 19 | private String packed; 20 | 21 | private Iso8583Message unpacked; 22 | 23 | private Iso8583Message draftUnpacked; 24 | 25 | @Before 26 | public void initialize() throws Exception { 27 | messageFactory = new Iso8583MessageFactory( 28 | "classpath:META-INF/codec8583.xml"); 29 | 30 | packed = "0200C00000000001000104000000000000000603000000499980000000000000000301"; 31 | 32 | unpacked = messageFactory.createMessage(); 33 | unpacked.setMti("0200"); 34 | unpacked.set(2, "030000"); 35 | unpacked.set(48, "9998"); 36 | unpacked.set(64, new BitSet()); 37 | unpacked.set(70, "301"); 38 | 39 | draftUnpacked = new Iso8583Message(); 40 | draftUnpacked.setMti("0200"); 41 | draftUnpacked.set(2, "030000"); 42 | draftUnpacked.set(48, "9998"); 43 | draftUnpacked.set(64, new BitSet()); 44 | draftUnpacked.set(70, "301"); 45 | } 46 | 47 | @Test 48 | public void quickstartTest() throws Exception { 49 | Iso8583Message msg = new Iso8583MessageFactory("classpath:META-INF/codec8583-qs.xml").createMessage(); 50 | 51 | msg.setMti("0800"); 52 | msg.set(7, "0627180510"); 53 | msg.set(11, "123456"); 54 | msg.set(70, "301"); 55 | byte[] packed = msg.pack(); 56 | 57 | assertEquals("0800822000000000000004000000000000000627180510123456301", new String(packed)); 58 | } 59 | 60 | @Test 61 | public void unpackFromBytesTest() throws Exception { 62 | Iso8583Message unpacked = messageFactory.createMessage(); 63 | unpacked.unpack(packed.getBytes()); 64 | 65 | assertEquals(this.unpacked, unpacked); 66 | } 67 | 68 | @Test 69 | public void unpackFromStringTest() throws Exception { 70 | Iso8583Message unpacked = messageFactory.createMessage(); 71 | unpacked.unpack(packed); 72 | assertEquals(this.unpacked, unpacked); 73 | 74 | unpacked = new Iso8583Message(); 75 | 76 | boolean error = false; 77 | try { 78 | unpacked.unpack(""); 79 | } catch (Throwable t) { 80 | error = true; 81 | } 82 | assertTrue(error); 83 | 84 | unpacked.attach(messageFactory); 85 | unpacked.unpack(packed); 86 | assertEquals(this.unpacked, unpacked); 87 | } 88 | 89 | @Test 90 | public void unpackFromEmptyStringTest() throws Exception { 91 | Iso8583Message unpacked = messageFactory.createMessage(); 92 | unpacked.unpack(""); 93 | assertEquals(messageFactory.createMessage(), unpacked); 94 | 95 | unpacked.detach(); 96 | 97 | boolean error = false; 98 | try { 99 | unpacked.unpack(""); 100 | } catch (Throwable t) { 101 | error = true; 102 | } 103 | assertTrue(error); 104 | 105 | unpacked = new Iso8583Message(); 106 | 107 | error = false; 108 | try { 109 | unpacked.unpack(""); 110 | } catch (Throwable t) { 111 | error = true; 112 | } 113 | assertTrue(error); 114 | 115 | unpacked.attach(messageFactory); 116 | unpacked.unpack(""); 117 | assertEquals(messageFactory.createMessage(), unpacked); 118 | } 119 | 120 | @Test 121 | public void unpackTestAfterSerialized() throws Exception { 122 | Iso8583Message unpacked = messageFactory.createMessage(); 123 | 124 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 125 | ObjectOutputStream serializer = new ObjectOutputStream(out); 126 | 127 | serializer.writeObject(unpacked); 128 | 129 | unpacked = null; 130 | 131 | ObjectInputStream deserializer = new ObjectInputStream( 132 | new ByteArrayInputStream(out.toByteArray())); 133 | unpacked = (Iso8583Message) deserializer.readObject(); 134 | 135 | unpacked.attach(messageFactory); 136 | unpacked.unpack(packed.getBytes()); 137 | 138 | assertEquals(this.unpacked, unpacked); 139 | } 140 | 141 | @Test 142 | public void pack2Test() throws Exception { 143 | String errorMsg = null; 144 | 145 | try { 146 | new Iso8583MessageFactory("classpath:META-INF/codec8583-4.xml") 147 | .createMessage(); 148 | } catch (IllegalArgumentException ex) { 149 | errorMsg = ex.getMessage(); 150 | } 151 | 152 | assertEquals("field #28 is not defined", errorMsg); 153 | } 154 | 155 | @Test 156 | public void packTest() throws Exception { 157 | byte[] packed = unpacked.pack(); 158 | assertEquals(this.packed, new String(packed)); 159 | 160 | boolean error = false; 161 | try { 162 | draftUnpacked.pack(); 163 | } catch (Throwable t) { 164 | error = true; 165 | } 166 | assertTrue(error); 167 | 168 | draftUnpacked.attach(messageFactory); 169 | packed = draftUnpacked.pack(); 170 | assertEquals(this.packed, new String(packed)); 171 | 172 | draftUnpacked.detach(); 173 | 174 | error = false; 175 | try { 176 | draftUnpacked.pack(); 177 | } catch (Throwable t) { 178 | error = true; 179 | } 180 | assertTrue(error); 181 | } 182 | 183 | @Test 184 | public void packTestAfterSerialized() throws Exception { 185 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 186 | ObjectOutputStream serializer = new ObjectOutputStream(out); 187 | 188 | serializer.writeObject(unpacked); 189 | 190 | unpacked = null; 191 | 192 | ObjectInputStream deserializer = new ObjectInputStream( 193 | new ByteArrayInputStream(out.toByteArray())); 194 | unpacked = (Iso8583Message) deserializer.readObject(); 195 | 196 | unpacked.attach(messageFactory); 197 | 198 | byte[] packed = unpacked.pack(); 199 | assertEquals(this.packed, new String(packed)); 200 | } 201 | } 202 | --------------------------------------------------------------------------------