Subreports within a subreport (IReport-JasperReports) - jasper-reports

I have a requirement that needs to have a subreport within a subreport. Is there a sample code which I can refer?
Thanks in advance.

You don't actually need any code at all to generate a subreport within a subreport. This can be done with reports that have no dynamic components (nothing in the detail band). Of course the resulting report won't be much use for anything interesting.
If you wanted a more interesting report than this, you'll need to provide data for the report and / or subreport. At that point the code will vary depending on where your data is coming from. If you can provide more information on what you are trying to do, we can perhaps be more help.
If the subreport has dynamic content, you will need to pass in to it access to an object which implements JRDataSource.
For example, I recently created a one page report that had multiple "clauses" in it. To make my life simpler, I stored the clauses in a Map and derived the JRDataSource object using the following code. The JRDataSource objects were then passed in as a field for the main report.
private static class ListMapDataSource implements JRRewindableDataSource {
private Map currentMap = null;
private int currentRow;
private int numberOfMoveFirsts = 0;
private List<Map<String, ? extends Object>> rowList;
ListMapDataSource(List<Map<String, ? extends Object>> rowList) {
this.rowList = rowList;
moveFirst();
}
ListMapDataSource(Map<String, ? extends Object> singleRow) {
this.rowList = new ArrayList<Map<String, ? extends Object>>(1);
this.rowList.add(singleRow);
moveFirst();
}
public boolean next() throws JRException {
if (currentRow >= rowList.size() - 1) {
return false;
}
currentRow++;
currentMap = rowList.get(currentRow);
return true;
}
public Object getFieldValue(JRField jrField) throws JRException {
String name = jrField.getName();
Class valueClass = jrField.getValueClass();
if (JasperReport.class.isAssignableFrom(valueClass)) {
}
return currentMap.get(name);
}
public void moveFirst() {
numberOfMoveFirsts++;
if (numberOfMoveFirsts > 10) {
System.out.println("Exceeded 10 moveFirst() calls. Aborting.");
System.exit(1);
}
currentRow = - 1;
currentMap = null;
}
}

Related

How to optimize SQL query in Anylogic

I am generating Agents with parameter values coming from SQL table in Anylogic. when agent is generated at source I am doing a v look up in table and extracting corresponding values from table. For now it is working perfectly but it is slowing down the performance.
Structure of Table looks like this
I am querying the data from this table with below code
double value_1 = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.avg_value)).get(0);
double value_min = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.min_value)).get(0);
double value_max = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.max_value)).get(0);
// Fetch the cluster number from account table
int cluster_num = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.cluster)).get(0);
int act_no = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.actno)).get(0);
String pay_term = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.pay_term)).get(0);
String pay_term_prob = (selectFrom(account_details)
.where(account_details.act_code.eq(z))
.list(account_details.pay_term_prob)).get(0);
But this is very slow and wants to improve the performance. someone mentioned that we can create a Java class and then add the table into collection . Is there any example where I can refer. I am finding it difficult to put entire code.
I have created a class using below code:
public class Customer {
private String act_code;
private int actno;
private double avg_value;
private String pay_term;
private String pay_term_prob;
private int cluster;
private double min_value;
private double max_value;
public String getact_code() {
return act_code;
}
public void setact_code(String act_code) {
this.act_code = act_code;
}
public int getactno() {
return actno;
}
public void setactno(int actno) {
this.actno = actno;
}
public double getavg_value() {
return avg_value;
}
public void setavg_value(double avg_value) {
this.avg_value = avg_value;
}
public String getpay_term() {
return pay_term;
}
public void setpay_term(String pay_term) {
this.pay_term = pay_term;
}
public String getpay_term_prob() {
return pay_term_prob;
}
public void setpay_term_prob(String pay_term_prob) {
this.pay_term_prob = pay_term_prob;
}
public int cluster() {
return cluster;
}
public void setcluster(int cluster) {
this.cluster = cluster;
}
public double getmin_value() {
return min_value;
}
public void setmin_value(double min_value) {
this.min_value = min_value;
}
public double getmax_value() {
return max_value;
}
public void setmax_value(double max_value) {
this.max_value = max_value;
}
}
Created collection object like this:
Pls provide an reference to add this database table into collection as a next step. then I want to query the collection based on the condition
You are on the right track here!
Every time you access the database to read data there is a computational overhead. So the best option is to access the database only once, at the start of the model. Create all the objects you need, store other data you will need later into Java classes, and then use the Java classes.
My suggestion is to create a Java class for each row in your table, like you have done. And then create a map object - like you have done, but with the key as String and the value as this new object.
Then on model start you can populate this map as follows:
List<Tuple> rows = selectFrom(customer).list();
for (Tuple row : rows) {
Customer customerData = new Customer(
row.get( customer.act_code ),
row.get( customer.actno ),
row.get( customer.avg_value )
);
mapOfCustomerData.put(customerData.act_code, customerData);
}
Where mapOfCustomerData is a linkedHashMap and customer is the name of the table
See the model created in this blog post for more details and an example on using a scenario object to store all the data from the Database in a separate object
Note: The code above is just an example - read this blog post for more details on using the AnyLogic INternal Database
Before using Java classes, try this first: click the "index" tickbox for all columns that you query with a WHERE clause.

Dynamic DataGrid in GWT

I am trying to construct a DataGrid in GWT that will show an arbitrary dataset taken from an rpc method.
I have done some progress as I get the fields from a method and the data from another.
I have managed to construct the Datagrid and add the columns from the rpc.getFields() method and fill the table using an AsyncDataProvider.
The problem is that when I refresh the browser, it duplicates all the columns at the Datagrid. I cannot figure out what to do. I tried to remove first all the columns but no luck.
I attach the code if anyone have an idea.
public class MyCallBack implements AsyncCallback<List<Field>> {
DataGrid<Record> dg;
public MyCallBack(DataGrid<Record> dgrid) {
this.dg=dgrid;
}
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
}
public void onSuccess(List<Field> result) {
for (int i=0;i<=result.size();i++) {
IndexedColumn ic = new IndexedColumn(i);
dg.addColumn(ic, result.get(i).getLabel());
}
}
public AsyncCallback<List<Field>> getCb() {
return this;
}
public void onModuleLoad() {
final DataGrid<Record> dg = new DataGrid<Record>();
MyCallBack mcb = new MyCallBack(dg);
DataProvider dp = new DataProvider();
DBConnectionAsync rpcService = (DBConnectionAsync) GWT.create(DBConnection.class);
ServiceDefTarget target = (ServiceDefTarget) rpcService;
String moduleRelativeURL = GWT.getModuleBaseURL() + "MySQLConnection";
target.setServiceEntryPoint(moduleRelativeURL);
rpcService.getFields(mcb.getCb());
dp.addDataDisplay(dg);
dg.setVisibleRange(0, 200);
SplitLayoutPanel slp = new SplitLayoutPanel();
slp.setHeight("700px");
slp.setWidth("1500px");
slp.addWest(dg, 770);
RootPanel.get().add(slp);
}
When you refresh a browser, all UI is lost. There is no difference between (a) show the UI for the first time or (b) show the UI after browser refresh.
Your comment "Only if I restart tomcat it works" suggests that the problem is on the server side. Most likely, you return twice the number of data points on a second call.
Try clearing the table before filling it like this:
public void onSuccess(List<Field> result) {
clearTable();
for (int i=0;i<=result.size();i++) {
IndexedColumn ic = new IndexedColumn(i);
dg.addColumn(ic, result.get(i).getLabel());
}
}
private void clearTable(){
while (dg.getColumnCount() > 0) {
db.removeColumn(0);
}
}

Spring Batch Footer Validation

I am using Spring batch for processing a file with a header, detail and footer records.
The footer contains the total number of records in the file.
If the detail record count dosent match the count in the footer, the file should not be processed.
I am using a Custom Line Tokenizer that processes the header, detail and footer record. When the footer record is encountered, if the count dosent match the detail record count, I am throwing an exception.
But the problem I am facing is if the chunk size is set to small numbers like 10 and the file has 20 records, the first 10 detail records are being persisted into the DB, even though the footer count dosent match the total number of records.
Is there a way to validate the footer count with the number of records in the file before the call to the Writer?
Thanks.
What you need is a reader with a footer callback handler defined. I had faced a similar problem and this link helped me a lot!
See the last post by Atefeh Zareh. He has also included the xml configuration.
And regarding the first ten being persisted, you can have another validation step before the main processing step which will just check the header and trailer counts. Do not write any persisting logic in the writer. If the count fails, stop the job so that it does not go into the processing step.
By writing our own Item Reader as well as Item classes to handle Header,Footer,Data records and finding the counts of Header,Footer,Data records
ItemReader Class
public class AggregateItemReader<T> implements ItemStreamReader<ResultHolder> {
private ItemStreamReader<AggregateItem<T>> itemReader;
#Override
public ResultHolder read() throws Exception {
ResultHolder holder = new ResultHolder();
while (process(itemReader.read(), holder)) {
continue;
}
if (!holder.isExhausted()) {
return holder;
}
else {
return null;
}
}
private boolean process(AggregateItem<T> value, ResultHolder holder) {
// finish processing if we hit the end of file
if (value == null) {
LOG.debug("Exhausted ItemReader");
holder.setExhausted(true);
return false;
}
// start a new collection
if (value.isHeader()) {
LOG.debug("Header Record detected");
holder.addHeaderRecordCount();
return true;
}
// mark we are finished with current collection
if (value.isFooter()) {
LOG.debug("Tailer Record detected");
holder.addTailerRecordCount();
holder.setFiledRecordCount(value.getFieldSet().readInt(3));
System.out.println("###########################################"+holder.getDataRecordCount()+"############################################");
return false;
}
// add a simple record to the current collection
holder.addDataRecordCount();
return true;
}
And Item Class is
public class AggregateItem<T> {
#SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getData(FieldSet fs) {
return new AggregateItem(fs, false, false, true);
}
#SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getFooter(FieldSet fs) {
return new AggregateItem(fs, false, true, false);
}
#SuppressWarnings("unchecked")
public static <T> AggregateItem<T> getHeader(FieldSet fs) {
return new AggregateItem(fs, true, false, false);
}
private boolean data = false;
private FieldSet fieldSet;
private boolean footer = false;
private boolean header = false;
private T item;
public AggregateItem(FieldSet fs, boolean header, boolean footer, boolean data) {
this(null);
this.header = header;
this.footer = footer;
this.data = data;
this.fieldSet = fs;
}
public AggregateItem(T item) {
super();
this.item = item;
}
public FieldSet getFieldSet() {
return fieldSet;
}
public T getItem() {
return item;
}
public boolean isData() {
return data;
}
public boolean isFooter() {
return footer;
}
public boolean isHeader() {
return header;
}
}
And ResultHolder class is
public class ResultHolder implements {
private Integer headerRecordCount = 0;
private Integer dataRecordCount = 0;
private Integer tailerRecordCount = 0;
private Integer filedRecordCount;//this is to save record count given in source File
private boolean exhausted = false;//setters & getters
}
If any doubts feel free to mail at sk.baji6#gmail.com

Get and Set attribute values of a class using aspectJ

I am using aspectj to add some field to a existing class and annotate it also.
I am using load time weaving .
Example :- I have a Class customer in which i am adding 3 string attributes. But my issues is that I have to set some values and get it also before my business call.
I am trying the below approach.
In my aj file i have added the below, my problem is in the Around pointcut , how do i get the attribute and set the attribute.
public String net.customers.PersonCustomer.getOfflineRiskCategory() {
return OfflineRiskCategory;
}
public void net.customers.PersonCustomer.setOfflineRiskCategory(String offlineRiskCategory) {
OfflineRiskCategory = offlineRiskCategory;
}
public String net.customers.PersonCustomer.getOnlineRiskCategory() {
return OnlineRiskCategory;
}
public void net.customers.PersonCustomer.setOnlineRiskCategory(String onlineRiskCategory) {
OnlineRiskCategory = onlineRiskCategory;
}
public String net.customers.PersonCustomer.getPersonCommercialStatus() {
return PersonCommercialStatus;
}
public void net.customers.PersonCustomer.setPersonCommercialStatus(String personCommercialStatus) {
PersonCommercialStatus = personCommercialStatus;
}
#Around("execution(* net.xxx.xxx.xxx.DataMigration.populateMap(..))")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
Object arguments[] = joinPoint.getArgs();
if (arguments != null) {
HashMap<String, String> hMap = (HashMap) arguments[0];
PersonCustomer cus = (PersonCustomer) arguments[1];
return joinPoint.proceed();
}
If anyone has ideas please let me know.
regards,
FT
First suggestion, I would avoid mixing code-style aspectj with annotation-style. Ie- instead of #Around, use around.
Second, instead of getting the arguments from the joinPoint, you should bind them in the pointcut:
Object around(Map map, PersonCustomer cust) :
execution(* net.xxx.xxx.xxx.DataMigration.populateMap(Map, PersonCustomer) && args(map, cust) {
...
return proceed(map, cust);
}
Now, to answer your question: you also need to use intertype declarations to add new fields to your class, so do something like this:
private String net.customers.PersonCustomer.OfflineRiskCategory;
private String net.customers.PersonCustomer.OnlineRiskCategory;
private String net.customers.PersonCustomer.PersonCommercialStatus;
Note that the private keyword here means private to the aspect, not to the class that you declare it on.

Creating custom ActionCell in CellTable Column

I want one of my table columns to have a deleteButton.
ActionCell<Entrata> deleteCell = new ActionCell<Entrata>("x",new Delegate<Entrata>() {
#Override
public void execute(Entrata object) {
// rpc stuff....
}
});
Ok but this line generates an error:
Column<Entrata,Entrata> deleteColumn = new Column<Entrata, Entrata>(deleteCell);
"Cannot instantiate the type Column"
What do you think?
Here you go with working code:
Assumptions:
TYPE - Is the class of the data you show in rows of Cell Table it the same because I assume you want reference to the instance of data when you going to delete it
public class DeleteColumn extends Column<TYPE, TYPE>
{
public DeleteColumn()
{
super(new ActionCell<TYPE>("Delete", new ActionCell.Delegate<TYPE>() {
#Override
public void execute(TYPE record)
{
/**
*Here you go. You got a reference to an object in a row that delete was clicked. Put your "delete" code here
*/
}
}));
}
#Override
public TYPE getValue(TYPE object)
{
return object;
}
};
From the doku:
A representation of a column in a table. The column may maintain view data for each cell on demand. New view data, if needed, is created by the cell's onBrowserEvent method, stored in the Column, and passed to future calls to Cell's
So you have to declar it something like this:
Column<String, String> colum = new Column<String, String>(null) {
#Override
public String getValue(String object) {
// TODO Auto-generated method stub
return null;
}
};
Still I don't exactly know how you implement the delete button, so it would be nice if you can give us the rest of your code.
This works
//table = initialized CellTable with content already loaded
ActionCell editCell = new ActionCell<EmployeeObject>("remove", new ActionCell.Delegate<EmployeeObject>() {
public void execute(EmployeeObject object){
List<EmployeeObject> list = new ArrayList<EmployeeObject>(table.getVisibleItems());
for(int i = 0; i < list.size(); i ++){
if(object.getFirstname().equals(list.get(i).getFirstname())){
list.remove(i);
break;
}
}
table.setRowData(list);
}
});
Column<EmployeeObject, ActionCell> editColumn = (new IdentityColumn(editCell));