Tuesday, November 19, 2013

NextReports Designer: View columns that have indexes

Even if NextReports Designer is a reporting tool and not a database tool, users asked to see what columns have indexes so they know if their queries are optimized or not.

From version 6.3 NextReports Designer will show indexed columns as an info icon

similar with those of primary keys and foreign keys. You can see this icon in "View Columns Info" action on any table:


You can also see this icon if you drag and drop a table in designer query perspective:

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!