Anchor doesn't work after merging two different PDF using iText - jasper-reports

I have created two PDF reports using Jasper and merged those into a single PDF file. The first PDF report contains the Anchor link and the second PDF report contains the Anchor target. After merging the two PDFs, the anchor does not work. How should I fix this?
part1.jrxml code
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 5.6.1.final using JasperReports Library version 5.6.1 -->
<!-- 2016-01-03T23:14:55 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="part1" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="8d0dcb70-0391-45e2-9263-4ac8cfa5f0de">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<queryString>
<![CDATA[]]>
</queryString>
<background>
<band splitType="Stretch"/>
</background>
<summary>
<band height="405" splitType="Stretch">
<textField>
<reportElement x="320" y="370" width="100" height="30" uuid="0f29cf02-60d5-43d7-b360-3254134a6f77"/>
<textFieldExpression><![CDATA["Anchor Name"]]></textFieldExpression>
<anchorNameExpression><![CDATA["expert"]]></anchorNameExpression>
</textField>
</band>
</summary>
</jasperReport>
part2.jrxml code
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 5.6.1.final using JasperReports Library version 5.6.1 -->
<!-- 2016-01-03T23:24:42 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="part2" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="3f401f6e-4962-4a54-9674-4b0c613f9e73">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<queryString>
<![CDATA[]]>
</queryString>
<background>
<band splitType="Stretch"/>
</background>
<summary>
<band height="389" splitType="Stretch">
<textField hyperlinkType="LocalAnchor">
<reportElement x="430" y="350" width="100" height="30" uuid="53f9f5fa-df7a-4fa3-bc1d-57b8be0c130a"/>
<textFieldExpression><![CDATA["Anchor Target"]]></textFieldExpression>
<hyperlinkReferenceExpression><![CDATA["./result.pdf"]]></hyperlinkReferenceExpression>
<hyperlinkAnchorExpression><![CDATA["expert"]]></hyperlinkAnchorExpression>
</textField>
</band>
</summary>
</jasperReport>
Merged.pdf
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
public class MergePdf {
public static void main(String[] args) throws IOException, DocumentException {
String RESULT= "/home/expert/Desktop/result.pdf";
String[] files = {"/home/expert/Desktop/part1.pdf", "/home/expert/Desktop/part2.pdf"};
mergePDF(files,RESULT);
}
public static boolean mergePDF(String sourcefiles[],String targetfile){
Document document = new Document();
PdfCopy copy;
try {
//copy = new PdfCopy(document, new FileOutputStream(targetfile));
copy = new PdfSmartCopy(document, new FileOutputStream(targetfile));
document.open();
PdfReader reader;
int n;
for (int i = 0; i < sourcefiles.length; i++) {
reader = new PdfReader(sourcefiles[i]);
n = reader.getNumberOfPages();
for (int page = 0; page < n; )
copy.addPage(copy.getImportedPage(reader, ++page));
copy.freeReader(reader);
reader.close();
}
document.close();
System.out.println("INFO :: Merging Complete of temp files");
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}

Consider to merge the JasperPrint and then to export to pdf, using the SimpleExporterInput.getInstance(List<JasperPrint>) as exporter input
This will make the bookmarks and anchors work correctly
Example
Map<String, Object> paramMap = new HashMap<String, Object>();
JasperReport report1 = JasperCompileManager.compileReport("part1.jrxml");
JasperReport report2 = JasperCompileManager.compileReport("part2.jrxml");
//Get all the JasperPrint and add them to my list
List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>();
JasperPrint jasperPrint1 = JasperFillManager.fillReport(report1, paramMap);
jasperPrintList.add(jasperPrint1);
JasperPrint jasperPrint2 = JasperFillManager.fillReport(report2, paramMap);
jasperPrintList.add(jasperPrint2);
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList)); //Set as export input my list with JasperPrint s
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("pdf/BookmarkTest.pdf"));
SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
configuration.setCreatingBatchModeBookmarks(true);
exporter.setConfiguration(configuration);
exporter.exportReport();

Related

Generating a text file with jasperReporting

this is my code java to generate a txt file with jasper :
package sms;
import module.User_Excel;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRTextExporter;
import net.sf.jasperreports.engine.export.JRTextExporterParameter;
import net.sf.jasperreports.export.Exporter;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleTextReportConfiguration;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
import org.springframework.util.ResourceUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Main_txt {
public static void main(String[] args) throws Exception {
System.out.println( "generating jasper text file [.txt]" );
// Define the parameter for the user name
Map<String, Object> params = new HashMap<String, Object>();
params.put("userName", "salma");
// Compile the JasperReport template
File template = ResourceUtils.getFile("classpath:template_txt.jrxml");
JasperReport report = JasperCompileManager.compileReport(template.getAbsolutePath());
// Fill the JasperPrint object
JasperPrint print = JasperFillManager.fillReport(report, params, new JREmptyDataSource());
// Export the JasperPrint to a text file
Exporter exporter = new JRTextExporter();
exporter.setExporterInput(new SimpleExporterInput(print));
exporter.setExporterOutput(new SimpleWriterExporterOutput("output.txt"));
SimpleTextReportConfiguration configuration = new SimpleTextReportConfiguration();
configuration.setPageWidthInChars(80); // Set the page width to 80 characters
configuration.setCharWidth((float)8); // Set the character width to 8 pixels
exporter.setConfiguration(configuration);
exporter.exportReport();
System.out.println("Report generated successfully!");
}
public static JRDataSource getDataBeanList() {
List<User_Excel> users = new ArrayList<User_Excel>();
users.add(new User_Excel("salma abou", 22, "salma.abou#email.com"));
users.add(new User_Excel("Jane Doe", 25, "jane.doe#email.com"));
return new JRBeanCollectionDataSource(users);
}
private static JasperReport getJasperReport() throws FileNotFoundException, JRException {
File template = ResourceUtils.getFile("classpath:template_txt.jrxml");
return JasperCompileManager.compileReport(template.getAbsolutePath());
}
private static Map<String, Object> getParameters(){
String userName = "salma aboumzrag";
Map<String, Object> parameters = new HashMap<>();
parameters.put("createdBy", "salma");
parameters.put("userName", userName);
return parameters;
}
}
and here is my template :
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="HelloUser" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
<parameter name="userName" class="java.lang.String"/>
<title>
<band height="79">
<textField>
<reportElement x="0" y="0" width="100" height="30"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font size="24"/>
</textElement>
<textFieldExpression><![CDATA["Hey, " + $P{userName}]]></textFieldExpression>
</textField>
</band>
</title>
</jasperReport>
i need to generate a text file saying Hello {user_name}
Igot ths error :
Exception in thread "main" net.sf.jasperreports.engine.JRRuntimeException: Character height in pixels or page height in characters must be specified and must be greater than zero.
at net.sf.jasperreports.engine.export.JRTextExporter.initReport(JRTextExporter.java:301)
at net.sf.jasperreports.engine.JRAbstractExporter.setCurrentExporterInputItem(JRAbstractExporter.java:616)
at net.sf.jasperreports.engine.export.JRTextExporter.exportReportToWriter(JRTextExporter.java:328)
at net.sf.jasperreports.engine.export.JRTextExporter.exportReport(JRTextExporter.java:206)
at sms.Main_txt.main(Main_txt.java:50)
i have to remove the font size="24" from my template because it- is not compatible with my config

createEntityManagerFactory is failing randomly

Now and then it is observed that the createEntityManagerFactory is failing. The stack trace is little confusing for me. Can anybody throw some light on it?
java.lang.StackOverflowError
at java.io.File.list(File.java:1133)
at java.io.File.listFiles(File.java:1297)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:90)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:96)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:96)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:96)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:96)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.init(DirectoryArchive.java:96)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.<init>(DirectoryArchive.java:74)
at org.eclipse.persistence.internal.jpa.deployment.DirectoryArchive.<init>(DirectoryArchive.java:54)
at org.eclipse.persistence.internal.jpa.deployment.ArchiveFactoryImpl.createArchive(ArchiveFactoryImpl.java:89)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.findPersistenceArchives(PersistenceUnitProcessor.java:302)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.findPersistenceArchives(PersistenceUnitProcessor.java:276)
at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.findPersistenceUnitInfoInArchives(JPAInitializer.java:150)
at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.findPersistenceUnitInfo(JPAInitializer.java:135)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:129)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:129)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:129)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:129)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
....
...
..
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:129)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:177)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
On further tracing i see that this is happening when a new EntityManagerFactory is being created after the close of existing one is failing with the following exceptions:
code:
synchronized (factoryLock) {
if (null != emFactory) {
if (true == emFactory.isOpen()) {
try {
emFactory.close();
} catch (IllegalStateException e) {
System.out.println(e.getMessage());
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
emFactory = null;
}
Map<String, String> properties = new HashMap<String, String>();
properties.put(PersistenceUnitProperties.JDBC_DRIVER, jdbcDriver);
properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
"com.ca.waae.dbaccess.custom.JPASessionCustomizer");
properties.put(PersistenceUnitProperties.JDBC_URL, jdbcUrl);
properties.put(PersistenceUnitProperties.JDBC_PROPERTY+"REQUEST_KERBEROS_SESSION", "true");
properties.put(PersistenceUnitProperties.JDBC_PROPERTY+"SERVICE_PRINCIPAL_NAME", dbPrincipalName);
emFactory = Persistence.createEntityManagerFactory(
"JPA", properties);
}
Exception:
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1440)
at java.util.HashMap$ValueIterator.next(HashMap.java:1469)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.clearStatementCache(DatabaseAccessor.java:342)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.disconnect(DatabaseAccessor.java:505)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.disconnect(DatabaseSessionImpl.java:415)
at org.eclipse.persistence.sessions.server.ServerSession.disconnect(ServerSession.java:504)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.logout(DatabaseSessionImpl.java:931)
at org.eclipse.persistence.sessions.server.ServerSession.logout(ServerSession.java:776)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.removeSessionFromGlobalSessionManager(EntityManagerSetupImpl.java:511)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.undeploy(EntityManagerSetupImpl.java:2850)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.close(EntityManagerFactoryDelegate.java:267)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.close(EntityManagerFactoryImpl.java:287)
at com.ca.waae.dbaccess.dao.AEConnection.createJpaEntityFactory(AEConnection.java:144)
persistent.xml contents are like
?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.
com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPA">
<class>com.xx.yy.dbaccess.model.table1</class>
<class>com.xx.yy.dbaccess.model.table2</class>
<class>com.xx.yy.dbaccess.model.table3</class>
<class>com.xx.yy.dbaccess.model.table4</class>
<class>com.xx.yy.dbaccess.model.table5</class>
<properties>
<property name="eclipselink.logging.level" value="ALL"/>
<property name="eclipselink.jdbc.cache-statements" value="true"/>
<property name="eclipselink.jpa.uppercase-column-names " value="false"/>
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.weaving" value="static"/>
</properties>
</persistence-unit>
</persistence>

org.hibernate.HibernateException: The database returned no natively generated identity value - Spring Batch for MultiReaderHibernateWriter

I am developing 'Multiresource ItemReader & HibernateItemWritter' from link: http://websystique.com/springbatch/spring-batch-multiresourceitemreader-hibernateitemwriter-example/. When I was running the Main program, I faced the below error:
Jul 27, 2016 12:27:36 AM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO: No TaskExecutor has been set, defaulting to synchronous executor.
Jul 27, 2016 12:27:37 AM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=examResultJob]] launched with the following parameters: [{}]
---------------------------------
ExamResult Job starts at :2016-07-27T00:27:37.294+05:30
Jul 27, 2016 12:27:37 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
Processing result :ExamResult [id=0, studentName=Brian Burlet, dob=1985-02-01, percentage=76.0]
Processing result :ExamResult [id=0, studentName=Jimmy Snuka, dob=1983-02-01, percentage=39.0]
Processing result :ExamResult [id=0, studentName=Renard konig, dob=1970-02-01, percentage=61.0]
Processing result :ExamResult [id=0, studentName=Kevin Richard, dob=2002-02-01, percentage=59.0]
Processing result :ExamResult [id=0, studentName=Sam Disilva, dob=1992-05-01, percentage=76.0]
Processing result :ExamResult [id=0, studentName=Bob corbet, dob=1990-07-10, percentage=29.0]
Processing result :ExamResult [id=0, studentName=Rick Ricky, dob=1973-02-01, percentage=54.0]
Processing result :ExamResult [id=0, studentName=Igor Watson, dob=1986-02-01, percentage=34.0]
Processing result :ExamResult [id=0, studentName=Peet Sampras, dob=1978-02-01, percentage=97.0]
Processing result :ExamResult [id=0, studentName=Rita Paul, dob=1993-02-01, percentage=92.0]
Hibernate: insert into EXAM_RESULT (DOB, PERCENTAGE, STUDENT_NAME) values (?, ?, ?)
Jul 27, 2016 12:18:09 AM
org.springframework.batch.core.step.AbstractStep execute
SEVERE: Encountered an error executing step step1 in job examResultJob
org.hibernate.HibernateException: The database returned no natively generated identity value
at org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:91)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:100)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3032)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3558)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:98)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:490)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:195)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:179)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:214)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:324)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:671)
at org.springframework.batch.item.database.HibernateItemWriter.doWrite(HibernateItemWriter.java:140)
at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:113)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)
at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199)
at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
at com.websystique.springbatch.Main.main(Main.java:22)
Any pointers to solve the issue?
ExamResult.java
#Entity
#Table(name = "EXAM_RESULT")
public class ExamResult {
#Id
//#GeneratedValue(strategy = GenerationType.IDENTITY)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "STUDENT_NAME", nullable = false)
private String studentName;
#Column(name = "DOB", nullable = false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate dob;
#Column(name = "PERCENTAGE", nullable = false)
private double percentage;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public LocalDate getDob() {
return dob;
}
public void setDob(LocalDate dob) {
this.dob = dob;
}
public double getPercentage() {
return percentage;
}
public void setPercentage(double percentage) {
this.percentage = percentage;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof ExamResult))
return false;
ExamResult other = (ExamResult) obj;
if (id != other.id)
return false;
return true;
}
#Override
public String toString() {
return "ExamResult [id=" + id + ", studentName=" + studentName
+ ", dob=" + dob + ", percentage=" + percentage + "]";
}
}
spring-batch-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:context-model.xml"/>
<!-- JobRepository and JobLauncher are configuration/setup classes -->
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<!-- ============= Multi Resource Item Reader ================== -->
<bean id="multiResourceItemReader" class="org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="classpath:csv/ExamResult*.txt" />
<property name="delegate" ref="flatFileItemReader" />
</bean>
<!-- =========== ItemReader reads a complete line one by one from input file ============-->
<bean id="flatFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="fieldSetMapper">
<!-- Mapper which maps each individual items in a record to properties in POJO -->
<bean class="com.websystique.springbatch.ExamResultFieldSetMapper" />
</property>
<property name="lineTokenizer">
<!-- A tokenizer class to be used when items in input record are separated by specific characters -->
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="|" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- ItemWriter which writes data to database -->
<bean id="databaseItemWriter" class="org.springframework.batch.item.database.HibernateItemWriter">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Optional ItemProcessor to perform business logic/filtering on the input records -->
<bean id="itemProcessor" class="com.websystique.springbatch.ExamResultItemProcessor" />
<!-- Optional JobExecutionListener to perform business logic before and after the job -->
<bean id="jobListener" class="com.websystique.springbatch.ExamResultJobListener" />
<!-- =========== Actual Job =========== -->
<batch:job id="examResultJob">
<batch:step id="step1">
<batch:tasklet transaction-manager="transactionManager">
<batch:chunk reader="multiResourceItemReader" writer="databaseItemWriter"
processor="itemProcessor" commit-interval="10" />
</batch:tasklet>
</batch:step>
<batch:listeners>
<batch:listener ref="jobListener" />
</batch:listeners>
</batch:job>
</beans>
context-model.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
default-autowire="byName" default-init-method="init">
<import resource="classpath:context-datasource.xml"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.websystique.springbatch.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<!-- <prop key="hibernate.format_sql">true</prop> -->
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Simply create exam_result like below:
CREATE TABLE `websystique`.`exam_result` (
`ID` INT NOT NULL AUTO_INCREMENT,
`STUDENT_NAME` VARCHAR(500) NULL,
`DOB` DATE NULL,
`PERCENTAGE` VARCHAR(500) NULL,
PRIMARY KEY (`ID`));

Using Spring Batch JdbcCursorItemReader with NamedParameters

The Spring Batch JdbcCursorItemReader can accept a preparedStatementSetter:
<bean id="reader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="..." />
<property name="sql" value="SELECT * FROM test WHERE col1 = ?">
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
This works well if the sql uses ? as placeholder(s), as in the above example. However, our pre-existing sql uses named parameters, e.g. SELECT * FROM test WHERE col1 = :param
.
Is there a way to get a JdbcCursorItemReader to work with a NamedPreparedStatementSetter rather than a simple PreparedStatementSetter?
Thanks
You can try with jobParameters. In this case you don't need any PreparedStatementSetter.
<bean id="reader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="..." />
<property name="sql" value="SELECT * FROM test WHERE col1 = #{jobParameters['col1']">
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
pass the value when running the job
JobParameters param = new JobParametersBuilder().addString("col1", "value1").toJobParameters();
JobExecution execution = jobLauncher.run(job, param);
Once we don't have an official solution from spring, we can fix this problem using a simple approach:
Define one interface to provide the SqlParameters:
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
public interface SqlParameterSourceProvider {
SqlParameterSource getSqlParameterSource();
}
Extending the JdbcCursorItemReader and adding the namedParameter features.
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.namedparam.*;
import org.springframework.util.Assert;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;
public class NamedParameterJdbcCursorItemReader<T> extends JdbcCursorItemReader<T> {
private SqlParameterSourceProvider parameterSourceProvider;
private String paramedSql;
public NamedParameterJdbcCursorItemReader(SqlParameterSourceProvider parameterSourceProvider) {
this.parameterSourceProvider = parameterSourceProvider;
}
#Override
public void setSql(String sql) {
Assert.notNull(parameterSourceProvider, "You have to set parameterSourceProvider before the SQL statement");
Assert.notNull(sql, "sql must not be null");
paramedSql = sql;
super.setSql(NamedParameterUtils.substituteNamedParameters(sql, parameterSourceProvider.getSqlParameterSource()));
}
#Override
protected void applyStatementSettings(PreparedStatement stmt) throws SQLException {
final ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(paramedSql);
final List<?> parameters = Arrays.asList(NamedParameterUtils.buildValueArray(parsedSql, parameterSourceProvider.getSqlParameterSource(), null));
for (int i = 0; i < parameters.size(); i++) {
StatementCreatorUtils.setParameterValue(stmt, i + 1, SqlTypeValue.TYPE_UNKNOWN, parameters.get(i));
}
}
}
Creating the concrete class that implements the interface SqlParameterSourceProvider and has the state with the updated value of the parameters to be used in your query.
public class MyCustomSqlParameterSourceProvider implements SqlParameterSourceProvider {
private Map<String, Object> params;
public void updateParams(Map<String, Object> params) {
this.params = params;
}
#Override
public SqlParameterSource getSqlParameterSource() {
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValues(params);
return paramSource;
}
}
Finally, update the spring configuration.
<bean id="reader" class="org.wisecoding.stackoverflow.NamedParameterJdbcCursorItemReader">
<constructor-arg ref="sqlParameterSourceProvider"/>
<property name="dataSource" ref="..." />
<property name="sql" value=SELECT * FROM test WHERE col1 = :param" />
<property name="rowMapper" ref="..." />
<property name="preparedStatementSetter" ref="..." />
</bean>
<bean id="sqlParameterSourceProvider" class="org.wisecoding.stackoverflow.MyCustomSqlParameterSourceProvider">
</bean>
Currently, there is not a way to do this. The JdbcCursorItemReader uses raw JDBC (PreparedStatement) instead of the Spring JdbcTemplate under the hood (since there is no way to get the underlying ResultSet when using JdbcTemplate). If you'd like to contribute this as a new feature, or request it as a new feature, feel free to do so at jira.spring.io
original solution in https://jira.spring.io/browse/BATCH-2521, but which does not support id in (:ids) clause.
here is an enhancement.
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
import java.util.Map;
#Slf4j
public class NamedParameterJdbcCursorItemReader<T> extends JdbcCursorItemReader<T> {
protected void setNamedParametersSql(String sql, Map<String, Object> parameters) {
val parsedSql = NamedParameterUtils.parseSqlStatement(sql);
val paramSource = new MapSqlParameterSource(parameters);
val sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
val declaredParams = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
val params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
val pscf = new PreparedStatementCreatorFactory(sql, declaredParams);
val pss = pscf.newPreparedStatementSetter(params);
log.info("sql: {}", sqlToUse);
log.info("parameters: {}", parameters);
setSql(sqlToUse);
setPreparedStatementSetter(pss);
}
}
Usage:
#Slf4j
public class UserItemJdbcReader extends NamedParameterJdbcCursorItemReader<UserEntity> {
#PostConstruct
public void init() {
val sql = "SELECT * FROM users WHERE id IN (:ids)";
val parameters = new HashMap<String, Object>(4);
parameters.put("ids", Arrays.asList(1,2,3));
setDataSource(dataSource);
setRowMapper(new UserRowMapper());
setNamedParametersSql(sql, parameters);
}
}
in my case I reuse ArgumentPreparedStatementSetter from spring-jdbc
private static final String SQL = "SELECT * FROM payments.transactions WHERE time_stamp >= ? AND time_stamp <= ?";
...
Object[] args = new Object[2];
args[0] = new Date(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli());
args[1] = new Date();
ArgumentPreparedStatementSetter argumentPreparedStatementSetter =
new ArgumentPreparedStatementSetter(args);
return new JdbcCursorItemReaderBuilder<>()
.name("dbReader")
.sql(SQL)
.preparedStatementSetter(argumentPreparedStatementSetter)
...

How to set up a scheduler in JBoss AS 5?

I have scheduled task in JBoss:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.varia.scheduler.Scheduler" name="acme:service=Scheduler">
<attribute name="…">…</attribute>
…
</mbean>
</server>
How to write this task, that will execute at 1:00 AM on the first day of every month?
Thank You!
How about using EJB Scheduler?
Otherwise, check here:
<mbean code="org.jboss.varia.scheduler.Scheduler" name="jboss.test:service=MyScheduler">
<attribute name="StartAtStartup">true</attribute>
<attribute name="SchedulableClass">test.MySchedulable</attribute>
<attribute name="SchedulableArguments">MySchedulable,100</attribute>
<attribute name="SchedulableArgumentTypes">java.lang.String,long</attribute>
<attribute name="InitialStartDate">NOW</attribute>
<attribute name="SchedulePeriod">5000</attribute>
<attribute name="InitialRepetitions">10</attribute>
</mbean>
Schedulable:
package test;
import java.util.Date;
import org.jboss.varia.scheduler.Schedulable;
import org.apache.log4j.Logger;
public class MySchedulable implements Schedulable
{
private static final Logger log = Logger.getLogger(MySchedulable.class);
private String name;
private long value;
public MySchedulable(String name, long value)
{
this.name = name;
this.value = value;
log.info("nt name: " + name + ", value: " + value);
}
public void perform(Date now, long repetitions)
{
log.info("perform(), time: " + now +", repetitions: " + repetitions +", name: " + name + ", value: " + value);
}
}
How about this
In jboss-service.xml
<!-- Put a real date here -->
<attribute name="InitialStartDate">01-01-01 01:00</attribute>
<attribute name="SchedulePeriod">86400000</attribute>
Then in Java
package com.example.scheduler.job;
import java.util.Date;
import org.jboss.varia.scheduler.Schedulable;
import org.apache.log4j.Logger;
public class MyJobScheduler implements Schedulable {
public MyJobScheduler() {}
public void perform(Date now, long repetitions) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(now);
int day = calendar.get(Calendar.DAY_OF_MONTH);
if(day == 1) {
// Do stuff
}
}
}
I know this question is old, but what do you think?