Sunday Aug 30, 2009

Writing Facebook Applications with Java EE (part 2)

In the first part of this blog, I showed how to register your application with facebook, create a web application and deal with Facebook authentication. In this part, I will show how to write a simple application, that shows the user their own Facebook UID and a list of all their friends. Nothing earth shatteringly useful, because this is just introduce you to the mechanics of writing a simple application.

Step 5: Write the application

Our application user is now authenticated. We can begin to make FQL calls and read/publish information to facebook. Our little sample, will use FQL to know more about the logged in user and the friends list.We told facebook that our application will run as an iframe in Facebook chrome. All we have to do is return some well formed html. We will do the "Hello World" type functionality and also show how to use FQL queries to extract information on all of the user's friends.

We will create a helper class Friend to hold the details of each facebbok user.  Later, I will show how to make this an Entity and store the data periststently, rather than make expensive and slow queries to facebook, repeatedly. The data could get stale and that is another issue to deal with later. Facebook does not encourage data caching.

public class Friend {

    private Long id;
    private String name;
    private String picurl;
    private String phone;

    public Friend() {
    }

    public Friend(Long id) {
        this.id = id;
    }

    public Friend(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Friend(Long id, String name, String pic) {
        this.id = id;
        this.name = name;
        this.picurl = pic;
    }

   // getters and setters have been omitted for brevity

}

The authenticated Facebook client is now available as a request attribute. We simply extract it and use it to make Facebook API calls. A helper method auth_getUserId provided by FacebookJsonRestClient extracts the facebook id of the logged in user. We will use this to get information on the user and friends.

 public class Canvas extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            FacebookJsonRestClient fbc = (FacebookJsonRestClient) request.getAttribute("auth.client");

            PrintWriter out = response.getWriter();
            long myUid = 0; Friend me = null;
            try {
                myUid = fbc.auth_getUserId(request.getParameter("auth_token"));
                me = findFacebookName("" + myUid, fbc);
            } catch (FacebookException ex) {
                Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
            }

            ArrayList<Friend> myFriends = findFacebookFriends(fbc);

// TODO: later in the blog,  show how data is output
    }

The method findFacebookName illustrates basic use of FQL that returns one result object. 

    private Friend findFacebookName(String fid, FacebookJsonRestClient fbc) {
        String name = null;
        String pic = null;
        try {
            String query = "SELECT name,pic FROM user WHERE uid=" + fid;
            org.json.JSONArray fa = null;
            fa = (org.json.JSONArray) fbc.fql_query(query);
            name = fa.getJSONObject(0).getString("name");
            pic = fa.getJSONObject(0).getString("pic");
        } catch (FacebookException ex) {
            Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
        } catch (JSONException ex) {
            Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
        }
        return new Friend(new Long(fid), pic, name);
    }

The method findFacebookFriends illustrates friends_get() that returns an array of Facebook Ids of all the user's friends. 

private ArrayList<Friend> findFacebookFriends(FacebookJsonRestClient fbc) {
        org.json.JSONArray resultArray = null;
        ArrayList friends = new ArrayList();
        try {
            resultArray = fbc.friends_get();
            for (int i = 0; i < resultArray.length(); i++) {
                try {
                    Long fid = resultArray.getLong(i);
                    String query = "SELECT name,pic FROM user WHERE uid=" + fid;
                    org.json.JSONArray fa = null;
                    try {
                        fa = (org.json.JSONArray) fbc.fql_query(query);
                        String pic = fa.getJSONObject(0).getString("pic");
                        String name = fa.getJSONObject(0).getString("name");
                        friends.add(new Friend(fid, name, pic));
                    } catch (FacebookException ex) {
                        Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } catch (JSONException ex) {
                    Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } catch (FacebookException ex) {
            Logger.getLogger(Canvas.class.getName()).log(Level.SEVERE, null, ex);
        }
        return friends;
    }

Spitting it all out

After getting all the data we need, it is time to output something that will be shown to the end user, as the output a HTML page is shown in an iframe.

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {

            // Data Extraction: See Above
            PrintWriter out = response.getWriter();
            out.println("<html>");
            out.println("<body>");
            out.println("Your Facebook Id:" + me.getId());

            out.println("Your friends:");
            out.println("<ol>");
            Iterator it = myFriends.iterator();
            while (it.hasNext()) {
                Friend f = (Friend) it.next();
                out.println("<li>Friend Name" + f.getName() + "</li>");
            }
            out.println("");
            out.println("</ol>");
            out.println("</body>");
            out.println("</html>");
            return;
        } catch (Throwable t) {
            t.printStackTrace();
        } finally {
            return;
        }
    }

Conclusion

Deploy the web application to a Java EE server that is visible to the internet and is accessible at the Canvas callback URL you used when the application was registered at Facebook.

The sample application can be accessed directly specifying the Canvas Callback URL specified at registration (http://sailfin.webhop.net/FacebookSample/Canvas)  or  http://apps.facebook.com/glassbook.  It produces output as expected showing my Facebook Id and the names of all my friends. Real applications are of course, going to be a lot more interesting... This should get you, the Java EE developer, going..


Friday Aug 28, 2009

Facebook Applications on Glassfish (part 1)

During this summer, I explored writing Facebook applications using Java EE, something I have wanted to look into for a while, but never got around to. Facebook had stopped official support for it's Java API, in May 2008, which is not so nice to the millions of Java programmers out there. Fortunately, the API has since evolved as Facebook Java API.  It is very usable and there are many blogs and examples on how to get started. After looking at various posts, it was relatively simple to write a basic facebook application and make it run on Glassfish application server. I will share what I have learned along the way.

I used a recent NetBeans Dev build (NetBeans IDE Dev (Build 200908070201))  and GlassFish v2.1, but feel free to use an setup you are comfortable with. The steps should work the same way with Eclipse or GlassFish v3.

Step 1

I am assuming you are a Facebook user. Who isn't these days :-). If not, go sign up first.

The next task is to get yourself facebook developer privileges, which you do by "installing" facebook developer application. The developer application allows you to register your new application, provide some basic details to facebook on where it runs, generate an Application Identifier, API key and Secret Key etc. which identify your application to facebook users and to facebook platform.

To get started, click on Setup New Application at the top of the page. 

Provide a name for your sample, Agree to the Facebook Terms and Save Changes.


After Step 1, facebook assigns an API key that identifies your Application's requests and also a secret key that must be supplied with every request This is what you will see after you hit Save Changes above.

I have whited out the App Id, API Key and Secret code that I obtained. You will see long hex strings. You have taken the first big step already.  There is an application now registered.

Step 2

Now provide some essential information about where your application is hosted, the main canvas page etc. If you are not familiar already, your facebook application will not run on facebook's servers. You have to host it somewhere. You can use a Glassfish or Tomcat hosting provider or do it from home, which is what I do. I use dyndns.org to get a public domain name that points back to my home server or laptop. This is obviously not recommended if your application becomes wildly popular, but it is good enough for this sample!

In Step 2, we will provide some more crucial information about your application.The bits of information that we plan to provide are under Canvas and Connect.


On this page, we will make some important choices.

  1. Canvas Page URL: Choose the common name that you want for your application's users. I chose glassbook. When facebook receives a request for this URL, it will map it to your application.
  2. Canvas Callback URL: Provide the full URL path to where your facebook application will eventually be running. I am hosting my sample on a domain called sailfin.webhop.net.  The domain is registered at dyndns.org, which offers free DNS services, with some limitations. Note the following:
    1. I used FacebookSample as the context root for my web application that will handle the application logic. You could choose anything you want for this. Just make sure to use the same context root when you develop the web application later.
    2. I declared that the receiver of facebook traffic is a servlet or JSP that is mapped to Canvas. You can use any name you want here and do the corresponding thing while developing the application.
  3. Use the defaults for all others. We will not use FBML in this sample.

 Now, click on Connect on the  left hand panel and supply the same path we provided for Canvas call back URL.


Thats it! You have registered an application. Now all that is left is to write it!

Step 3

Now we will develop the web application, called FacebookSample. In NetBeans, create a new project, called FacebookSample.

Note how I used the context root: FacebookSample


Then I created a servlet called Canvas:

And a ServletFilter called FacebokAuthFilter


 At the point, in NetBeans there should be two source files in the project structure.


You already know that we intend to put the application logic in Canvas.java servlet class.We have not filled in anything there yet. We will return to it soon.

Before we start writing code, need to add some Facebook Java API jar files to your web application. In NetBeans, you can do this by right clicking on the FacebookSample application, choosing Properties and then Libraries. You must add the following 3 jar files:

  1. commons-logging-1.1.1.jar
  2. facebook-java-api-2.1.1.jar
  3. json-20070829.jar

All of these are in the facebook Java API bundle you downloaded at the top of the tutorial.

Macintosh-202:lib Sreeram$ pwd
/Users/Sreeram/facebook-java-api-2.1.1/lib
dhcp-usca14-133-138:lib Sreeram$ ls -l 
total 3568
-rw-r--r--  1 Sreeram  Sreeram   62983 Dec 31  2007 activation-1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  243016 Jan 15  2009 commons-lang-2.2.jar
-rw-r--r--  1 Sreeram  Sreeram   60686 Sep 20  2008 commons-logging-1.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  137560 May  1 08:26 facebook-java-api-2.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram  278382 May  1 08:25 facebook-java-api-schema-2.1.1.jar
-rw-r--r--  1 Sreeram  Sreeram   89967 Sep 27  2008 jaxb-api-2.1.jar
-rw-r--r--  1 Sreeram  Sreeram  856752 Nov 24  2008 jaxb-impl-2.1.9.jar
-rw-r--r--  1 Sreeram  Sreeram   41829 Dec 31  2007 json-20070829.jar
-rw-r--r--  1 Sreeram  Sreeram   15949 Jan 15  2009 runtime-0.4.1.3.jar
-rw-r--r--  1 Sreeram  Sreeram   23346 Sep 27  2008 stax-api-1.0-2.jar

Now we are ready to start coding, but there is one other topic I need to introduce: why do we need FacebookAuthenticationFilter.java. That is the topic of the next section.

Step 4: Facebook Authentication

Only registered Facebook users can access your application. We need to authenticate users and force login if necessary. Login is handled by Facebook. Our application will make calls to Facebook APIs in the context of authenticated user.

Our application, may sometimes need permissions to do some things, such as read and publish to a stream. We need to request the user to grant such permissions.

We will use a Servlet Filter for check whether the user is logged in and request necessary permissions. 

Now lets dissect FacebookAuthenticationFilter.java

   /\*\*
     \* Init method for this filter
     \*/
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
        if (this.filterConfig != null) {
            _apiKey = filterConfig.getInitParameter("api_key");
            _secretKey = filterConfig.getInitParameter("secret_key");
            if (debug) {
                log("FaceBookAuthFilter:Initializing filter");
            }
        }
    }

You need to supply the API Key and Secret Key received from facebook in the web.xml, so the Servlet Filter can use then in its requests redirected to facebook. This is what your web.xml would look like. Plugin the API key and Secret code you got from Facebook.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <filter>
        <filter-name>FacebookAuthFilter</filter-name>
        <filter-class>org.glassfish.samples.facebook.FacebookAuthFilter</filter-class>
        <init-param>
            <param-name>api_key</param-name>
            <param-value>Your API Key Here</param-value>
        </init-param>
        <init-param>
            <param-name>secret_key</param-name>
            <param-value>Your Secret Key Here</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FacebookAuthFilter</filter-name>
        <url-pattern>/\*</url-pattern>
    </filter-mapping>
    <servlet>
        <servlet-name>Canvas</servlet-name>
        <servlet-class>org.glassfish.samples.facebook.Canvas</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Canvas</servlet-name>
        <url-pattern>/Canvas</url-pattern>
    </servlet-mapping>
</web-app>

Back to the Filter

     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        try {
            FacebookJsonRestClient authClient = getAuthenticatedClient((HttpServletRequest) request,_apiKey, _secretKey);
            request.setAttribute("auth.client", authClient);
            filterConfig.getServletContext().setAttribute("fbc", request.getAttribute("auth.client"));
            chain.doFilter(request, response);
        } catch (FailedLoginException fle) {
            //user not logged in
            request.setAttribute("auth.client", null);
            forceLogin((HttpServletResponse) response);
        } catch (Exception e) {
            //handle exception
        }
    }

We first try to create a FacebookJsonRestClient object. This logic is encapsulated in the getAuthenticatedClient method. We will check the incoming request for the presence of two request parameters: auth_token and session_key. If a session key is present and is valid, the client object is instantiated. If only an auth_token is present, a client is instantiated and a new session created. The facebook session lasts about an hour. Infinite sessions are a different beast and one needs to request the user to grant offline access privileges. I have not played with it yet.

private FacebookJsonRestClient getAuthenticatedClient(HttpServletRequest request, String apiKey, String secretKey) throws FailedLoginException, FacebookException {
        String authToken = request.getParameter("auth_token");
        String sessionKey = request.getParameter(FacebookParam.SESSION_KEY.toString());
        FacebookJsonRestClient fbClient = null;
        if (sessionKey != null) {
            fbClient = new FacebookJsonRestClient(apiKey, secretKey, sessionKey);
        } else if (authToken != null) {
            fbClient = new FacebookJsonRestClient(apiKey, secretKey);
            //establish session
            fbClient.auth_getSession(authToken);
        } else {
            throw new FailedLoginException("Session key not found");
        }
        //fbClient.setIsDesktop(false);
        return fbClient;
    }

If there is no valid session established for the user, a FailedLoginException is thrown and we call forceLogin to cplete the Login process.  Otherwise, the client is objected is inserted into the request attributes for later retrieval.

     private void forceLogin(HttpServletResponse response) {
        try {
            String redirect = "http://www.facebook.com/login.php?" + "api_key=" + _apiKey + "&connect_display=popup" + "&v=1.0" + "&next=http://apps.facebook.com/glassbook" + "&cancel_url=http://www.facebook.com/connect/login_failure.html" + "&fbconnect=true" + "&return_session=true"
            response.sendRedirect(redirect);
        } catch (Exception ioe) {
            //handle exception
        }
    }

I used next=http://apps.facebook.com/glassbook to point to my test program. You will need to change the  next parameter to point to your application canvas URL.

 In the next part, I will walk through the rest of the application, the part that implements the canvas. Won't be long.

Thursday Feb 12, 2009

Designing scalable, reliable, and efficient systems

Designing Scalable, reliable and efficient systems is the goal of systems engineering. We see that in the way Google scales their services to billions or the Amazon cloud. But before the internet big boys, this used to be the sole domain of the telecom guys. Well, it still is their domain because there are nearly 4 billion cell phones and god knows how many landline phones in operation. Switches that set up all these calls are quite hard to build.

Today, Andreas Burmester sent a link to a paper that appeared in Ericsson Review. It describes how they built a full system for delivering continuous services using only open source components. Notable how they depend on Java EE and GlassFish Communications Server in the middleware tier. They used Open SAF and Linux clustering at the lower levels.

Tuesday Dec 23, 2008

Introducing GlassFish Communications Server

This is the big blog that goes over what is Project SailFin.  I hope it is an interesting read and I hope to receive your comments.

Introduction

Convergence at happening at various levels in communication industry. Carriers seek to consolidate fixed and mobile services. There is operator consolidation due to acquisitions. When two operators merge, they need to rapidly combine subscriber databases, CRM and billing systems, to reap the cost savings benefits. So carriers find that moving to a standards-based network and software infrastructure is good for them. It allows them to be agile and and keep costs low. Increasingly you hear about a Services Delivery platform (SDP), one universal platform for network facing functions, operating consumer portals, running CRM applications, integration with OSS/BSS and even service exposure through gateways. We wanted to drive GlassFish adoption in this challenging segment: if it is good enough for carriers, it is more than good enough for enterprises.  Project SailFin started with this vision in June 2007. There is a lot of magic that goes into delivering reliable digital television and home phone services, besides an application server, however good and extensive it may be. Carriers and Network Equipment Providers are good at building SDPs.We just want to be a part of it with GlassFish.

Services Delivery platforms are mission critical. Lets face it, software bugs and hardware failures are unavoidable. So the game was about detecting failures, rapid recovery, and keeping downtime to a minimum. Clusters need to expand and shrink with demand fluctuations. Upgrades need to be performed without downtime. A lot of the work that happened this past year went into integrating a JSR289 compliant SIP Servlets Container in GlassFish, adding a converged load balancer and session data replication system. Well, we are done and about ready to make it generally available. The official name is GlassFish Communications Server (GlassFish CS), because it is based on GlassFish Enterprise. We may also use the nickname SailFin to refer to the same thing.

GlassFish CS is an open-source applications server that supports Java EE 5 specification and SIP Servlets 1.1 API (figure 1). It is based on the GlassFish v2.1 and so it inherits much of the core architecture and administrative infrastructure. Onecan deploy Java EE Applications, pure SIP applications and converged applications that mix all of the above. In addition, SailFin includes a novel built-in converged load balancer, support for session data high availability, support for integration in SAF API based deployments, choice of Application Routers and IMS/Diameter support in future release. Since GlassFish Communications Server is built on GlassFish Enterprise Server v2.1, it puts fresh and powerful technology in the hands of developers for creating next generation services. Developers can mix SIP Servlets technology with technologies like EJB, Java Persistence API, JDBC, Web services, and reuse container services like JNDI, JMS, Dependency Injection, Security, Transaction management.

Sailfin sub systems
Figure 1 GlassFish: An Integrated Execution Platform for Converged SOA, SIP, and Java EE Services

SIP Protocol Stack and SIP Servlets

GlassFish CS integrates a high-performance SIP protocol stack implemented using Grizzly. Incoming requests pass through a chain of handlers that perform specific functions. For example, the Overload Handler, if enabled, would send an appropriate error response, if the server is overloaded. The optional load balancer, if enabled, would apply the specified sticky load balancing logic and forward the request to the appropriate instance in the cluster, or pass it up the stack. Initial requests are matched with deployed applications and appropriately routed. Optionally, the default or user deployed Application Router is consulted to make the initial routing decisions. Many SIP listeners can be configured to accept TCP and or UDP traffic on multiple network interfaces. SIP over TLS is supported.



Figure 2: Sip Protocol and Request Processing Stack in GlassFish

Web Services

Network Services like dialing, SMS and service enablers like location are often exposed to developers using web services gateways. Web Services are mechanism to mash-up services from simpler building blocks. SailFin includes Metro Web Services stack. Metro implements important WS-\* standards and WS-I standardized interoperability profiles in order to assure interoperability between Java and .NET web services. Metro web services is a popular stack reused by many and well tuned for performance. It is likely to be of great interest to Carriers who are looking to build service gateways.

Figure 3: Metro Web Services Stack in GlassFish

JBI and Open ESB Support

GlassFish has built-in support for Open ESB, by including the implementation of Java Business Integration (JBI) specifications. JBI as specified in JSR 208. This is a Java standard for structuring business systems according to a service-oriented architecture (SOA). In JBI approach to SOA, a composite application is assembled from distinct services, where each service performs one or more business-related processes. JBI gives an enterprise a lot of agility in building composite applications because services and data that are used in one application can be shared and reused in other applications.

Open ESB runtime hosts a set of pluggable component containers, which integrate various types of IT assets. These pluggable component containers are interconnected with a fast, reliable, in-memory messaging bus called the Normalized Message Router (NMR) also referred to as the JBI Bus. Service containers adapt IT assets to a standard services model, based on XML message exchange using standardized message exchange patterns (MEP) based on abstract WSDL. This improves interoperability and allows a mix-and-match of technologies from various vendors. When sending and receiving messages outside the JBI environment, the engine component containers communicate using the in-memory NMR messaging infrastructure and pass messages out to the client through an appropriate binding component container. When communication is entirely within the JBI environment, no protocol conversion, message serialization, or message normalization is necessary because all messages are already normalized and are in standard abstract WSDL format. JBI standardizes the way composite applications are packaged.

GlassFish is Open ESB ready, because it contains the Normalized Message Router and a Java EE Service Engine that is used to expose any EJB or Web Service End Points on the JBI bus, optionally. With this basic infrastructure SGCS instance can host service engine and binding components for any protocol, participate in workflows and integrate with billing, provisioning or network element management systems.

Management and Monitoring 

GlassFish management framework allows an administrator to configure and monitor instances and clusters securely and remotely, from a web-based central administration console. Administration in a carrier deployment environment can be automated in many ways. The command line interface (CLI) can be used to script and automate processes. A stable JMX API is made available to programmatically monitor the server, query configuration and change configuration data.



Figure 4: Centralized Administration


GlassFish administration infrastructure, based on Domain Administration Server (DAS) and Node Agent (NA) is carried over. DAS performs aggregate actions such as starting and stopping clusters and instances, propagating configuration changes and distributing deployed applications, to affected instances. DAS also manages the central repository where all deployed applications, libraries and configuration data is stored. The repository can be automatically backed up and restored, to revert to a previous configuration after failure. The DAS is not necessary to be up and running for normal operation of services in a domain. Node Agents assist the DAS in managing the lifecycle of instances and watchdog restart service for instances. Communication between the DAS, NA and instances is always secure.

Monitoring is supported through JMX and SNMP interfaces. Monitoring level may be varied dynamically from OFF to LOW and high, changing the amount of information that is collected. Monitoring level can be controlled at fine-grained level to watch only the desired sub-systems making it suitable for production deployments where performance degradation of running services is not desirable. Similar to monitoring, logging can also be enabled and disabled dynamically for any sub-system, log verbosity level controlled and log files automatically rotated for field serviceability. Additional log filters can be installed on the field for customization.

Administration Web console is commonly used to administer and monitor GlassFish Communication Server. The web console provides an intuitive interface to navigate the complex configuration elements and wizards for completing common tasks like deploying applications, creating clusters and configuring high-availability and load balancer.


Figure 5: GlassFish Web Administration Console


GlassfIsh provides a Self Management Framework. System administrators, responsible for monitoring the application server for unpredictable conditions and apply corrective actions, no longer have to watch for these conditions manually. This feature enables prevention of failures by detecting emerging problems rapidly and preemptively addressing them, thus improving availability through self-healing. A self-management rule is an association between an event and actions. Events and Actions are performed by MBeans. Rules can be created to act on pre-defined events or new event types. Some pre-defined event sources are:

•    Lifecycle events: Event is generated when an instance is ready, shutdown or abruptly down
•    Monitor event: Monitor any statistic and generate an event when a threshold is crossed
•    Log events: When a log message is produced at a certain level from a specified logger
•    Trace events: configured to emit an event when a specified EJB or Servlet is entered/exited
•    Timer events: used to perform actions at pre-determined times
•    Notification events: Generic JMX notification event


Carrier Grade Service Execution

In this section, we will look at how SailFin provides high quality and continuous service. High availability requires that:

•    System operates at the desired latency levels even when above the engineered capacity
•    System throughput is steady and is stable under increased loads 
•    Hardware and software failures are tolerated
•    Service failover is reliable, fast and invisible to the clients
•    Client’s application state is persisted across recovery
•    System and services are designed to scale horizontally
•    Adding/Removing capacity to/from the platform should not affect running services and clients
•    Spread the load evenly based on simple and configurable criteria
•    Configuration must be allowed to change dynamically without needing restarts
•    Detect and correctly handle load spikes and overloaded resource conditions

GlassFish Communication Server is designed to provide carrier grade service execution environment for web and converged SIP applications.

Active and Fully Replicated Services

Java EE and SIP Container services are replicated in every instance in a cluster. Each server instance has a local JNDI service that is kept synchronized with global namespace maintained on the Domain Administration Server, local Java Message Service, Transaction Manager, Timer Service and so on. There are no specially designated instances that perform special functions. This eliminates all single points of failure. Since services are available locally in every instance, default service invocation is local and optimized to be fast. Services scale naturally as more instances and capacity is added.

GlassFish uses Active/Active approach to high availability. All deployed applications are available at every instance in the cluster and the load balancer can send request to any of them. There is no need to configure an active primary and standby secondary. All servers actively handle traffic. There is no need to configure passive stand-by servers for the uncommon failure scenario. Hardware investment is efficiently utilized.

Cluster health is actively monitored by a heartbeat service that detects when an instance goes down and triggers appropriate recovery actions from neighboring instances. For example, when a server crashes, in-flight distributed transactions are arranged for automatic recovery by another instance, to prevent database row locking from freezing the application for other users.  If the failed instance tries to come up during the recovery, it is paused until recovery is completed and then allowed to join the cluster and process traffic.

Performance: Low Latency and Consistent Throughput

Using the SipInviteProxy performance test with immediate call tear down (Call Length is 0 seconds), GlassFish Communications Server is benchmarked at 900 CPS on a dual processor 2-core (2.8GHz AMD) system using SuSE Linux and Sun JDK 1.5u12. Average latency is 13.67ms. 99.86% percent of calls complete in under 120ms in this stress load. Since this is based on GlassFish, all other containers are also well tuned for performance. GlassFish was used to publish very impressive SPECjAppServer2004 benchmarks scores.

Overload Protection

SIP is an asynchronous Peer-to-Peer protocol. SIP requests are retransmitted, if responses are not received in time. When a server falls behind in handling traffic, retransmissions are inevitable. This can lead to snowball effect of increasing traffic, spiraling degradation in quality of service and even total service failure. GlassFish Communication Server employs Overload Protection features that constantly monitor the system CPU utilization and Java Heap memory utilization to trigger traffic throttling logic. New incoming requests are replied with 503 Service Unavailable responses, until the system returns to operating in safe and sustainable condition. Clients may choose to try another server or try again after some time. Existing clients and traffic is ensured with consistent service levels.

Converged Load Balancing

Communications service delivery platforms run on horizontally scaled blade servers. It is important to distribute traffic uniformly across all the blades. It is more efficient to route the subsequent messages to the same target server where the session state is cached in memory. In converged collaborative applications, one or more users may interact with the same service and use different protocols like SIP and HTTP concurrently. Converged Load Balancing refers to a unique feature in GlassFish Communications Server that recognizes if the incoming SIP and HTTP messages belong to the same executing application session instance and route them coherently to the same target server.

Converged Load Balancing (CLB) function can be enabled in any GlassFish cluster. When enabled for self-load balancing function, each instance can act as a load balancer in addition to handling traffic.Customers save money because they can use a simple L3 load balancer and do not need the more expensive SIP capable load balancers from third parties.


Figure 6: Horizontal Scaling with Converged Load Balancer

It is possible to use GlassFish clusters without self-load balancing and use an external SIP aware hardware load balancer. When load-balancing logic is done inside the server instance, a simple L3 load balancer will suffice to distribute incoming packets to any instance in server.

The default CLB policy performs sticky round robin load balancing on SIP and HTTP traffic. Since many SIP clients and proxies may not preserve all headers, no additional SIP headers are added. The load balancing decision consumes SIP from-tag, to-tag, and call-id parameters of the request. HTTP requests are load balanced using the session identifier, in this mode.

As additional hardware capacity is added to the cluster it is important that the benefit is made immediately visible to all clients, both old and new. CLB monitors cluster size increase and incorporates them into the load-balancing table. Requests that are not already sticky to target servers are directed to the new server instances. Server capacity can also be reduced and user sessions and requests are migrated to remaining load processing servers. The dynamic clustering capability enables planned downtime and service upgrades without disrupting the entire service. Blades can be brought down one by one, for maintenance and restarted to resume function. This functionality is based on applying a consistent hashing scheme to configurable headers or parts of incoming requests.

Data Centric Rules

The default SIP and HTTP load balancing policies suitable for many scenarios and provide sticky load distribution. However, in many IMS scenarios it may be necessary to look inside different SIP headers and URL fields or even translate URI domains. HTTP load balancing may need to consult custom cookies and headers. GlassFish Communications Server provides a facility for the administrator to customize the load balancing to be based on data embedded in SIP and HTTP messages. The consistent-hash algorithm is applied to these administrator specified filed. For example, pne may specify SIP and HTTP rules as: if a Conference-Name header is available in a SIP message load balancing is performed on that, otherwise use the user part of the From: SIP header. For HTTP requests, look for a parameter called Conference-Name in the request or use the Host: header.

                  <user-centric-rules>   
                     <sip-rules>
                        <if>
                           <header name="Conference-Name"

                                 return="request.Conference-Name">
                              <exist/>
                          </header>
                      <else return="request.to.uri.resolve.user" />
                      </if>
                    </sip-rules>

                    <http-rules>
                      <if>
                        <request-uri parameter="ConferenceName" 

                             return="parameter.ConferenceName">
                          <exist/>
                        </request-uri>
                      <else return="request.Host"/>
                    </if>
                  </http-rules>
              </user-centric-rules>

Session Data Availability

While CLB assures service availability, even load distribution, fail over of requests and fail back. But the data associated with user sessions must be restored after a failure. GlassFish employs a Peer-To-Peer in-memory replication system to save critical container and user interaction state and ensure data availability. All active SIP dialogs have container state: dialog state represented as Dialog Fragments, Session object(s) comprising of SipSession, SipApplicationSession and HttpSession, and associated timers. Modified state objects are replicated to a peer, at the end of every SIP transaction or after a web request is completed. Just like the CLB, the replication management sub-system also runs inside the GlassFish server instance. It is responsible for making replicas and saving them to its replica peer, and acting as a replicating peer to another instance in the cluster. It is also responsible for delivering requested replicas acquiring replicas, during fail over and cluster healing.  


Figure 7: Session Data Replication in GlassFish

The diagram above shows a healthy four-instance GlassFish cluster running is highly available mode with CLB and session data replication enabled. For illustration, we show two SIP user agents and a HTTP browser interacting with the converged service. The CLB has directed this traffic collectively to Instance 4. The state for the interaction consists of one SipApplicationSession, two SipSession objects, one HttpSession object and possibly many SipTimer objects. These objects are transparently replicated to the peer, Instance 1.

When a failure occurs and Instance 4 does down, the CLB performs request rerouting. For illustration lets assume that this group of requests are now sent to Instance 3. This instance does not have the necessary session data and when the request is received that touches this data, a query is sent to locate the replica. Instance 1 responds to this query and delivers the network of dialog state and session data to Instance 3. The session data ownership is now migrated to Instance 3 and it will maintain replicas on its replication partner. When instances leave or enter the cluster, replication relations are recalculated to always ensure that there is always one replica available in the cluster.

2008 is over and SailFin is getting ready to leave the station

My last post was exulting about JSR289 passing the vote way back in July. We have been moving along since then. I thought SailFin would be the first to pass the JSR289 compatibility tests. But Oracle made sure that they already passed the TCK by the time it was made public! And then we found that there were issues in the TCK that needed discussion with the Spec lead. Thanks to Mihir, we got past all of that and had a clean run in November.

The economic turmoil and U.S presidential election have taken their share of headline news. It has been a less sensational and productive year for SailFin community. Some major accomplishments:

  • Community membership crossed 200, with over 45 with developer status.
  • Found early adopters through the community. Great interest seen from companies building unified communications solutions and conferencing systems for enterprises and SMBs.
  • Ericsson has been a tremendous partner all along. Ericsson Service Development Studio 4.1 is an Eclipse based IDE that includes SailFin by default.
  • IPTV live field trials with GlassFish and SailFin with Sonaecom in Portugal. I am told some more such things are in progress.
The GA release of SailFin is planned January 2009. As we approach this big date, there will be many more informative blog entries on the performance, unique features, and the team behind SailFin.

Thursday Jul 24, 2008

JSR-289 passes JCP Exec Committe Vote

The JCP Executive Committee has approved the JSR 289 Final Approval Ballot. Congratulations to the EG and Spec Leads! We had many along way, so it is good to name them all. Nasir Khan, Jarek Wilkiewicz, Mihir Kulkarni and Yannis. JSR-289 standardizes the converged SIP Servlets and Java EE application model which is a great step forward and keeps up the momentum. We just got a TCK preview. Hope to get the final version of TCK soon. Look for more news on SailFin release dates with JSR-289 compatibility, high availability and everything else we are working on.

Monday May 21, 2007

Adding Voice to Java Web Applications - Samples

We just posted our slides for the Java One talk (TS-4919: Adding Telephony to Enterprise Java Applications) on sailfin website. During the talk we described two samples. A simple Click-To-Dial applications that lets two logged in users have a conversation and a full-blown multi-uaser collaboration application Conference Manager with live voice mixing. The source code for the latter is coming soon. Enjoy the Click-To-Dial sample and let us know how it works for you.

Tuesday May 08, 2007

Project SailFin launches in GlassFish Community

surfinduke

After last JavaOne I started looking at a completely different area, Java and Communications. After tinkering to see how I could add voice to a Java EE web application, it seemed like there was no easy and portable way to do this. I looked around to see what was already there and was close enough to Java EE, and could be accepted by enterprise developers. The answer seemed to be SIP Servlets. Sun joined the JSR-289 expert group and focused on the proposed application model that combines SIP and Java EE. JSR-289 is in Early Draft Review stage. Take a look and get involved.

We were also lucky to find a great partner in Ericsson. By the end of the 2006, we had Ericsson's SIP Application Server running alongside GlassFish. We were able to inject Java EE services like EntityManager inside Sip Servlets and initiate calls from inside web applications. One thing led to another and here we are at another JavaOne! SailFin is live today as the first open source SIP Servlets technology project, in the GlassFish Community. Visit us to see the sources and build instructions.

We sent around an evaluation kit inside Sun and the people at Sun Labs built an amazing fully Java EE and JSR-289 based Conferencing application on top of SailFin. Jonathan Kaplan from the Labs and I have a talk about this on Thursday (TS-4919: Adding Telephony to Java Technology Based Enterprise Applications, 4:10-5:10pm, Hall E, Rm 134). Also visit us at the Pod (# 968) to see the demo.

An intersting tidbit: The Surfing Duke image on SailFin project web page was designed by James Gosling. Thanks James.
About

Various things I do at Sun Microsystems.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
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
   
       
Today