Archive for January, 2012

16
Jan
12

Invoke Server Side Code Using GWT

This page describes how to Invoke Server Side Code to retrieve data from the server side and display the results in a JavaScript pop-up.

Background

GWT generates JavaScript code that makes a call to server side components thru the Servlet Interface. The Service Implementation class extends the “RemoteServiceServlet” class. This allows GWT to respond to requests made from the GWT generated Javascript.

Requirements

Procedure

Before we begin we need to create directories.

mkdir -p src/main/java/com/test/server

Create the Interface

First you create a an interface that can be used by the client. Maven generates a client side Interface based this. The interface class should be in the module’s client package.

vi src/main/java/com/test/client/GreetingService.java

package com.test.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String input) throws IllegalArgumentException;
}

Create the Implementation

The implementation class should be in the module’s server package.

vi src/main/java/com/test/server/GreetingServiceImpl.java

package com.test.server;

import com.test.client.GreetingService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
    GreetingService {

  public String greetServer(String input) throws IllegalArgumentException {
    String serverInfo = getServletContext().getServerInfo();
    String userAgent = getThreadLocalRequest().getHeader("User-Agent");

    return "Hello, " + input + "! I am running " + serverInfo
        + ".It looks like you are using:" + userAgent;
  }
}

Define the Servlet

Add the servlet to the web.xml.

vi src/main/webapp/WEB-INF/web.xml

  <!-- Servlets -->
  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>com.test.server.GreetingServiceImpl</servlet-class>
  </servlet>

  <!-- Servlet-Mapping -->
  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>com.test.Matrix/greet</url-pattern>
  </servlet-mapping>

Change the EntryPoint

Make the changes described in the following patch file by hand to the existing file.

vi src/main/java/com/test/client/Matrix.java

--- src/main/java/com/test/client/Matrix.java
+++ src/main/java/com/test/client/Matrix.java	
@@ -5,15 +5,26 @@

+import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.RootPanel;
 
 public class Matrix implements EntryPoint {
-
+	private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
+	
 	public void onModuleLoad() {
 		Button button = new Button("Send", new ClickHandler() {
 			public void onClick(ClickEvent event) {
-				Window.alert("Hello World!");
+		        greetingService.greetServer("World", new AsyncCallback<String>() {
+		            public void onFailure(Throwable caught) {
+		              // Show the RPC error message to the user
+		              Window.alert("Remote Procedure Call - Failure");
+		            }
+
+		            public void onSuccess(String result) {
+		                Window.alert(result);
+		            }
+		          });
 			}
 		});
 		button.setStyleName("sendButton");

Test the application

  1. Right click on the project in Eclipse and Refresh.
  2. right click on the project -> Maven -> Update Project Configuration.

Everything should compile fine in eclipse.

Next go to the command prompt and type the following in the project’s base folder.

mvn compile gwt:run

After clicking the button on the screen a JavaScript alert box will open returning text from the server side. You can use Firefox FireBug plugin to verify the server side communication.

Troubleshooting

  • Is the Service interface in the client package of the module’s package?
  • Is the service implementation in the server package of the module’s package?
  • Does the web.xml file specify the servlet class implementaion?
  • Does the web.xml specify the url-pattern that points to the gwt.xml file name/[remoteServiceRelativePath]. (without gwt.xml extension)
    For Example: com/test/AlbumSearch.gwt.xml and a @RemoteServiceRelativePath(“musicsearch”) on the interface will translate to:
    <url-pattern>com.test.AlbumSearch/musicsearch</url-pattern>
    
14
Jan
12

Default Log4j Property File

This page describes the process of setting up a Log4j configuration file. It goes thru some example log4j configuration files and describes what each one does. I finish up by discussing TimeBasedRollingPolicy with an example.

Requirements

  • Basic Understanding of Maven

POM

The following dependencies should be placed in your pom.xml file before starting.

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.15</version>
	<exclusions>
		<exclusion>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
		</exclusion>
		<exclusion>
			<groupId>javax.jms</groupId>
			<artifactId>jms</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jdmk</groupId>
			<artifactId>jmxtools</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jmx</groupId>
			<artifactId>jmxri</artifactId>
		</exclusion>
		<exclusion>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
		</exclusion>
	</exclusions>
</dependency>
	<dependency>
	  <groupId>commons-logging</groupId>
	  <artifactId>commons-logging</artifactId>
	  <version>1.0.4</version>
	</dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>apache-log4j-extras</artifactId>
      <version>1.0</version>
    </dependency>

Programmatic Configuration

Before we discuss the proper way to initialize logging lets talk about a quick and dirty way. Put the following static block of code into your entry point (Main) class. It sets the logging level of the default appender to debug and sets it to output to the console.

static {
	Logger root = Logger.getRootLogger();
	root.addAppender(new ConsoleAppender(
	    new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));		
}

Property Based Configuration (Legacy)

This is the default log4j.properties file with basic logging to the console. Be careful with it because it will be verbose if you are running in a servlet engine or JEE container. a more reasonable value for the rootLogger would be FATAL. Additional packages can be defined on a case by case basis.

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n

Additional packages could be added to to the file by putting in the following lines:

log4j.logger.org.vtechfw=DEBUG
log4j.logger.org.vtechfw.web=INFO

XML Based Configuration

A similar configuration however in XML is seen below.

Its important to understand the difference between the logger level and the appender threshold.

Once the logger level test is passed the log message will be sent to the appender associated with the logger as well as the appenders associated with the parent loggers without the log-level being re-tested. This is counter intuitive to the expected outcome.

It is possible to override the default behavior so that appender accumulation is no longer additive by setting the additivity flag to false.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
  
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out"/>
        <param name="Threshold" value="INFO" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p %c - %m%n"/>
        </layout>
    </appender>
    <logger name="org.springframework" additivity="false">
        <level value="INFO"/>
        <appender-ref ref="CONSOLE"/> 
    </logger>
    <root>
        <level value="ERROR"/>
        <appender-ref ref="CONSOLE"/>
    </root> 
</log4j:configuration>

File Appender (Size Based)

  <appender name="R" class="org.apache.log4j.RollingFileAppender"> 
    <param name="file" value="example.log"/>
    <param name="MaxFileSize" value="100KB"/>
    <!-- Keep one backup file -->
    <param name="MaxBackupIndex" value="1"/>
    <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%p %t %c - %m%n"/> 
    </layout> 
  </appender> 

RollingFileAppender Example

The following appender will roll when the file size is reached.

  <appender name="R" class="org.apache.log4j.RollingFileAppender">
    <param name="file" value="example.log">
    <param name="MaxFileSize" value="100KB">
    <!-- Keep one backup file -->
    <param name="MaxBackupIndex" value="1">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%p %t %c - %m%n">
    </layout>
  </appender>

DailyRollingFileAppender Example

The following appender will log to the /tmp/test.log file and at midnight it will roll it over to a dated filename and continue with a fresh test.log file for the next day.

	<appender name="DRFA" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File" value="/tmp/test.log">
		<param name="DatePattern" value="'.'yyyy-MM-dd">
		<param name="Append" value="true">
		<param name="Threshold" value="DEBUG">
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %c - %m%n">
		</layout>
	</appender>

TimeBasedRollingPolicy Example

This Policy is the most flexable way to roll your files over. You can not only customize how often the file rolls over but the policy will allow you to compress your log files using .zip or .gz files.

This Rolling Policy was was originally intended to be in the next version of log4j but the development effort for that stopped. Therefore the log4j team decided to roll it up into an “extra” package. In order to use the log4j-extra package you need to make sure to include the following in your pom.xml file

    <dependency>
      <groupId>log4j</groupId>
      <artifactId>apache-log4j-extras</artifactId>
      <version>1.0</version>
    </dependency>

This is what my log4j.xml looks like.




<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<appender name="A1" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out">
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %c - %m%n">
		</layout>
	</appender>

    <appender name="DRFA" class="org.apache.log4j.rolling.RollingFileAppender">
		<rollingpolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
		    <param name="FileNamePattern" value="/tmp/info-%d{yyyy-MM-dd-HH-mm}.log.gz">
		    <param name="ActiveFileName" value="/tmp/info.log">
		</rollingpolicy>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p %c - %m%n">
        </layout>
    </appender>
	<logger name="com.test">
		<level value="debug"></level>
		<appender-ref ref="DRFA"></appender-ref>
	</logger>
	<root>
		<priority value="fatal"></priority>
		<appender-ref ref="A1"></appender-ref>
	</root>
</log4j:configuration>
  1. If you put a “.gz” or “.zip” at the end of your FileNamePattern then the Policy will compress after rolling over.
  2. The FileNamePattern also dictates how often the roll over occurs.
    • %d – daily
    • %d{yyyy-MM} – monthly
    • %d{yyyy-MM-dd} – daily
    • so on and so forth

To use the appender just include line highlighted below in your logger element:

	<logger name="org.vtechfw">
		<level value="debug"></level>
		<appender-ref ref="DRFA"></appender-ref>
	</logger>

In the Java Code

In the above example classes in the org.vtechfw package would print DEBUG messages and above and in the web package INFO messages and above.

Logging In your Source Code

    protected final Log logger = LogFactory.getLog(getClass());

After you define the above attribute just use one of the convenience methods to log.

Fastest Way of Logging

For some Logger logger, writing,

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

incurs the cost of constructing the message parameter, that is converting both integer i and entry[i] to a String, and concatenating intermediate strings. This, regardless of whether the message will be logged or not.

One possible way to avoid the cost of parameter construction is by surrounding the log statement with a test. Here is an example.

if(logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

The jury is out on wheather to do this across the board or only with log statements that have string concatination. Its your code. You decide.

Side note:
TOO much logging? Consider implementing a batch logger. It would dump a log to the file only when there is some type of error.




Follow

Get every new post delivered to your Inbox.

Join 50 other followers