Monday, November 18, 2013

NextReports: Use reports to create portions of your web application

NextReports Server allows users to integrate charts & reports as iframes inside other applications using an embedded code.

If users do not want to use NextReports Server, there is also the possibility to use the generated reports inside iframes.

NextReports Server is implemented using Wicket framework. In Wicket , a simple document inline frame can be implemented to be used with an iframe tag inside html markup. This makes it very easy to use any Next report to show data from your database inside an application. After you have a NextReportPanel class like the one following, you do not need to write code to get particular data, you just have to create a report! and reuse this panel.

Lets say we want to see some report inside our web application.

The html file will look like:
<html>
    <wicket:panel>
        <iframe height="400px" wicket:id="report"></iframe>
    </wicket:panel>
</html>
Our Wicket component will be just a Wicket Panel. A ByteArrayResource just retrieves the report bytes which can also be cached if we want to. In this example we generate a HTML file:
public class NextReportPanel extends Panel { 
    private String reportName;
       
    // our object model (used to pass parameters to Next report)
    private Model model;
    
    // cache for report data per model
    private static Map<String, byte[]> dataMap = new HashMap<String, byte[]>(); 

    public NextReportPanel(String id, String reportName, IModel<String> model) {
        super(id);        
        this.reportName = reportName; 
        this.model = model;
        setRenderBodyOnly(true);
        add(new DocumentInlineFrame("report", new ReportResource()));
    }
    
    private String getModelId() {
        String id = "";
        if (model.getObject() != null) {
            id = model.getObject().getId();            
        } 
        return id;
    }    

    class ReportResource extends ByteArrayResource {
                
        private static final long serialVersionUID = -6307719094949487807L;
        private byte[] data;

        public ReportResource() {
            super("text/html");                    
        }
        
        @Override
        protected byte[] getData(final Attributes attributes) {            
            String id = getModelId();
            data = dataMap.get(id);            
            if (data == null) {                    
                data = generateReport();                
                dataMap.put(id, data);                
            }     
            return data;
        }                
        
        @Override
        protected void configureResponse(ResourceResponse response, Attributes attributes) {
            response.setCacheDuration(Duration.NONE); 
        }
              
        private byte[] generateReport() {            
            HashMap<String, Object> pValues = new HashMap<String, Object>();
            pValues.put("Id", getModelId());
            ByteArrayOutputStream output;
            Connection connection = null;
            Report report = getReport();
            try {
                output = new ByteArrayOutputStream();
                connection = ConnectionUtil.createConnection();
                FluentReportRunner.report(report).
                    connectTo(connection).
                    withQueryTimeout(60).
                    withParameterValues(pValues).
                    formatAs(ReportRunner.HTML_FORMAT).
                    run(output);                
                return output.toByteArray();
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                return new byte[0];
            } finally {
                ConnectionUtil.closeConnection(connection);
            }
        }

        private Report getReport() {
            InputStream is = getClass().getResourceAsStream("/" + reportName);
            try {
                return ReportUtil.loadReport(is);
            } catch (LoadReportException e) {
                e.printStackTrace();
                return null;
            }
        }  
    }        
 }
This panel can be added in any page with different reports. To modify data (if users want to see more / less data) you will just have to modify the report! No source code modification!

No comments: