Thursday, January 11, 2007

I've finally done XFire plugin for Grails

Last post, I mentioned about Grails plugin architecture in 0.4. This great feature allows us to develop our own plugins. I firstly thought that it might be difficult to develop my own one. But after having a look into some plugin codes in Grails itself, and another one - OpenLaszlo plugin. I finally got some ideas about how the plugin works, and what to do.

However, I was suffered a bit by bugs from Spring Bean Builder because it doesn't provide complete APIs to cover methods I need, such as "bean.initMethod". Anyway, it's not too hard to figure it out, and I have some workaround to avoid these bugs. I'm planning to fix them soon after my XFire plugin is stable for Grails 0.4.

So, what's about the XFire plugin for Grails ?
It's a plugin to expose a Grils service as a Web service. Only requirement is that the service must have "XFireService" suffix. The plugin scans pulbic methods of the service, and generates complex type definition for parameter and return types using a modified XFire's Aegis engine.
For a Grails domain class, this plugin will generate type information for every properties, including "id", but it will ignore "version" and other Groovy specific properties.
If you want to exclude some methods, you can define "static excludes = []" in the service.

Here's some example:


class MyXFireService {

def static excludes = ["notMe"]

def String myMethod(MyDomain d) {
d.save()
return "test"
}

def String notMe() {
return "nothing"
}
}



I've added a page for this plugin at Grails space here:
http://grails.org/XFire+plugin

Saturday, January 06, 2007

XFire for Grails Applications - the pre-plugin Era

I've updated my Grails from 0.3.1 to 0.4 snapshot and its new coming plug-in architecture looks very promising. I'm hoping that someone will implement an XFire plugin for Grails soon (mentioned some where in Grails' wiki). Anyway, I'm going to talk about how to integrate XFire into an Grails application manually.

Here, I briefly show you steps to integrate annotation-based XFire Web services into your Grails Applications.

1. download XFire distro (I'm using 1.2.3).
2. put everything (.jar files) of XFire into ${YOUR_GRAILS_APP}\lib
3. create your Web service class in src/java
4. modify resources.xml
5. modify web.template.xml
6. grails run-app

It's still configuration-based approach, not conventional yet.
Anyway, this might be useful to someone, who currently need to use XFire, when the XFire plugin still be an imaginary thing.

Note that, this covers only HTTP-based transportation of XFire, since Grails is mainly for Web.

Let's go into details:
Before starting, you have to put all XFire .jar files into your /lib folder first.

So, you can start by put your annotation-based classes in "src/java" folder.


@WebService
public class MyService {

@WebMethod
public String doSomething() {
return "hello";
}

@WebMethod(exclude=true)
public void hideMePlease() {
return;
}

}


what you needs are modification of "resources.xml" for spring, and "web.template.xml".

OK, then add some XML chunks into your spring/resources.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<!-- You need this line to import "xfire" and
"xfire.transportManager" references in -->
<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />

<!-- Your service goes here -->
<bean name="myService" class="org.codehaus.xfire.spring.ServiceBean">
<property name="xfire" ref="xfire"/>
<property name="serviceBean" ref="myService"/>
<property name="serviceClass" value="MyService"/>
<property name="serviceFactory" ref="jsr181"/>
</bean>

<!-- Here's initialising an "jsr181" instance to be
a factory object for your services -->
<bean id="jsr181"
class="org.codehaus.xfire.spring.config.ServiceFactoryBean"
init-method="initialize">
<constructor-arg index="0" value="jsr181" />
<property name="transportManager" ref="xfire.transportManager" />
</bean>

</beans>


Finally, put some servlet configuration into your "web.template.xml", like this

<servlet>
<servlet-name>XFireServlet</servlet-name>
<display-name>XFire Servlet</display-name>
<servlet-class>
org.codehaus.xfire.spring.XFireSpringServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>XFireServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>


OK, let's type "grails run-app" and browse to "http://localhost:8080/${your_grails_app}/services/myService/" to see its WSDL link.
And that's all, your XFire service is now ready.

Friday, December 08, 2006

Are you suffering from using Dojo in Grails ?

Everything works fine for Grails 0.3.1 when I'm not using Dojo.
But after I'm using it with Grails, I'm suffering from the 100% CPU usage.
This performance hit's caused by Jetty (Grails' default server) is trying to response Dojo files.

From my understanding, it might be that
1. Jetty in Grails distribution has not been configured for this purpose ? or
2. It's normal that a Servlet container's not good at serving a big static file ?

Anyway, I still don't know what's going on inside the container, but I've got a workaround for this problem.
My current solution is to use lighttpd as the front server to serve this Dojo monster ;)
I connect lighttpd with Grails' server using the mod_proxy.
Here's my current config in \etc\lighttpd.conf


proxy.server = ( "/" =>
( "127.0.0.1" =>
(
"host" => "127.0.0.1",
"port" => 8080
)
)
)



Then you need to put your Dojo files into the \htdocs, and correct all script's references in your GSP pages.
Lighttpd uses the default 80 port. So, you just point your browser to http://127.0.0.1//, every should work correctly.

IMO, this solution should work for the production phase as well.

Friday, December 01, 2006

Minimum "rt.jar" for Hello World

Here's a list of classes that are needed to run a Java hello world program.
I find this list using java -verbose (motivated by this post).

== listfile.txt ==
/java/io/BufferedInputStream.class
/java/io/BufferedOutputStream.class
/java/io/BufferedWriter.class
/java/io/Closeable.class
/java/io/DataInput.class
/java/io/DataInputStream.class
/java/io/ExpiringCache.class
/java/io/ExpiringCache$1.class
/java/io/ExpiringCache$Entry.class
/java/io/File.class
/java/io/FileDescriptor.class
/java/io/FileInputStream.class
/java/io/FileOutputStream.class
/java/io/FilePermission.class
/java/io/FilePermission$1.class
/java/io/FilePermissionCollection.class
/java/io/FileSystem.class
/java/io/FilterInputStream.class
/java/io/FilterOutputStream.class
/java/io/Flushable.class
/java/io/InputStream.class
/java/io/ObjectStreamClass.class
/java/io/ObjectStreamField.class
/java/io/OutputStream.class
/java/io/OutputStreamWriter.class
/java/io/PrintStream.class
/java/io/Serializable.class
/java/io/Win32FileSystem.class
/java/io/WinNTFileSystem.class
/java/io/Writer.class
/java/lang/AbstractStringBuilder.class
/java/lang/Appendable.class
/java/lang/ArithmeticException.class
/java/lang/ArrayStoreException.class
/java/lang/Boolean.class
/java/lang/Byte.class
/java/lang/CharSequence.class
/java/lang/Character.class
/java/lang/CharacterDataLatin1.class
/java/lang/Class.class
/java/lang/Class$1.class
/java/lang/Class$3.class
/java/lang/ClassCastException.class
/java/lang/ClassLoader.class
/java/lang/ClassLoader$3.class
/java/lang/ClassLoader$NativeLibrary.class
/java/lang/ClassNotFoundException.class
/java/lang/Cloneable.class
/java/lang/Comparable.class
/java/lang/Compiler.class
/java/lang/Compiler$1.class
/java/lang/Double.class
/java/lang/Error.class
/java/lang/Exception.class
/java/lang/Float.class
/java/lang/IncompatibleClassChangeError.class
/java/lang/Integer.class
/java/lang/Iterable.class
/java/lang/LinkageError.class
/java/lang/Long.class
/java/lang/Math.class
/java/lang/NoClassDefFoundError.class
/java/lang/NoSuchMethodError.class
/java/lang/NullPointerException.class
/java/lang/Number.class
/java/lang/Object.class
/java/lang/OutOfMemoryError.class
/java/lang/Readable.class
/java/lang/Runnable.class
/java/lang/Runtime.class
/java/lang/RuntimeException.class
/java/lang/RuntimePermission.class
/java/lang/Short.class
/java/lang/Shutdown.class
/java/lang/Shutdown$Lock.class
/java/lang/StackOverflowError.class
/java/lang/StackTraceElement.class
/java/lang/StrictMath.class
/java/lang/String.class
/java/lang/String$CaseInsensitiveComparator.class
/java/lang/StringBuffer.class
/java/lang/StringBuilder.class
/java/lang/StringCoding.class
/java/lang/StringCoding$CharsetSD.class
/java/lang/StringCoding$CharsetSE.class
/java/lang/StringCoding$StringDecoder.class
/java/lang/StringCoding$StringEncoder.class
/java/lang/System.class
/java/lang/System$2.class
/java/lang/SystemClassLoaderAction.class
/java/lang/Terminator.class
/java/lang/Terminator$1.class
/java/lang/Thread.class
/java/lang/Thread$UncaughtExceptionHandler.class
/java/lang/ThreadDeath.class
/java/lang/ThreadGroup.class
/java/lang/ThreadLocal.class
/java/lang/ThreadLocal$ThreadLocalMap.class
/java/lang/ThreadLocal$ThreadLocalMap$Entry.class
/java/lang/Throwable.class
/java/lang/VirtualMachineError.class
/java/lang/annotation/Annotation.class
/java/lang/management/MemoryUsage.class
/java/lang/ref/FinalReference.class
/java/lang/ref/Finalizer.class
/java/lang/ref/Finalizer$FinalizerThread.class
/java/lang/ref/PhantomReference.class
/java/lang/ref/Reference.class
/java/lang/ref/Reference$Lock.class
/java/lang/ref/Reference$ReferenceHandler.class
/java/lang/ref/ReferenceQueue.class
/java/lang/ref/ReferenceQueue$Lock.class
/java/lang/ref/ReferenceQueue$Null.class
/java/lang/ref/SoftReference.class
/java/lang/ref/WeakReference.class
/java/lang/reflect/AccessibleObject.class
/java/lang/reflect/AnnotatedElement.class
/java/lang/reflect/Constructor.class
/java/lang/reflect/Field.class
/java/lang/reflect/GenericDeclaration.class
/java/lang/reflect/Member.class
/java/lang/reflect/Method.class
/java/lang/reflect/Modifier.class
/java/lang/reflect/ReflectAccess.class
/java/lang/reflect/ReflectPermission.class
/java/lang/reflect/Type.class
/java/net/ContentHandler.class
/java/net/Parts.class
/java/net/URL.class
/java/net/URLClassLoader.class
/java/net/URLClassLoader$1.class
/java/net/URLConnection.class
/java/net/URLStreamHandler.class
/java/net/URLStreamHandlerFactory.class
/java/net/UnknownContentHandler.class
/java/nio/Bits.class
/java/nio/Buffer.class
/java/nio/ByteBuffer.class
/java/nio/ByteOrder.class
/java/nio/CharBuffer.class
/java/nio/HeapByteBuffer.class
/java/nio/HeapCharBuffer.class
/java/nio/charset/Charset.class
/java/nio/charset/Charset$3.class
/java/nio/charset/CharsetDecoder.class
/java/nio/charset/CharsetEncoder.class
/java/nio/charset/CoderResult.class
/java/nio/charset/CoderResult$1.class
/java/nio/charset/CoderResult$2.class
/java/nio/charset/CoderResult$Cache.class
/java/nio/charset/CodingErrorAction.class
/java/nio/charset/spi/CharsetProvider.class
/java/security/AccessControlContext.class
/java/security/AccessController.class
/java/security/AllPermission.class
/java/security/BasicPermission.class
/java/security/BasicPermissionCollection.class
/java/security/CodeSource.class
/java/security/Guard.class
/java/security/Permission.class
/java/security/PermissionCollection.class
/java/security/Permissions.class
/java/security/Principal.class
/java/security/PrivilegedAction.class
/java/security/PrivilegedActionException.class
/java/security/PrivilegedExceptionAction.class
/java/security/ProtectionDomain.class
/java/security/SecureClassLoader.class
/java/security/UnresolvedPermission.class
/java/security/cert/Certificate.class
/java/util/AbstractCollection.class
/java/util/AbstractList.class
/java/util/AbstractMap.class
/java/util/AbstractSet.class
/java/util/ArrayList.class
/java/util/BitSet.class
/java/util/Collection.class
/java/util/Collections.class
/java/util/Collections$EmptyList.class
/java/util/Collections$EmptyMap.class
/java/util/Collections$EmptySet.class
/java/util/Collections$ReverseComparator.class
/java/util/Collections$SynchronizedMap.class
/java/util/Comparator.class
/java/util/Dictionary.class
/java/util/Enumeration.class
/java/util/HashMap.class
/java/util/HashMap$Entry.class
/java/util/HashSet.class
/java/util/Hashtable.class
/java/util/Hashtable$EmptyEnumerator.class
/java/util/Hashtable$EmptyIterator.class
/java/util/Hashtable$Entry.class
/java/util/Iterator.class
/java/util/LinkedHashMap.class
/java/util/LinkedHashMap$Entry.class
/java/util/List.class
/java/util/Locale.class
/java/util/Map.class
/java/util/Map$Entry.class
/java/util/Properties.class
/java/util/Random.class
/java/util/RandomAccess.class
/java/util/Set.class
/java/util/SortedMap.class
/java/util/Stack.class
/java/util/StringTokenizer.class
/java/util/TreeMap.class
/java/util/TreeMap$Entry.class
/java/util/Vector.class
/java/util/concurrent/atomic/AtomicLong.class
/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.class
/java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.class
/java/util/jar/JarEntry.class
/java/util/jar/JarFile.class
/java/util/jar/JarFile$JarFileEntry.class
/java/util/jar/JavaUtilJarAccessImpl.class
/java/util/zip/Inflater.class
/java/util/zip/InflaterInputStream.class
/java/util/zip/ZipConstants.class
/java/util/zip/ZipEntry.class
/java/util/zip/ZipFile.class
/java/util/zip/ZipFile$2.class
/java/util/zip/ZipFile$ZipFileInputStream.class
/sun/io/Converters.class
/sun/misc/ASCIICaseInsensitiveComparator.class
/sun/misc/AtomicLong.class
/sun/misc/AtomicLongCSImpl.class
/sun/misc/ExtensionDependency.class
/sun/misc/FileURLMapper.class
/sun/misc/JarIndex.class
/sun/misc/JavaLangAccess.class
/sun/misc/JavaUtilJarAccess.class
/sun/misc/Launcher.class
/sun/misc/Launcher$AppClassLoader.class
/sun/misc/Launcher$AppClassLoader$1.class
/sun/misc/Launcher$ExtClassLoader.class
/sun/misc/Launcher$ExtClassLoader$1.class
/sun/misc/Launcher$Factory.class
/sun/misc/NativeSignalHandler.class
/sun/misc/Resource.class
/sun/misc/SharedSecrets.class
/sun/misc/Signal.class
/sun/misc/SignalHandler.class
/sun/misc/SoftCache.class
/sun/misc/URLClassPath.class
/sun/misc/URLClassPath$3.class
/sun/misc/URLClassPath$FileLoader.class
/sun/misc/URLClassPath$FileLoader$1.class
/sun/misc/URLClassPath$JarLoader.class
/sun/misc/URLClassPath$Loader.class
/sun/misc/Unsafe.class
/sun/misc/VM.class
/sun/misc/Version.class
/sun/net/www/MessageHeader.class
/sun/net/www/ParseUtil.class
/sun/net/www/URLConnection.class
/sun/net/www/protocol/file/FileURLConnection.class
/sun/net/www/protocol/file/Handler.class
/sun/net/www/protocol/jar/Handler.class
/sun/nio/ByteBuffered.class
/sun/nio/cs/AbstractCharsetProvider.class
/sun/nio/cs/FastCharsetProvider.class
/sun/nio/cs/HistoricallyNamedCharset.class
/sun/nio/cs/MS1252.class
/sun/nio/cs/MS1252$Decoder.class
/sun/nio/cs/MS1252$Encoder.class
/sun/nio/cs/SingleByteDecoder.class
/sun/nio/cs/SingleByteEncoder.class
/sun/nio/cs/StandardCharsets.class
/sun/nio/cs/StandardCharsets$Aliases.class
/sun/nio/cs/StandardCharsets$Cache.class
/sun/nio/cs/StandardCharsets$Classes.class
/sun/nio/cs/StreamEncoder.class
/sun/nio/cs/StreamEncoder$CharsetSE.class
/sun/nio/cs/Surrogate.class
/sun/nio/cs/Surrogate$Parser.class
/sun/nio/cs/ext/ExtendedCharsets.class
/sun/nio/cs/ext/MS874.class
/sun/nio/cs/ext/MS874$Decoder.class
/sun/nio/cs/ext/MS874$Encoder.class
/sun/reflect/ConstantPool.class
/sun/reflect/ConstructorAccessor.class
/sun/reflect/ConstructorAccessorImpl.class
/sun/reflect/DelegatingClassLoader.class
/sun/reflect/DelegatingConstructorAccessorImpl.class
/sun/reflect/LangReflectAccess.class
/sun/reflect/MagicAccessorImpl.class
/sun/reflect/MethodAccessor.class
/sun/reflect/MethodAccessorImpl.class
/sun/reflect/NativeConstructorAccessorImpl.class
/sun/reflect/Reflection.class
/sun/reflect/ReflectionFactory.class
/sun/reflect/ReflectionFactory$1.class
/sun/reflect/ReflectionFactory$GetReflectionFactoryAction.class
/sun/reflect/misc/ReflectUtil.class
/sun/security/action/GetPropertyAction.class
/sun/security/util/Debug.class
/sun/util/PreHashedMap.class



The following is a command for 7z to strip down the rt.jar (from 37,043 Kb to 1,806 Kb).

7z.exe d -r -x@listfile.txt rt.jar *.class



I tested with JRE 1.5_08 on Windows XP.