Friday, October 12, 2007

Class.forName("fully.qualified.ClassName").newInstance() in GWT

In Java, when we design something to work generically like loading a plugin Class or something like that, we use the classloader to load some arbitrary class and instantiate it using the Class.newInstance() (Assuming that our Class has a Zero argument constructor) or using the constructors through the Class's getConstructor method.

This feature cannot be used in GWT, as you may all know that the client code (JavaScript) is statically generated. There is no Classloader or no Class.newInstance() or no reflection at all in Javascript. So to provide very least feature of instantiating a Class by knowing its classname, here is a tip that you may like.

We may not require all the Class types to be available for dynamic instantiation. So we are gonna mark the required Class types as Instantiable (A marker interface).
Now, we need some factory class which has a method newInstance(String className), using which we can create an instance of specified classname.



1 package name.aanand.gwt.client;

2

3
/**

4 * Platform factory to create instance of any {@link Instantiable} type.

5 * @author aanandn

6 *

7 */

8 public interface Factory {

9 Instantiable getInstance(String className);

10 }




Now we are gonna create a Class called ReflectiveFactory which is defined as follows...


1 package name.aanand.gwt.client;

2

3

4 /**

5 * Factory class for instantiating any {@link Instantiable} type by providing

6 * the fully qualified Class name.

7 * @author aanandn

8 *

9 */

10 public class ReflectiveFactory implements FactoryWrapper{

11 }


The ReflectiveFactory implements an interface called FactoryWrapper which is again a marker interface to identify the factory classes for which Wrapper implementations or Proxies have to be generated. Now we are ready with our base interfaces. And here begins how its achieved...

First have a singleton class which instantiates our Factory like this:

factory = (Factory) GWT.create(ReflectiveFactory.class);

and return this factory whenever its asked for.

Now you may wonder, how will it work without any real code in the ReflectiveFactory. So here is the explaination of how its gonna work.

  1. We are going to extend the GWT compiler to generate a wrapper or proxy for each of the Classes which implement FactoryWrapper.
  2. The generator should create a new class with name Wrapper, which implements Factory.
  3. In the case of ReflectiveFactory, first we are going to get all the Instantiable types.
  4. And finally generate the method newInstance(String className), conditionally returning one of the Reflectables based on the specified className.
To extend GWTCompiler we need to add an entry in our module XML as follows:


1 <module>
2
3 -- Inherit the core Web Toolkit stuff. -->
4 <inherits name='com.google.gwt.user.User'/>
5
6 -- Specify the app entry point class. -->
7 <entry-point class='name.aanand.gwt.client.MainEntryPoint'/>
8
9
<generate-with class="name.aanand.gwt.generator.FactoryGenerator" >
10
<when-type-assignable class="name.aanand.gwt.client.FactoryWrapper" />
11
</generate-with>
12
13
</module>
14



The FactoryGenerator class should extend the abstract class Generator and implement its method
public String generate(TreeLogger logger, GeneratorContext context, String typeName)

Simple implemenation of FactoryGenerator is given below:



1 package name.aanand.gwt.generator;

2

3 import java.io.PrintWriter;

4

5 import com.google.gwt.core.ext.Generator;

6 import com.google.gwt.core.ext.GeneratorContext;

7 import com.google.gwt.core.ext.TreeLogger;

8 import com.google.gwt.core.ext.UnableToCompleteException;

9 import com.google.gwt.core.ext.typeinfo.JClassType;

10 import com.google.gwt.core.ext.typeinfo.NotFoundException;

11 import com.google.gwt.core.ext.typeinfo.TypeOracle;

12 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;

13 import com.google.gwt.user.rebind.SourceWriter;

14

15 public class FactoryGenerator extends Generator {

16

17 public String generate(TreeLogger logger, GeneratorContext context,

18 String typeName) throws UnableToCompleteException {

19 logger.log(TreeLogger.INFO, "Generating source for " + typeName, null);

20 TypeOracle typeOracle = context.getTypeOracle();

21

22 JClassType clazz = typeOracle.findType(typeName);

23 if (clazz == null) {

24 logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"

25 + typeName + "'", null);

26 throw new UnableToCompleteException();

27 }

28

29 try {

30 logger.log(TreeLogger.INFO, "Generating source for "

31 + clazz.getQualifiedSourceName(), null);

32

33 JClassType reflectableType = typeOracle

34 .getType("name.aanand.gwt.client.Instantiable");

35 SourceWriter sourceWriter = getSourceWriter(clazz, context, logger);

36 if (sourceWriter != null) {

37 sourceWriter.println("public "

38 + reflectableType.getQualifiedSourceName()

39 + " newInstance(String className) {");

40 JClassType[] types = typeOracle.getTypes();

41 int count = 0;

42 for (int i = 0; i < types.length; i++) {

43 if (types[i].isInterface() == null

44 && types[i].isAssignableTo(reflectableType)) {

45 if (count == 0) {

46 sourceWriter.println(" if(\""

47 + types[i].getQualifiedSourceName()

48 + "\".equals(className)) {"

49 + " return new "

50 + types[i].getQualifiedSourceName() + "();"

51 + "}");

52 } else {

53 sourceWriter.println(" else if(\""

54 + types[i].getQualifiedSourceName()

55 + "\".equals(className)) {"

56 + " return new "

57 + types[i].getQualifiedSourceName() + "();"

58 + "}");

59 }

60 count++;

61 }

62 }

63 sourceWriter.println("return null;");

64 sourceWriter.println("}");

65 sourceWriter.commit(logger);

66 logger.log(TreeLogger.INFO, "Done Generating source for "

67 + clazz.getName(), null);

68 return clazz.getQualifiedSourceName() + "Wrapper";

69 }

70 } catch (NotFoundException e) {

71 e.printStackTrace();

72 }

73 return null;

74

75 }

76

77 public SourceWriter getSourceWriter(JClassType classType,

78 GeneratorContext context, TreeLogger logger) {

79

80 String packageName = classType.getPackage().getName();

81 String simpleName = classType.getSimpleSourceName() + "Wrapper";

82 ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(

83 packageName, simpleName);

84 composer.addImplementedInterface("name.aanand.gwt.client.Factory");

85 PrintWriter printWriter = context.tryCreate(logger, packageName,

86 simpleName);

87 if (printWriter == null) {

88 return null;

89 } else {

90 SourceWriter sw = composer.createSourceWriter(context, printWriter);

91 return sw;

92 }

93 }

94

95 }

96




Now compile your code with GWTCompiler and start using as shown below:

Factory factory = (Factory) GWT.create(ReflectiveFactory.class);
factory.newInstance("fully.qualified.Classname");

Thats all folks!

Monday, October 08, 2007

Simple Key Mappings for VIM

These are very simple key-mappings for VIM 7.0 and above, to play with tabs (or tab pages).


 5 set nu!

 6 set wrap!

 7 color desert

 8 set guioptions+=b

 9 :map <C-N> <M>:tabnew<CR>

10 :map <S-TAB> <M>:tabnext<CR>

11 :map <C-F4> <M>:tabclose!<CR>

12 :map <C-O> <M>:browse tabnew<CR>


All are command mode shortcuts.

CTRL-N  -  creates a new tab page.
CTRL-O  -  Opens a file in a new tab page.
CTRL-F4 - Closes current tab page

SHIFT-TAB - rotates through the tab pages.

Happy Vimming!

Sunday, September 02, 2007

FIndex

This a product of my last two or three weekends. It actually began as a duplicate file finder and has grown upto a source code search tool powered by Ctags the famaous code indexing utility.

The duplicate finder works based on file hashes using the Tiger Hash algorithm (BouncyCastle's impl).

The Code search is simply a UI to search Ctags tag files in each of your configured code repositories.




More at http://aanand.name/findex


Wednesday, July 25, 2007

Embedded tomcat without deployment descriptor(web.xml)

I just had to write some code for running a single servlet for testing and wrote this java program which uses Embedded tomcat.
The following code doesn't use web.xml to configure the context. Context configuration is done programmatically using the StandardContext class in catalina.jar. I have added a servlet and mapped it to the URL "/example".


System.setProperty("catalina.home", "./");
Embedded embedded = new Embedded();
Engine engine = null;
Host host = null;
// Create an embedded server
embedded = new Embedded();

// print all log statments to standard error
embedded.setDebug(0);
embedded.setLogger(new SystemOutLogger());

// Create an engine
engine = embedded.createEngine();
engine.setDefaultHost("localhost");

// Create a default virtual host
host = embedded.createHost("localhost", "./");
engine.addChild(host);


StandardContext context = (StandardContext) embedded.createContext("/ContextPath","/test");
context.setWorkDir("./test");
context.setConfigured(true);
Wrapper servlet = context.createWrapper();
servlet.setServletClass(ExampleServlet.class.getName());
servlet.setName("example");
context.addChild(servlet);
context.addServletMapping("/example", "example");

host.addChild(context);
host.setAutoDeploy(true);

// Install the assembled container hierarchy
embedded.addEngine(engine);

// Assemble and install a default HTTP connector
Connector connector = embedded.createConnector("127.0.0.1", 8080,
false);
embedded.addConnector(connector);
// Start the embedded server
embedded.start()


This may help while writing unit tests for servlets which cannot be tested with cactus or httpUnit.

Happy coding...

Sunday, May 27, 2007

Cream 0.39 beta2 looks good


After a long time I visited cream to check for updates. And i found a new version in beta stage. Its looks good and it has now got more items in settings menu. And more over you have a singe session mode, which turns VIM into a singleton application.
And the features of VIM 7.1 make it much more beautiful.


The application looks to be much faster, but it lags while processing huge documents. Particularly while editing large XML docs. But otherwise its cool as it was before and with new awesome features.
Long live VIM and Cream....

Tuesday, March 13, 2007

ClassLoader and the order of classpath entries

JBossAOP provides runtime aspectization feature. For this it has a classloader instrumentor which modifies the java.lang.ClassLoader which will intercept the call and invoke the interceptor chain.

Based on their docs
java -Xbootclasspath/p:<aop boot classpath as described> \
-Djboss.aop.path=<path to jboss-aop.xml> \
-classpath <path to your classes> com.blah.MyMainClass
The above command is used to execute a java class with the instrumented classloader. When i used this command, i had the bootclasspath as
(through eclipse) JRE Classpath;{generated ClassLoader};{JBossAOP jars};
It dint work as expected, that is the interceptors weren't invoked.

Then i remembered of ClassLoaders and the way it loads the classes. That is it searches the given paths, one by one and loads the class. Then i changed the order of the entries as {generated ClassLoader};{JBossAOP jars};JRE Classpath;. Now everything worked fine and the result was as expected.

The important point to remember is that, if you have duplicate classes like the one used above, java.lang.ClassLoader, the order of the desired class (instrumented ClassLoader) in the classpath should be at the top so that it will be loaded before other duplicate gets loaded.

Lesson learnt: order of the classpath entries is very important

Sunday, February 11, 2007

textEditorsInTheWorld++

I have been search, playing with and reviewing a number of text editors and now i have planned to roll out my own editor called MyMate soon.

This will be a project where i will learn advance C++ and I'm gonna enjoy using JUCE. The project is an inspiration from the wonderful editor TextMate.

This is an initial screen of MyMate(just started to work on it)


I'm not a very good C++ programmer, so i would like someone to guide me and help me in this project.
Anybody interested to help me, just add comment and we'll start a project with a repository in SourceForge.