Buscar este blog

miércoles, 30 de diciembre de 2015

Log4j 1.x - Custom ThrowableRenderer

With log4j 1.x you can customize the format of your message logs with EnhancedPatternLayout,
There is a special Conversion Character to customize exception traces called throwable. But if you need more control about how to print exceptions you can hook your own renderer.

Create a class which implements org.apache.log4j.spi.ThrowableRenderer.
package es.cixtec.complexarchetype.web.log4j;

import org.apache.log4j.spi.ThrowableRenderer;

public class MyCustomThrowableRenderer implements ThrowableRenderer {

    @Override
    public String[] doRender(final Throwable t) {
        // do something with t
        return new String[] { "This", "is", "a", "custom", "trace" };
    }
}

Then, in log4j.xml, you need to link this class by using the throwableRenderer tag.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true"  xmlns:log4j='http://jakarta.apache.org/log4j/'>
    
    <throwableRenderer class="es.sisifo.test.web.log4j.MyCustomThrowableRenderer"/>
    
    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.EnhancedPatternLayout">
        <param name="ConversionPattern" 
          value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
        </layout>
    </appender>
    
    <appender name="LOG" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${jboss.server.log.dir}/test-web.log" />
        <param name="DatePattern" value="'.'yyyy-MM-dd"/>
        <layout class="org.apache.log4j.EnhancedPatternLayout">
            <param name="ConversionPattern" value="[%-5p][%d{ISO8601}][%-4L] %F>%m%n" />
        </layout>
    </appender>
    

    <root>
        <level value="DEBUG" />
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="LOG" />
    </root>

</log4j:configuration>

As result, when a exception is logged you get something like this.
LOGGER.error("Exceptions happens", new NullPointerException());

[ERROR][2015-12-30 11:33:09,003][45  ] GridServiceImpl.java>Exceptions happens
This
is
a
custom
trace

lunes, 28 de diciembre de 2015

JBoss - Useful system properties

This post is a recollection of some magic system properties to tweak JBoss. Some of them were found by our development team while others where found by our customer.
These were tested with JBoss EAP 6.2 and JBoss EAP 6.4.

Some of these properties can be found in the following page: https://docs.jboss.org/jbossweb/7.0.x/sysprops.html. Others are more hidden.

In domain mode, you can add a system property to a server with the following command:
[domain@localhost:9999 /] /host=hostController01/server-config=serv-one/system-property=popertyName:add(value=propertyValue)

Clear JSP cache on context destroy

Used in order to force JBoss to clean all .jsp an .class files during an application redeploy.

Key: DELETE_WORK_DIR_ONCONTEXTDESTROY
Value: true


Set server bind addres

Used in order to set a specific IP to a server when the host machine has multiple network interfaces.

Key 1: jboss.bind.address
Value: any valid address

Key 2: jboss.bind.address.unsecure
Value: any valid address

With these properties, in domain mode, you can multiple servers with different IPs address in the same machine.


Configure default request encoding

Used in order to send data encoded in a particular charset to the server.

Key 1: org.apache.catalina.connector.URI_ENCODING 
value: UTF-8

Key 2: org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING 
value: true


Configure maximun POST parammeter

Used in order to allow the browser to send a POST with a huge number of parameters, i.e, to submit a form with a lot of fields.

Key: org.apache.tomcat.util.http.Parameters.MAX_COUNT
value: a big number

CentOS SMB windows share

The purpose of this post is to show how to configure a shared directory between windows and UNIX.

In windows side

You need set a directory as shared.
Optionally you can add some users who will be allowed to acces to this directory. Keep in mind that de owner (the user who created the dir is also allowed to access).

For example, the user winuser with pass winpass share the folder winshare. The windows PC IP is 192.168.1.133.

In unix side

Install the following packages:
[root@host]# yum install samba-client samba-common cifs-utils

Create the associated dir in mount directory:
[root@host]# mkdir /mnt/winshareInUnix

In order to mount the dir you have two options:
Option 1 - Auto mount on startup:
You have to edit the /etc/fstab file and append the following line:
[root@host]# //192.168.1.133/winshare /mnt/winshareInUnix cifs user,uid=500,gid=500,rw,suid,username=winuser,password=winpass 0 0

Option 2 - Manual mount
[root@host]# mount -t cifs //192.168.1.133/winshare /mnt/winshareInUnix-o username=winuser,password=winpass ,sec=ntlm
(...)
[root@10 mnt]# umount /mnt/winshareInUnix

sábado, 26 de diciembre de 2015

Java - Web based protocol handler with Inno Setup

This is the second post about how to build and launch a desktop app from a web app, i.e, from a browser.

In the previous post (http://trabajosdesisifo.blogspot.com.es/2015/12/java-bundle-jre-inside-executable-file.html) I built and packed up a desktop java app. Now I want to be able to invoke this app, wich is running in the user PC, from the browser. In order to do that you need to create a custom protocol handler and register it in the user PC.

With a protocol invocation a browser can launch a user app. A very common example of this type of invocation is "mailto:". Just like when you click a link which points to "http:xxxx" the browser calls himself, when you click a link  which points to "mailto:mymail@gmail.com" the browser call the user app associated with the mailto protocol.

The magic with this type of invocations happens in the windows registry. There must be an entry in the registry that associates the protocol name with some local app. In this way, when the browser requested for this protocol, windows check its registry, reads the path to the local app, and calls it with the appropriate params.


I have installed Outlook as my default mail app, so the value of the key containing the app path is "C:\PROGRA~2\MICROS~1\Office12\OUTLOOK.EXE" -c IPM.Note /m "%1". 

If I type the following command in a DOS window I will call my Outlook to send a message to someDir@gmail.com:
"C:\PROGRA~2\MICROS~1\Office12\OUTLOOK.EXE" -c IPM.Note /m "someDir@gmail.com"

You can check in the Microsoft doc, https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx, what this registry entries means.


So, back to my desktop app, what I´m going to do is to register custom protocol called "desktop01:". This will be done during the installation of the own application, so I need to modify the installer script to tweak the registry.

Step 4, modify Inno Setup script

Inno Setup is like a compiler, you start with a code file (.java or, in this case .iss) and in the end you get the compilation (.class or in this case a .exe). In the Step 3 of this serie of post, I created the script file by using the graphical wizard, but the result was a .iss file like this one.

Desktop.iss
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "DesktopApp"
#define MyAppVersion "1.0.0"
#define MyAppPublisher "Sisifo INC"
#define MyAppURL "http://trabajosdesisifo.blogspot.com.es/"
#define MyAppExeName "desktopApp.exe"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{732AE723-F81E-4F76-A792-F94CC358F9C6}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "E:\desktopApp\desktopApp.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\desktopApp\resources\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent


As you can see, the script is divided in sections marked with the "[xxxx]". This is what really tells Inno Setup how to build the installer.

I want to register a custom protocol called "desktop01:", so according with MS doc, you need to create the following registry entries:

HKEY_CLASSES_ROOT
   desktop01
      (Default) = "URL:My custom protocol handler 01"
      URL Protocol = ""
      DefaultIcon
         (Default) = "desktopApp.exe,1"
      shell
         open
            command
               (Default) = "C:\Archivos de programa\DesktopApp\desktopApp.exe" "%1"

Some of the values are variables you can obtain from Inno Setup in runtime, so the final path will depend on the user election.

To translate this registry entries into the Inno Setup script, you have to added the following lines in this file.
[Registry]
Root: HKCR; Subkey: "desktop01"; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01"; ValueType: string; ValueName: ""; ValueData: "URL:My custom protocol handler 01"; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01\DefaultIcon"; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{#MyAppExeName},1"; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01\Shell\open\command"; Flags: uninsdeletekey
Root: HKCR; Subkey: "desktop01\Shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey

The complete doc about how to manage registry with Inno Setup can be found in its offical doc, http://www.jrsoftware.org/ishelp/index.php?topic=registrysection.

Then you need to rebuild the installer.

When you reinstall the app, and check the registry, you will found the new entries.


To test the app, I create the following simple HTML:
<html>

<body> 
 <a href="desktop01:myCustomArgument">Launch App</a> 
</script>

</body>
</html>

When you click in the link, the browser will show a warning to confirm the launch of the desktop app.



This solution supports only one argument, but you can pass multiple parameters in a query string - like fashion, just like in a URL.

Java - Bundle JRE inside executable file - Launch4j and Inno Setup

This is the first of a serie of two posts about how to launch a desktop java application from a web browser. In this case I´ll work in a desktop app because it has to be able to access local resources in the user PC (for example, applets could do this, but they are far deprecated).

The requirements of the desktop application are as follow:
  1. It must be as isolated as be possible, i.e., it must not depend on the user JRE.
  2. It must be easy to install.
  3. It must be invoked from a web application, i.e, from a web browser.
  4. It must be easily upgradeable.

In this post I´ll explain how to convert a desktop java application in a exe file for windows, and how
to put a embedded JRE inside of it.

All java app needs a Java Runtime Environment in which it´s executed. JRE is a free software you can download from Oracle site and it is used to execute java applications, i.e, jars. But one user only can have one default JRE, and this might not be the last release or might not be the one you need.
In this cases there are two solutions, the obvious is to force the user to use the JRE you need, which imply upgrade/downgrade to the required version. In much cases this is not a valid option because the new JRE may break other applications.
So the recommended solution is that the application be shipped with its own JRE, and this one will be used only by this app. In order to achieve this we will need two programs:
  1. Launch4j. To put it simple, tis is a exe wrapper. You have a jar file and conver it to a exe file for windows with a specifyc JRE.
  2. Inno Setup. This is a installer builder. You have a exe file and some aditional resources, and you get a new full installer wizard.

Step 1, the desktop app

In this posts I´ll use a very simple app comprised of two files.

Main:
package es.sisifo.desktop;

import java.io.IOException;

public class Main {
 public static void main(String[] args) throws IOException {
  String[] textosAMostrar;
  if (args == null || args.length == 0) {
   textosAMostrar = new String[]{"No se han recibido argumentos"};
  }
  else {
   textosAMostrar = args;
  }
  
  SimpleJFrame simpleJFrame = new SimpleJFrame(textosAMostrar);
  simpleJFrame.setVisible(true);
 }
}

SimpleJFrame:
package es.sisifo.desktop;

import java.awt.GridLayout;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class SimpleJFrame extends JFrame {
 private static final long serialVersionUID = -1153732581002339155L;

 public SimpleJFrame(String[] textosAMostrar) throws IOException {
  super("Simple App");
  setLayout(new GridLayout(textosAMostrar.length, 1));
  for(int i=0; i<textosAMostrar.length; i++) {
   JLabel texto = new JLabel("Texto " + i + ": " + textosAMostrar[i]);
   add(texto);
  }
  
  setBounds(500, 250, 300, 250);

  setResizable(true);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 }
}

And, of course, the POM.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>es.sisifo</groupId>
 <artifactId>desktop-1</artifactId>
 <version>0.0.1-SNAPSHOT</version>

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.3</version>
    <configuration>
     <source>1.8</source>
     <target>1.8</target>
    </configuration>
   </plugin>


   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.6</version>
    <executions>
     <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
       <goal>single</goal>
      </goals>
      <configuration>
       <archive>
        <manifest>
         <mainClass>es.sisifo.desktop.Main</mainClass>
        </manifest>
        <manifestEntries>
         <Permissions>all-permissions</Permissions>
         <Application-Name>Example Desktop app</Application-Name>        
         <Built-By>Sisifo</Built-By>
        </manifestEntries>
       </archive>
       <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
       </descriptorRefs>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</project>

This app just receives a list of arguments a prints them in  JFrame.
In the pom.xml file, you specify to build the whole app in a single jar and that the main class (i.e. the default entry point) is es.sisifo.desktop.Main.

Step 2, build the exe

You need to download Launch4j. This is a standalone app.

There are a lot of configuration options to create your exe, but in this case we will need just to specify three things:
  1. The output exe file. This will be the exe generated by this program.
  2. The input jar. This is the desktop app created in step one.
  3. The JRE path. This is the bundled JRE the app will use to run.

The important part here is the JRE path. The app must not depend on the user JRE, so it will carry its own JRE. In this case I downloaded the 32 bits JRE from oracle and unzziped it in a bin folder.
I chose to use a 32 bits JRE because I don´t know if the final users will have a 64 bits system.

This is my folder structure:
  • work folder (any folder)
    • bin
      • jre1.8.0_66 (the JRE folder)
      • desktop-1-0.0.1-SNAPSHOT-jar-with-dependencies.jar (the app jar)



Note that the "Bundled JRE path", it is a relative path. You can not set an absolute path here, because you don´t know where the JRE will be in the final user PC.

Finally, you save your configuration file (I named it as "desktop.xml") and you build the exe by clicking in the gear icon.


Ok, now you have a exe file which launch your java app. But if you want to distribute this program as is, you have to ship the the exe file, the jar file and the JRE folder too. The final user will have to create a work folder, anywhere she wish, but this folder must have the structure presented previously, otherwise the exe will not found the jar or the JRE. Cumbersome.

Step 3, build the installer

Lets make the user life more ease and create a windows installer. You need to download Inno Setup.

Inno Setup is configured upon a script file. You can write your script manually, but it has a very useful script wizard, so you will not need to write any code.

Before we start with the installer, you need to reorganize your work folder. You need to create a new folder, for example resources, and put the JRE and the jar inside it. The result is as follow:
  • work folder (any folder)
    • resources
      • bin
        • jre1.8.0_66 (the JRE folder)
        • desktop-1-0.0.1-SNAPSHOT-jar-with-dependencies.jar (the app jar)
    • desktopApp.exe
As you can see next, you need a resources folder in order Inno Setup take all its content and package it inside the installer.


Now, Inno Setup. The first time you run Inno Setup you will see a screen to create your own script or build one from the wizard, In this case we will use the last one.

The wizard is quite simple, so most of the time you can press next without any further configuration.

The result is a classical exe installer placed in a output folder. When you run this installer a wizard will be launched with the options you configured previously. The result is a the new app installed in your system.



At this point you have a distributable installer of about 40 MB that you can send to any windows user, and you can be sure your app will work on its PC.


In the next post I will show how to make this application is launched from a web browser.