Monthly Archives: May 2007

JavaScript ClassLoader and Hotspot

If you are familiar with Java debugging, you must know there is a technology called “Hotspot“. One feature of Hotspot is to replace old classes bytecodes with a new ones that are generated by dynamic compilers. This feature helps developers a lot in debugging. That is to say, when a developer load a very complex application in debugging mode, he want to modify the sources a little, he can just do it, the compiler will compile those related classes and notify classloader to load those affected classes bytecodes. And the modified codes are on effects. It saves lots of time by avoiding closing, reopening and waiting big applications again and again. This is very convenient when comparing to those static compiled applications written by C or C++ languages.

OK, now comes to JavaScript classloader and Hotspot technologies. JavaScript classloader technology are already proved by Java2Script. You can load JavaScript classes on demands, and using SCRIPT in asynchronous mode or XMLHttpRequest (XHR) in synchronous or asynchronous modes. And these days, Java2Script is also implementing JavaScript’s Hotspot technology (Not released publicly at the time of this writing, but you can check Java2Script out from SVN repository right now using its 3.3 compiler branch.). Such JavaScript Hotspot technology is not complicate, because JavaScript is already a very robust and convenient language to do so. All Java2Script implementation is to clean those classes’ declaration inside JavaScript class inheritance system simulator. And then reload the *.js using Java2Script’s classloader. In the implementation, classloader does not change class or object’s prototype when a reloaded class is redefined, it’s possible to keep all classes relationships without breaking those already instantiated instances.

To trigger Java2Script class simulator to Hotspot swapping, there is a thread trying to load an updating JavaScript classes list from Java2Script compiler in Eclipse. Its work is simple, just trying to load http://127.0.0.1:1725/<session>.js. And the server listening on default port 1725 is started by Java2Script compiler, called “Java2Script Inner Hotspot Server (J2SIHS)”. When a compiling occurs, compiler will notify this server that a class is updated, and the server will add the information to the list. Once a JavaScript request arrives, it will send out the list according to the request session id. And when the JavaScript client thread gets the updated classes list, it will try to unload related classes and reload them. That is the rough procedure of Java2Script Hotspot technology.

By using Hotspot, I think it is much more convenient for me to develop JavaScript RIA in Java codes than before, especially in developing SWT applications.

Posted in Architecture | 29 Comments

What is Java2Script’s SimpleRPC

By using Java2Script’s SimpleRPC, there are no needs to know RPC (Remote Procedure Call) and no needs to know Java Servlet or J2EE! Only knowing developing Java desktop application is enough for developers. Here is magic.

Java2Script recommends writing applications in desktop ways. This means that all logics are developed in one container. But when you want to deploy the applications in a Browser/Server mode, you have to tear your applications into server logics and client logics. And to integrate logics between server and client, you need to transfer the datum, which you may be required to know how to wrap and unwrap data. This transformation and wrapping is the essence of RPC.

Java2Script also does the above wrapping for you, so you have no needs to know RPC wrapping. And Java2Script uses threads to simulate the remote J2EE server in local mode, so you can see no remote server and you can debug your logics smoothly as Eclipse JDT provide a very smoothly debugging experience for threads. As in normal J2EE server, each request is stateless. In such a way, Java2Script’s SimpleRPCRunnable instance (for Java local Thread) should be designed as a stateless instance.

In simple, Java2Script wraps and unwraps data between server (J2EE basing on Java) and client (Browser basing on JavaScript). And in local Java mode, Java threads are performing as J2EE server, which is much easier to be understood and to be debugged.

For more details about SimpleRPC, such as why not using Java’s RMI,? Java’s serializations, or JSON’s RPC, please keep tuned for the later articles.

Posted in Architecture | 92 Comments

Clarify Goal of Java2Script

Java2Script is not providing a JavaScript library for AJAX developers. Java2Script is providing tools to convert Java desktop applications into web applications.

By reading comments about Java2Script online, I found that someone treat Java2Script as a JavaScript library such as Prototype. In early stage of Java2Script development, “J2SClazz” is separated from Java2Script’s Class Inheritance Simulator to provide a better acceptance of Java2Script Pacemaker, but as later developer prove that “J2SClazz” is just too simple to prove the power of Java2Script technology, I did not update it afterwards.

You can write your JavaScript using “J2SClazz” library actually. But I don’t think it is convenient to do so. And if you also use Java2Script’s SWT library, you may find it very hard to use up all power of Java2Script. Only in Eclipse’s Java editor, you can create lots of anonymous event listeners (also anonymous inner class) for those UI components. And only in Eclipse, you can create a Dialog by dragging and dropping. If you write all your codes from scratch, you need lots of work. And you can not debug those JavaScript codes, which is always buggy!

I know that there are lots of differences between normal web applications and desktop applications. But developing desktop applications is a lot faster than web applications, there is no needs to care about HTML, CSS, or HTTP server and database server. So developing desktop applications is much easy for most of developers. And it will also increase the speed of new products. You know speed is one of the most important factor of new web applications. So desktop applications to web applications converting is an acceptable way for web applications.

And Java2Script is originally designed for such a developing ways. Java2Script is not aiming to provide a JavaScript library so that you can write your JavaScript codes much easier. What Java2Script is trying to provide is a tool help developers to develop web applications in a Java way, or in a desktop way. If this way is not a 100% pure way, we do want it to be 90% pure, which may help developers to write and debug their codes in a their much more familiar way.

In simple, Java2Script is providing tools not libraries.

Posted in Architecture | 1 Comment

ClassLoader Summary

Here is ClassLoader summary inside ClassLoader.js, for more information, please also read the ClassLoader source.

ClassLoader creates SCRIPT elements and setup class path and onload callback to continue class loading.

In the onload callbacks, ClazzLoader will try to calculate the next-to-be-load *.js and load it. In *.js, it will contains some codes like
Clazz.load (…, “$wt.widgets.Control”, …);
to provide information to build up the class dependency tree.

Some known problems of different browsers:

  1. In IE, loading *.js through SCRIPT will first triggers onreadstatechange event, and then executes inner *.js source.
  2. In Firefox, loading *.js will first executes *.js source and then triggers onload event.
  3. In Opera, similar to IE, but trigger onload event. (TODO: More details should be studied. Currently, Opera supports no multiple-thread-loading)

For class dependency tree, actually, it is not a tree. It is a reference net with nodes have n parents and n children. There is a root, which ClassLoader knows where to start searching and loading classes, for such a net. Each node is a class. Each class may require a set of must-classes, which must be loaded before itself getting initialized, and also need a set
of optional classes, which also be loaded before being called.

The class loading status will be in 6 stages.

  1. Unknown, the class is newly introduced by other class.
  2. Known, the class is already mentioned by other class.
  3. Loaded, *.js source is in memory, but may not be initialized yet. It requires all its must-classes be intiailized, which is in the next stage.
  4. Musts loaded, all must classes is already loaded and declared.
  5. Declared, the class is already declared (ClazzLoader#isClassDefined).
  6. Optionals loaded, all optional classes is loaded and declared.

The ClassLoader tries to load all necessary classes in order, and intialize them in order. For such job, it will traverse the dependency tree, and try to next class to-be-loaded. Sometime, the class dependencies may be in one or more cycles, which must be broken down so classes is loaded in correct order.

Loading order and intializing order is very important for the ClassLoader. The following technical options are considered:

  1. SCRIPT is loading asynchronously, which means controling order must use callback methods to continue.
  2. Multiple loading threads are later introduced, which requires the ClassLoader should use variables to record the class status.
  3. Different browsers have different loading orders, which means extra tests should be tested to make sure loading order won’t be broken.
  4. Java2Script simulator itself have some loading orders that must be honored, which means it should be integrated seamlessly to Clazz system.
  5. Packed *.z.js is introduced to avoid lots of small *.js which requires lots of HTTP connections, which means that packed *.z.js should be treated specially (There will be mappings for such packed classes).
  6. *.js or *.css loading may fail according to network status, which means another loading try should be performed, so ClazzLoader is more robust.
  7. SWT lazy loading is later introduced, which means that class loading process may be paused and should be resumed later.
Posted in Architecture | 11 Comments

Content of Inside Java2Script

Here is a rough content list of the book “Inside Java2Script”:

  1. Overview of Java2Script
  2. Tutorial of Java2Script: Core, SWT, AJAX
  3. JavaScript Class Inheritance Simulator
  4. HTML +CSS Widgets and SWT
  5. AJAX and SimpleRPC
  6. Inside ClassLoader
  7. More about Asynchronous Programming
  8. Plugin and Mixture of OtherLibraries

If you are familiar with or experienced in writing a book, please share your thoughts with me. Thanks.

Posted in Uncategorized | Leave a comment

JDT Compiling and Java2Script Compiling

One feature that I like Java2Script is its full integration with Eclipse JDT’s incremental building.

Java2Script reuses Eclipse JDT to compile *.java into *.js. As Eclipse JDT supports incremental building, so Java2Script also supports this feature. The magic is that when a *.java file is passed into JDT’s ImageCompiler, it is also passed through Java2ScriptImageCompiler.

To understand JDT’s incremental building, when a *.java is modified and compiled, this file will be compiled, and as always, this modification may affect other *.java files, that is to say, some other classes may need recompiling. JDT uses some algorithms to figure out those delta *.java and compile it, and compiling continues until there is no affected files that need to be compiled.

As compiling has its entry, Java2Script just install an extra compiler at the entry so that a *.java file is compiled into *.class, it also be compiled into *.js. This is? the whole magic of Java2Script builder.

But to inject a Java2Script compiler into existed JDT plugin requires some works. First JDT’s compiler is not designed to be injected. Modified the JDT sources and recompiling the plugin do works. But it’s not quite suitable for public, as it need to overwrite original JDT plugin jars. There is another factor that make a little difficult in implementing Java2Script compiler based JDT. A lot of classes in JDT are package accessible or their methods are not public. It need a lot of works to do so that those restricts can be avoided. And besides, Java2Script compiler codes must be maintainable, or when a new Eclipse version is released, all those hard works need to re-do.

In current Java2Script compiler, it reuses codes in package org.eclipse.jdt.internal.core.builder. All it need is to move all the sources into a new package named net.sf.j2s.core.builder. And some new proxy classes or new inherited classes are added so it is possible to access inner data structure. And Java2ScriptImageCompiler is injected into those JDT normal compiling process. And there are some tricks here. To convert some instances between two different classes without trigger ClassClastError, one instance (e.g. net.sf.j2s.core.builder.State instance) is serialized into DataInputStream first, and then it will be de-serialized into another instance (org.eclipse.jdt.internal.core.builder.State.). In all, in implementing Java2Script compiler, it use all kinds of tricks to expose JDT’s inner data structures to outside compilers.

For more details, please compare the Java2Script sources (net.sf.j2s.core.builder, net.sf.j2s.core.compiler) with sources in JDT (org.eclipse.jdt.internal.core.builder, org.eclipse.jdt.core.compiler)

Posted in Hacks | 2 Comments

Java to JavaScript Compiler Discussion (2)

First, there are no clever ways for ClassLoader.
Second, in my conception, there are another term “asynchronous programming” besides “synchronous programming”.
Third, Java2Script compiler does perform very poorly at loading huge arsenal of SWT classes.

In the implementation of Java2Script ClassLoader (not full APIs implemented), it mainly supports three modes:
1. Asynchronous over SCRIPT tags (mainly in used)
2. Asynchronous over XMLHttpRequest (not used a lot)
3. Synchronous over XMLHttpRequest (seldom used),

Up until now, I seldom use ClassLoader.loadClass in synchronous XHR mode, as the browser may be locked. Instead, an asynchronous ClassLoader wrapper is introduced:

public class AClass {
// Java2Script compiler will generate different scripts without Thread for this method body
public static void load(final String clazzName, final Runnable afterLoaded) {
new Thread(new Runnable() {
public void run() {
try {
Class clz = Class.forName(clazzName);
if (afterLoaded instanceof ARunnable) {
ARunnable runnable = (ARunnable) afterLoaded;
runnable.setClazz(clz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
return ;
}
afterLoaded.run();
}
}).start();
}
}

Java2Script recommends using this kind of asynchronous ClassLoader, in which the compiler will modify AClass.load with JavaScript codes without java.lang.Thread but with asynchronous XMLHttpRequest or SCRIPT-tag class loading codes.

And now it comes to something about “Asynchronous Programming” v.s. “Synchronous Programming”, if we use asynchronous class loading.

We know that JavaScript does not support Thread like Java. But when you use Java, lots of Thread things will be introduced. For example, when you use GUI toolkit to open a dialog, there are threads running? already. But when we introduce UI widgets in JavaScript, we have no Threads. What we can use are asynchronous callbacks. And we do use use asynchronous callbacks a lot in XMLHttpRequest. So if we take asynchronous callbacks for granted, we should always considering “Asynchronous Programming” pattern. That is to say, when we know some calls are *time-consuming*, we should put following codes into a callback and let that method call to call back later. So RPC and Class.forName call should be wrapped into a callback by developer intentionally.

Here is an example for scenario of using asynchronous class loader. There is a page, with many tabs. And each tab will present a different thing (a different class). We need not to load all those tab classes in starting up. We just need to load that tab class only when user switches to that tab. When user switches, here asynchronous class loader should be used to load the tab page class:

tabFolder.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
//...
Object data = item.getData(); // class name actually
if (data != null) {
// ASWTClass#shellLoad is actually similar to AClass#load
ASWTClass.shellLoad(tabFolder.getShell(), (String) data, new ARunnable() {
public void run() {
try {
Constructor constructor = getClazz().getConstructor(new Class[] {ControlExample.class});
Object inst = constructor.newInstance(new Object[] {ControlExample.this});
Tab tab = (Tab) inst;
// ... do the following layout job
} catch (Throwable e) {
e.printStackTrace();
throw (Error) e;
}
}
});
}
}
});

Here when asynchronous class loader is loading classes, show some texts saying “fetching data …” should be fine.

The problem of *huge* number of HTTP round-trips is a *huge* problem of Java2Script compiler. So packed *.z.js, which is similar to *.jar, is introduced. First ClassLoader is designed to load class in per class mode but is also designed to load all related classes when one class is required. For example, when instantiating class A must require instantiating class B, then ClassLoader will try to load class B when class A is required, and only marks class A as loaded after class B or other classes are loaded. This may require algorithm to calculate class dependencies, which may be similar to GWT’s call graph. So if class A and class B have their relationship, we can pack A.js and B.js together to reduce the number of HTTP round-trips. In practical implementation of J2S’ SWT, ToolBar and ToolItem are packed as ToolBar.z.js, Shell.js, Decorations.js and Display.js are packed as Shell.z.js. This is a way Java2Script compiler trying to reduce *huge* number of HTTP round-trips. But as mentioned, the loading performance is not good enough. And the packing algorithm may require professional design besides compiler’s capabilities.

Actually, the original design was to pack most of? library *.js into some (less than 15 or 20) *.z.js files. And those *.z.js are static with different release versions. Other pages (or other websites’ pages) may load these static libraries when necessary. As different pages have common *.z.js URLs. There are no needs to download them again once they are already downloaded by other visited pages (Just like Flash is required to install once). And if the *.js is distributed on a fast network (like Google network or other distributed publishing network). In fact, maybe these library *.z.js are not too huge for such publishing and not small enough to be efficient libraries, as this design is not yet proved.

GWT’s *.js seems to be project-dependent. And different projects only share a bootstrap library and not share some big *.js libraries (But do share in Java source level). Am I right?

Currently Java2Script’s ClassLoader just ignore “Class not found” silently when SCRIPT-tag gets nothing. And this should be fixed. “Method not found” exceptions existed already before Java reflection was implemented.

As mentioned in my last post, I admired GWT team for the motivation of “to be as small and as efficient as possible” and “excellent 100k ~ 200k final *.js files with very good performance”. And I learned that two separate goals:
(1) Create highly optimized JS output
(2) Optionally, publish selected parts of your code with a JS-compatible API
For such design, without ClassLoader and Java reflection should be OK for me. But I am still wondering whether it’s a must feature or not for enterprise edition of GWT projects. OK, I am just wondering from my lazy perspective.

Maybe I should learn something from GWT’s motivation and goals. Maybe it’s direction for JavaScript, also for Java2Script. And may be it’s not. No matter what, I learned that my early (in May) understanding of GWT compiler was totally wrong. And thanks for Bruce, and thanks for this thread and all participators,? I have a better understanding of GWT compiler now.

By the way, about “Asynchronous Programming” v.s. “Synchronous Programming”, I think there are should be something inside. And I are wondering Java to JavaScript compiler should consider this seriously or not.

Posted in Architecture | Leave a comment

Java to JavaScript Compiler Discussion (1)

Last year, I joined in a discussion about Java to JavaScript compiler in Google Web Toolkit (GWT) group. I think it is worthy to re-post my opinions here for a better understanding of Java2Script. Or later I may use the discussion to clarify my opinions.

—————————

“To be as small and as efficient as possible”!? I admire GWT team for their excellent 100k ~ 200k final *.js files with very good performance.

Java2Script (http://j2s.sourceforge.net/), as mentioned,? is a similar project for Java to JavaScript code generation. But the motivation in Java2Script is something different: “To provide same familiar Java APIs in JavaScript”.

I am just a lazy developer, lazy to learn new APIs for some same functions. For example, Swing and SWT are similar GUI toolkit. And using SWT can do all the things that Swing can do and vice versa. I would be lazy to learn one of them only and not to learn the other. And I prefer to SWT. And as now I am familiar with SWT, and if all things done by using GWT can be done by using SWT, I would be lazy not to learn the new GWT APIs but use my familiar SWT. So this lazy programmer will use Java2Script and its Java2Script SWT library.

In order to provide the same familiar Java APIs in JavaScript, Java2Script has to keep all fields, all methods, all inheritances and all polymorphic information of a class in the JavaScript codes so developer will always be happy and feel comfortable with those familiar APIs. Java2Script is actually providing compiler that compiles Java sources into static JavaScript libraries.

And following, I will just try to figure out my understanding of GWT’s Java to JavaScript compiling procedure. If I am wrong, please be kind to correct me.

GWT’s compiling procedure is somewhat similar to the procedure of compiling C sources into an executable file. In C compiling, C source is first compiled into an *.obj.? And then comes a linker, which will link *.obj with other *.lib files into an *.exe. In the linking procedure, not all method calls in those *.lib are linked into *.exe file. Only those which are used in the *.obj will be kept. Others may be discarded so the final *.exe is small and efficient. In order to find out which methods must be kept in linking, some recursive searching algorithm may be required.

In GWT compiling, there are no middle *.obj actually. GWT compiler tracks down those method calls which are related to the application. And if the other methods have no relationship with the application, they will be discarded even they are marked “public”. So the final *.js is very small and efficient. Those class meta information discarded may include class inheritances, overriding, polymorphisms and other OO information. So after compiling, there are actually not OO JavaScript. So OO concepts like “this” keyword or reflection calls can not be used. In the whole compiling, the key technology of GWT may be the algorithm to flat those super calls and polymorphic method calls into static calls correctly.

And I admire GWT team for their excellent 100k ~ 200k final *.js files with very good performance.

Even basing on the same JDT toolkit, compilers with different motivations result in different JavaScripts. In a comparison, Java2Script generates 500k+ *.js files, and? has its bottleneck on long waiting on loading those bundles of huge *.js files and poor performance on spending most of its CPU time in searching for polymorphic method calls. In fact, Java2Script has many optimizations on reducing the generated *.js file size and improving JavaScript performance, like minimizing variable name identities, generating smart scripts to avoid polymorphic method calls and others. But it seems that Java2Script is still far behind GWT in file size and performance.

But GWT, as the above compiling process described, may have its difficulties in supporting Java refection and dynamical class loading. But Java2Script already has its ClassLoader and is loading classes lazily. And it also has its early Java reflection implementation on JUnit tests (Reusing JUnit tests directly). But the way, GWT APIs and Java2Script SWT APIs is far different for comparison.

In some simple words, GWT compiler is an excellent Java to JavaScript *runtime compiler*, while Java2Script is a Java to JavaScript *library compiler*.

Maybe GWT would be kind to support Java reflection and dynamic class loading, if more developers vote for such features.

Posted in Architecture | 561 Comments

IE Hack: JavaScript Memory Leaks

The following is an article that I posted about one and a half years ago. I just repost it here as this is a hack to build up Java2Script Pacemaker.

—————————————————-

Yes, I knew there was JavaScript memory leak in IE. I developed JavaScript codes mainly by Firefox/Mozilla, so I won’t notice the codes were leaking memory. These days I was developing J2S application in Eclipse, and found that the J2S applications were runnig more and more slowly in the J2S Console, which embed IE Browser widget. Once I did not think that memory leaking will make such poor performance. The slowness that I couldn’t stand finally taught me the lesson and I decided to fix the leaking codes.

Searching the net, I found that lots of articles were talking about this problem. I mainly read Justin Rogers’ Understanding and Solving Internet Explorer Leak Patterns. And after finishing the articles, I monitored one J2S SWT application (SWT Tree Snippet) while tring to refresh the page. I found 5 times of refreshing will leaking the memory from about 22M to 31M! Then I knew that maybe about 100M+ of memories was leaked in developing J2S applications when I felt the slowness of J2S Console.

I added a handler to the “onunload” event to break those circular references, codes like following:

/*
* Only IE need to release the resources so that no memory is leaked
*/
if (window.attachEvent) {
window.attachEvent (“onunload”, function () {
try {
org.eclipse.swt.widgets.Display.releaseAllResources ();
} catch (e) {
}
return true;
});
}

In the static method org.eclipse.swt.widgets.Display.releaseAllResources, I set those elements’ on* handlers to null and set those Controls’ parent and children to null. Things did work much better. But it was not fixed compeletely. Once I refreshed for a couple of times, I noticed that the browser will leak some 10~100k gradually. That was to say it will take about 10~100 times of refreshing for about 1M leaking and users will only perceive the slowness after about 1000 times of refreshing. So it was considered as working better.
I tried other ways to solve this leaking but did not get the right entrance.The current Java2Script library is almost built on closures of JavaScript, which will leak memory easily and hide leadking codes deep inside the whole codes. Replacing all those codes that using closures? No. Without closures, it’s somewhat hard to implement the Java Class inheritance.

It’s as Justin Roger’s saying “not all memory leaks are easy to find”. Memory leaking is just awful enough! 🙁

Posted in Hacks | 41 Comments

Reusing: Spirit of Java2Script

The following is an article that I posted about one and a half years ago. I just repost it here, because I think Reusing Java codes and tools is my fundamental point to build Java2Script Pacemaker.

—————————————————-

There are two advances of Java2Script technologies:

  1. Reusing existed Java codes
  2. Reusing existed Java tools

It’s totally about reusing. Reusing is the most important things in the programming world: source codes reusing, binary library reusing, model pattern reusing, framework reusing. Without reusing, it will mean that everyone should have to re-inhevent the wheel and then we will always stay in the stage of round wheels. Thanks to the reusing, we have great world now.

Java2Script Pacemaker is developed to give developers a toolkit of reusing existed codes and tools. And Java2Script Pacemaker is reusing other codes and tools:

  1. J2S is reusing Eclipse JDT (J2S won’t exist without JDT)
  2. J2S is reusing Java SDK’s java.* sources
  3. J2S is reusing SWT sources and models (org.eclipse.swt.*) and Visual Editor

Reusing does not mean that the sources or tools should be reused without modifications. In above reusings, I extend some extension points of JDT to given new functions, and I modify parts of the sources java.* so that the generated JavaScript is simple, and I have to reinvent the SWT Widgets inside Browser beside reusing the Events and Layouts of SWT.

Reusing already saves me a lot of time. Without JDT, I won’t have the abilities to parse the Java sources and building the DOM tree and binding. Without DOM tree and binding, I can’t generated the JavaScript codes. Without reusing java.* sources, I will have to spend times to re-write those complicated Map, Set and List implementations. Without org.eclipse.swt.layout.*, I will dedicate most of my time in tunning the layout! Without all these reusing, J2S and the related JavaScript version of SWT won’t come out in a short time. Thanks to the reusing.

Following is the questions and answers I am thinking these days:
Q: Does the Java2Script Pacemaker focus on reusing source codes only?
A: Always reusing source codes is the first of step of reusing others. But you should have already noticed that J2S is also reusing tools including Visual Editor and the Eclipse Platform.

Q: Is Java2Script Pacemaker have the abilities to reuse existed frameworks?
A: I think we should not make too much expectation on the JavaScript codes. But we can integrate the Java2Script Pacemaker with other existed frameworks, as Java2Script technology is still developing.

Q: Will Java2Script be hot in the future?
A: I don’t know. But I know, for sure, that reusing existed codes will save people’s efforts in the progress of converting desktop applications into web applications. And reusing will always be the spirit of programming.

Enjoy using Java2Script, enjoy reusing and keep thinking in reusing.

Posted in Articles | 1 Comment