I have two XML Files that contain information about some classes. After parsing the XML i want to instantiate these classes via Reflection.
I parse the xml with DOM and Recursion. What i want to know is which is the most generic way to implement it. Which is the optimal way to transfer the information and build the GUI.
I really cannot think anything else expect many IF...ELSE(
like this:
if (node.getNodeName() == "class") {
Class cls = Class.forName(node.getNodeValue());
}
)
statements but i do not think that this is the optimal way.
The dom parser:
for (int count = 0; count < nodeList.getLength(); count++) {
Node tempNode = nodeList.item(count);
// make sure it's element node.
if (tempNode.getNodeType() == Node.ELEMENT_NODE) {
// get node name and value
System.out.println("\nNode Name =" + tempNode.getNodeName() + " [OPEN]");
System.out.println("Node Value =" + tempNode.getNodeValue());
if (tempNode.hasAttributes()) {
// get attributes names and values
NamedNodeMap nodeMap = tempNode.getAttributes();
for (int i = 0; i < nodeMap.getLength(); i++) {
Node node = nodeMap.item(i);
System.out.println("attr name : " + node.getNodeName());
System.out.println("attr value : " + node.getNodeValue());
// System.out.println("Node Value : " +);
if (node.getNodeName() == "class") {
Class cls = Class.forName(node.getNodeValue());
}
}
}
if (tempNode.hasChildNodes()) {
// loop again if has child nodes
printNote(tempNode.getChildNodes());
}
System.out.println("Node Name =" + tempNode.getNodeName() + " [CLOSE]");
}
The XML files looks like this:
<ui-model>
<waui>
<abstract-container wauiId = '1'>
<abstract-button wauiId = '2'></abstract-button>
<abstract-button wauiId = '3'></abstract-button>
<abstract-button wauiId = '4'></abstract-button>
</abstract-container>
</waui>
<wrm>
<wr-item wauiId = '2'>
<abstract-properties>
<abstract-property name='text'>Button1</abstract-property>
</abstract-properties>
<polymorphic-properties>
<polymorphic-instance piId='swingRectButton'>
<polymorphic-property name='width'>100</polymorphic-property>
<polymorphic-property name='height'>50</polymorphic-property>
</polymorphic-instance>
<polymorphic-instance piId='swingRoundButton'>
<polymorphic-property name='radius'>80</polymorphic-property>
<polymorphic-property name='background-color'>red</polymorphic-property>
</polymorphic-instance>
</polymorphic-properties>
</wr-item>
<wr-item wauiId = '3'>
<abstract-properties>
<abstract-property name='text'>Button2</abstract-property>
</abstract-properties>
<polymorphic-properties>
<polymorphic-instance piId='swingRectButton'>
<polymorphic-property name='width'>200</polymorphic-property>
<polymorphic-property name='height'>60</polymorphic-property>
</polymorphic-instance>
</polymorphic-properties>
</wr-item>
<wr-item wauiId = '4'>
<abstract-properties>
<abstract-property name='text'>Button3</abstract-property>
</abstract-properties>
<polymorphic-properties>
<polymorphic-instance piId='swingRoundButton'>
<polymorphic-property name='radius'>9</polymorphic-property>
<polymorphic-property name='background-color'>blue</polymorphic-property>
</polymorphic-instance>
</polymorphic-properties>
</wr-item>
</wrm>
<widget name='abstract-button'>
<abstract-properties>
<property name='text' id='wsl_1'/>
</abstract-properties>
<polymorphic-instances>
<instance name='swingRectButton'>
<polymorphic-properties>
<property name='width' />
<property name='height' />
</polymorphic-properties>
</instance>
<instance name='swingRoundButton'>
<property name='radius' />
<property name='background-color' />
</instance>
</polymorphic-instances>
<polymorphic-instances-api>
<polymorphic-instance id='swingRectButton' class='javax.swing.JButton'>
<property name='text'>
<native-method>setText</native-method>
<param-type>String</param-type>
</property>
<property name='width'>
<native-method>setWidth</native-method>
<param-type>Integer</param-type>
</property>
<property name='height'>
<native-method>setHeight</native-method>
<param-type>Integer</param-type>
</property>
</polymorphic-instance>
<polymorphic-instance id='swingRoundButton' class='gr.epp.aswing.RoundButton'>
<property name='text'>
<native-method>setLabel</native-method>
<param-type>String</param-type>
</property>
<property name='radius'>
<native-method>setRadius</native-method>
<param-type>Integer</param-type>
</property>
<property name='background-color'>
<native-method>setBackgroundColor</native-method>
<param-type>String</param-type>
</property>
</polymorphic-instance>
</polymorphic-instances-api>
I thought about writing this as a comment to your question, but after more thought, I think it is an appropriate answer.
Avoid premature optimization.
If you've already written code that works and you're running into a specific problem then explain that problem. But you should not try to optimize your code unless there is an identifiable problem with it.
See http://c2.com/cgi/wiki?PrematureOptimization
Related
I am having similar issue while inserting data to a DB table with 27 columns. I am using NamedParameterJdbcTemplate class to insert data. Any help in this regard is really helpful. Please find the below code snippet
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("Id", 12345678)
.addValue("packageId", info.getIrocPkgId())
.addValue("isAsgn", 1)
.addValue("startTm", info.getStartTm())
.addValue("endTm", info.getEndTm())
.addValue("type", ConstantVal.TASK)
.addValue("note", ConstantVal.ETA + ":" + info.getEta())
.addValue("fdbk", ConstantVal.EMPTY)
.addValue("sCnt", 1)
.addValue("aCd", ConstantVal.ETA)
.addValue("isAuto", 1)
.addValue("dfltStartTm", info.getStartTm())
.addValue("dfltEndTm", info.getEndTm())
.addValue("aInfo", ConstantVal.EMPTY)
.addValue("stat", ConstantVal.ACTIVE)
.addValue("cnclTask", ConstantVal.ZERO)
.addValue("asgnNbr", ConstantVal.EMPTY)
.addValue("priInd", ConstantVal.ZERO)
.addValue("ovlpMatchNbr", ConstantVal.EMPTY)
.addValue("attchIds", ConstantVal.EMPTY)
.addValue("aType", ConstantVal.EMPTY)
.addValue("lInd", ConstantVal.ZERO)
.addValue("pAsgn", ConstantVal.ZERO)
.addValue("rId", ConstantVal.EMPTY)
.addValue("bInd", ConstantVal.EMPTY)
.addValue("createDtTm", new Timestamp((new Date()).getTime()))
.addValue("updatedDtTm", ConstantVal.EMPTY);
int nb = namedParameterJdbcTemplate.update(insertRecords, parameters, keyHolder,new String[] { "ID" });
SQL Query in beans.xml is given below
<bean id="insertRecords" class="java.lang.String"
scope="prototype">
<constructor-arg type="java.lang.String"
value="
INSERT
INTO
XYZ
(
ID,
PACKAGE_ID,
IS_ASGN,
START_TM,
END_TM,
TYPE,
NOTE,
FDBK,
S_CNT,
A_CD,
IS_AUTO,
DFLT_START_TM,
DFLT_END_TM,
A_INFO,
STAT,
IS_CNCL_TASK,
ASGN_NBR,
PRI_ASGN_IND,
OVLP_MATCH_NBR,
A_IDS,
ASGN_TYPE,
LOCK_IND,
P_ASGN,
R_ID,
B_IND,
CREATED_DT_TM,
UPDATED_DT_TM
)
VALUES
(
:Id,
:packageId,:isAsgn,:startTm,:endTm,:type,:note,:fdbk,:sCnt,:aCd,:isAuto,:dfltStartTm,:dfltEndTm,:aInfo,
:stat,:cnclTask,:asgnNbr,:priInd,:ovlpMatchNbr,:attchIds,:aType,:lInd,:pAsgn,:rId,
:bInd,:createDtTm,:updatedDtTm) " />
</bean>
I am seeing the below error while inserting data
java.lang.ArrayIndexOutOfBoundsException
at oracle.jdbc.driver.OracleSql.computeBasicInfo(OracleSql.java:950)
at oracle.jdbc.driver.OracleSql.getSqlKind(OracleSql.java:623)
at oracle.jdbc.driver.OraclePreparedStatement.<init>(OraclePreparedStatement.java:1212)
at oracle.jdbc.driver.T4CPreparedStatement.<init>(T4CPreparedStatement.java:28)
at oracle.jdbc.driver.T4CDriverExtension.allocatePreparedStatement(T4CDriverExtension.java:68)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:3140)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:3042)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:6022)
at oracle.jdbc.OracleConnectionWrapper.prepareStatement(OracleConnectionWrapper.java:679)
at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.pmiPrepareStatement(WSJdbcConnection.java:5071)
at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.prepareStatement(WSJdbcConnection.java:4946)
at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:231)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:638)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:943)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:344)
I have a spring-batch application that reads a file with this reader :
<bean id="tradeItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource">
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg value="${input.file.path}/#{jobExecutionContext['trades']}" type="java.lang.String"/>
</bean>
</property>
<property name="linesToSkip" value="1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<!-- split it -->
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<beans:property name="strict" value="false" />
<beans:property name="includedFields" value="0,2,3,6" />
<property name="names"
value="field0,field2,field3,field6" />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="trade" />
</bean>
</property>
</bean>
</property>
</bean>
The fields are delimited by a comma ,, and here is the catch : some fields look like [LON, TGT] and the line ends up wrongly parsed, because of the comma inside the square brackets.
Example :
Input : Global,,VERIFIED,[LON, TGT],ERerd,3456585,QTR,20190929,20231020
Desired output : Global, VERIFIED, [LON, TGT], QTR
Actual output : Global, VERIFIED, [LON, 3456585
How can I achieve that ? I don't have control over the input file.
EDIT
This is not a duplicate, as the proposed solution would not work : here we don't have a single quote-character, but we have 2 different ones, the opening bracket and the closing bracket.
As explained by Luca Basso Ricci, my input csv is invalid, but I still have to deal with it because I have no control over it.
So I wrote my own delimited line tokenizer, which is just the DelimitedLineTokenizer with a rewritten isDelimiter() method, and replaced it in the conf file :
private boolean isDelimiter(char[] chars, int i, String token, int endIndexLastDelimiter) {
boolean result = false;
int openingBrackets = StringUtils.countOccurrencesOf(new String(Arrays.copyOfRange(chars, 0, i)), "[");
int closingBrackets = StringUtils.countOccurrencesOf(new String(Arrays.copyOfRange(chars, 0, i)), "]");
boolean inBrackets = (openingBrackets - closingBrackets > 0);
if ((i - endIndexLastDelimiter >= this.delimiter.length()) &&
(i >= token.length() - 1)) {
String end = new String(chars, i - token.length() + 1, token.length());
if (token.equals(end)) {
result = !inBrackets;
}
}
return result;
}
I want to extrat some data from an invoice (XML) using Java. I'm using the example on this link (https://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/)
The problem is my XML doesn't look like the one in the example, here is mine:
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:bfa2="http://www.buzonfiscal.com/ns/addenda/bf/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" NumCtaPago="4007" LugarExpedicion="CUAJIMALPA DE MORELOS,CIUDAD DE MEXICO" metodoDePago="99" tipoDeComprobante="ingreso" total="2490" subTotal="2146.55" fecha="2016-12-14T10:23:08" folio="57318" serie="BT" version="3.2" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd http://www.buzonfiscal.com/ns/addenda/bf/2 http://www.buzonfiscal.com/schema/xsd/Addenda_BF_v20.xsd">
<cfdi:Emisor nombre="BEST BUY STORES S. DE R.L. DE C.V." rfc="BBS070606D33">
<cfdi:DomicilioFiscal codigoPostal="05348" pais="MEXICO" estado="CIUDAD DE MEXICO" municipio="CUAJIMALPA DE MORELOS" referencia="EDIFICIO CENTURY PLAZA" colonia="SANTA FE CUAJIMALPA" noInterior="PISO 2 OFNA 202 Y 203 P3 Y P4" noExterior="440" calle="AV. SANTA FE" />
<cfdi:ExpedidoEn codigoPostal="05348" pais="MEXICO" estado="CIUDAD DE MEXICO" municipio="CUAJIMALPA DE MORELOS" colonia="SANTA FE" calle="AVENIDA SANTA FE NO. 440 PISO 2 (OFICINA 203 Y 204),PISO 3 Y PISO 4" />
<cfdi:RegimenFiscal Regimen="Regimen General de Ley Personas Morales" />
</cfdi:Emisor>
<cfdi:Receptor nombre="VIALCOMA S.A DE C.V" rfc="VIA8011248W0">
<cfdi:Domicilio codigoPostal="54080" pais="México" estado="Estado de México" municipio="Tlalnepantla de Baz" referencia="VIALCOMA S.A. de C.V." localidad="Tlalnepantla de Baz" colonia="EL MIRADOR" noExterior="107" calle="AV. GUSTAVO BAZ " />
</cfdi:Receptor>
<cfdi:Conceptos>
<cfdi:Concepto importe="2146.55" valorUnitario="2146.55" descripcion="PANASONIC PHONE KX-PRD260MEB" noIdentificacion="000000001000189023" unidad="PZA" cantidad="1" />
</cfdi:Conceptos>
<cfdi:Impuestos totalImpuestosTrasladados="343.45">
<cfdi:Traslados>
<cfdi:Traslado importe="343.45" tasa="16.0" impuesto="IVA" />
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigital.xsd" UUID="2e36935c-4948-4f7b-9b29-477546aa2922" version="1.0" />
</cfdi:Complemento>
<cfdi:Addenda>
<bfa2:AddendaBuzonFiscal version="2.0">
<bfa2:Receptor email="" />
<bfa2:TipoDocumento descripcion="Factura" nombreCorto="FAC" />
<bfa2:CFD totalConLetra="Dos mil cuatrocientos noventa pesos 00/100 M.N." fechaEnvio="2016-12-12T10:42:15-06:00" />
<bfa2:Extra valor="02028001014520161212" atributo="numTicket" />
</bfa2:AddendaBuzonFiscal>
</cfdi:Addenda>
</cfdi:Comprobante>
I want to get (print on console) the data on "folio" "serie" and "UUID"
Can someone help me please?
The following should give your desire output.This example is based on DOM parser as you have provide.
System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
NodeList nList = doc.getElementsByTagName("cfdi:Comprobante");
org.w3c.dom.Node nNode = nList.item(0);
System.out.println("folio: " + ((Element) nNode).getAttribute("folio"));
System.out.println("serie: " + ((Element) nNode).getAttribute("serie"));
NodeList list = doc.getElementsByTagName("cfdi:Complemento");
for (int i = 0; i < 1; i++) {
NodeList child = list.item(i).getChildNodes();
for (int j = 0; j < child.getLength(); j++) {
if (child.item(j).getNodeName().equals("tfd:TimbreFiscalDigital")) {
String uuid = ((Element)(child.item(j))).getAttribute("UUID");
System.out.println("UUID : " + uuid);
}
}
}
console output:
Root element :cfdi:Comprobante
----------------------------
folio: 57318
serie: BT
UUID : 2e36935c-4948-4f7b-9b29-477546aa2922
I have to migrate some data from a database to another and I'm using Spring Batch with partition. The configuration of the job is the following
...
...
<bean id="migrationProcessor" class="it.migrazione.MigrazioneProcessor" scope="step"/>
<bean id="migrationWriter" class="it.migrazione.MigrazioneWriter" scope="step"/>
<bean id="migrationReader" class="it.migrazione.MigrazioneReader" scope="step"/>
<bean id="partitioner" class="it.migrazione.MigrazionePartitioner" />
<bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor"/>
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="10" />
<property name="allowCoreThreadTimeOut" value="true" />
</bean>
<job id="migrationJob" xmlns="http://www.springframework.org/schema/batch">
<step id="masterStep">
<partition step="slave" partitioner="partitioner">
<handler grid-size="10" task-executor="threadPoolTaskExecutor" />
</partition>
</step>
</job>
<step id="slave" xmlns="http://www.springframework.org/schema/batch">
<tasklet throttle-limit="1" transaction-manager="transactionManager">
<chunk reader="migrationReader"
processor="migrationProcessor"
writer="migrationWriter"
commit-interval="1"/>
</tasklet>
</step>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
...
...
Job knows how many row must be migrated, so the partitioner creates 10 contexts with a specific range related
for (int threadCount = 1; threadCount <= gridSize; threadCount++) {
if (threadCount == 1)
fromRow = 0;
else
fromRow = toRow + 1;
toRow += delta;
context = new ExecutionContext();
context.putInt("fromRow", fromRow);
context.putInt("toRow", toRow);
context.putString("name", "Processing Thread" + threadCount);
result.put("partition" + threadCount, context);
logger.info("Partition number >> " + threadCount + " from Row#: "
+ fromRow + " to Row#: " + toRow);
}
When I run this job I have some threads that read another time. For example Thread#1 call another time the reader,processor and writer while. I don't understand why, but is it possible to have one thread that executes once the chunk, without checking that read is already called? When the writer related to a specific partition ends, why the thread calls the reader another time? It is like reader doesn't immediately see the changes made by writer.
We are using Spring Batch Chunk to read messages from JMS destination and write to a flat file. In this regard, we have below observations,
If the message broker goes down while the reader reads the messages and commit count is not reached, what ever number of messages read so far are being passed to Writer and then batch is going in to FAILED state. Is this the default behaviour of Chunk?
If at all the answer for point 1 is YES, how do we make sure that this partial chunk is not sent to Writer. (To give more background to this issue, we have the JMS Session Transacted in the JMS Template, so when the chunk fails to read complete number of messages equal to Commit Count, all the messages read in the partial chunk are being rolled back to the JMS destination, where as the same partial chunk is being written to file. This is causing duplicates in the file when we restart the batch job).
Any help would be greatly appreciated.
EDIT
The configuration is as shown below,
Chunk:
<batch:step id="step-1" next="step-2">
<batch:tasklet allow-start-if-complete="false">
<batch:chunk reader="jms-reader-1-1" writer="file-writer-1-1" commit-interval="1000">
</batch:chunk>
</batch:step>
Writer (Flat File) :
<bean scope="step" class="o.s.b.i.f.FlatFileItemWriter" id="file-writer-1-1">
<property name="resource" value="file:#{T(com.test.core.BatchConfiguration).BATCH_VFS_LOCAL_TEMP_LOCATION}/#{T(com.test.utils.ThreadContextUtils).getJobInstanceIdAsString()}/AssetMesage"/>
<property name="lineAggregator">
<bean class="o.s.b.i.f.t.DelimitedLineAggregator">
<property name="delimiter" value=","/>
<property name="fieldExtractor">
<bean class="o.s.b.i.f.t.BeanWrapperFieldExtractor">
<property name="names" value="assetId,assetName,assetDesc"/>
</bean>
</property>
</bean>
</property>
</bean>
Reader (JMS):
<bean scope="step" class="com.test.runtime.impl.item.readers.JMSItemReader" id="jms-reader-1-1">
<property name="adapter">
<bean class="com.test.adapter.impl.JMSAdapter">
<property name="resource" ref="JMS.vmsmartbatch02_Regression"/>
<property name="retryerId" value="JMS.vmsmartbatch02_Regression-retryer"/>
</bean>
</property>
<property name="destination" value="#{jobParameters[source1jmsdestination] != null ? jobParameters[source1jmsdestination] : "sourceTopic"}"/><property name="durableSubscriberName" value="sourceTopicDS"/><property name="destinationType" value="Topic"/>
<property name="ackMode" value="#{T(javax.jms.Session).CLIENT_ACKNOWLEDGE}"/>
<property name="maxMessageCount" value="2000"/>
</bean>
EDIT 2
below is the core reader logic I am using,
Reader
public Object read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
Object item = null;
try {
if(ackMode != 0 && ackMode >= 1 && ackMode <= 3){
adapter.getResource().setSessionAcknowledgeMode(ackMode);
}
if(maxMessageCount > 0){
ThreadContextUtils.addToExecutionContext("maxMessageCount", maxMessageCount);
if(ThreadContextUtils.getExecutionContext().containsKey("readMessageCount")) {
readMessageCount = ThreadContextUtils.getExecutionContext().getInt("readMessageCount");
}
}
if (TOPIC_KEY.equalsIgnoreCase(destinationType)
&& durableSubscriberName != null) {
item = (Object) adapter.invoke(REC_DS_AND_CONVERT_SELECTED,
OBJECT_CLASS, destination, durableSubscriberName,
receiveTimeout, filter == null ? "" : filter);
} else {
item = (Object) adapter.invoke(REC_AND_CONVERT_SELECTED,
OBJECT_CLASS, destination,
receiveTimeout <= 0 ? adapter.getResource()
.getReceiveTimeout() : receiveTimeout,
(filter == null ? "" : filter));
}
if(maxMessageCount > 0){
if( item !=null){
readMessageCount++;
ThreadContextUtils.addToExecutionContext("readMessageCount", readMessageCount);
}
}
return item;
} finally {
}
}