Displaying PDF documents on Netbeans RCP

This article explains how to display PDF documents on Netbeans RCP, using JasperReports libraries.

This article appeared first at techtavern.wordpress.com.

The proposed solution uses a TopComponent instance in editor mode to display each PDF document. It assumes that there is a JasperPrint object that represents a page-oriented document that can be viewed, printed or exported to other formats. The TopComponent will use a JRViewer to render the PDF document. The JRViewer handles scrolling, zooming, paging and even printing and saving as PDF, Excel and other formats.

Required libraries

Your module (or some depended module) requires to import JasperReport and POI libraries. Following JARs worked for me and were downloaded from Maven Central Repository: jasperreports-6.0.0.jar, commons-codec-1.5.jar, dom4j-1.6.1.jar, stax-api-1.0.1.jar, poi-ooxml-schemas-3.10-FINAL-20140208.jar, poi-scratchpad-3.10-FINAL-20140208.jar, poi-3.10-FINAL-20140208.jar.

Create an empty TopComponent

Create a TopComponent named “JasperViewerTopComponent”. Add no content to it. Change annotation as shown above:

@TopComponent.Description(
    preferredID = "JasperViewerTopComponent",
    iconBase = "br/.../libs/jasper/JasperViewerTopComponent",
    persistenceType = TopComponent.PERSISTENCE_NEVER
)
@TopComponent.Registration(mode = "editor", openAtStartup = false)

Some comments about the annotations:

  • Remove @ActionID, @ActionReference and @TopComponent.OpenActionRegistration annotations that are generated automatically by the IDE. This annotations would create a menu entry in the “Window” menu to open a singleton TopComponent, that means, there would be only one TopComponent to display one PDF file at time.
  • Also remove @ConvertAsProperties annotation and edit @TopComponent.Description to set persistenceType to TopComponent.PERSISTENCE_NEVER. The original persistence type works only for singleton TopComponents.
  • Also remove @Messages annotation, as TopComponent title and tooltip will be set manually.
  • @TopComponent.Registration(mode = “editor”, openAtStartup = false). A TopComponent of mode “editor” is arranged centrally, surrounded by other non-editor TopComponents. This is usually the best alternative.

Change constructor

Replace the empty argument constructor by following constructor:

public JasperViewerTopComponent(String title, JasperPrint jasperPrint) {
  this.jasperPrint = jasperPrint;
  initComponents();
  setName(title);
  setToolTipText(title);
// CAUTION:
// Import net.sf.jasperreports.view.JRViewer
// Won't work with net.sf.jasperreports.swing.JRViewer
  JRViewer viewer = new JRViewer(jasperPrint);
  JRSaveContributor[] contrbs = viewer.getSaveContributors();
// Remove save-as features you don't want.
// This example keeps only save as PDF and Excel options.
  for (JRSaveContributor saveContributor : contrbs) {
    if (!(saveContributor instanceof JRSingleSheetXlsSaveContributor
     || saveContributor instanceof JRPdfSaveContributor)) {
       viewer.removeSaveContributor(saveContributor);
    }
 }
 add(viewer, BorderLayout.CENTER);
}

Some comments about the constructor:

  • There are two classes named JRViewer. Make sure to use net.sf.jasperreports.view.JRViewer!
  • JRViewer will take care of scrolling, zooming, paging and even printing and saving as PDF, Excel and other formats
  • It is simpler to create the JRViewer within the constructor instead of within the initComponents() method. As initComponents() is maintained by Matisse, you would have to use an attribute to pass the jasperPrint instance to JRViewer constructor.

Create utility method to open PDF files

public static void openReport(final String title, final JasperPrint jasperprint) {
  SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
      JasperViewerTopComponent tc = new JasperViewerTopComponent(title, jasperprint);
      tc.open();
      tc.requestActive();
    }
  });
}

That’s it.

HttpURLConnection and GET query parameters

I regret that JAVA SE still lacks any decent native HTTP client framework! Simple use cases like GET requests with query parameters require handcrafted coding with HttpURLConnection.

This article appeared first at techtavern.wordpress.com.

HttpURLConnection misses methods to set query parameters. There is no URI builder facility as found on Apache HTTP Client. You are on your own.

Therefore, I wrote the applyParameter method that takes care of GET query parameters.

URI baseUri = new URI("www.exemple.com/search");
URI uri = applyParameters(baseUri, "word","java");
HttpURLConnection connection = 
    (HttpURLConnection) uri.toURL().openConnection();
connection.setDoInput(true);
connection.setDoOutput(false);
connection.setRequestMethod("GET");
connection.connect();
if (connection.getResponseCode() == 
   HttpURLConnection.HTTP_OK) {
   // ...
}

The applyParameters method looks like:

URI applyParameters(URI baseUri, String[] urlParameters)
   StringBuilder query = new StringBuilder();
   boolean first = true;
   for (int i = 0; i < urlParameters.length; i += 2) {
     if (first) {
        first = false;
     } else {
        query.append("&");
     }
     try {
        query.append(urlParameters[i]).append("=")
             .append(URLEncoder.encode(urlParameters[i + 1], "UTF-8"));
     } catch (UnsupportedEncodingException ex) {
        /* As URLEncoder are always correct, this exception
         * should never be thrown. */
       throw new RuntimeException(ex);
     }
   }
   try {
      return new URI(uri.getScheme(), uri.getAuthority(), 
         uri.getPath(), query.toString(), null);
   } catch (URISyntaxException ex) {
     /* As baseUri and query are correct, this exception
      * should never be thrown. */
      throw new RuntimeException(ex);
   }
}

I had to bother about catching two exception that I know that will never be thrown: URISyntaxException and UnsupportedEncodingException. I had to join parameters by hand into a string. I had to care about safe web encoding. Shame on you JAVA!

Fortunately, at least I figured out that the URI constructor allows to append the query string to the base URI.

Update licence header without plugin

This article explains how to update license header for your java source files without any tool. It works for Notepad++, Netbeans and Eclipse and does not require installing any additional plugin.

This article appeared first at techtavern.wordpress.com.

Option 1: Using Notepad++

Open Notepad++ and navigate to Search->Find ind Files. Fill the dialog as shown below.

update-license-header-withou-any-tool-notepadplusplus

Find what: \A(.*?^package){1}
Replace with: /\*\r\n \* (line 1)\r\n \* (line 2).\r\n \*/\r\npackage
Directory: The root directory of your source code.
Filters: *.java
Activate “Regular expression” and “. maches newline”.

When using non-English license text, use UTF8 escaping for non-ascii chars. For example, use “\xE3” instead of “ã” (more examples)

Pros: Does not require any IDE.
Cons: Does not work properly for non-English license headers. Unfortunately, Notepad++ does not allow setting the encoding for the affected files.

Options 2: Using Netbeans IDE

Open the java project with Netbeans IDE, select it and navigate to Edit->Replace in Projects.

Fill the dialog as shown below.

update-license-header-withou-any-tool-netbeans

Containing text: (?s)\A(.*?^package){1}
Match: Regular expression
Replace with: /\*\r\n \* (line 1)\r\n \* (line 2).\r\n \*/\r\npackage
Scope: Your java project or browser the source root directory
File name patterns: *.java

Click on continue. A new window opens listing all affected files. Confirm.

Pros: Works better than Netbeans License Changer plugin. Supports non-English languages and respects your encoding.

Cons: Replaces at most 500 files at time. For large projects, you are required do repeat this recipe on each subdirectory.

Options 3: Using Eclipse IDE

Open the java project with Eclipse IDE, select it and navigate to Search->File.

Fill the dialog as shown below.

update-license-header-withou-any-tool-eclipse

Containing text: (?s)\A(.*?^package){1}
Activate “Regular expression”
File name patterns: *.java

Click “Replace”. A new windows opens listing all affected files and a new dialog asks for the new text: /\*\r\n \* (line 1)\r\n \* (line 2).\r\n \*/\r\npackage

update-license-header-withou-any-tool-eclipse-2

Click “Preview” to see how files are going to be changes. Or click “OK”.

Pros: Supports non-English languages and respects your encoding. Updates file only if license header is already correct.

Cons: not known yet.

Comparing your Oracle databases

This article suggests an approach to compare your development, test and production databases using SQL scripts executed from a Servlet.

This article appeared first on techtavern.wordpress.com

Create a Servlet that produces following SQL statements as a text report: (replace **** with a proper value applicable to your database).

  • Tables, sequences and views: SELECT OBJECT_TYPE, OBJECT_NAME, STATUS FROM ALL_OBJECTS WHERE OWNER = ‘****’ ORDER BY OBJECT_TYPE, OBJECT_NAME
  • Columns of each table: SELECT TABLE_NAME, COLUMN_NAME, QUALIFIED_COL_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, CHARACTER_SET_NAME, CHAR_COL_DECL_LENGTH, CHAR_LENGTH, CHAR_USED FROM ALL_TAB_COLS WHERE OWNER = ‘****’ ORDER BY TABLE_NAME, COLUMN_NAME
  • Constrains of each table: SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE, STATUS, SEARCH_CONDITION, R_CONSTRAINT_NAME, DELETE_RULE, DEFERRABLE, DEFERRED, VALIDATED, GENERATED FROM ALL_CONSTRAINTS WHERE OWNER = ‘****’ ORDER BY TABLE_NAME, CONSTRAINT_NAME
  • Sequences: SELECT SEQUENCE_NAME, INCREMENT_BY, MIN_VALUE, MAX_VALUE, CACHE_SIZE, CYCLE_FLAG, ORDER_FLAG FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = ‘****’ ORDER BY SEQUENCE_NAME

For security reasons, you may prefer to output them into the application log.

You may request these reports on each of your environments and compare them side-by-side, for example, using Beyond Compare.

Netbeans RCP: increasing JVM memory settings

This article explains how to increase memory limits for your Netbeans RCP application when using Ant to create a ZIP package or a Windows installer.

This article appeared originally at techtavern.wordpress.com.

Introduction

Both ZIP package and Windows installer contain an executable that reads JVM and bootstrap settings from the etc/application_name.conf file. This file is copied from the laucher configuration template at netbeans-installation\harness\etc\app.conf. The default options contains all command line parameters passed to the executable. JVM parameters are prefixed by “-J”.

By default, this file has very tight memory settings (heap from 24 upto 64MB):

default_options="--branding ${branding.token} -J-Xms24m -J-Xmx64m"

Solution 1: Edit app.conf

Open netbeans-installation\harness\etc\app.conf and increase the -J-Xms and -J-Xmx parameters. However, this may require administrator priviledges if Netbeans IDE was installed into the application directory. The change will affect all application you build on the machine and will not get into your version control. You need to rememberto edit this file again on a fresh install.

Solution 2: Create your own app.conf

Create your own app.conf file within your application suite directory. Mention this file using the app.conf property within the nbproject/project.properties file of your main application suite project.

# Main-Suite\nbproject\project.properties:
app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif
app.name=${branding.token}
app.title=...
app.conf=nbproject/custom.conf

My custom.conf looks like the original app.conf:

# Main-Suite\nbproject\custom.conf:
# ${HOME} will be replaced by user home directory according to platform
default_userdir="${HOME}/.${APPNAME}/${buildnumber}"
default_mac_userdir="${HOME}/Library/Application Support/${APPNAME}/${buildnumber}"

# options used by the launcher by default, can be overridden by explicit
# command line switches
default_options="--branding ${branding.token} -J-Xms128m -J-Xmx512m"

As the custom.conf resides inside the project configuration directory, it will be versioned by source control and used by every distribution build.

References

Calling Objectify within DeferredTask

This article explains how to call Objectify within a DeferredTask on Google App Engine push queue.

This article appeared first on techtavern.wordpress.com

Objectify Wiki presents a clear explanation how to user ObjectifyFilter to get or inject a Objectify instance into your servlet. However there is no word using Objectify within push queues.

Solution 1: Create task with worker URLs that are mapped to your servlet

Let ObjectifyFilter inject the Objectify instance. It your responsibility to encode and handle parameters and to secure your URLs.

Solution 2: Create a DeferredTask

Let GAE handle parameters and security for you. Call ObjectifyService.begin() to manually start an Objectify session. Close this session manually when the task finishes. A try-with-resources block handles everything for you.

import com.googlecode.objectify.ObjectifyService;

public class MyTask implements DeferredTask {
   final String parameter;
   public MyTask(String parameter) {
      this.parameter = parameter;
   }

   @Override
   public void run() {
      try (Closeable closeable = ObjectifyService.begin()) {
          Objectify ofy = MyObjectifyService.ofy();          
          // start transactions, read or write data.
          // ...
      } catch (IOException | RuntimeException e) {
          // log or handle failure.
      }
   }
}

I recommend a class that statically registers your entities before calling any Objectify method.

public class MyObjectifyService {
   static {
      factory().register(MyEntity.class);
      // ...
   }
   public static Objectify ofy() {
      return ObjectifyService.ofy();
   }
}

References:

Google App Engine Java SDK advices

It would have been nice if I knew this beforehand about Google App Engine Java SDK

This article originally appeared on https://techtavern.wordpress.com

GAE infrastructure is a kind of Java 7 platform. You may compile your code using the current Java 8 SDK, as long as source code version is set to Java 7. You may deploy and run your application locally with Java 8, too.

However, when deploying to Google infrastructure, there are some pitfalls.

  1. The appcfg script pre-compiles your JSP files using the Java SDK on the PATH or set by JAVA_HOME system property. If this SDK is not Java 7, appcfg will create and upload incompatible class files.
  2. Java SDK 7 is not available anymore for download on Oracle website.

I have found Java SDK 7 (7u79) installer for download still available on http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

Probably, you do not want do pollute your development environment by installing a deprecated SDK. This article explains how to extract a portable SDK without running the installer. And if you do not want to mess your current PATH and JAVA_HOME system variables globally, you may set them within the appcfg.cmd file.

setlocal
set JAVA_HOME=C:\Users\Daniel\Programas\jdk7
set PATH=C:\Users\Daniel\Programas\jdk7\bin
java -Duser.language=EN -Xmx1100m -cp "%~dp0\..\lib\appengine-tools-api.jar" 
     com.google.appengine.tools.admin.AppCfg %*
endlocal
Follow

Get every new post delivered to your Inbox.

Join 429 other followers