Tuesday Mar 10, 2009
In Cometd environment, one can access cometd services through
simple Javascript,
Java API for Bayeux Protoc,
DOJO, etc.
In the Grizzly Issue 174,
developer amplus has contributed a first porting of Jetty Bayeux Java Client to
Grizzly.
A modification of the contribution has been checkin to Grizzly.
The above client code is based on Jetty 6.1.11.
Subsequently, various cometd bugs has been fixed in Grizzly 1.9.8 or later.
In this blog, we will describe how to use the Jetty Bayeux client in Grizzly with
GlassFish v3.
Environment Setting
In this moment, comet support is turned off by default.
The comet/cometd can be turned on in GlassFish v3 by adding the following property
to corresponding
http-listener.
In our case, it is the
http-listener-1.
<property name="cometSupport" value="true">
Note that it is recommended that one should set the above property by using asadmin rather
than directly editing the domain.xml. For instance,
asadmin set server.http-service.http-listener.http-listener-1.property.cometSupport=true
Download the following jars and put it under $GLASSFISH_HOME/domains/domain1/lib:
- grizzly-cometd-client-1.9.8.jar
- cometd-bayeux-6.1.11.jar
- jetty-6.1.11.jar
- jetty-client-6.1.11.jar
- jetty-util-6.1.11.jar
The first jar is from
Grizzly repository.
Note that you may like to get the correct Grizzly version working with your GlassFish v3.
(For instance, one can find out the Grizzly version in
MANIFEST.MF of
web-glue.jar.)
The remaining jars are from
Jetty repository 6.1.11.
Finally, we have to start the server.
A Cometd client application using Jetty Bayeux client
In our example, we will create a web Bayeux Client for
Cometd Chat Sample.
It can be downloaded
here.
One need to import Jetty's classes as follows:
import org.mortbay.cometd.AbstractBayeux;
import org.mortbay.cometd.client.BayeuxClient;
import org.mortbay.jetty.client.HttpClient;
import org.mortbay.thread.QueuedThreadPool;
import org.mortbay.util.ajax.JSON;
import dojox.cometd.Bayeux;
import dojox.cometd.Client;
import dojox.cometd.Message;
import dojox.cometd.MessageListener;
Then one need to create a BayeuxClient in as follows:
- Create a HttpClient.
httpClient = new HttpClient();
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
httpClient.setMaxConnectionsPerAddress(50);
- Create a QueuedThreadPool for the HttpClient.
QueuedThreadPool pool = new QueuedThreadPool();
pool.setMaxThreads(50);
pool.setDaemon(true);
httpClient.setThreadPool(pool);
- Start the HttpClient and create a BayeuxClient.
httpClient.start();
client = new BayeuxClient(httpClient, address, cometdUri) {
public void deliver(Client from, Message message) {
// do something
super.deliver(from, message);
}
};
where address is an InetSocketAddress and cometdUri is the cometd service uri.
- Create a MessageListener for the BayeuxClient.
MessageListener listener = new MessageListener() {
public void deliver(Client fromClient, Client toClient, Message msg) {
Object data = msg.get(AbstractBayeux.DATA_FIELD);
if (data != null) {
// do something
}
}
};
client.addListener(listener);
This listener is a no-op as we only use the client to send message in our case.
- Start the BayeuxClient and subscribe the channel.
client.start();
client.subscribe(channel);
With the setup above, the JSON message can be published as follows:
Object msg=new JSON.Literal("{\"user\":\"" + name + "\",\"chat\":\"" + chat + "\"}");
client.publish(channel, msg, String.valueOf(mid.getAndIncrement()));
where msg is a JSON object associated to data.
Comparison with Java API for Bayeux Protocol
In this section, we will compare Jetty Bayeux client with the
Java API for Bayeux Protocol.
For convenience, I will summarize the Java API for Bayeux Protocol as follows:
- Get the CometContext.
CometEngine context = CometEngine.getEngine().getCometContext(channel);
- Create the DeliverResponse.
Map map = new HashMap();
map.put(messageDataName, messageDataValue);
Data data = new Data();
data.setMapData(map);
DeliverResponse deliverResponse = new DeliverResponse();
deliverResponse.setChannel("/service/echo");
deliverResponse.setClientId(clientId);
deliverResponse.setData(data);
deliverResponse.setLast(true);
deliverResponse.setFollow(true);
deliverResponse.setFinished(true);
Note that in this moment, one has to setFinished(true)
in addition to setLast(true).
- Notify the deliverResponse
context.notify(deliverResponse);
| | Jetty Bayeux Client | Java API for Bayeux Protocol
|
|---|
| Setup | more involved | simple
|
|---|
| Access Cometd Service | local and remote | local
|
|---|
| Client | in server and standlone | in server
|
|---|
| Construction of JSON messages | some explicitly | all use API
|
|---|
Friday Sep 26, 2008
In Enabling HTTP Compression in GlassFish,
Jean-Francois discussed about compression in
GlassFish.
There are four properties to configure compression, namely:
- compression
- compressionMinSize (in OCTET)
- compressableMimeType
- noCompressionUserAgents
One can turn compression
on and off by setting
compression = force and
compression = off respectively.
And one can also turn on the compression
if the content-length is unknown or known to be greater than a certain size.
There are two properties related to this: compression and compressionMinSize.
In this blog, we will discuss various ways to accomplish this scenario
in GlassFish v3.
compression vs compressionMinSize
| property | possible value if set | Default
|
|---|
| compression | on, force, off, integer | off
|
| compressionMinSize | integer | 2048
|
There are several possible combinations. We will summarize the behaviors
of GlassFish v3 in the below table.
In the following, α and β are integers.
| compression | compressionMinSize | Result
|
|---|
| on | β | compression with min size β
|
| on | not set | compression with default min size (2048)
|
| force | β or not set | compression with no size constraint
|
| α | β or not set | compression with min size α
|
| off or not set | β or not set | no compression
|
So, roughly speaking, whenever there is conflicting
information between compression and compressionMinSize, the
compression property will take precedence.
Since we use strict inequality to check for known
content length, the following are equivalent:
compression = force
compression = on and compressionMinSize = any negative integer
How to test it?
If one has turned on compression in GlassFish, then one will get HTTP
compression if the HTTP request is
- using HTTP 1.1
- with a HTTP header:
Accept-Encoding: gzip
- the content-length is unknown or greater than the compression minimum size
(or compression = force)
One can confirm that there is a HTTP compression by using Firefox with Firebug.
There will be a HTTP response header:
Note that one can also notice some changes in HTTP response
for HTTP compression by using the http client posted in one of my previous
blogs.
Thursday Aug 14, 2008
WEBDAV (RFC 4918)
protocol is a predecessor to HTTP/1.1 for management resources, etc.
The WEBDAV code in GlassFish
workspace is based on Tomcat. Jean-Francois blogged about this
in 2006.
WEBDAV Level 2 will be a supported feature in GlassFish v3.
In this blog, we would provide additonal information about WEBDAV in
GlassFish v3.
Configuration of WebDAVServlet
WEBDAV can be enabled by specifying the
org.apache.catalina.servlets.WebdavServlet in web.xml
for a given web application.
Also, it can be enabled and configured globally in
default-web.xml.
One can configure WebDAVServlet by specifying the init-param as follows:
| init-param | Type | Description | Default
|
|---|
| debug | int | debug level | 0 (no debug)
|
| listings | boolean | whether one can list resources | false
|
| readonly | boolean | whether resources are readonly | true
|
It is important to note that
when listings is set to true
or readonly is set to false, one must
set up security constraints and turn on security manager.
WEBDAV Clients
I have verified that the following WEBDAV clients work with GlassFish v3:
- Microsoft Word 2002 and 2003
File > Open > the url
- Internet Explorer 6 and 7
File > Open (check "Open as Web Folder") > the url
Note that under "Internet Options > Programs > HTML editor",
we may like to set it to Microsoft Word above or Mircrosoft FrontPage.
Hand-On Examples on WEBDAV protocol
WEBDAV includes the following HTTP methods:
- PROPFIND
- PROPMATCH
- MKCOL
- GET
- HEAD
- POST
- DELETE
- PUT
- COPY
- MOVE
- LOCK
- UNLOCK
I find that it is a good exercise to send HTTP requests directly and
see what happens there. For instance,
- the following HTTP request copy index.html to index2.html:
COPY /webdavtest/index.html HTTP/1.1
Host: localhost
Destination: http://localhost:8080/webdavtest/index2.html
Connection: close
- the following HTTP request delete the index2.html created above:
DELETE /webdavtest/index2.html HTTP/1.1
Host: localhost
Connection: close
There are many ways to send http client requests to server.
I find that it is quite handy to have the following Ruby script.
#!/usr/bin/ruby
require "socket"
if ARGV.length != 3
puts "ruby httpclient.rb <host> <port> <http request file>\n"
exit
end
host = ARGV[0];
port = ARGV[1].to_i;
filename = ARGV[2];
socket = TCPSocket.open(host, port)
file = File.new(filename)
while line = file.gets
command = line.chomp
puts command + "\r\n"
socket.write(command + "\r\n")
end
puts socket.readlines
socket.close
Note that you may like to update the path of ruby or
run the interpretator directly.
Tuesday Jul 15, 2008
Common Gateway Interface (CGI)
supports dynamic contents in web environment.
CGI programs are executable programs in the server platform with specific output.
It can be a Bourne shell script, Perl script or even a C binary executable.
It was very popular before the the appearance of Servlet, JSP and PHP.
The CGI code in GlassFish
workspace is based on Tomcat.
In GlassFish v3, CGI will be a supported feature.
Let us look at a very simple example.
Create a CGI script
In our example, we have a simple Perl program,
hello, to print a hello message and the timestamp
of the server.
#!/bin/perl
print "Content-type: text/html\n\n";
print "Hello World: ";
print scalar localtime;
print "\n";
Enabling CGI processing and packaging the war file
The CGI processing can be enabled in a war file by adding
CGIServlet et al in web.xml as follows:
<web-app>
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>
</web-app>
In this case, one need to package the hello
under the default cgiPathPrefix which is
WEB-INF/cgi.
For security, it is highly recommended that the contents / binaries of
CGI programs should be prohibited from direct viewing or download.
Alternatively, one can enable CGI by uncommenting the corresponding sections
in default-web.xml.
In our case, the CGI program can be
invoked through http://localhost:8080/YOUR_CONTEXT/cgi-bin/hello .
Configuration of CGIServlet
One can configure CGIServlet by specifying the init-param as follows:
| init-param | Type | Description | Default
|
|---|
cgiPathPrefix | String | subdirectory containing the cgi programs | WEB-INF/cgi
|
debug | int | debug level | 0 (no debug)
|
executable | String | executable for running the CGI script | perl
|
parameterEncoding | String | encoding use for parameter | System.getProperty("file.encoding", "UTF-8")
|
passShellEnvironment | boolean | whether to pass environment properties to CGI program | false
|
CGI with native executables
GlassFish v3 CGI can work with native executables as follows:
- set the
init-param with name executable to be the empty String in web.xml
- has exploded directory structure for the war in a directory, say
/export/cgitest
- make sure those executables has the executable bits set correctly
- deploy the "directory" (not the "war"), for instance
asadmin deploy /export/cgitest
Note that one works with the exploded directory structure rather than war
file as the executable bits information is lost during the process of
jar and unjar.
Friday Jul 11, 2008
Server Side Include (SSI)
allows including dynamic contents in html.
SSI and CGI were very popular before the the appearance of JSP and PHP.
The SSI code in GlassFish
workspace is based on Tomcat.
In GlassFish v3, SSI will be a supported feature.
Let us look at a very simple example.
Create a SSI file
In our example, we create a
index.shtml which
- includes the content of
header.html,
- prints a Hello message with server side timestamp, and
- executes a command say, uname (or any command in your operating system).
The page is as follows:
<!--#include virtual="header.html"-->
<br>Hello, it is <!--#echo var="DATE_LOCAL"-->.
<br>Result: <!--#exec cmd="uname"-->
Note that the extension shtml is configurable
in web.xml (see servlet-mapping below).
Enable SSI processing
The SSI processing can be enabled in a war file by adding
SSIServlet et al in web.xml as follows:
<web-app>
<servlet>
<servlet-name>ssi</servlet-name>
<servlet-class>org.apache.catalina.ssi.SSIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ssi</servlet-name>
<url-pattern>*.shtml</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>shtml</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
</web-app>
One can find more details about the configuration of SSIServlet in
the section below.
Alternatively, one can enable SSI by uncommenting the corresponding sections
in default-web.xml.
Note that the mime-mapping is to notify the browser
that the result of shtml file is of content-type: text/html.
If you don't specify this, then GlassFish will try to get the
mime-type from default-web.xml or
the default in the system.
Configuration of SSIServlet
One can configure SSIServlet by specifying the init-param as follows:
| init-param | Type | Description | Default
|
|---|
| buffered | boolean (or String converted to boolean) | whether the output should be buffered | false
|
| debug | int | represents debug level | 0 (no debug)
|
| expires | Long | expiration time in seconds | do not set "Expires" header in Http Response
|
| inputEncoding | String | encoding for SSI input if there is no URL content encoding specified | server platform encoding
|
| isVirtualWebappRelative | boolean (or String converted to boolean) | whether the "virtual" path of "#include" directive is relative to content-root | false (means relative to the given SSI file)
|
| outputEncoding | String | encoding for SSI output | UTF-8
|
Friday May 25, 2007
Security is very essential, especially in the enterprise
environment.
In this blog, we will compare security of Profiles in
GlassFish (GF) v2 and also note those feature availability in
Sun Java System Application Server (SJSAS) 8.x Enterprise Edition.
Note that
Enterprise Profile is not available in public yet and will
be in beta around July 2007. More information on
Profiles in GlassFish v2 can be found
here.
With JDK 1.5 and NSS 3.11.4, Enterprise Profile in
GlassFish v2 and SJSAS 8.x EE (but not available in GF v2
Cluster Profile) support the following:
- management of the PKCS#11 modules using
modutil
- explicit reference of keys in PKCS#11 providers for https
or iiop/SSL listeners. (Note that with JDK 1.5 or later, one
can add PKCS#11 providers to a given JDK. But those
keys cannot be references by current server.)
- Elliptic Curve algorithm for SSL and other crypto operations
(need Enterprise Profile GlassFish v2 and JDK 1.6)
In SJSAS 8.2 EE and the coming GlassFish v2 Enterprise Profile,
there is support for the use of private key in Solaris 10
Softtoken. As an example, let us take a look at how to set up
Solaris 10 Softtoken.
- Initialize Solaris 10 Softtoken password if you have not.
/bin/pktool setpin
- Register the Solaris 10 Softtoken to NSS.
modutil -dbdir $SJSAS_HOME/domains/domain1/config -force -add "Solaris 10 Softtoken" -libfile /usr/lib/libpkcs11.so -mechanisms RSA:DSA
- Verify that the token is added properly and find out
the corresponding token name.
modutil -dbdir $SJSAS_HOME/domains/domain1/config -list
A sample output is as follows:
Using database directory ....
Listing of PKCS #11 Modules
-----------------------------------------------------------
1. NSS Internal PKCS #11 Module
slots: 2 slots attached
status: loaded
slot: NSS Internal Cryptographic Services
token: NSS Generic Crypto Services
slot: NSS User Private Key and Certificate Services
token: NSS Certificate DB
2. Solaris 10 Softtoken
library name: /usr/lib/libpkcs11.so
slots: 1 slot attached
status: loaded
slot: Sun Crypto Softtoken
token: Sun Software PKCS#11 softtoken
-----------------------------------------------------------
In this case, the token name is "Sun Software PKCS#11 softtoken".
And this will be used in subsequent commands.
- Create a private key and certificate in Solaris 10 Softtoken.
certutil -S -x -n mytestcert -t "u,u,u" -v 120 -s "cn=j2ee,ou=J2EE,o=Sun,L=Santa Clara,ST=California,C=US" -d $SJSAS_HOME/domains/domain1/config -h "Sun Software PKCS#11 softtoken"
A sample output is as follows:
Enter Password or Pin for "Sun Software PKCS#11 softtoken":
A random seed must be generated that will be used in the
creation of your key. One of the easiest ways to create a
random seed is to use the timing of keystrokes on a keyboard.
To begin, type keys on the keyboard until this progress meter
is full. DO NOT USE THE AUTOREPEAT FUNCTION ON YOUR KEYBOARD!
Continue typing until the progress meter is full:
|************************************************************|
Finished. Press enter to continue:
Generating key. This may take a few moments...
- Change the
cert-nickname to
"Sun Software PKCS#11 softtoken:mytestcert" in your listeners.
- Restart the server, then it will prompt the password for
Solaris 10 Softtoken as follows:
Please enter password for NSS slot Sun Software
PKCS#11 softtoken>
Monday Apr 23, 2007
In these few months, there were several discussions
of using GlassFish JDBCRealm with MySQL. In this blog,
I will share my experience about using GlassFish
JDBCRealm with MySQL.
- Download the
MySQL Community Server.
I have downloaded the Solaris 10 (x86, 32 bit TAR package),
version 5.0.37, of the "MySQL Community Server".
- Expand the download file.
gunzip mysql-5.0.37-solaris10-i386.tar.gz
tar xf mysql-5.0.37-solaris10-i386.tar
cd mysql-5.0.37-solaris10-i386
and read INSTALL-BINARY.
- Set up the grant table.
scripts/mysql_install_db
- Start the MySQL server.
bin/mysqld_safe
- Set a password for the MySQL "root" user
bin/mysqladmin -u root password YOUR_PASSWORD
- Create database and table. The following is a
sample command.
bin/mysql -u root --password=YOUR_PASSWORD
create database database01;
use database01;
create table usertable(userid varchar(10) primary key, password varchar(32) not null);
create table grouptable(userid varchar(10), groupid varchar(20) not null, primary key (userid, groupid));
alter table grouptable add constraint FK_USERID foreign key(userid) references usertable(userid);
commit;
grant all privileges on *.* to 'root'@'YOUR_HOST' identified by 'YOUR_PASSWORD' with grant option;
Note that you may like to replace YOUR_PASSWORD and
YOUR_HOST in above.
- Populate user, group and passwor data.
For the purpose of testing the database, you may try to use
clear text password first as follows:
insert into usertable values ('webuser', 'webuser');
insert into grouptable values ('webuser', 'employee');
For MD5, please take a look at
another blog on JDBCRealm.
- Download
the JDBC driver from Connectors > Connector/J .
I have downloaded mysql-connector-java-5.0.5-bin.zip
- Unpack the package and copy the JDBC driver to $GLASS_HOME/lib.
unzip mysql-connector-java-5.0.5-bin.jar
cd mysql-connector-java-5.0.5
cp mysql-connector-java-5.0.5-bin.jar $GLASSFISH_HOME/lib
- Restart the GlassFish server in order to pick up the JBDC driver.
- Create a Connector pool in Admin Console as follows:
| Name | MySQLPool
|
| Resource Type | javax.sql.DataSource
|
| Database Vendor | MySQL
|
then click "Next" and
add the following properties:
| serverName | YOUR_HOST
|
| port | 3306
|
| databaseName | database01
|
| user | root
|
| password | YOUR_PASSWORD
|
Note that different versions of the JDBC driver may
have different properties. You may need to check the
readme file there. Furthermore, you may need to remove
extra default properties from Admin Console.
- Create a DataSource
jdbc/mysql
associated with the above pool.
- Create a JDBCRealm, named
jdbcrealm
with the following properties:
| datasource-jndi | jdbc/mysql
|
| user-table | usertable
|
| user-name-column | userid
|
| password-name-column | password
|
| group-table | grouptable
|
| group-name-column | groupid
|
| jaas-context | jdbcRealm
|
| digest-algorithm | none
|
Note that if you are using MD5 for password data, then you
need to set value of digest-algorithm to MD5.
- Now a JDBCRealm is ready and it can be used by specifying
it in deployment descriptors.
If there is anything wrong and cannot authenticate,
then one can turn on security log to FINE level and
check if there is any exception in
server.log.
Friday Apr 06, 2007
GlassFish uses Java JKS for storing keys and certificates.
Out of the box, the keyStore (keystore.jks) and
the trustStore (cacerts.jks) reside in
$GLASSFISH_HOME/domains/domain1.
Even though there are several CA root certificates in
cacerts.jks, there is only one private key in
keystore.jks.
GlassFish supports the use of multiple private keys in a given
domains. For instance, you may have two https listeners having
different server private keys. This is a very useful scenario
especially when one have
EC key.
So, in a given domain, we can have one https listener using
RSA key for normal browser and one https listener using EC
key for PDA.
In this blog, we will discuss the configuration when
there are multiple private keys in a given domain of GlassFish.
In this case, one needs to specify the private key / certificate
to be used for SSL communication. If the information is
not specified, then the server will pick up one which may
not be desirable.
Since one wants to be more precise in security environment,
one would like to specify the corresponding certificate
nickname in order to pick up the correct key.
There are two kinds of certificate nicknames: inbound,
https outbound.
Inbound Certificate Nickname
One needs to specify the inbound cert-nickname
for a given listener in domain.xml. For instance,
in http listener, it is as follows:
<http-listener ... security-enabled="true" ... />
<ssl cert-nickname="s1as" ... />
...
Instead of hand-crafting the domain.xml, it would
be a good idea to use Admin Console as follows:
Configuration > HTTP Services > Http listeners > http-listener-2,
and choose SSL tab and enter the valid alias value you
want in "Certificate Nickname" textbox.
Then one needs to restart the given domain (if there is a change
of certificate nickname) in order to activate the change.
Similarly for iiop listeners.
Https Outbound Certificate Nickname
GlassFish also supports the https outbound from server.
A private key / certificate is used for https outbound mutual
SSL authentication.
In this case, we can specify the https outbound certificate
nickname as jvm-options in domain.xml:
-Dcom.sun.enterprise.security.httpsOutboundKeyAlias=YOUR_ALIAS
One can achieve this through Admin Console as follows:
Application Server > JVM Settings > JVM Options >
Add JVM option, and enter the above jvm option in the
new textbox. Then one needs to restart the server in order to
activate this change.