Dienstag Mai 12, 2009

UNIX DaytimeServer - the Scala way

I'm playing around with Scala. No, frankly I'm in love with it. While reading through "Programming in Scala" (which is a perfect introduction into the subject), I converted the Daytime Server into a Scala version. Get the NetBeans Project.

Here's how it looks like:

 

 1 package daytimeserver
 2 
 3 import java.io.IOException
 4 import java.nio.ByteBuffer
 5 import java.util.Date
 6 import java.nio.channels.SelectionKey
 7 
 8 import com.sun.grizzly.{ ProtocolFilter, Context, Controller, ProtocolChain,
 9                          DefaultProtocolChain, ProtocolChainInstanceHandler, TCPSelectorHandler }
10 
11 import com.sun.grizzly.util.OutputWriter
12 
13 class MyTCPSelectorHandler extends TCPSelectorHandler {
14 
15     override def onAcceptInterest(key:SelectionKey, ctx: Context ) : Boolean = {
16         var channel = acceptWithoutRegistration(key)
17 
18         if (channel != null) {
19             configureChannel(channel)
20             var readKey = channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE)
21             readKey.attach(System.currentTimeMillis())
22         }
23         
24         false
25     }
26 }
27 
28 class MyProtocolChainInstanceHandler extends ProtocolChainInstanceHandler {
29 
30     private var protocolChain = new DefaultProtocolChain()
31 
32     def poll() : ProtocolChain = protocolChain
33     def offer(instance: ProtocolChain ) : Boolean = true
34 }
35 
36 class DaytimeWriterFilter extends ProtocolFilter {
37 
38     def execute(ctx: Context) : Boolean = {
39         if (ctx.getProtocol() == Controller.Protocol.TCP) {
40             var channel = ctx.getSelectionKey().channel()
41             var now = (new Date()).toString() + "\\n"
42             var buffer =  ByteBuffer.wrap(now.getBytes())
43 
44             OutputWriter.flushChannel(channel, buffer)
45 
46             channel.close()
47             buffer.clear()
48         }
49         false
50     }
51 
52     def postExecute(ctx : Context ) : Boolean  = false
53 }
54 
55 object DaytimeServer extends Application {
56 
57     val PORT : Int = 1405
58     var controller = new Controller()
59     var tcpSelectorHandler = new MyTCPSelectorHandler()
60     var pciHandler = new MyProtocolChainInstanceHandler()
61     var protocolChain = pciHandler.poll()
62 
63     tcpSelectorHandler.setPort(PORT)
64     controller.addSelectorHandler(tcpSelectorHandler)
65     controller.setProtocolChainInstanceHandler(pciHandler)
66     protocolChain.addFilter(new DaytimeWriterFilter())
67 
68     try {
69         println("Starting Daytime server running on port " + PORT)
70         controller.start()
71     } catch {
72         case ex: IOException => println("Exception:" + ex)
73     }
74 }
75 

Donnerstag Feb 26, 2009

Writing a UNIX daytime server (RFC 867) using Grizzly 1.9.x

This week, i started to write some kind of "Hello, World" programs for the superb Grizzly NIO framework. I used Jean-Francois Arcand's intro documentation as a foundation.

My goal was to create a simple Grizzly version of the UNIX daytime server (RFC 867). I based my tiny little program on Grizzly 1.9.7 therefore i had to remove the DefaultPipeline/setPipeline code which was needed with Grizzly 1.0.x in his examples. The tricky part was to tell Grizzly to process the ProtocolFilter on an accepted connection, rather than waiting for some data coming upstream. This is how the daytime server works - you connect to it, you get the date/time and the server closes the connection. 

Thanks to Oleksiy Stashok's reply on the grizzly users mailinglist this was fixed quite fast.  

Here's my poor man's version of a unix daytime server: 

 24 public class Main {
 25 
 26     private static int PORT = 1405;
 27 
 28     public static void main(String[] args) {
 29         Controller controller = new Controller();
 30 
 31         TCPSelectorHandler tcpSelectorHandler = new TCPSelectorHandler() {
 32 
 33             @Override
 34             public boolean onAcceptInterest(SelectionKey key,
 35                     Context ctx) throws IOException {
 36                 SelectableChannel channel = acceptWithoutRegistration(key);
 37 
 38                 if (channel != null) {
 39                     configureChannel(channel);
 40                     SelectionKey readKey =
 41                             channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
 42                     readKey.attach(System.currentTimeMillis());
 43                 }
 44                 return false;
 45             }
 46         };
 47 
 48         tcpSelectorHandler.setPort(PORT);
 49         
 50         controller.addSelectorHandler(tcpSelectorHandler);
 51 
 52         ProtocolChainInstanceHandler pciHandler =
 53             new ProtocolChainInstanceHandler() {
 54 
 55                 final private ProtocolChain protocolChain = new DefaultProtocolChain();
 56 
 57                 public ProtocolChain poll() {
 58                     return protocolChain;
 59                 }
 60 
 61                 public boolean offer(ProtocolChain instance) {
 62                     return true;
 63                 }
 64             };
 65             
 66         controller.setProtocolChainInstanceHandler(pciHandler);
 67 
 68         ProtocolChain protocolChain = pciHandler.poll();
 69         protocolChain.addFilter(new DaytimeWriterFilter());
 70 
 71         try {
 72             System.out.println("Starting Daytime server running on port " + PORT);
 73             controller.start();
 74         } catch (IOException ex) {
 75             Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
 76         }
 77 
 78     }
 79 }
 80 
 81 class DaytimeWriterFilter implements ProtocolFilter {
 82 
 83     public boolean execute(Context ctx) throws IOException {
 84         if (ctx.getProtocol() == Controller.Protocol.TCP) {
 85             SelectableChannel channel = ctx.getSelectionKey().channel();
 86 
 87             String now = (new Date()).toString() + "\\n";
 88 
 89             ByteBuffer buffer =  ByteBuffer.wrap(now.getBytes());
 90 
 91             OutputWriter.flushChannel(channel, buffer);
 92 
 93             channel.close();
 94             buffer.clear();
 95         }
 96 
 97         return false;
 98     }
 99 
100     public boolean postExecute(Context ctx) throws IOException {
101         return false;   // game over
102     }
103 
104 }

Freitag Feb 20, 2009

Running Openbravo on Glassfish v3

Last week i tried to run Openbravo 2.40 on Glassfish v3 (prelude version). Here i like to share my findings and how to get this setup running for those who follow. I neither explain how to install the necessary database nor the tomcat installation. The database was in my case PostgreSQL. I did the installation on a MacBook Pro/Intel running Mac OS X 10.5.6.

I had to get the "official" installation image for Openbravo on my platform (Mac OSX) which asks for the location of a pre-installed tomcat and login credentials for either a Oracle or PostgreSQL database. You have to run the standard installation process to get all schemas and data loaded into your preferred DB.

This can take up quite some time, but after this installation Openbravo could be found in tomcat's webapps directory: $TOMCAT_HOME/webapps/openbravo/openbravo.war. Trying to deploy this WAR-archive right away to Glassfish fails for reasons I'm going to explain below. Since there is one slight modification to Openbravo's deployment-descriptor (WEB-INF/web.xml) needed, we're unpack openbravo.war into it's own directory and deploy the application out of this directory.

The problem with the existing deployment-descriptor is, that it's written for Servlet 2.3 webcontainers like Glassfish v2 or tomcat. Glassfish v3 adheres to the Servlet 2.4 specification which is a bit picky about url-pattern. In principle this means you have to code this:

<url-pattern>
       /ad_callouts/SL_ProductionPlan_Conversion.html
</url-pattern>

this way:

<url-pattern>/ad_callouts/SL_ProductionPlan_Conversion.html</url-pattern>

This is tracked, accepted and fixed as issue 7493 in Openbravo. Once this change makes it into Openbravo, this whole document becomes obsolete. But till then you have to apply this patch to WEB-INF/web.xml to rewrite the deployment descriptor.

After this modification, just deploy Openbravo using Glassfish's admin GUI using this trail: Applications/Web Applications/Deploy ...:

After a few seconds the new deployed application should show up in the list of your web-applications:


Now you should be able to login using Openbravo's default account Openbravo/openbravo :

which in turn take you to Openbravo's main dashboard:



About

schmidtm

Search

Categories
Archives
« April 2014
MoDiMiDoFrSaSo
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Heute