Skip navigation
1 2 Previous Next

bhavanishankar

26 posts

Recently there has been lot of requests in GlassFish community asking for programmatic interface to run asadmin commands from within a servlet. This is very easy when the servlet is deployed on Embedded GlassFish.

When you embed GlassFish, you just need to bind the embeddable command runner in JNDI, like this:
import org.glassfish.embeddable.*; import javax.naming.InitialContext;    public class GlassFishEmbedded {    public static void main(String... args) {     GlassFishProperties props = new GlassFishProperties();     props.setPort("http-listener", 8080);     GlassFish glassfish = GlassFishRuntime.bootstrap().newGlassFish(props);     glassfish.start();       // Bind the command runner in JNDI tree with your own mapped-name     CommandRunner commandRunner = glassfish.getCommandRunner();     new InitialContext().bind("org.glassfish.embeddable.CommandRunner", commandRunner);      // Deploy your web-app containg RunAdminCommandsServlet using glassfish.getDeployer().deploy(...) method  } }  Thats it, now from your RunAdminCommandsServlet you can inject the command runner like this:
import org.glassfish.embeddable.*; import javax.annotation.Resource;    @WebServlet(name = "RunAdminCommandsServlet",   urlPatterns = "/RunAdminCommandsServlet")  public class RunAdminCommandsServlet extends HttpServlet {     @Resource(mappedName = "org.glassfish.embeddable.CommandRunner")   CommandRunner commandRunner;     @Override   protected void doGet(HttpServletRequest httpServletRequest,     HttpServletResponse httpServletResponse) throws ServletException, IOException {       if (commandRunner != null) {         CommandResult result = commandRunner.run("create-jdbc-connection-pool",                                              "--datasourceclassname=org.apache.derby.jdbc.ClientDataSource",                                              "--restype=javax.sql.XADataSource",                                             "--property=portNumber=1527:password=APP:user=APP:serverName=localhost:databaseName=sun-appserv-samples:connectionAttributes=create\\=true",                                              "sample_derby_pool");      }    }  }

Embeddability of GlassFish is been around for quite some time now. In 3.1, the embeddable APIs have been revised. Most of the GlassFish community is already aware of the API revision, however I would like to briefly describe the revised APIs in this blog and welcome any feedback.

Embeddable API overview:

API JavaDocs are at http://embedded-glassfish.java.net/nonav/apidocs/

The APIs are briefly categorized as :

(a) Top level APIs (org.glassfish.embeddable) : Provides classes and interfaces necessary to embed GlassFish and perform lifecycle operations, application deployments and runtime configurations

(b) Scattered Archive APIs (org.glassfish.embeddable.archive) : Abstraction for a scattered Java EE archive (parts disseminated in various directories).

(c) Web Container APIs  (org.glassfish.embebdable.web, org.glassfish.embeddable.web.config) : Provides classes and interfaces necessary to programmatically configure embedded WebContainer and create contexts, virtual servers, and web listeners.

(d) Advanced pluggability (org.glassfish.embeddable.spi) : Provides classes and interfaces necessary to plugin a custom GlassFish runtime.

(e) EJB container APIs (javax.ejb.embeddable) : Refer "Embedded Server Guide" for EJB embeddable APIs

Basic examples of embedding GlassFish and deploying applications to embedded GlassFish:

These examples are can be run with either of the following jars in your CLASSPATH:

Full profile uber jar : http://download.java.net/maven/glassfish/org/glassfish/extras/glassfish-embedded-all/3.1/glassfish-embedded-all-3.1.jar
Web profile uber jar: http://download.java.net/maven/glassfish/org/glassfish/extras/glassfish-embedded-web/3.1/glassfish-embedded-web-3.1.jar
Installed GlassFish's shell jar : $GF_INSTALLATION/lib/embedded/glassfish-embedded-static-shell.jar

Once you have ANY ONE of the above jar file with you, GlassFish can be embedded in your application by simply doing:

import org.glassfish.embeddable.*;

/** Create and start GlassFish */ GlassFish glassfish = GlassFishRuntime.bootstrap().newGlassFish();
glassfish.start();


Let us say that you would like 8080 web container port to be started while embedding GlassFish, then you have to do this:

import org.glassfish.embeddable.*;

/** Create and start GlassFish which listens at 8080 http port */ GlassFishProperties gfProps = new GlassFishProperties(); gfProps.setPort("http-listener", 8080); // refer JavaDocs for the details of this API. GlassFish glassfish = GlassFishRuntime.bootstrap().newGlassFish(gfProps);
glassfish.start();


Or let us say that you have 3.1 installation and want to embed GlassFish domain1 in your application, then you can do:

import org.glassfish.embeddable.*;

/** Bootstrap the GlassFish runtime pointing to 3.1 installation */
BootstrapProperties bsProps = new BootstrapProperties();
bsProps.setInstallRoot(System.getEnv("GF_INSTALLATION"));
GlassFishRuntime gfRuntime = GlassFishRuntime.bootstrap(bsProps);

/** Point GlassFish to domain1 */ GlassFishProperties gfProps = new GlassFishProperties(); gfProps.setInstanceRoot(System.getEnv("GF_INSTALLATION") + "/domains/domain1"); GlassFish glassfish = gfRuntime.newGlassFish(gfProps);

glassfish.start();


Note: If you have a custom domain.xml while embedding GlassFish, then you can use setConfigFileURI(String configFile) API of GlassFishProperties. JavaDoc has all the details.

Once you have the GlassFish embedded and is running, you may like to deploy a pre-built Java EE archive using the code below:

import org.glassfish.embeddable.*;

// Obtain the deployer from the glassfish which is embedded via the piece of code above.
Deployer deployer = glassfish.getDeployer();

// syntax of deployment params are same as how they are passed to 'asadmin deploy' command.
deployer.deploy(new File("simple.war"), "--contextroot=test", "--name=test", "--force=true");

// if you have no deployment params to pass, then simply do this:
deployer.deploy(new File("simple.war"));


If your archive is not pre-built, instead it's components are scattered in multiple directories, then you may be interested in using the scattered archive APIs:

import org.glassfish.embeddable.*;
import org.glassfish.embeddable.archive.*;

Deployer deployer = glassfish.getDeployer();

// Create a scattered web application.
ScatteredArchive archive = new ScatteredArchive("testapp", ScatteredArchive.Type.WAR);
// target/classes directory contains my complied servlets
archive.addClassPath(new File("target", "classes"));
// resources/sun-web.xml is my WEB-INF/sun-web.xml
archive.addMetadata(new File("resources", "sun-web.xml"));
// resources/MyLogFactory is my META-INF/services/org.apache.commons.logging.LogFactory
archive.addMetadata(new File("resources", "MyLogFactory"), "META-INF/services/org.apache.commons.logging.LogFactory");

deployer.deploy(archive.toURI())


Similarly, the scattered enterprise application (EAR type) can be deployed like this:

import org.glassfish.embeddable.*;
import org.glassfish.embeddable.archive.*;

Deployer deployer = glassfish.getDeployer();

// Create a scattered web application.
ScatteredArchive webmodule = new ScatteredArchive("testweb", ScatteredArchive.Type.WAR);
// target/classes directory contains my complied servlets
webmodule.addClassPath(new File("target", "classes"));
// resources/sun-web.xml is my WEB-INF/sun-web.xml
webmodule.addMetadata(new File("resources", "sun-web.xml"));

// Create a scattered enterprise archive.
ScatteredEnterpriseArchive archive = new ScatteredEnterpriseArchive("testapp");
// src/application.xml is my META-INF/application.xml
archive.addMetadata(new File("src", "application.xml"));
// Add scattered web module to the scattered enterprise archive.
// src/application.xml references Web module as "scattered.war". Hence specify the name while adding the archive.
archive.addArchive(webmodule.toURI(), "scattered.war");
// lib/mylibrary.jar is a library JAR file.
archive.addArchive(new File("lib", "mylibrary.jar"));
// target/ejbclasses contain my compiled EJB module.
// src/application.xml references EJB module as "ejb.jar". Hence specify the name while adding the archive.
archive.addArchive(new File("target", "ejbclasses"), "ejb.jar");

deployer.deploy(archive.toURI())


Finally, towards the end of your application, you would like to stop/dispose your embedded GlassFish:

import org.glassfish.embeddable.*;

/** Stop GlassFish */ glassfish.stop(); // you can start it again.

/** Dispose GlassFish */
glassfish.dispose(); // you can not start it again. But you can embed a fresh glassfish with GlassFishRuntime.bootstrap().newGlassFish()


More Examples:

If you checkout https://svn.java.net/svn/glassfish~svn/trunk/v3/tests/embedded you will find many more examples which cover embeddable web container APIs also.

Feedback:

If you have any feebback on the APIs, please send them to dev@glassfish.java.net or dev@embedded-glassfish.java.net

This blog shows how to programatically change the log levels of a particular logger in Embedded GlassFish.

I did a search on the internet for information on how to change the log levels of a particular logger in Embedded GlassFish. The only information I could find was http://docs.sun.com/app/docs/doc/821-1208/gjlfe?l=en&a=view which requires changing $JAVA_HOME/jre/lib/logging.properties. But I am not comfortable changing it at the JDK level.

So, I wrote the following piece of code. May be the Embedded GlassFish users will find it useful:


import org.glassfish.embeddable.*;

// Create Embedded GlassFish
GlassFish glassfish = GlassFishRuntime.bootstrap().newGlassFish();

// Set the log levels. For example, set 'deployment' and 'server' log levels to FINEST
Logger.getLogger(
"").getHandlers()[0].setLevel(Level.FINEST);
Logger.getLogger(
"javax.enterprise.system.tools.deployment").setLevel(Level.FINEST);
Logger.getLogger(
"javax.enterprise.system").setLevel(Level.FINEST);

// Start Embedded GlassFish and deploy an application.
// You will see all the FINEST logs printed on the console.
glassfish.start();
glassfish.getDeployer().deploy(
new File("sample.war"));

// Dispose Embedded GlassFish
glassfish.dispose();

 

The above code uses GlassFish 3.1 Embedded APIs and should be run using latest Embedded GlassFish JAR (3.1-SNAPSHOT is here).

Another alternative non programmatic way is to create a custom logging configuration file (customlogging.properties) with the following contents:

handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINEST
javax.enterprise.system.tools.deployment.level = FINEST
javax.enterprise.system.level = FINEST

and pass it while invoking your application (say MyEmbeddedGlassFish), like this:

java -Djava.util.logging.config.file=customlogging.properties MyEmbeddedGlassFish

(Refer http://docs.sun.com/app/docs/doc/820-7692/abluj?l=en&a=view for the logger names)

To start using Embedded GlassFish Server Open Source Edition 3.1 in your Maven project, all you need to do is to have the following configuration in your pom.xml: 
<project>
  ...
  <packaging>ear |ejb|jar|rar|war</packaging>
  ...
  <build>

    ...
    <plugins>
            <plugin>
                <groupId>org.glassfish</groupId>
                <artifactId>maven-embedded-glassfish-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <app>target/test.war</app>
                    <name>test</name>
                    <ports>
                        <http-listener>8080</http-listener>
                        <https-listener>8181</https-listener>
                    </ports>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>start</goal>  <!-- this will run during pre-integration-test phase -->
                            <goal>deploy</goal>  <!-- this will run during pre-integration-test phase -->
                            <goal>undeploy</goal>  <!-- this will run during post-integration-test phase -->
                            <goal>stop</goal>  <!-- this will run during post-integration-test phase -->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        <!-- Run maven tests during integration-test phase. 
         Because the Embeddeded GlassFish should be up & running with the app deployed
        in order to run the tests. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <skip>false</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            ...
    </plugins>
      ...
  </build>
      ...
      <repositories>
        <repository>
            <id>glassfish-releases</id>
            <url>http://download.java.net/maven/glassfish</url>
        </repository>
    </repositories>
    ...
</project>

In 3.1 version of the plugin, lot of new configuration options are added to start/admin/deploy/undeploy goals.

I have made the complete 3.1 plugin documentation available athttp://embedded-glassfish.java.net/nonav/plugindocs/3.1/plugin-info.html

Please read the plugin documentation for the new configuration options. If you come across any issues while using the plugin or have any questions about it, please write to users@glassfish.java.net or users@embedded-glassfish.java.net

In addition to the plugin document, as a reference, there are plenty of tests @ http://java.net/projects/glassfish/sources/svn/show/trunk/v3/tests/embedded/maven-pluginwhich use this plugin.

This blog describes how to configure org.glassfish:maven-embedded-glassfish-plugin for deploying more than one application.

There was a community request for this. Refer:

http://java.net/projects/glassfish/lists/users/archive/2012-02/message/382
http://stackoverflow.com/questions/9280413/maven-embedded-glassfish-plugin-deploying-2-applications

The following pom.xml snippet shows how to configure the plugin to achieve this:

            <plugin>
                <groupId>org.glassfish</groupId>
                <artifactId>maven-embedded-glassfish-plugin</artifactId>
                <version>4.0-SNAPSHOT</version>

                <!-- Plugin level configurations -->
                <configuration>
                    <goalPrefix>glassfish</goalPrefix>
                    <app>target/firstapp.war</app>
                    <port>8080</port>
                    <ports>
                        <https-listener>8181</https-listener>
                    </ports>
                    <name>firstapp</name>
                    <serverID>embedded</serverID>
                </configuration>

                <executions>

                    <!-- Start embedded GlassFish -->
                    <execution>
                        <id>start</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>

                    <!-- Run some admin commands -->
                    <execution>
                        <id>admin</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>admin</goal>
                        </goals>
                        <configuration>
                            <commands>
                                <param>list-applications</param>
                            </commands>
                        </configuration>
                    </execution>

                    <!-- Perform normal deployment (first application) using plugin level configurations -->
                    <execution>
                        <id>deploy</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                    </execution>

                    <!-- Deploy second application (using goal specific configurations) -->
                    <execution>
                        <id>deploy2</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                        <configuration>
                            <app>secondapp/secondapp.war</app>
                            <contextRoot>secondapp</contextRoot>
                            <name>secondapp</name>
                            <deploymentParams>
                                <param>--verify=true</param>
                            </deploymentParams>
                        </configuration>
                    </execution>

                    <!-- Undeploy the second application (using goal specific configurations) -->
                    <execution>
                        <id>undeploy</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>undeploy</goal>
                        </goals>
                        <configuration>
                            <name>secondapp</name>
                        </configuration>
                    </execution>

                    <!-- Perform normal undeploy (i.e., first app) using plugin level configurations and stop embedded GlassFish -->
                    <execution>
                        <id>stop</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>undeploy</goal>
                            <goal>stop</goal>
                        </goals>
                    </execution>

                </executions>
            </plugin>

With 4.0-SNAPSHOT version of the plugin, 'mvn embedd-glassfish:run' is also enhanced to run all the 'admin' goals, and all the 'deploy' goals.

The following devtest should serve more details:

http://java.net/projects/glassfish/sources/svn/show/trunk/main/appserver/tests/embedded/maven-plugin/multipleApps

Checkout the devtest with : svn checkout https://svn.java.net/svn/glassfish~svn/trunk/main/appserver/tests/embedded/maven-plugin/multipleApps

 

In one of my previous blog, I provided some preliminary notes about running CAFE apps on top of Oracle Converged  Communications Server (OCCAS) which covered two party call and voice  conference.

Now that we have MSRP support in CAFE for doing session mode IM, large file transfers, etc., which apparently works in OCCAS, it may be worth sharing a quick note on how to enable/use it in OCCAS.

For "Installing OCCAS" and "Installing CAFE on OCCAS" please refer my previous blog.

To enable MSRP, just copy OCCAS_HOME/user_projects/domains/base_domain/lib/msrp-connector-ra.rar  to OCCAS_HOME/user_projects/domains/base_domain/autodeploy/

Thats it, OCCAS is now ready for deploying the CAFE applications to do  session mode IM, large file transfers using MSRP:

https://sailfin-cafe.dev.java.net/files/documents/10280/151122/occas-msrp.png

Some sample applications for trying out :

(1) Sending large file from the remote client browser to the conference  attendees: Deploy cafemsrp_browser_file_transfer.war by copying it to OCCAS_HOME/user_projects/domains/base_domain/autodeploy/.  Refer my earlier blog for the details of the application.

(2) In a voice conference, sending the large file from one attendee to all the other attendees: Deploy voice_and_msrp-1.0-SNAPSHOT.war by just copying it  to OCCAS_HOME /user_projects/domains/base_domain/autodeploy/.  Watch SCREENCAST (~30 seconds, ~4 MB) to see how the  sample works. To run this sample you also need to start the jvoicebridge  as instructed here.

The javadocs for MSRP*** apis are at http://download.java.net/javaee5/sailfin-cafe/v1/apidocs/

For comments/questions or trouble running the samples, wriie to me  directly at bhavanishankar@dev.java.net

MSRP support in CAFE has been evolving since I last wrote about it.

Among the many new things, I am going to cover one of its important capability i.e., ability to send large file(s) from a browser running on a remote machine to the SIP phones. Without such a support in CAFE/MSRP, it is very hard (if not impossible) to achieve such a functionality in a converged container.




Figure 1. Sending large file from remote client browser to the SIP phones.


In Figure 1, Alice, Bhavani and Bob are in a voice conference named conf1@example.com. Some other user running on a remote machine sends a large file from his browser to conf1@example.com using CAFE/MSRP.  (Note that the SIP phones of Alice, Bhavani and Bob are MSRP capable eg.., Mercuro, Blink.)

CAFE/MSRP provides very simple APIs to do this. The end user need to write a simple web application and deploy it in CAFE container. The web application needs to contain following simple things:

(a) HTML page for the client browser (test.html):

 

(b) HTTP Servlet to handle the browser request and send the file to the SIP phones using the simple CAFE/MSRP APIs:

 

 

(c) And off course a VoiceConferenceBean is required for handling the voice conference. This bean gets invoked when the user joins the voice conference (As I mentioned earlier, we are sending file to voice conference attendees, using (a) and (b)).

 

To try it yourself:

The complete application is available here : https://sailfin-cafe.dev.java.net/files/documents/10280/150937/cafemsrp_browser_file_transfer_1.0.war

Deploy it on SailFin container with CAFE framework (Get SailFin from sailfin.dev.java.net and CAFE from sailfin-cafe.dev.java.net ).

Once the application is deployed, let your SIP clients join the voice conference viz., conf1@example.com (refer initial few steps in my earlier SCREENCAST on how to create/join voice conference). Once the voice conference is established, send the file to conference attendees from remote browser by accessing http://<your-server-host:port>/cafemsrp_browser_file_transfer

For OCCAS deployment, I plan to write CAFE/MSRP on Oracle Communications Converged Application Server (OCCAS 4.0) which will cover how to deploy/run this application.

For the more details on MSRP APIs, refer CAFE javadocs at http://download.java.net/javaee5/sailfin-cafe/v1/apidocs/index.html

Write to me directly at bhavanishankar@dev.java.net for any comments/questions.

MSRP protocol support has been recently added to SailFin CAFE. This feature is available in the latest sailfin-cafe downloads.

With the MSRP protocol it is now possible to do the following using SailFin CAFE:

       
  • Session mode instant messaging
  •    
  • Large file transfers.

(more to come in the forthcoming builds)

SailFin CAFE added two new APIs to support MSRP, which are:

       
  • org.glassfish.cafe.api.MSRPConversation
  •    
  • org.glassfish.cafe.api.MSRPConference

This blog covers how the large file can be tranferred across the attendees when you are in a voice conference. Instead of the plain text, I have created a screencast which covers all the details. Please click here to watch the SCREENCAST (around 30 seconds, sized ~4 MB)

To try it yourself : 

The deployed quality-msrptests-test1-1.0-SNAPSHOT.war has 2 CAFE communication beans in it. One bean handles the voice conference and the other one handles the msrp.

Wrt screencast, here is the brief description of the beans (quality-msrptests-test1-1.0-SNAPSHOT.war file has the complete source code):

Bean which handles the voice conference:

Bean which handles the MSRP file transfer:


Send your comments to me directly @ bhavanishankar@dev.java.net

 

Installing OCCAS

Install OCCAS 4.0 under directory /opt/oracle (here in after referred to as OCCAS_HOME), and configure a domain by running OCCAS_HOME/wlserver_10.3/common/bin/config.sh (with all default options). With that, you will have a domain created at OCCAS_HOME/user_projects/domains/base_domain

Installing CAFE on OCCAS

Get the latest CAFE promoted build from here. Unzip the downloaded sailfin-cafe-v1-b<number>_installer.jar under OCCAS_HOME/user_projects/domains/base_domain/lib

Set the environment variable EXTRA_JAVA_PROPERTIES="-Dwlss.local.serialization=false" and run OCCAS_HOME/user_projects/domains/base_domain/bin/startWebLogic.sh to start OCCAS.

With that, CAFE framework is all set on OCCAS to run your CAFE applications.

Running CAFE apps on OCCAS:

I will provide some example CAFE applications to run it on OCCAS.

(1) Simple two party call

Deploy the simple two-party-call.war CAFE application by dropping it under OCCAS_HOME/user_projects/domains/base_domain/autodeploy directory. Now the application is ready to make two party calls. Refer to the final section of binod's blog to test this application using X-Lite.

The two-party-call.war has the following contents:

./WEB-INF/classes/org/glassfish/cafe/testapp/SimpleCommsBean.class

package org.glassfish.cafe.testapp;

import org.glassfish.cafe.api.bean.CommunicationBean;

@CommunicationBean
public class SimpleCommsBean {
}

./WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
  <listener>
    <listener-class>
     org.glassfish.cafe.integration.occas.CafeContextListener
   </listener-class>
</listener>
</web-app>

./WEB-INF/sip.xml

<?xml version="1.0" encoding="UTF-8"?>
<sip-app xmlns="http://www.jcp.org/xml/ns/sipservlet" xmlns:javaee="http://java.sun.com/xml/ns/javaee">
    <app-name>two-party-call</app-name>
    <servlet>
        <javaee:servlet-name>two-party-call__CafeServlet</javaee:servlet-name>
        <javaee:servlet-class>org.glassfish.cafe.core.Servlet</javaee:servlet-class>
        <javaee:load-on-startup>0</javaee:load-on-startup>
    </servlet>
</sip-app>


Note:
The app-name and servlet-name prefix should match the name of the .war file (two-party-call in this case)

This is the same CAFE application that you would have run on SailFin server, but with the addition of two deployment descriptors (WEB-INF/web.xml & WEB-INF/sip.xml).

(2) Conference application

In order to run conference application you need a media mixer. So, we need to first integrate the jvoicebridge (bundled with CAFE) with OCCAS, by following these steps :

       
  1. $ cd OCCAS_HOME/user_projects/domains/base_domain/lib/jvb/bridge
         
  2.    
  3. Edit run.properties to change voicebridge.sip.port=5070. (Otherwise the port 5060 will conflict with OCCAS)
         
  4.    
  5. Start jvoicebridge by running OCCAS_HOME/modules/org.apache.ant_1.6.5/bin/ant -f run.xml (make sure ANT_HOME is set to OCCAS_HOME/modules/org.apache.ant_1.6.5, and JAVA_HOME is set to OCCAS_HOME/jdk160_05)
         
  6.    
  7. Deploy the jvoicebridge connector by copying OCCAS_HOME/user_projects/domains/base_domain/lib/jvb-ra.rar to OCCAS_HOME/user_projects/domains/base_domain/autodeploy directory.

With that, the jvoicebridge is integrated with OCCAS-CAFE. Now deploy your conf-app.war CAFE application by dropping it under OCCAS_HOME/user_projects/domains/base_domain/autodeploy directory.


Note :
Prior to deploying conf-app.war, undeploy two-party-call.war by deleting it from autodeploy directory.

Now your CAFE application is ready to handle the conference calls, and the configuration looks like this:

If you are using X-Lite phone, then type "conf1@example.com" on the dial-pad of each each phone and click the dial button. You can see each one of them joining the conference, like this:

On the console where you started the jvoicebridge, you can see various control messages that are printed by the jvoicebridge.

Now to offer some insight into the deployed conf-app.war, it just has one simple communication bean (shown below), and the deployment descriptors:

./WEB-INF/classes/org/glassfish/cafe/testapp/YourCommunicationPOJO.class

package org.glassfish.cafe.testapp;

import org.glassfish.cafe.api.Conversation;
import org.glassfish.cafe.api.CommunicationSession;
import org.glassfish.cafe.api.CommunicationContext;
import org.glassfish.cafe.api.Context;
import org.glassfish.cafe.api.bean.CommunicationBean;
import org.glassfish.cafe.api.bean.CommunicationEvent;

@CommunicationBean
public class YourCommunicationPOJO {

    @Context CommunicationSession sess;
    @Context CommunicationContext ctx;

    @CommunicationEvent(type=CommunicationEvent.Type.INITIALIZATION)
    void handleInit() {
         Conversation call = (Conversation) ctx.getCommunication();
         String confName = call.getCallee().getName();
         if (confName.equalsIgnoreCase("conf1@example.com")) {
             sess.createConference(confName, call);
         }
    }
}

The deployment descriptors are same as that of two-party-call.war with app-name and servlet prefix set as conf-app in WEB-INF/sip.xml

(3) Accessing communication session from jsp and http servlet

If you want to do something as in binod's blog with CAFE on OCCAS, then you can access the communication session from jsp or http servlet like this:

public class SimpleTestServlet extends HttpServlet{

    @Context CommunicationSession session; // as of now, this injection does not work on OCCAS

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            if(session == null) {
                session = (CommunicationSession)request.getSession().getAttribute(CommunicationSession.NAME);
            }
                ....
    }
}

Ditto for jsp:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="org.glassfish.cafe.api.CommunicationSession"%>
<%
    CommunicationSession commSession = (CommunicationSession) session.getAttribute(CommunicationSession.NAME);
    ...
%>

 

Continue reading MSRP on OCCAS with CAFE

This blog answers some of the commonly asked questions about SailFin HA

[Note : my-app, my-node-agent, my-cluster, my-instance are the names I used, feel free to choose the names of your choice]


What is the minimum requirement to use high availability in SailFin:

You need to have a SailFin cluster with at least 2 instances.

How to enable high availability for an application?

You just need to deploy your application with the following option:

asadmin deploy --target my-cluster --availabilityenabled=true my-app.[sar|war|ear]

After deploying the application, how to ensure that the high availability is enabled?

Look for the following string in SAILFIN_INSTALL_DIR/nodeagents/my-node-agent/my-instance/logs/server.log :

Application /my-app configured with SIP persistence type: replicated, frequency: sip-transaction, and scope: session

After deploying the application my SAILFIN_INSTALL_DIR/nodeagents/my-node-agent/my-instance/logs/server.log shows the following message, what should I do?

Invalid session management configuration for non-distributable SIP application [my-app]: persistence-type = [replicated] / persistenceFrequency = [sip-transaction] / persistenceScope = [session]: Defaulting to memory

Add <distributable/> element to WEB-INF/sip.xml in my-app.[sar|war] and deploy the application again. Example sip.xml is here :

<?xml version="1.0"?>
<sip-app  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.jcp.org/xml/ns/sipservlet http://www.jcp.org/xml/ns/sipservlet/sip-app_1_1.xsd"
          version="1.1">
    <display-name>my-app</display-name>
    <description>my-app</description>
    <distributable/>
    ....
</sip-app>

After deploying the application my SAILFIN_INSTALL_DIR/nodeagents/my-node-agent/my-instance/logs/server.log shows the following message, what should I do?

WEB0129: Invalid Session Management Configuration for non-distributable app [my-app] - defaulting to memory: persistence-type = [replicated] / persistenceFrequency = [web-method] / persistenceScope = [session]

Inconsistent SIP and HTTP persistence configuration for converged application my-app, falling back to memory-only

This happens when my-app.[war|sar] has both WEB-INF/web.xml and WEB-INF/sip.xml and one of them is missing the <distributable/> element. To fix the error, add <distributable/> element to both WEB-INF/web.xml and WEB-INF/sip.xml, and redeploy your application.

Is there a quick way to start using high availability in SailFin without having to write my own application?

Yes, just install SailFin V2 and the bundled Basic3pcc sample will help you to just get started. This sample itself will create and configure the cluster for you. Which means if you just have the base SailFin V2 installed, you can just start exploring high availabilty in SailFin cluster. The instructions for using the sample are at :

http://wiki.glassfish.java.net/Wiki.jsp?page=SipBasic3pccHighAvailability

How to enable debug logging for high availabilty?

Set the following log levels:

asadmin set my-cluster-config.log-service.module-log-levels.property.ShoalLogger=CONFIG
asadmin set my-cluster-config.log-service.module-log-levels.property.ssr=FINEST
asadmin set my-cluster-config.log-service.module-log-levels.property.com\\.sun\\.enterprise\\.ee\\.web\\.sessmgmt\\.availability=FINEST
asadmin set my-cluster-config.log-service.module-log-levels.property.com\\.sun\\.enterprise\\.ee\\.web\\.sessmgmt\\.pipe=FINEST

Where do I find more information about SailFin high availability?

http://sailfin.dev.java.net (check Articles and Resource section)
http://www.sun.com/sip
http://www.java.net/blogs/bhavanishankar
http://blogs.sun.com/shreedhar

Whom should I contact if I have more questions on SailFin high availability?

Post it as a comment in this blog or write to users@sailfin.dev.java.net

What is rolling upgrade?

Rolling upgrade is a zero downtime upgrade of the SailFin cluster.

It can broadly be classfied into the following types :

       
  • Upgrade of your running application.
  •    
  • Upgrade of your hardware hosting the SailFin cluster.
  •    
  • Upgrade of your running SailFin cluster from version 'x' to version 'y' ('y' should be backward compatible with 'x')
  •    
  • As simple as applying a bugfix patches to your running SailFin cluster.

Goal of this write up is to give a preview of Rolling Upgrade feature in SailFin, with an example of application upgrade.

To achieve any type of rolling upgrade, you need to have at least 2 instance cluster with your application deployed as high-availability (HA) enabled (i.e., you need to have your application deployed with : asadmin deploy --target <your-cluster> --availabilityenabled=true <your-app>)


Example of rolling upgrade of an application in SailFin cluster:

In this example, we will go through :

       
  • How the application looks before the rolling upgrade
  •    
  • Performing the rolling upgrade.
  •    
  • How the application looks after the rolling upgrade

Before the rolling upgrade:

 

Deploy and execute the Basic3pcc cluster sample as explained in my previous blog post by following "Instructions to deploy" and "Instructions to execute" sections.

Now the call is in progress between Alice and Bob, and your (i.e., Alice's) web browser displays the call history as shown the figure below (Note that I also clicked 'Call Adam', 'Call Eve' before clicking 'Call Bob', so the 'Call History' shows those statuses as well) :



Figure 1. Alice's browser showing the call call history, login time, etc [Before the Rolling Upgrade]

Now, without logging out from the browser, and without disconnecting the call between Alice and Bob, let us perform the rolling upgrade of Basic3pcc sample application.

 

Performing the Rolling Upgrade:

       
  1. % cd SF_HOME/samples/sipservlet/Basic3pcc
        It would point to the sailfin sample 'Basic3pcc' directory
  2.    
       
  3. % SF_HOME/lib/ant/bin/ant do-rollingupgrade
       
    It would do the rolling upgrade of Basic3pcc sample application. This step may take a while, wait for its completion.
Thats about it, the rolling upgrade of the application is done!

Internal details (what takes place during do-rollingupgrade) :

1. Upgrading the application: In this example, I wanted to provide a better user interface than what is shown in Figure 1. So, I upgraded 3pccConvergedApp.sar by updating its .jsp files, and adding some new .css, image files, etc.

2. Disabling dynamic reconfiguration: This is required so that the upgraded application does not get distributed immediately to the cluster instead it gets re-deployed instance-by-instance as we do the rolling of each instance in the cluster.

3. Deploying the upgraded application. Because of step (2), the instances in the cluster will still be running the older version of the application, until we execute the following step.

4. Rolling an instance (this step should be performed for all the instances in the cluster one-by-one)
       
  • Disable the instance: CLB will remove this instance from its healthy instances list, and will no longer route any requests to this instance.
  •    
  • Finish replicating: Ensure that any outstanding (asynchronous) replications are finished.
  •    
  • Restart the instance:  Stop the instance and start it back.
  •    
  • Restore the sessions: Bring back all the sessions which were replicated by this instance prior to doing the rolling.
  •    
  • Enable the instance: CLB will add this instance to its healthy instances list, and will start routing the requests to this instance.
  •    
  • Reconile the sessions: Ensure that all the sessions are of correct/highest version. Since there was no downtime during the rolling upgrade, the sessions might have been accessed from a different instance, hence those sessions need to be brought back to this instance during this step. (Note : After enabling and before reconciling, a separate technique is used to ensure that highest version of the session is discovered and used).

After the rolling upgrade:

 

Click on "Refresh Page" link in your (i.e., Alice's) browser, and you will see a all new upgraded user interface, and with no loss of your session:



Figure 2. Alice's browser showing the call call history, login time, etc [After the Rolling Upgrade]

You can also see that the ongoing call between Alice and Bob also gets handled by rolled instance (instance4) gracefully.

You can check that out by clicking "Hang Up" button in Alice's phone. The BYE request sent from Alice's phone gets routed to the rolled instance4 and the upgraded ConvergedApp running in instance4 will process the BYE request using the same session which was created before doing the rolling upgrade. So the call will between Alice and Bob gets ended gracefully.

 


Summary :


We demonstrated a seamless rolling upgrade of a running application in SailFin cluster with no downtime, no session/call loss.

 


The "Basic3pcc" sample demonstrates a simple Third Party Call Control (3pcc) application in SailFin.

This blog describes how to explore out-of-box cluster and high availability features of SailFin using this sample.

First read my previous blog post to get the overall understanding of this sample.


Instructions to deploy Basic3pcc sample to SailFin cluster

       
  1. Download the latest SailFin from here. Follow this link to unbundle and configure your SailFin.
  2.    
       
  3. Set the environment variables SF_HOME=<your sailfin installation dir>, HOST_IP_ADDRESS=<your actual ip address, not localhost/127.0.0.1>
  4.    
       
  5. % cd SF_HOME/samples/sipservlet/Basic3pcc
        It would point to the sailfin sample 'Basic3pcc' direcotry
  6.    
       
  7. % SF_HOME/lib/ant/bin/ant
        It would check your environment variable settings and it would display the available targets for use.
  8.    
       
  9. % SF_HOME/lib/ant/bin/ant setup-cluster
        it would setup a SailFin cluster as shown in figure below:
       
       
       
        Figure 1. SailFin cluster having 4 instances with instance1 used exclusively as a front-end for this demo.    
  10.    
       
  11. % SF_HOME/lib/ant/bin/ant deploy-cluster
        It would deploy both 3pccConvergedApp.sar and 3pccRegistrarAndProxy.sar files on SailFin cluster with high-availability-enabled=true.
  12.    
       
  13. [Optional step] % SF_HOME/lib/ant/bin/ant build
        Execute this step only if you want to modify this sample and rebuild the sample yourself. If you do this step, you need to redeploy the sample using step (6).

Instructions to execute the Basic3pcc sample application

       
  1. Setup your X-Lite softphones using platform specific steps (1) - (4) described in the CallSetup sample application's "Instructions execute the sample application" section by pointing to Telco AS:15060 instead of Telco AS:5060
       
        While configuring make sure that the X-Lite listens on the correct IP address, not on localhost/127.0.0.1. For example, in Linux this can be done by specifying the IP address at Menu > System Settings > Network > Listen on IP. 
       
        As mentioned in the instruction, you need to register both Alice's and Bob's X-Lite phones with SailFin. The registration happens as per the figure below:
       
       
       
        Figure 2. Registration of SIP phones of Alice and Bob with SailFin cluster
  2.    
       
  3. Now Browse to http://<your-host>:<your-port>/3pcc     (eg., http://localhost:18080/3pcc) and login as Alice. Use Alice as the the password.
       
        Note that the sample has pre-provisioned list of users which are Alice, Bob, Adam, Eve (with password same as user name). If you wish to re-provision the users, you can do so by editing SF_HOME/samples/sipservlet/Basic3pcc/userdb.properties     file. If you do that then you need to re-build and re-deploy the sample using step (7) & (6) of the above section.
         
  4.    
  5. Once you are logged in, you will see a list of buddies in your web page. Select the radio button against "Bob" and click "Call" button. This will establish a call between you (i.e., Alice) and Bob, as shown in the figure below:
       
       
                                                                                   
       
        Figure 3. Alice and Bob are talking
       

        Alice's browser will be updated with the call status and call history, as shown in the figure below:
       
       
       
        Figure 4. Alice's browser showing the call status and call history
       
        The call establishment between you (i.e., Alice) and Bob is done as per 3pcc, as shown in Figure 4 of my previous blog post
       
        Internal details of how the call establishment between Alice and Bob takes place in the SailFin cluster is described in the figure below:
       
       
       
        Figure 5. Internal details of the call establishment between Alice and Bob in the SailFin cluster.
       
        Description of various steps shown in Figure 5:
       
        (1) Alice clicks "Call" Bob@sailfin.org from her browser.
       
        (2) The http request gets routed to instance4.
       
        (3) In instance4, upon receiving the http request, the CallInitiatorServlet (of ConvergedApp) creates INVITE Alice@sailfin.org request and sends it to CLB front-end so that the INVITE request gets forwarded to a different application (RegistrarAndProxyApp in this case).
       
        The reason for forwarding to a different application is because, in real IMS deployments, ConvergedApp is not expected to maintain the location/registration information of the SIP phones, instead registration/location information is maintained by a different application which is RegistrarAndProxyApp in our deployment. So these two need to be separated as different entities.
       
        (4) CLB front-end routes this INVITE request to the correct server instance which has Alice's registration information.
       
        (5) ProxyServlet (of RegistrarAndProxyApp) running in instance4 sends out the INVITE request to Alice's registered location available in Alice's_SipAppSession.
       
        (6) Once Alice answers the call, the B2BUAServlet (of ConvergedApp) tries to place a call to Bob@sailfin.org by sending a INVITE Bob@sailfin.org request to CLB front end.
       
        (7) CLB front-end routes this INVITE request to the correct server instance which has Bob's registration information.
       
        (8) ProxyServlet (of RegistrarAndProxyApp) running in instance3 sends out the INVITE request to Bob's registered location available in Bob's_SipAppSession.

Exploring the failover capabilities:

As shown in Figure 4, the current serving instance is 'instance4'.

Now, to test the failover, you can stop the instance4 by executing % asadmin stop-instance instance4

After the instance4 is stopped, you can click "Refresh Page" link (as shown in Figure 4) in your web page. Once the page reloads, notice the label at the bottom of the page : "This page is served by SailFin ..." gets changed from instance4 to a different instance. You willl also notice that, all other data i.e., call history, login time are not lost. These data were stored in SipApplicationSession and ConvergedHttpSession respectively, and were replicated, and hence there is no data or session loss when the serving instance was brought down.

The ongoing call between Alice and Bob also gets handled by the different instance when instance4 is brought down. You can check this by clicking "Hang Up" button in Alice's phone. The BYE request sent from Alice's phone gets routed to a different live instance and the ConvergedApp running in that instance will recover/resume Alice's and Bob's SipSessions, and processes the BYE request, and the call gets ended gracefully on both Alice's and Bob's phones.

 


 


The newly introduced "Basic3pcc" sample demonstrates a simple Third Party Call Control (3pcc) application in SailFin. Download latest SailFin to get this sample.

This sample includes 2 applications as shown in the figure below:


Figure 1. Applications bundled in Basic3pcc sample.

 

Application #1 (i.e., 3pccConvergedApp.sar) is a 3pcc call controller application. CallInitiatorServlet, which is a http servlet, is also part of this application using which the user can initiate a 3pcc call from the browser.

Application #2 (i.e., 3pccRegistrarAndProxy.sar) contains the RegistrarServlet to keep the registration details of user's SIP phone, and a ProxyServlet to proxy the SIP requests to the registered location of user's SIP phone.

Overall workings of the sample is described in the figure below:

 


Figure 2. Overall workings of the sample

 


Instructions to deploy the sample application Basic3pcc

Note: For executing sailfin samples user must have installed and configured SailFin server. Here 'SF_HOME' is the sailfin installation directory.

       
  1. Set the environment variables SF_HOME=<your sailfin installation dir> and HOST_IP_ADDRESS=<your actual ip address, not localhost/127.0.0.1>
  2.    
       
  3. % ./asadmin start-domain domain1
        It would start the server.
  4.    
       
  5. % cd SF_HOME/samples/sipservlet/Basic3pcc
        It would point to the sailfin sample 'Basic3pcc' direcotry
  6.    
       
  7. % SF_HOME/lib/ant/bin/ant
        It would check your environment variable settings and it would display the available targets for use.
  8.    
       
  9. % SF_HOME/lib/ant/bin/ant deploy
        It would deploy both 3pccConvergedApp.sar and 3pccRegistrarAndProxy.sar files on SailFin server.
  10.    
       
  11. [Optional step] % SF_HOME/lib/ant/bin/ant build
        Execute this step only if you want to modify this sample and rebuild the sample yourself. If you do this step, you need to redeploy the sample using step (5).

Instructions to execute the sample application Basic3pcc

       
  1. Setup your X-Lite softphones using platform specific steps (1) - (4) described in the CallSetup sample application's "Instructions execute the sample application" section. While configuring make sure that the X-Lite listens on the correct IP address, not on localhost/127.0.0.1. For example, in Linux this can be done by specifying the IP address at Menu > System Settings > Network > Listen on IP. 
       
        As mentioned in the instruction, you need to register both Alice's and Bob's X-Lite phones with SailFin.
  2.    
       
  3. Now Browse to http://<your-host>:<your-port>/3pcc (eg., http://localhost:8080/3pcc) and login as Alice. Use Alice as the the password.
       
        Note that the sample has pre-provisioned list of users which are Alice, Bob, Adam, Eve (with password same as user name). If you wish to re-provision the users, you can do so by editing SF_HOME/samples/sipservlet/Basic3pcc/userdb.properties file. If you do that then you need to re-build and re-deploy the sample using step (6) & (5) of the above section.
  4.    
       
  5. Once you are logged in, you will see the page like this :
       
       
        Figure 3. Brower view after Alice logged in
       
  6.    
       
  7. Select the radio button against "Bob" and click "Call" button. This will establish a call between you (i.e., Alice) and Bob. The web page will also be updated with the call status and call history.
       
        The call establishment between you (i.e., Alice) and Bob is done as per 3pcc :

 


       Figure 4. Third Party Call Control (3pcc) call establishment.