JPOS unpacking running example - iso8583

I'm trying to use the JPOS library to pack/unpack ISO8583-1987 messages.
I have a problem with the format, and i can't find any running example on the internet.
Could someone give me a running example of Unpacking a hexadecimal message, because there is a lot of examples with ASCII message, but this is not what i need.
Thank you all for your time & attention
Julien

I'm assuming you have the hex string representing the message in a String, in that case you have to convert it into a byte array.
For example assuming you have the string as an argument to your main. Anyhow you have to know the format of the iso message contained in that hex representation. For example if the message is binary you have to choose ISO87BPackager, if it is ascii you have to choose ISO87APackager.
import org.jpos.iso.packager.ISO87BPackager;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOUtil;
public class ParseISOMsg {
public static void main(String[] args) throws ISOException {
String hexmsg = args[0];
// convert hex string to byte array
byte[] bmsg =ISOUtil.hex2byte(hexmsg);
ISOMsg m = new ISOMsg();
// set packager, change ISO87BPackager for the matching one.
m.setPackager(new ISO87BPackager());
//unpack the message using the packager
m.unpack(bmsg);
//dump the message to standar output
m.dump(System.out, "");
}
}
For example if you call java -cp .:jpos.jar ParseISOMsg 080000200000008000001234563132333435363738 it should print:
<isomsg>
<!-- org.jpos.iso.packager.ISO87BPackager -->
<field id="0" value="0800"/>
<field id="11" value="123456"/>
<field id="41" value="12345678"/>
</isomsg>

Related

Base64 string to pdf in groovy

I am new to groovy and to this forum.
I am using a middleware tool(SAP CPI) where I am getting a pdf in base64 string format. I need to send the pdf to another system.
This is what I did:
Store the Base64 input in a string.
Pass it through a Base64 Decoder(this is an inbuilt function)
Use below code and pass the base64 string as an input to "body":
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message){
def body = message.getBody(String.class);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
outputStream.write(body.getBytes())
message.setBody(outputStream.toString())
return message;
}
what I get as an output looks something like below:
%PDF-1.7
%????
5 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
endobj
14 0 obj
<</Title(T....
and so on..
Now when I save this output as a pdf file, it is either blank or it says "There was an error opening this document. The file is damaged and could not be repaired."
What am I doing wrong? Thanks in advance!
Note: Due to limitation of the middleware, I cannot create a whole project, but will rather have to use processData() function and can manipulate the string inside it. Thanks!

Get Jackson XMLMapper to read root element name

How do I get Jackson's XMLMapper to read the name of the root xml element when deserializing?
I am deserializing input XML to generic Java class, LinkedHashMap and then to JSON. I want to dynamically read the root element of input XML on deserialization to LinkedHashMap.
Code
XmlMapper xmlMapper = new XmlMapper();
Map entries = xmlMapper.readValue(new File("source.xml"), LinkedHashMap.class);
ObjectMapper jsonMapper = new ObjectMapper();
String json = jsonMapper.writer().writeValueAsString(entries);
System.out.println(json);
Input XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<File>
<NumLeases>1</NumLeases>
<NEDOCO>18738</NEDOCO>
<NWUNIT>0004</NWUNIT>
<FLAG>SUCCESS</FLAG>
<MESSAGE>Test Upload</MESSAGE>
<Lease>
<LeaseVersion>1</LeaseVersion>
<F1501B>
<NEDOCO>18738</NEDOCO>
<NWUNIT>0004</NWUNIT>
<NTRUSTRECORDKEY>12</NTRUSTRECORDKEY>
</F1501B>
</Lease>
</File>
Actual Output
{"NumLeases":"1","NEDOCO":"18738","NWUNIT":"0004","FLAG":"SUCCESS","MESSAGE":"Test Upload","Lease":{"LeaseVersion":"1","F1501B":{"NEDOCO":"18738","NWUNIT":"0004","NTRUSTRECORDKEY":"12"}}}
Expected Output (Note: There is a root element named "File" present in JSON)
{"File":{"NumLeases":"1","NEDOCO":"18738","NWUNIT":"0004","FLAG":"SUCCESS","MESSAGE":"Test Upload","Lease":{"LeaseVersion":"1","F1501B":{"NEDOCO":"18738","NWUNIT":"0004","NTRUSTRECORDKEY":"12"}}}}
There's probably some switch somewhere to set it. Any help shall be appreciated.
Sadly there is no flag for that. It can be done with a custom implementation of com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer. (Jackson How-To: Custom Deserializers):
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
import java.io.File;
import java.io.IOException;
//...
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(new SimpleModule().addDeserializer(JsonNode.class,
new JsonNodeDeserializer() {
#Override
public JsonNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String rootName = ((FromXmlParser)p).getStaxReader().getLocalName();
return ctxt.getNodeFactory()
.objectNode().set(rootName, super.deserialize(p, ctxt));
}
}));
JsonNode entries = xmlMapper.readTree(new File("source.xml"));
System.out.println(entries);
The accepted answer works for Jackson 2.10.* (and older probably), but not for any of the newer versions (might get fixed in 2.14 - source).
What worked for me:
public class CustomJsonNodeDeserializer extends JsonNodeDeserializer {
#Override
public JsonNode deserialize(JsonParser p, DeserializationContext context) throws IOException {
//first deserialize
JsonNode rootNode = super.deserialize(p, context);
//then get the root name
String rootName = ((FromXmlParser)p).getStaxReader().getLocalName();
return context.getNodeFactory().objectNode().set(rootName, rootNode);
}
}
I will update my answer if there's a new better solution.
While this Question has an accepted answer, I found that it doesn't work on the latest Jackson version 2.13.2 and uses flawed approach anyway.
new SimpleModule().addDeserializer(JsonNode.class,
new JsonNodeDeserializer() {
#Override
public JsonNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String rootName = ((FromXmlParser)p).getStaxReader().getLocalName();
return ctxt.getNodeFactory()
.objectNode().set(rootName, super.deserialize(p, ctxt));
}
}));
The .getLocalName() call will return the name of the first child element, not the actual root of the parsed input. Also, fetching just the name of the element ignores the attributes, so you'll end up with just a duplicated tag name in your output.
What to do instead?
After trying a number of workarounds, I've found only one that works properly. You have to let Jackson do its root node removal and fool it with a dummy wrapper tag.
JsonNode jsonNode = XML_MAPPER.readTree("<tag>" + nestedXmlString + "</tag>");
This will wrap the XML with a dummy <tag> which is then immediately removed and forgotten.
Then, you can work with the output tree as usual:
toXmlGenerator.writeTree(jsonNode);
Caution
However, please be aware that if your XML input String contains the XML Header declaration (<?xml...), then wrapping it with a dummy tag will result in a parsing exception. To avoid this, you'll have to first remove the declaration string from the input:
String nestedXmlString = input;
if (nestedXmlString.startsWith("<?xml")) {
nestedXmlString = nestedXmlString.substring(nestedXmlString.indexOf("?>") + 2);
}

Parsing Request Payload string

can anyone help me in parsing data from Request Payload string like following one:
7|0|5|https://www.bosscapital.com/app/Basic/|B8CC86B6E3BFEAF758DE5845F8EBEA08|com.optionfair.client.common.services.TradingService|getAssetDailyTicks|J|1|2|3|4|2|5|5|CB|U9mc4GQ|
Thanks & Regards
Ajay
You can call the Split() method on strings to split them at a certain character. Alternatively, you can use Regex.Split(value, "<pattern>"); for splitting, e.g. if you have multiple characters you want to split at. <pattern> is a string here, so you can provide more than one character (e.g. "\r\n" to find line breaks).
using System;
class Program {
static void Main() {
string s = "7|0|5|https://www.bosscapital.com/app/Basic/|B8CC86B6E3BFEAF758DE5845F8EBEA08|com.optionfair.client.common.services.TradingService|getAssetDailyTicks|J|1|2|3|4|2|5|5|CB|U9mc4GQ|";
// Split string at pipe character
string[] parts = s.Split('|');
// Process segments
foreach (string segment in parts) {
Console.WriteLine(segment);
// Use the segmented data...
}
}
}

Writing Contents with Header using BeanIO

I am trying to write some contents from one csv file to another csv file using BeanIO. I am able to get the contents but the header is not writing to destination file. I don know how to fix this. Please some one help me on this. Following is the code
StreamFactory factory = StreamFactory.newInstance();
factory.load("config" + File.separatorChar
+ CSVMain.prop.getProperty("ordersmapping"));
orderWriter = factory.createWriter("salesOrder", new File(property));
for (int i = 0; i < orders.size(); i++) {
orderWriter.write(orders.get(i));
}
orderWriter.flush();
orderWriter.close();
the code is written inside a method. And I also want to remove the carriage return(\r) from the output.
Thanks in advance.
I got the answer from the Google Groups thread which utilizes a class for the header and then sets the fields to ignore, basically overriding. I did not want to create a dedicated class so instead I re-used the map class as follows:
<stream name="XYZ" format="csv">
<parser>
<property name="alwaysQuote" value="true" />
</parser>
<record name="header" class="map" order="1" minOccurs="1" maxOccurs="1">
<field name="Name" default="Name" ignore="true"/>
<field name="Surname" default="Surname" ignore="
</record>
<record name="record" class="map" order="2">
<field name="Name"/>
<field name="Surname"/>
</record>
</stream>
You may use the this util method to easily create a Header without any additional class or XML configuration.
public static void main(String[] args) {
final String factoryName = "comma delimited csv factory";
final String headerName = "CarHeader";
final var builder = new StreamBuilder(factoryName)
.format("csv")
.addRecord(Headers.of(Car.class, headerName))
.addRecord(Car.class)
;
final var factory = StreamFactory.newInstance();
factory.define(builder);
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
final BeanWriter writer = factory.createWriter(factoryName, new OutputStreamWriter(bout));
try {
writer.write(headerName, null);
writer.write(new Car("Ford Ka", 2016));
writer.write(new Car("Ford Fusion", 2020));
} finally {
writer.close();
}
System.out.println(bout.toString());
// Model,Year
// Ford Ka,2016
// Ford Fusion,2020
}

Set last_modified field when not defined in document in Solr

I'm using Solr 4.6 example's SimplePostTool to import documents from the filesystem to Solr. All it's ok, but the field last_modified is filled only when the original document has metadata for it. If the field is not present Solr extractor leaves the field blank.
I tried to modify SimplePostTool to set this field using the file system modification date, but then I get this error when I try to import files that already have last_modified field from the metadata:
430584 [qtp1214238505-16] ERROR org.apache.solr.core.SolrCore –
org.apache.solr.common.SolrException: ERROR:
[doc=4861976] multiple values encountered for non multiValued field
last_modified: [2013-12-22T14:03:10.000Z, 2013-07-02T11:29:20.000Z]
I'm thinking about using a custom field for file system date, but in my case, metadata date if preferable when is available. Is there any way to merge them at import time?
Thanks!
You can set a default value in your schema. Something like this should work:
<field name="my_date" type="date" indexed="true" stored="true" multiValued="false" default="NOW" />
Field Type Definition:
<fieldType name="date" class="solr.TrieDateField" sortMissingLast="true" omitNorms="true"/>
while creating a document the solr takes all input as text and then validates according to the given data type , Hence any form of valid date format accepted ,would work fine with the solr .
For current time
Any default value
regards
Rajat
I finally solved the issue creating a custom Update Request Processor, as explained here: http://wiki.apache.org/solr/UpdateRequestProcessor
My processor is as follows:
package com.mycompany.solr;
import java.io.IOException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.processor.UpdateRequestProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
public class LastModifiedMergeProcessorFactory
extends UpdateRequestProcessorFactory {
#Override
public UpdateRequestProcessor getInstance(SolrQueryRequest req,
SolrQueryResponse rsp, UpdateRequestProcessor next) {
return new LastModifiedMergeProcessor(next);
}
}
class LastModifiedMergeProcessor extends UpdateRequestProcessor {
public LastModifiedMergeProcessor(UpdateRequestProcessor next) {
super(next);
}
#Override
public void processAdd(AddUpdateCommand cmd) throws IOException {
SolrInputDocument doc = cmd.getSolrInputDocument();
Object metaDate = doc.getFieldValue( "last_modified" );
Object fileDate = doc.getFieldValue( "file_date" );
if( metaDate == null && fileDate != null) {
doc.addField( "last_modified", fileDate );
}
// pass it up the chain
super.processAdd(cmd);
}
}
Where file_date is a field I set with the file modification date at import time.