master
rex.lin@szhyweb.com 1 year ago
commit bbcd47f6f8
  1. 11
      HYWEB-N5Core/.classpath
  2. 17
      HYWEB-N5Core/.project
  3. 2
      HYWEB-N5Core/.settings/org.eclipse.core.resources.prefs
  4. 12
      HYWEB-N5Core/.settings/org.eclipse.jdt.core.prefs
  5. 282
      HYWEB-N5Core/EftlinkConfig.properties
  6. BIN
      HYWEB-N5Core/bin/com/hyweb/.DS_Store
  7. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/Constants.class
  8. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/N5Core.class
  9. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/Version.class
  10. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/JsonParser$CharsRange.class
  11. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/JsonParser$Property.class
  12. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/JsonParser.class
  13. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/N5Message.class
  14. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/Base64$InputStream.class
  15. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/Base64$OutputStream.class
  16. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/Base64.class
  17. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/HashUtil.class
  18. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/JSONReader.class
  19. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/message/utils/Utils.class
  20. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/test/MinuteCounter.class
  21. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/test/Thread1.class
  22. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/test/Thread2.class
  23. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/test/Thread3.class
  24. BIN
      HYWEB-N5Core/bin/com/hyweb/n5/eftcore/test/testPackReqMsg.class
  25. BIN
      HYWEB-N5Core/lib/.DS_Store
  26. BIN
      HYWEB-N5Core/lib/._.DS_Store
  27. BIN
      HYWEB-N5Core/lib/._log4j-1.2-api-2.16.0.jar
  28. BIN
      HYWEB-N5Core/lib/._log4j-api-2.16.0.jar
  29. BIN
      HYWEB-N5Core/lib/._log4j-core-2.16.0.jar
  30. BIN
      HYWEB-N5Core/lib/eftlink.jar
  31. BIN
      HYWEB-N5Core/lib/log4j-1.2-api-2.16.0.jar
  32. BIN
      HYWEB-N5Core/lib/log4j-api-2.16.0.jar
  33. BIN
      HYWEB-N5Core/lib/log4j-core-2.16.0.jar
  34. BIN
      HYWEB-N5Core/src/com/hyweb/.DS_Store
  35. 9
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/Constants.java
  36. 1313
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/N5Core.java
  37. 5
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/Version.java
  38. 266
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/JsonParser.java
  39. 161
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/N5Message.java
  40. 1451
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/utils/Base64.java
  41. 144
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/utils/HashUtil.java
  42. 223
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/utils/JSONReader.java
  43. 998
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/message/utils/Utils.java
  44. 227
      HYWEB-N5Core/src/com/hyweb/n5/eftcore/test/testPackReqMsg.java

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/CDC-1.0%Foundation-1.0"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/CORE_LIBS"/>
<classpathentry kind="lib" path="lib/eftlink.jar"/>
<classpathentry kind="lib" path="lib/log4j-1.2-api-2.16.0.jar"/>
<classpathentry kind="lib" path="lib/log4j-api-2.16.0.jar"/>
<classpathentry kind="lib" path="lib/log4j-core-2.16.0.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>HYWEB-N5Core</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

@ -0,0 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8

@ -0,0 +1,282 @@
# Eftlink Configuration Properties
##################################
# Basic Settings
################
# Socket config for OPI Server
ServerChannel0 = 10100
ServerChannel1 = 10101
#Channel1IP = 1.2.3.4
# Whether to use secure TLS socket communication. Default true. This feature should not be disabled
# without express authorisation from Oracle.
TLSEnabled = true
# OPIServerDelegate - allows OPIServer operation to be delegated to an alternate class
# e.g. an extended class to include tracking/logging
#OPIServerDelegate = manito.eft.tlog.TLogOPIServer
# EFTLink Server (single multi-client host) setup
#################################################
# Number of eftlink instances to be hosted. Set to zero to run standard EFTLink application.
NumServers = 0
# Whether EFTLink is to be accessed via a single common server socket, with messages routed by POS ID
# Note - in this mode, channel 1 will run on the same client socket as channel 0.
SingleSocket = false
# server/ped identifier list - mandatory when using ped pool. 1-based.
server1.description = EFT 1
server2.description = EFT 2
# Whether to run a pool of PED shared between POSs. (many-many link)
# Note - this option not available in SingleSocket mode.
PEDPoolEnabled = false
# Number of potential POS clients when using PED pool.
#NumClients = 2
# pos identifier list - mandatory when using ped pool. 1-based.
pos1.description = POS 1
pos2.description = POS 2
# sub-pool restrictions/pre-selections. prefix the server id with '*' to specify a default association.
pos1.subpool = *EFT 1, EFT 2
pos2.subpool = EFT 1, EFT 2
# Whether to run a pool of printers shared between POSs. (many-many link)
# Printer pool is accessed via the "master" channel 0. Channel 1 will run on the same client socket as channel 0.
PrinterPoolEnabled = false
# Environment Settings
######################
# POS type that EftLink is connected to. This can be set explicitly (e.g. Lucas,
# Retail-J, Oscar) or set to "Auto" for the POS type to be deduced from the OPI
# message header
PosType = auto
###################################################################################
#
# Configuration Hierarchy
# -----------------------
#
# The settings immediately below may be set in two different ways.
# 1. as a default value determined by the PosType.
# 2. as a setting in this file, overriding any value set in 1 above. To avoid
# overriding the pos-dependent defaults, settings have to be commented-out
# in this file.
#
####################################################################################
# Static/Dynamic Configuration
##############################
# Eftlink can be configured to pick up its configuration dynamically from POS
# messages. A default setting is implied by the POS type setting above, but this
# can be overridden.
#DynamicConfiguration = false
# The level of IFSF compliance for the POS interface - IFSF or LUCAS
#PosIfsfCompliance = LUCAS
###################################################################################
#
# Configuration Hierarchy
# -----------------------
#
# All the remaining settings may be set in three different ways.
# 1. as a default value determined by the PosType.
# 2. as a setting in this file, overriding any value set in 1 above. To avoid
# overriding the pos-dependent defaults, settings have to be commented-out
# in this file.
# 3. as a dynamic setting in a message from the POS (if this feature
# is enabled), overriding any value set in 1 or 2 above.
#
####################################################################################
# Language / Internationalisation
#################################
# Language for display texts. For whatever country code is set, there must be a
# matching LangXX.properties file. A hierarchy is implied e.g. EN_US is taken as
# an extension of EN
DisplayLanguage = EN
# Number of decimal places to show
DecimalPlaces = 2
# number and type of EPS sub-systems
####################################
# built-in cores can be specified by short name e.g Simulated, OPIClient.
# plugin cores must be specified by their full package name, and the package
# must be added to the execution classpath
NumEPSCores = 1
EPSCore0 = Simulated
#EPSCore0 = OPIClient ATS
#EPSCore1 = OPIClient Loyalty
#EPSCore2 = CardReader
# Secondary server socket for reentrant calling into Eftlink from core 0.
# All such messages received on this socket must go to a single designated core, other than core 0.
# SecondaryServer: ServerSocket port number
#SecondaryServerPort = 10200
# SecondaryServerCore: core to which secondary messages will be passed
#SecondaryServerCore = 1
# A particular core can be designated to handle loyalty operations. If not set, they go to core 0.
# LoyaltyCore: core designated for Loyalty requests.
#LoyaltyCore = 1
# A particular core can be designated for handling card swipe/read requests. If not set, they go to core 0.
# CardReaderCore: core designated for CardSwipe/CardRead requests.
#CardReaderCore = 2
# Cores can also delegate card reading to the card reader e.g to read the card as part of a LoyaltyAward.
# CardReaderCoreDelegateList: CSV list of cores delegating their card reading.
#CardReaderCoreDelegateList = 0,1
# The POS can be designated for handling card swipe/read requests. If not set, they go to core 0.
# POSCardReader - boolean, default false. Sets whether the POS is to be used for CardSwipe/CardRead requests.
POSCardReader = false
# Cores can also delegate card reading to the POS card reader e.g to read the card as part of a LoyaltyAward.
# POSCardReaderDelegateList: CSV list of cores delegating their card reading.
#POSCardReaderDelegateList = 0,1
# A particular core can be designated to handle Agent operations (e.g.bill payment, telephone top-up). If not set, they
# go to core 0.
# AgentCore: core designated for agent requests.
#AgentCore = 1
# Channel 1 device proxy settings
#################################
# Whether to use a display server delegate class to control pop-up dialogs directly from EftLink instead of via Channel1
DelegatedDisplay = false
# DelegatedDisplay parameters
# DelegatedDisplayHandler - class implementing pop-up dialogs. default - manito.deviceproxy.DeviceProxy
# DisplayScheme - scheme name defining screen layout and colours. default - xxx
# DisplayLayout - optional secondary scheme name defining different layouts based on the same colour scheme
# DelegatedDisplayOverride - optional override to revert some display operations back to the POS e.g. to support
# alternate input sources.
# None (default) - no overrides, all input/output request handled by delegated display
# KeyedInput - keypad/keyboard reverted to POS
# AllInput - all input request reverted to POS
#DisplayScheme = iridium
#DisplayLayout = default
#DelegatedDisplayOverride = KeyedInput
# Other settings are available in the scheme definition file.
# whether to precede each print request with a TXT_PRINTING (e.g. "Printing. Please Wait") dialog.
ShowPrintingDialog = false
# Whether to request forced input (no cancellation) on input requests to the POS, if not explicitly set by the core.
ForcedInput = false
# whether device events e.g. CardInserted are supported by the POS. Boolean, default false. This is normally set
# automatically based on the POS type, but can be explicitly set here.
#DeviceEvents =
# POS settings
##############
# Whether combined payment with loyalty is supported - default true
# N.B. combined payment with loyalty is automatically disabled if a part payment
# is detected.
PaymentWithLoyalty = true
# Whether SaleItem values should be validated to ensure that the sum of the items matches the overall value
# defaults to true
ValidateItemValues=true
# whether the printer status is implied online
# i.e. if the POS can only send requests when the printer is online and with paper,
# we do not need an explicit check
#PrinterImpliedOnline = true
# currency symbol conversion
CURRENCY_156 = GBP
CURRENCY_163 = GBP
CURRENCY_164 = EUR
CURRENCY_213 = EUR
# Spooled print options
#######################
# DespoolOnLogon - spooled reports are automatically printed on next logon. default false
# DespoolOnMaintenance - spooled reports are automatically printed on next maintenance/administration use. default true
# DespoolOnReconciliation - spooled reports are automatically printed at next shift close. default true
# Dayend settings
#################
# Whether Eftlink is to relay POS reconciliation message on to other instances of EftLink
# If set true, EftLink uses the same dayend client list as for manito.eft.opi.server.Dayend below
DistributedDayend = false
# List of client systems to which a reconciliation message should be sent by the manito.eft.opi.server.Dayend operation.
# NumDayendClients - number of clients to be processed
# DayendClientxIP - IP of remote system where EftLink is running
# DayendClientxChannel0 - Port which EftLink is running on, usually 10100
# DayendClientxBatch - batch file to be run locally instead of sending message
# DayendClientxCore - specific individual core to send the request to
NumDayendClients = 1
DayendClient0IP=127.0.0.1
DayendClient0Channel0=10100
#DayendClient0Core = EftDevice
#DayendClient0Batch = dayend.bat
#DayendClient1IP=127.0.0.1
DayendClient1Channel0=10100
#DayendClient2IP=127.0.0.1
DayendClient2Channel0=10100
#DayendClient3IP=127.0.0.1
DayendClient3Channel0=10100
#DayendClient4IP=127.0.0.1
DayendClient4Channel0=10100
#Crypto-Agility - Communications
#Protocols Secure setting
ProtocolsWhiteList=SSLv2Hello,TLSv1.2
#Protocols Default
#ProtocolsWhiteList=SSLv2Hello,TLSv1.2
#Protocols Java 1.6 setting for backwards compatibility
#ProtocolsWhiteList=SSLv2Hello,TLSv1.2,TLSv1,TLSv1.1
#Cipher Secure setting
CipherWhiteList=TLS_DHE_.*_WITH_AES_128_.*,TLS_ECDHE_.*_WITH_AES_128_.*,TLS_ECDH_.*_WITH_AES_128_.*
CipherBlackList=SSL_.*,TLS_EMPTY_.*,.*_SHA,.*_3DES_.*,.*_DES_.*,.*_WITH_NULL_.*,.*_anon_.*
#Cipher Default
#CipherWhiteList=TLS_DHE_.*_WITH_AES_128_.*,TLS_ECDHE_.*_WITH_AES_128_.*,TLS_ECDH_.*_WITH_AES_128_.*
#CipherBlackList=SSL_.*,TLS_EMPTY_.*,.*_SHA,.*_3DES_.*,.*_DES_.*,.*_WITH_NULL_.*,.*_anon_.*
#Cipher Java 1.6 setting for backwards compatibility
#CipherWhiteList=
#CipherBlackList=SSL_.*
# Allow the application to correctly secure access to data folders when running under the Windows Local System
# account. It is strongly recommended that the application is not configured to run using the Windows Local
# System account, instead use the Windows Local Service account when use of a local Windows machine account is
# desired. Note that the Windows Network Service account should not be used.
# Default value for this setting is false.
AllowMapMachineNameToSystemAccount=
#Proxy settings - Set the proxy server details when EFTLink runs in an environment where all http outbound calls are routed to a proxy.
#https.proxyHost=adc-proxy.oracle.com
#https.proxyPort=80
#http.proxyHost=adc-proxy.oracle.com
#http.proxyPort=80

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,9 @@
package com.hyweb.n5.eftcore;
public class Constants {
public static final String Entry_Swipe = "Magstripe";
public static final String Entry_Manual = "Manual";
public static final String Entry_Chip = "Chip";
public static final String Entry_Contactless = "Contactless";
public static final String Entry_Unknown = "Unknown";
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
package com.hyweb.n5.eftcore;
public class Version {
public static final String VERSION = "HYWEB_N5 Core v3.09";
}

@ -0,0 +1,266 @@
package com.hyweb.n5.eftcore.message;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class JsonParser {
private final String json;
public JsonParser(String json) {
this.json = json;
}
public Object parse() {
CharsRange trimmedJson = newRange(0, json.length()).trim();
return processValue(trimmedJson);
}
private Object processPlainObject(CharsRange range) {
List<Property> properties = processProperties(newRange(range.start + 1, range.end - 1));
Map<String, Object> object = new HashMap<>();
//properties.forEach(prop -> object.put(prop.name, prop.value));
for (Property prop: properties)
{
object.put(prop.name, prop.value);
}
return object;
}
private List<Property> processProperties(CharsRange range)
{
List<Property> properties = new ArrayList<>();
int nameStartMark = range.start;
for (int i = range.start; i < range.end; i++)
{
char ch = json.charAt(i);
if (ch == ':')
{
CharsRange nameToken = newRange(nameStartMark, i).trim();
AtomicInteger readCursor = new AtomicInteger();
CharsRange valueSegment = findNextValue(newRange(++i, range.end), readCursor);
i = readCursor.intValue() + 1;
nameStartMark = i;
//Logger.info("nameToken:{},\nvalueSegment:{}", nameToken, valueSegment);
//TODO::valid nameToken is start and end with '"'
final String name = newRange(nameToken.start + 1, nameToken.end - 1).toString();
final Object value = processValue(valueSegment);
properties.add(Property.of(name, value));
}
}
return properties;
}
private List<?> processArray(CharsRange range)
{
return processElements(newRange(range.start + 1, range.end - 1));
}
private List<?> processElements(CharsRange range)
{
List<Object> array = new ArrayList<>();
int elementStartMark = range.start;
for (int i = range.start; i < range.end; i++)
{
AtomicInteger readCursor = new AtomicInteger();
CharsRange elementSegment = findNextValue(newRange(elementStartMark, range.end), readCursor); Object elementValue = processValue(elementSegment);
array.add(elementValue);
i = readCursor.intValue(); elementStartMark = i + 1;
}
return array;
}
private CharsRange findNextValue(CharsRange chars, AtomicInteger readCursor)
{
CharsRange trimChars = chars.trimLeft();
if (trimChars.relativeChar(0) == '{')
{
return completeSymbolPair(trimChars, readCursor, "{}");
}
else if (trimChars.relativeChar(0) == '[')
{
return completeSymbolPair(trimChars, readCursor, "[]");
}
else
{
int i;
for (i = trimChars.start + 1; i < trimChars.end; i++)
{
char ch = json.charAt(i);
if (ch == ',')
{
break;
}
}
readCursor.set(i);
return newRange(trimChars.start, i).trim();
}
}
private CharsRange completeSymbolPair(CharsRange trimChars, AtomicInteger readCursor, String symbolPair)
{
int leftSymbol = symbolPair.charAt(0);
int rightSymbol = symbolPair.charAt(1);
int symbolsScore = 1; //nested object
int i;
CharsRange valueSegment = null;
for (i = trimChars.start + 1; i < trimChars.end; i++)
{
char ch = json.charAt(i);
if (ch == leftSymbol)
{
symbolsScore++;
}
else if (ch == rightSymbol)
{
symbolsScore--;
}
if (symbolsScore == 0) {
valueSegment = newRange(trimChars.start, i + 1);
break;
}
}
for (; i < trimChars.end; i++)
{
char chx = json.charAt(i);
if (chx == ',')
{
break;
}
}
readCursor.set(i);
return valueSegment;
}
private Object processValue(CharsRange valueSegment)
{
final Object value;
if (valueSegment.relativeChar(0) == '"')
{
value = newRange(valueSegment.start + 1, valueSegment.end - 1).toString();
}
else if (valueSegment.relativeChar(0) == '{')
{
value = processPlainObject(valueSegment);
}
else if (valueSegment.relativeChar(0) == '[')
{
value = processArray(valueSegment);
}
else if (valueSegment.equalsString("true"))
{
value = true;
}
else if (valueSegment.equalsString("false"))
{
value = false;
}
else if (valueSegment.equalsString("null"))
{
value = null;
}
else
{
value = Double.parseDouble(valueSegment.toString());
}
return value;
}
static class Property
{
final String name;
final Object value;
Property(String name, Object value)
{
this.name = name; this.value = value;
}
static Property of(String name, Object value)
{
return new Property(name, value);
}
}
CharsRange newRange(int start, int end) {
return new CharsRange(start, end);
}
class CharsRange
{
final int start;
final int end;
CharsRange(int start, int end)
{
this.start = start;
this.end = end;
}
CharsRange trimLeft()
{
int newStart = -1;
for (int i = start; i < end; i++)
{
if (!Character.isWhitespace(json.charAt(i)))
{
newStart = i;
break;
}
}
if (newStart == -1)
{
throw new IllegalArgumentException("illegal blank string!");
}
return newRange(newStart, end);
}
CharsRange trimRight()
{
int newEnd = -1;
for (int i = end - 1; i >= start; i--)
{
if (!Character.isWhitespace(json.charAt(i)))
{
newEnd = i + 1;
break;
}
}
if (newEnd == -1)
{
throw new IllegalArgumentException("illegal blank string!");
}
return newRange(start, newEnd);
}
CharsRange trim()
{
return this.trimLeft().trimRight();
}
char relativeChar(int index)
{
return json.charAt(start + index);
}
public boolean equalsString(String str)
{
return json.regionMatches(true, start, str, 0, str.length());
}
@Override public String toString()
{
return json.subSequence(start, end).toString();
}
}
}

@ -0,0 +1,161 @@
package com.hyweb.n5.eftcore.message;
import java.math.BigDecimal;
import com.hyweb.n5.eftcore.message.utils.Utils;
public class N5Message {
public final static byte STX = 0x02;
public final static byte ETX = 0x03;
private final static int BytesOfLengthIndicator = 2;
//private final static int BytesOfMAC = 32;
private byte[] body;
private byte[] mac;
private boolean isDeviceDisplay;
private final static String DEVICE_DISPLAY_ALIAS = "devicedisplay:";
public N5Message()
{}
public byte[] getBody() {
return body;
}
public void setBody(byte[] body) {
this.body = body;
String tmpStr = new String(body);
if (tmpStr.startsWith(DEVICE_DISPLAY_ALIAS))
isDeviceDisplay = true;
else
isDeviceDisplay = false;
}
public byte[] getMac() {
return mac;
}
public void setMac(byte[] mac) {
this.mac = mac;
}
// private boolean parse(byte[] src)
// {
// int msglength = 0;
//
// if (src.length < (1 + 1 + BytesOfLengthIndicator + BytesOfMAC))
// return false;
// if (src[0] != STX)
// return false;
// if (src[src.length - 1] != ETX)
// return false;
//
// byte[] len = new byte[] { src[1], src[2] };
// String lenStr = Utils.bcd2Str(len);
// msglength = Integer.parseInt(lenStr);
//
// if (src.length != (1 + 1 + msglength + BytesOfLengthIndicator + BytesOfMAC))
// return false;
//
// System.arraycopy(src, 3, body, 0, msglength);
// System.arraycopy(src, src.length - 2 - BytesOfMAC, mac, 0, BytesOfMAC);
// return true;
// }
public boolean isDeviceDisplay() {
return isDeviceDisplay;
}
public byte[] toBytes(){
if (null == body || null == mac)
return null;
byte[] result = new byte[2 + BytesOfLengthIndicator + body.length + mac.length];
byte[] len = Utils.str2Bcd(Utils.addZeroForNum(Integer.toString(body.length), 4));
result[0] = STX;
result[1] = len[0];
result[2] = len[1];
System.arraycopy(body, 0, result, 3, body.length);
System.arraycopy(mac, 0, result, body.length + 3, mac.length);
result[result.length-1] = ETX;
return result;
}
public static String createParamRequestJsonMsg()
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"PARAM\",");
respMsg.append("\"PAYMENT_APP_ID\":\"CC\"}");
return respMsg.toString();
}
public static String createTxnInquiryRequestJsonMsg(String txnId)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"RETRIEVAL\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\"}");
return respMsg.toString();
}
public static String createCardPurchaseRequestJsonMsg(String txnId, BigDecimal txnAmt, BigDecimal tipAmt, String paymentAppId, String qrcValue, boolean ifPrintSS)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"SALE\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\",");
respMsg.append("\"TXN_AMT\":" + txnAmt + ",");
if (null != tipAmt)
respMsg.append("\"TIPS\":" + tipAmt + ",");
respMsg.append("\"PAYMENT_APP_ID\":\"" + paymentAppId + "\",");
if (null != qrcValue)
respMsg.append("\"QRC_VALUE\":\"" + qrcValue + "\",");
respMsg.append("\"PRINT_SS\":" + ifPrintSS + "}");
return respMsg.toString();
}
public static String createCardRefundRequestJsonMsg(String txnId, BigDecimal txnAmt, String paymentAppId, String qrcValue, boolean ifPrintSS)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"REFUND\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\",");
respMsg.append("\"TXN_AMT\":" + txnAmt + ",");
respMsg.append("\"PAYMENT_APP_ID\":\"" + paymentAppId + "\",");
if (null != qrcValue)
respMsg.append("\"QRC_VALUE\":\"" + qrcValue + "\",");
respMsg.append("\"PRINT_SS\":" + ifPrintSS + "}");
return respMsg.toString();
}
public static String createPaymentReversalRequestJsonMsg(String txnId)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"REVERSAL\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\"}");
return respMsg.toString();
}
public static String createSettlementRequestJsonMsg(boolean ifPrintSS)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"SETTLE\",");
respMsg.append("\"PRINT_SS\":" + ifPrintSS + "}");
return respMsg.toString();
}
public static String createCardVoidRequestJsonMsg(String txnId, String paymentAppId, String qrcValue, boolean ifPrintSS)
{
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"VOID\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\",");
respMsg.append("\"PAYMENT_APP_ID\":\"" + paymentAppId + "\",");
if (null != qrcValue)
respMsg.append("\"QRC_VALUE\":\"" + qrcValue + "\",");
respMsg.append("\"PRINT_SS\":" + ifPrintSS + "}");
return respMsg.toString();
}
}

@ -0,0 +1,144 @@
/**
* @author slai
*
* Created Date: Mar 12, 2005
*
* Copyright 2004 Bank of China Credit Card (International) Ltd. All Rights Reserved.
*
* This software is the proprietary information of Bank of China Credit Card (International) Ltd.
* Use is subject to license terms.
*
* Update History:
* Date Author Changes
* Mar 12, 2005 slai Document Created
*/
package com.hyweb.n5.eftcore.message.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/*
* HashUtility.java
*
* Class Description:
*
*/
public class HashUtil {
protected static final int BUFFER_SIZE = 4096;
public static String desToHex(byte[] bytes) {
StringBuffer sb = new StringBuffer("");
for (byte b : bytes) {
String st = String.format("%02X", b);
sb.append(st);
}
return sb.toString();
}
public static String getMD5(byte[] data) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5"); // or SHA(longer)
md.update(data);
return Base64.encodeBytes(md.digest());
} catch (NoSuchAlgorithmException e) {
e.getMessage();
e.printStackTrace();
}
return "";
}
public static String getMD5(File file) {
MessageDigest md = null;
FileInputStream fin = null;
byte[] buffer = new byte[BUFFER_SIZE];
try {
md = MessageDigest.getInstance("MD5"); // or SHA(longer)
fin = new FileInputStream(file);
int n = 0;
while (-1 != (n = fin.read(buffer))) {
md.update(buffer, 0, n);
}
return Base64.encodeBytes(md.digest());
} catch (NoSuchAlgorithmException e) {
e.getMessage();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fin.close();
} catch (Exception e) {
}
}
return "";
}
public static String getMD5(String data) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5"); // or SHA(longer)
md.update(data.getBytes());
return Base64.encodeBytes(md.digest());
} catch (NoSuchAlgorithmException e) {
e.getMessage();
e.printStackTrace();
}
return "";
}
public static byte[] getMD5WithoutBase64(String data) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5"); // or SHA(longer)
md.update(data.getBytes());
return md.digest();
} catch (NoSuchAlgorithmException e) {
e.getMessage();
e.printStackTrace();
}
return new byte[0];
}
public static boolean checkMD5(String input, String digest) {
String base64MD = digest;
String xmlString = input;
/**
* Hash the XML message and get the hash value
*/
String xmlMD = getMD5(xmlString);
/**
* Message Digest Checking
*/
if (!base64MD.equals(xmlMD)) {
return false;
} else
return true;
}
public static String getSHA1(String randomNum) {
String B64 = "";
try {
MessageDigest sha = MessageDigest.getInstance("SHA-1");
sha.reset();
sha.update(randomNum.getBytes());
byte[] pwhash = sha.digest();
B64 = Base64.encodeBytes(pwhash);
} catch (NoSuchAlgorithmException nsae) {
System.out.println(nsae.getMessage());
}
return B64;
}
}

@ -0,0 +1,223 @@
package com.hyweb.n5.eftcore.message.utils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JSONReader {
private static final Object OBJECT_END = new Object();
private static final Object ARRAY_END = new Object();
private static final Object COLON = new Object();
private static final Object COMMA = new Object();
public static final int FIRST = 0;
public static final int CURRENT = 1;
public static final int NEXT = 2;
private static Map<Character, Character> escapes = new HashMap<Character, Character>();
static {
escapes.put(Character.valueOf('"'), Character.valueOf('"'));
escapes.put(Character.valueOf('\\'), Character.valueOf('\\'));
escapes.put(Character.valueOf('/'), Character.valueOf('/'));
escapes.put(Character.valueOf('b'), Character.valueOf('\b'));
escapes.put(Character.valueOf('f'), Character.valueOf('\f'));
escapes.put(Character.valueOf('n'), Character.valueOf('\n'));
escapes.put(Character.valueOf('r'), Character.valueOf('\r'));
escapes.put(Character.valueOf('t'), Character.valueOf('\t'));
}
private CharacterIterator it;
private char c;
private Object token;
private StringBuffer buf = new StringBuffer();
private char next() {
c = it.next();
return c;
}
private void skipWhiteSpace() {
while (Character.isWhitespace(c)) {
next();
}
}
public Object read(CharacterIterator ci, int start) {
it = ci;
switch (start) {
case FIRST:
c = it.first();
break;
case CURRENT:
c = it.current();
break;
case NEXT:
c = it.next();
break;
}
return read();
}
public Object read(CharacterIterator it) {
return read(it, NEXT);
}
public Object read(String string) {
return read(new StringCharacterIterator(string), FIRST);
}
private Object read() {
skipWhiteSpace();
char ch = c;
next();
switch (ch) {
case '"': token = string(); break;
case '[': token = array(); break;
case ']': token = ARRAY_END; break;
case ',': token = COMMA; break;
case '{': token = object(); break;
case '}': token = OBJECT_END; break;
case ':': token = COLON; break;
case 't':
next(); next(); next(); // assumed r-u-e
token = Boolean.TRUE;
break;
case'f':
next(); next(); next(); next(); // assumed a-l-s-e
token = Boolean.FALSE;
break;
case 'n':
next(); next(); next(); // assumed u-l-l
token = null;
break;
default:
c = it.previous();
if (Character.isDigit(c) || c == '-') {
token = number();
}
}
//logger.debug("token: " + token);
System.out.println("token: " + token); // enable this line to see the token stream
return token;
}
private Object object() {
Map<Object, Object> ret = new HashMap<Object, Object>();
Object key = read();
while (token != OBJECT_END) {
read(); // should be a colon
if (token != OBJECT_END) {
ret.put(key, read());
if (read() == COMMA) {
key = read();
}
}
}
return ret;
}
private Object array() {
List<Object> ret = new ArrayList<Object>();
Object value = read();
while (token != ARRAY_END) {
ret.add(value);
if (read() == COMMA) {
value = read();
}
}
return ret;
}
private Object number() {
int length = 0;
boolean isFloatingPoint = false;
buf.setLength(0);
if (c == '-') {
add();
}
length += addDigits();
if (c == '.') {
add();
length += addDigits();
isFloatingPoint = true;
}
if (c == 'e' || c == 'E') {
add();
if (c == '+' || c == '-') {
add();
}
addDigits();
isFloatingPoint = true;
}
String s = buf.toString();
return isFloatingPoint
? (length < 17) ? (Object)Double.valueOf(s) : new BigDecimal(s)
: (length < 19) ? (Object)Long.valueOf(s) : new BigInteger(s);
}
private int addDigits() {
int ret;
for (ret = 0; Character.isDigit(c); ++ret) {
add();
}
return ret;
}
private Object string() {
buf.setLength(0);
while (c != '"') {
if (c == '\\') {
next();
if (c == 'u') {
add(unicode());
} else {
Object value = escapes.get(Character.valueOf(c));
if (value != null) {
add(((Character) value).charValue());
}
}
} else {
add();
}
}
next();
return buf.toString();
}
private void add(char cc) {
buf.append(cc);
next();
}
private void add() {
add(c);
}
private char unicode() {
int value = 0;
for (int i = 0; i < 4; ++i) {
switch (next()) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + c - '0';
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
value = (value << 4) + c - 'k';
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
value = (value << 4) + c - 'K';
break;
}
}
return (char) value;
}
}

@ -0,0 +1,998 @@
package com.hyweb.n5.eftcore.message.utils;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The Class Utils.
*/
public class Utils {
/** The Constant ZERO_PADDING. */
public final static String ZERO_PADDING = "0000000000000000";
private final static String regEx="[\n`~!@#$%^&*()+=|{}':;',\\[\\?~!@#¥%……&*()——+|{}【】‘;:”“’。, 、?]";
/**
* Clear byte array.
*
* @param buffer
* the buffer
* @return
*/
public static String trimChars(String originalStr) {
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(originalStr);
return m.replaceAll("").trim();
}
/**
* Clear byte array.
*
* @param buffer
* the buffer
*/
public static void clearByteArray(final byte[] buffer) {
int i = 0;
final int length = buffer.length;
for (; i < length; i++) {
buffer[i] = (byte) 0;
}
}
/**
* To hex string.
*
* @param data
* the data
* @param length
* the length
* @return the string
*/
public static String toHexString(final byte[] data, final int length) {
final String digits = "0123456789ABCDEF";
final StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
final int b = data[i];
char c = digits.charAt((b >> 4) & 0xf);
sb.append(c);
c = digits.charAt(b & 0xf);
sb.append(c);
}
return sb.toString();
}
/**
* BC darray to string.
*
* @param data
* the data
* @param offset
* the offset
* @param length
* the length
* @return the string
*/
public static String BCDarrayToString(final byte[] data, final int offset,
final int length) {
String s = "";
byte hi;
byte lo;
Integer hiInteger;
Integer loInteger;
boolean maskZeros = true;
if ((offset >= data.length) || (offset + length > data.length)) {
throw new ArrayIndexOutOfBoundsException();
}
for (int i = offset; i < (offset + length); i++) {
hi = (byte) ((data[i] >>> 4) & 0xF);
lo = (byte) (data[i] & 0xF);
if (hi > 9 || lo > 9)
throw new IllegalArgumentException();
hiInteger = new Integer(hi);
loInteger = new Integer(lo);
if (!maskZeros || (hi != 0)) {
maskZeros = false;
s = s + hiInteger.toString();
}
if (!maskZeros || (lo != 0)) {
maskZeros = false;
s = s + loInteger.toString();
}
if (i == (offset + length - 2)) {
s = s + ".";
maskZeros = false;
}
}
if ((s.equalsIgnoreCase("")) || (s.charAt(0) == '.'))
s = "0" + s;
return s;
}
/**
* Encode byte array.
*
* @param s
* the s
* @return the byte[]
*/
public static byte[] encodeByteArray(final byte[] s) {
int i = 0, j = 0;
final int originalLength = s.length;
final int max = s.length - (originalLength % 2);
final byte[] buf = new byte[(originalLength + (originalLength % 2)) / 2];
if (originalLength % 2 == 1) {
buf[j++] = (byte) ((s[i++] - '0'));
}
while (i < max) {
buf[j++] = (byte) ((((s[i++] - '0') << 4) | (s[i++] - '0')));
}
return buf;
}
// public static byte[] encodeBCDString(String s) {
// int i = 0, j = 0;
// int max = s.length() - (s.length() % 2);
// byte[] buf = new byte[(s.length() + (s.length() % 2)) / 2];
// while (i < max) {
// buf[j++] = (byte) ((((s.charAt(i++) - '0') << 4) | (s.charAt(i++) -
// '0')));
// }
// if ((s.length() % 2) == 1) { // If odd, add pad char
// buf[j] = (byte) ((s.charAt(i++) - '0') << 4 | 0x0A);
// }
// return buf;
// }
/** Hexadecimal string prefix. */
private static final String HEX_PREFIX = "0x";
/**
* Returns the entire array as a hexadecimal string that starts with the
* prefix '0x'.
*
* @param data
* bytes to be converted into a hex string
* @return a hexadecimal string.
*/
public static String getAsHexString(final byte[] data) {
return getAsHexString(data, false);
}
/**
* Make short.
*
* @param byte1
* the byte1
* @param byte2
* the byte2
* @return the short
*/
public static short makeShort(final byte byte1, final byte byte2) {
short tmp = (short) (0x00FF & byte1);
tmp = (short) ((0x00ff & tmp) << 8);
short tmp2 = (short) (0x00FF & byte2);
return (short) (tmp | tmp2);
}
/**
* Returns the entire array as a hexadecimal string.
*
* @param data
* bytes to be converted into a hex string
* @param prefix
* if true then string will start with '0x'
* @return a hexadecimal string.
*/
public static final String getAsHexString(final byte[] data,
final boolean prefix) {
return getAsHexString(data, 0, data.length, prefix);
}
// public static final String getAsHexString(int value, int npad)
// {
// String s = getAsHexString(value, false);
// int need = npad - s.length();
// if((need <= 0) || (need > ZERO_PADDING.length())) return s;
// return ZERO_PADDING.substring(0, need) + s;
// }
/**
* Returns the given integer as a hexadecimal string that starts with the
* prefix '0x'.
*
* @param value
* the integer value.
* @param prefix
* the prefix
* @return a hexadecimal string.
*/
// public static final String getAsHexString(int value) {
// return getAsHexString(value, true);
// }
/**
* Returns the given integer as a hexadecimal string.
*
* @param value
* the integer value.
* @param prefix
* prefix if true then string will start with '0x'
* @return a hexadecimal string.
*/
public static final String getAsHexString(final int value,
final boolean prefix) {
return (prefix ? HEX_PREFIX : "") + Integer.toHexString(value);
}
/**
* Checks if the given value falls into the unsigned short value range
* (0-65535). This range is used when defining block numbers and amounts in
* the read and write requests.
*
* @param data
* the data
* @param offset
* the offset
* @param len
* the len
* @return the as hex string
*/
// public static final boolean isShort(int value) {
// return (value >= 0 && value <= 65535);
// }
/**
* Returns the given byte value as a hexadecimal string.
*
* @param b
* the byte value
* @param prefix
* prefix if true then string will start with '0x'
* @return a hexadecimal string.
*/
// public static final String getAsHexString(byte b, boolean prefix) {
// StringBuffer sb = new StringBuffer();
//
// if (prefix) {
// sb.append(HEX_PREFIX);
// }
//
// appendByte(b, sb);
// return sb.toString();
// }
/**
* Returns the given byte array as a hexadecimal string without splitting it
* to multiple lines. The returned string will start with the prefix '0x'.
*
* @param data
* bytes to be converted into a hex string
* @param offset
* offset into the data array
* @param len
* maximum length to be read starting from offset (will stop at
* array end if too big)
* @return a hexadecimal string.
*/
public static final String getAsHexString(final byte[] data,
final int offset, final int len) {
return getAsHexString(data, offset, len, false);
}
/**
* Returns the given byte array as a hexadecimal string without splitting it
* to multiple lines.
*
* @param data
* bytes to be converted into a hex string
* @param offset
* offset into the data array
* @param len
* maximum length to be read starting from offset (will stop at
* array end if too big)
* @param prefix
* if true then string will start with '0x'
* @return a hexadecimal string.
*/
public static final String getAsHexString(final byte[] data,
final int offset, int len, final boolean prefix) {
final StringBuffer sb = new StringBuffer();
if (offset + len > data.length) {
len = data.length - offset;
}
for (int i = offset; i < offset + len; i++) {
final byte b = data[i];
appendByte(b, sb);
}
return sb.toString();
}
/**
* Returns the given byte array as a hexadecimal string that is split into
* lines of 16 bytes. Each line starts with a offset number.
*
* @param hexString
* the hex string
* @return the byte[]
*/
// public static final String getAsHexStringL(byte[] data) {
// return getAsHexStringL(data, 16, true);
// }
/**
* Returns the given byte array as a hexadecimal string that is split into
* lines of arbitrary number of bytes.
*
* @param perLine
* how many bytes there should be per line.
* @param showAddr
* if true then displays byte index in the beginning of lines.
* @return given bytes as a hexadecimal string.
*/
// public static final String getAsHexStringL(byte[] data, int perLine,
// boolean showAddr) {
// StringBuffer sb = new StringBuffer();
// int count = 0;
// appendAddress(count, sb);
//
// for (int i = 0; i < data.length; i++) {
// appendByte(data[i], sb);
//
// if (i < (data.length - 1)) {
// count++;
//
// if ((count % perLine) == 0) {
// sb.append('\n');
//
// if (showAddr) {
// appendAddress(count, sb);
// }
//
// } else {
// sb.append(' ');
// }
//
// }
//
// }
//
// return sb.toString();
// }
public static String str2HexStr(String str)
{
char[] chars = "0123456789ABCDEF".toCharArray();
StringBuilder sb = new StringBuilder("");
byte[] bs = str.getBytes();
int bit;
for (int i = 0; i < bs.length; i++)
{
bit = (bs[i] & 0x0f0) >> 4;
sb.append(chars[bit]);
bit = bs[i] & 0x0f;
sb.append(chars[bit]);
//sb.append(' ');
}
return sb.toString().trim();
}
/**
* Constructs a byte array from the given hexadecimal string. The string may
* begin with the prefix '0x'.
*
* @param hexString
* the hexadecimal string.
* @return a byte array. Never <code>null</code>.
*
* @throws NumberFormatException
* if the string has invalid characters.
*/
public static final byte[] readHexString(String hexString) {
if (hexString == null || hexString.length() == 0
|| hexString.equals(HEX_PREFIX)) {
return new byte[] {};
} else {
if (hexString.startsWith(HEX_PREFIX)) {
hexString = hexString.substring(2);
}
final byte[] data = new byte[hexString.length() / 2];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (Integer.parseInt(
hexString.substring(i * 2, i * 2 + 2), 16) & 0xFF);
}
return data;
}
}
/**
* Appends a address (array offset) to the given string.
*
* @param byteValue
* the byte value
* @param sb
* the sb
*/
// private static final void appendAddress(int addr, StringBuffer sb) {
// appendByte(addr, sb);
// sb.append("-: ");
// }
/**
* Appends a byte to the given string.
*/
private static final void appendByte(final int byteValue,
final StringBuffer sb) {
final String bStr = Integer.toHexString(byteValue & 0xFF);
if (bStr.length() < 2) {
sb.append('0');
}
sb.append(bStr);
}
/**
* Reads an (signed) integer from the given byte array starting at the
* specified array index.
*
* @param data
* byte array containing the 4 integer bytes.
* @param offset
* beginning of the integer value in the array.
* @param littleEndian
* true if little endian byte order is used. If false then the
* integer is read using big endian.
* @return the read integer value.
*/
// public static final int readInt(byte[] data, int offset, boolean
// littleEndian) {
//
// int tmpLength = (data.length - offset);
// if( tmpLength < 4) {
// byte[] tmpBuffer = {(byte)0, (byte)0, (byte)0, (byte)0};
// System.arraycopy(data, 0, tmpBuffer, (4 - tmpLength), tmpLength);
// data = tmpBuffer;
// }
// if (littleEndian) {
// return (((data[offset + 3] & 0xff) << 24) |
// ((data[offset + 2] & 0xff) << 16) |
// ((data[offset + 1] & 0xff) << 8) |
// (data[offset + 0] & 0xff));
// } else {
// return (((data[offset + 0] & 0xff) << 24) |
// ((data[offset + 1] & 0xff) << 16) |
// ((data[offset + 2] & 0xff) << 8) |
// (data[offset + 3] & 0xff));
// }
// }
/**
* Reads an integer from the given byte array starting at the specified
* array index using big endian byte order.
*
* @return the read integer value.
*/
// public static final int readInt(byte[] data, int offset) {
// return readInt(data, offset, false);
// }
/**
* Reads a (signed) short integer from the byte array.
*
* @param data
* byte array containing the 2 integer bytes.
* @param offset
* beginning of the short integer value in the array.
* @param littleEndian
* true if little endian byte order is used. If false then the
* integer is read using big endian.
* @return the read short integer value.
*/
public static final int readShort(final byte[] data, final int offset,
final boolean littleEndian) {
if (littleEndian) {
return ((data[offset + 1] << 8) | (data[offset] & 0xFF)) & 0xFFFF;
} else {
return ((data[offset] << 8) | (data[offset + 1] & 0xFF)) & 0xFFFF;
}
}
/**
* Reads a (signed) short integer from the byte array using big endian byte
* order.
*
* @param data
* the data
* @param offset
* the offset
* @return the short
*/
public static final short readShort(final byte[] data, final int offset) {
return (short) (readShort(data, offset, false));
}
/**
* Writes a short integer (2B) to the byte array.
*
* @param aArray
* the a array
* @param aOffset
* the a offset
* @param bArray
* the b array
* @param bOffset
* the b offset
* @param length
* the length
* @return true, if successful
*/
// public static final void writeShort(byte[] data, int offset, int value,
// boolean littleEndian) {
//
// if (littleEndian) {
// data[offset + 1] = (byte)((value >> 8) & 0xFF);
// data[offset + 0] = (byte)(value & 0xFF);
// } else {
// data[offset + 0] = (byte)((value >> 8) & 0xFF);
// data[offset + 1] = (byte)(value & 0xFF);
// }
// }
/**
* Writes a short integer (2B) to the byte array using big endian byte
* order.
*/
// public static final void writeShort(byte[] data, int offset, int value) {
// writeShort(data, offset, value, false);
// }
/**
* Writes a integer (4B) to the byte array.
*
* @param data
* a byte array.
* @param offset
* defines the offset of the integer in the array.
* @param value
* the value to be written.
* @param littleEndian
* if true then little endianness is used. Otherwise big endian.
*/
// public static final void writeInt(byte[] data, int offset, long value,
// boolean littleEndian) {
//
// if (littleEndian) {
// data[offset + 3] = (byte)((value >> 24) & 0xFF);
// data[offset + 2] = (byte)((value >> 16) & 0xFF);
// data[offset + 1] = (byte)((value >> 8) & 0xFF);
// data[offset + 0] = (byte)(value & 0xFF);
// } else {
// data[offset + 0] = (byte)((value >> 24) & 0xFF);
// data[offset + 1] = (byte)((value >> 16) & 0xFF);
// data[offset + 2] = (byte)((value >> 8) & 0xFF);
// data[offset + 3] = (byte)(value & 0xFF);
// }
// }
/**
* Writes a integer (4B) to the byte array using big endian byte order.
*/
// public static final void writeInt(byte[] data, int offset, long value) {
// writeInt(data, offset, value, false);
// }
/**
* Returns a copy of the given byte array.
*/
// public static final byte[] arrayCopy(byte[] src) {
//
// if (src == null) {
// return null;
// } else {
// byte[] ret = new byte[src.length];
// System.arraycopy(src, 0, ret, 0, src.length);
// return ret;
// }
// }
/**
* Compare two byte arrays.
*
* @param aArray
* the a array
* @param aOffset
* the a offset
* @param bArray
* the b array
* @param bOffset
* the b offset
* @param length
* the length
* @return true, if successful
*/
public static final boolean arrayCompare(final byte[] aArray,
final int aOffset, final byte[] bArray, final int bOffset,
final int length) {
if ((aOffset + length > aArray.length)
|| (bOffset + length > bArray.length)) {
return false;
}
for (int index = 0; index < length; index++) {
if (aArray[aOffset + index] != bArray[bOffset + index]) {
return false;
}
}
return true;
}
/**
* Returns true if the two given byte arrays have matching content or if
* they both are <code>null</code>.
*
* @param a
* the a
* @param b
* the b
* @param aOffset
* defines where to start comparing bytes in the <code>a</code>
* array.
* @param bOffset
* defines where to start comparing bytes in the <code>b</code>
* array.
* @param len
* defines how many bytes should be compared.
* @return true, if successful
*/
public static final boolean equals(final byte[] a, final byte[] b,
final int aOffset, final int bOffset, final int len) {
if (a == null && b == null) {
return true;
} else if (a != null && b != null && (aOffset + len) <= a.length
&& (bOffset + len) <= b.length) {
for (int i = 0; i < len; i++) {
if (a[aOffset + i] != b[bOffset + i]) {
return false;
}
}
return true;
} else {
return false;
}
}
/**
* Returns true if the two given byte arrays are equal in length and in
* their contents match, or if they both are <code>null</code>.
*
* @param a
* the a
* @param b
* the b
* @return true, if successful
*/
public static final boolean equals(final byte[] a, final byte[] b) {
if (a == null && b == null) {
return true;
} else if (a != null && b != null && a.length == b.length) {
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
} else {
return false;
}
}
public static boolean isNumeric(String str){
Pattern pattern = Pattern.compile("[0-9]*");
return pattern.matcher(str).matches();
}
public static String fill(String input, int size, char symbol) {
while (input.length() < size) {
input = input + symbol;
}
return input;
}
public static String fillbyRight(String input, int size, char symbol) {
while (input.length() < size) {
input = symbol + input;
}
return input;
}
/**
* Compares two sets of bytes. Both sets are in the given byte array at
* specified indices. No bounds checking is done for the parameters.
*
* @param tag
* the tag
* @param buffer
* the buffer
* @param offset
* the offset
* @param length
* the length
* @return <code>true</code> if the two sets are equal.
* @throws CardException
* the card exception
*/
// public static final boolean byteEquals(byte[] bytes, int aOffset, int
// bOffset, int len, boolean inverted) {
//
// for (int i = 0; i < len; i++) {
// if ((inverted && bytes[aOffset + i] != (~bytes[bOffset + i])) ||
// (!inverted && (bytes[aOffset + i] != bytes[bOffset + i])))
// {
// return false;
// }
// }
//
// return true;
// }
// public static byte getByteValue(byte[] buffer, int bitoffset, int length)
// {
// int offset = bitoffset/8;
// int inbitoffset = bitoffset%8;
// int short_value = ((buffer[offset]<<8)+(0x00FF&buffer[offset+1]));
// short return_value = (short)(((byte)( short_value>>>(8-inbitoffset))));
// return_value &= (0x00ff);
//
// byte ret = (byte) ((return_value)>>>(8-length));
//
// return ret;
// }
public static int findTag(final byte tag, final byte[] buffer,
final int offset, final int length) throws RuntimeException {
for (int i = 0; i < length; i++) {
if (buffer[offset + i] == tag) {
return (offset + i);
}
}
throw new RuntimeException();
}
/**
* Find tag.
*
* @param tag
* the tag
* @param buffer
* the buffer
* @param offset
* the offset
* @param length
* the length
* @return the int
* @throws CardException
* the card exception
*/
public static int findTag(final short tag, final byte[] buffer,
final int offset, final int length) throws RuntimeException {
for (int i = 0; i < length; i++) {
if (readShort(buffer, (offset + i)) == tag) {
return (offset + i);
}
}
throw new RuntimeException();
}
// public static String getValueAsString(byte[] buffer, int tagOffset, int
// length) throws CardException {
//
// int tmpLength = buffer[tagOffset+1];
// // If the buffer size is too short to contain the whole value
// if((length-2) < tmpLength)
// throw new CardException();
// else {
// byte[] tmpBuffer = new byte[tmpLength];
// System.arraycopy(buffer, tagOffset+2, tmpBuffer, 0, tmpLength);
// return new String(tmpBuffer);
// }
// }
// public static byte[] getValueasByteArray(byte[] buffer, int tagOffset,
// int length) throws CardException {
//
// int tmpLength = buffer[tagOffset+1];
// // If the buffer size is too short to contain the whole value
// if((length-2) < tmpLength)
// throw new CardException();
// else {
// byte[] tmpBuffer = new byte[tmpLength];
// System.arraycopy(buffer, tagOffset+2, tmpBuffer, 0, tmpLength);
// return tmpBuffer;
// }
// }
// public static int getInt24Value(byte[]buffer, int bitoffset){
//
// int value ;
// value = getByteValue(buffer, bitoffset+16,8 )&0x00FF;
//
// value += (getByteValue (buffer, bitoffset+8, 8)<< 8 ) &0x00FF;
//
// value += (getByteValue (buffer, bitoffset+0, 8)<< 16 ) &0x00FF;
//
// return value;
// }
// public static int lastIndexOf(String input, String str){
// int index = -1;
// int tempIndex = 0;
// while(tempIndex != -1){
// tempIndex = input.indexOf(str, index + 1);
// if(tempIndex != -1){
// index = tempIndex;
// }
// }
// return index;
// }
// public static int countIndexOf(String input, char c){
// int lastIndex = 0;
// int count = 0;
//
// while(lastIndex != -1){
//
// lastIndex = input.indexOf(c,lastIndex + 1);
//
// if( lastIndex != -1){
// count ++;
// }
// }
// return count;
// }
public static String unPadLeft(String s, char c)
{
if(s.trim().length() == 0 && c == ' ')
return Character.toString(c);
if(s.trim().length() == 0)
return s;
String sTrim = s.trim();
int fill = 0;
int end;
for(end = sTrim.length(); fill < end && sTrim.charAt(fill) == c; fill++);
return fill >= end ? sTrim.substring(fill - 1, end) : sTrim.substring(fill, end);
}
public static String addCharForNum(String str, int strLength) {
int strLen = str.length();
if (strLen < strLength) {
while (strLen < strLength) {
StringBuffer sb = new StringBuffer();
//sb.append("F").append(str);
sb.append(str).append("F");
str = sb.toString();
strLen = str.length();
}
}
return str;
}
public static String hexify (byte bytes[]) {
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
StringBuffer buf = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; ++i) {
buf.append(hexDigits[(bytes[i] & 0xf0) >> 4]);
buf.append(hexDigits[bytes[i] & 0x0f]);
}
return buf.toString();
}
public static String addZeroForNum(String str, int strLength) {
int strLen = str.length();
StringBuffer sb = null;
while (strLen < strLength) {
sb = new StringBuffer();
sb.append("0").append(str);// 左补0
// sb.append(str).append("0");//<EFBFBD>?<EFBFBD>补0
str = sb.toString();
strLen = str.length();
}
return str;
}
/**
* @功能: BCD<EFBFBD>?转为10进制串
* @<EFBFBD>?<EFBFBD>: BCD<EFBFBD>?
* @结果: 10进制串
*/
public static String bcd2Str(byte[] bytes) {
StringBuffer temp = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
int h = ((bytes[i] & 0xff) >> 4) + 48;
temp.append((char) h);
int l = ((bytes[i] & 0x0f)) + 48;
temp.append((char) l);
}
return temp.toString();
}
/**
* @功能: 10进制串转为BCD<EFBFBD>?
* @<EFBFBD>?<EFBFBD>: 10进制串
* @结果: BCD<EFBFBD>?
*/
public static byte[] str2Bcd(String s) {
if (s.length() % 2 != 0) {
s = "0" + s;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
char[] cs = s.toCharArray();
for (int i = 0; i < cs.length; i += 2) {
int h = cs[i] - 48;
int l = cs[i + 1] - 48;
baos.write(h << 4 | l);
}
return baos.toByteArray();
}
public static Map<?,?> jsonList2Map(List<?> jsonList)
{
Map<String,String> resultMap = new HashMap<String, String>();
for (int i = 0; i<jsonList.size(); i++)
{
String tmpStr = (String) jsonList.get(i);
String key = tmpStr.split("=")[0];
String value = tmpStr.split("=")[1];
resultMap.put(key, value);
}
return resultMap;
}
}

@ -0,0 +1,227 @@
package com.hyweb.n5.eftcore.test;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class testPackReqMsg {
private final static int twepoch = 25771200;// 1546272000000L/1000/60;
/** 序列在id中占的位数 */
private final static long sequenceBits = 7L;
/** 时间截向左移7位 */
private final static long timestampLeftShift = sequenceBits;
/** 生成序列的掩码,这里为127 */
private final static int sequenceMask = -1 ^ (-1 << sequenceBits);
/** 分钟内序列(0~127) */
private static int sequence = 0;
private static int laterSequence = 0;
/** 上次生成ID的时间戳 */
private static int lastTimestamp = -1;
private final static MinuteCounter counter = new MinuteCounter();
/** 预支时间标志位 */
static boolean isAdvance = false;
public static String getTxnId() {
StringBuffer txnId = new StringBuffer();
Date date = Date.from(Instant.now());
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
txnId.append(sdf.format(date));
Random random = new Random(date.getTime());
for(int i=0; i<3; i++){
int r = random.nextInt(10);
txnId.append(r);
}
return txnId.toString();
}
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
public static synchronized int nextId() {
int timestamp = timeGen();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if(timestamp > counter.get()) {
counter.set(timestamp);
isAdvance = false;
}
// 如果是同一时间生成的,则进行分钟内序列
if (lastTimestamp == timestamp || isAdvance) {
if(!isAdvance) {
sequence = (sequence + 1) & sequenceMask;
}
// 分钟内自增列溢出
if (sequence == 0) {
// 预支下一个分钟,获得新的时间戳
isAdvance = true;
int laterTimestamp = counter.get();
if (laterSequence == 0) {
laterTimestamp = counter.incrementAndGet();
}
int nextId = ((laterTimestamp - twepoch) << timestampLeftShift) //
| laterSequence;
laterSequence = (laterSequence + 1) & sequenceMask;
return nextId;
}
}
// 时间戳改变,分钟内序列重置
else {
sequence = 0;
laterSequence = 0;
}
// 上次生成ID的时间截
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成32位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| sequence;
}
/**
* 返回以分钟为单位的当前时间
*
* @return 当前时间(分钟)
*/
protected static int timeGen() {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
return Integer.valueOf(timestamp);
}
private static String formatedLine(String lstr,String rstr)
{
int lLen = lstr.length();
int rLen = rstr.length();
int spLen = 60 - lLen - rLen;
rstr = String.format("%"+Integer.toString(spLen + rLen)+"s", rstr);
return lstr + rstr;
}
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
formatedLine("1234","5678");
System.out.println(Instant.now() +"str:" + sdf.format(Date.from(Instant.now())));
System.out.println(sdf.format(new Date()));
System.out.println(System.currentTimeMillis() + "str:" + sdf.format(new Date(System.currentTimeMillis())));
System.out.println("0, " +Thread.currentThread().getId());
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
Thread3 thread3 = new Thread3();
System.out.println("1, " +thread1.getId());
System.out.println("2, " +thread2.getId());
System.out.println("3, " +thread3.getId());
//thread1.run();
//thread2.run();
//thread3.run();
for (int i = 0 ; i < 1000000000 ; i++)
{
System.out.println(i +", " + testPackReqMsg.getTxnId());
}
/*// TODO Auto-generated method stub
String txnId = "20190124164613768351";
String macKey = "0EAEA18F7A46B9C8765B3DB313267C75";
BigDecimal txnAmt = new BigDecimal(13.35);
boolean ifPrintSS = false;
BigDecimal tipAmt = null;
String paymentAppId = "";
String qrcValue = null;
StringBuffer respMsg = new StringBuffer();
respMsg.append("{\"EVENT_NAME\":\"SALE\",");
respMsg.append("\"TXN_ID\":\"" + txnId + "\",");
respMsg.append("\"TXN_AMT\":" + txnAmt + ",");
if (null != tipAmt)
respMsg.append("\"TIPS\":" + tipAmt + ",");
respMsg.append("\"PAYMENT_APP_ID\":\"" + paymentAppId + "\",");
if (null != qrcValue)
respMsg.append("\"QRC_VALUE\":\"" + qrcValue + "\",");
respMsg.append("\"PRINT_SS\":" + ifPrintSS + "}");
//{"EVENT_NAME":"SALE","TXN_ID":"20190124164613768351","TXN_AMT":13.35,"PAYMENT_APP_ID":"","PRINT_SS":false}
byte[] macMD5Hash = HashUtil.getMD5WithoutBase64(respMsg.toString() + '&' + macKey);
String macMD5Hex = Utils.toHexString(macMD5Hash, macMD5Hash.length);
N5Message requestMsg = new N5Message();
try {
requestMsg.setBody(respMsg.toString().getBytes("UTF-8"));
requestMsg.setMac(Utils.readHexString(macMD5Hex));
byte[] finalRequestMsg = requestMsg.toBytes();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
*/
}
}
class MinuteCounter {
private static final int MASK = 0x7FFFFFFF;
private final AtomicInteger atom;
public MinuteCounter() {
atom = new AtomicInteger(0);
}
public final int incrementAndGet() {
return atom.incrementAndGet() & MASK;
}
public int get() {
return atom.get() & MASK;
}
public void set(int newValue) {
atom.set(newValue & MASK);
}
}
class Thread1 extends Thread{
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("1, " +sdf.format(new Date()));
System.out.println("1*" + System.currentTimeMillis());
System.out.println("1#" + testPackReqMsg.nextId());
}
}
class Thread2 extends Thread{
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("2, " +sdf.format(new Date()));
System.out.println("2*" + System.currentTimeMillis());
System.out.println("2#" + testPackReqMsg.nextId());
}
}
class Thread3 extends Thread{
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("3, " +sdf.format(new Date()));
System.out.println("3*" + System.currentTimeMillis());
System.out.println("3#" + testPackReqMsg.nextId());
}
}
Loading…
Cancel
Save