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.

Monday Jul 13, 2009

Support for Cloud images of SailFin

If you are looking for support for SailFin AMI, I am told there are currently two issues:

  1. This AMI was packaged with OpenSolaris Just Enough OS (jeOS) and they say it is not supported yet on EC2. I know it has been in use for a while, so they may be close to offering support. I do not know.
  2. The SailFin build is v2b20. The supported release is 1.5

This should not stop you doing a Beta using this AMI.

The PM wants to know which platforms there is demand on. So post a comment or two to let him know what you are looking for.

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.

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.

Wednesday Apr 05, 2006

resource consumption management in glassfish

One of the nice things I like in my job at Sun is that I get to meet really demanding customers at our Executive Briefing Center. We get to talk with some really good technical guys, who are thinking ahead and seeing around the curve. Last year we were talking to a couple of guys in a major financial company on the east coast. They had heard about Solaris Containers aka Zones and were wondering how it could ease management of the dozens of J2EE applications they now have to manage.

Zones give a fairly lower virtualization of system resources. Each zone has a distinct IP address and hostname and root file systems. You can automate and recreate a similar looking zone on a different machine. One could put a J2EE application server and one business application in each zone and you could do very well isolating and managing resources consumed by each of the apps. In fact we found that this was exactly the model followed at another major financial house that is moving to Solaris 10.

But Zones are only on Solaris 10 and upwards. What about Linux and Windows? What if the applications were numbering in dozens or hundreds and had a fairly limited usage? Would it not be nice if you could deploy them all as you would normally do, one one Application Server, but still be assure Quality of Service? Things I heard mentioned were:

  • Be able to reserve a specific percentage of request processing capability for a particular business service. OS level resource management capabilities are usually too low level.
  • be able to specify ceilings on resource utilization so that heavier than expected traffic to one application, does not adversely affect other co-redident applications.
  • Then it got a bot more esoteric. Be able to give priority access to one application user over another, when accessing some manager resource, say a database connection pool. Web Identity based resource allocation policies are all but impossible at OS level.
  • So we got thinking and did some thing pretty interesting in project Glassfish. We found out that by placing a policy engine that examines incoming service requests and assigning them to worker threads based on the policy file, gave us a coarse but fairly accurate control on overall resource consumption. We could restrict no more than say 20 users to a particular web application, at any time. We could set aside some request processing threads, so that users of an important time-sensitive application always received good service, even if there was an over abundance of users for some other co-resident applications. Pretty neat. Jeanfrancois implemented this logic on top of Grizzly, the high performance all Java HTTP engine we have under Glassfish Application Server (Happy to to say that it beats some of the best C++ based HTTP engines out there for latency and throughput!). Me and jeanfrancois have a BOF coming up at the upcoming JavaOne on this topic. Jeanfrancois will be blogging about this soon, so you can look at the code and give us feedback. This is an experimental feature right now. We want to get community feedback and contribution before roling it in as a supported feature.

    If you havent already looked at Glassfish, go take a look at http://glassfish.dev.java.net. The code is already checked in.

    Sunday Jun 26, 2005

    Java One, San Francisco and MOMA

    JavaOne 2005 is finally here! Been working frantically the past few weeks going over slides from all the accepted talks in core enterprise track. We had the biggest track, nearly 30 talks. Working with the reviewers and speakers was a great experience. Had great reviewers and the Speakers went to great lengths to accomodate the feedback. The talks aappear more balanced, cleaner and deeper. The core track team is hoping that the attendees would notice the hardwork. We do track attendee responses to the surveys. Do fill out yours. We actually read them! Some of it goes back to the speakers. Everyone wins. Went to Moscone early in the afternoon. Great weather. Registered early (a very good thing to do!). My talk (TS-7123, Sun Application Server 9.0 and the Java EE SDK) in on tomorrow. My co-speakers showed up, as we signed up for speaker coaching. Last I had speaker coaching was in 1999 (Java HotSpot VM launch, great memories) and my rusty style got a good tuneup. Highly recommend it. It is free. Dropped in at the NetBeans day event at the Argent. Nice crowd. The talks were packing the rooms. Ludo was buzzed about NetBeans 4.1 and 4.2. Parking was easy today at the 3rd Street Moscone garage. I am sure it will not be that easy tomorrow. The MOMA cafe looked very inviting, but I will be back for four more days

    Tuesday Mar 01, 2005

    JavaOne 2005 - Core Enterprise Track Progress Report

    Designing the Core Enterprise Track planning has been a great deal of fun. First of all we ended up with over 440 submissions just for this track. This is actually a small improvement over last year, despite the shorter CFP period this year. Quite heartening.

    As expected we have a great deal of submissions in the SOA space. Not surprising. So as to not fill the agenda with SOA alone we decided on some key buckets and themes and made sure we had a balanced track. These are the "buckets" within this track for 2005:

    \* Interesting experiments on/around J2EE
    \* Diverse Opinions
    \* Whats cool in App Server X
    \* J2EE 5.0
    \* Service Oriented Architecture
    \* Performance
    \* Security/Identity
    \* Exploiting J2EE APIs better

    The selection process for technical sessions is coming to an end. We will be notifying the selected presenters soon. We have an engaging set of speakers, and a diverse topic set to look forward to.

    Thursday Jan 20, 2005

    Planning the Core J2EE Track at Java One 2005

    Java One is coming up in June and the Call For Proposals (CFP) has been out for a few weeks now. If you have missed it, take a look at the CFP. It is time for me to come out my shell and start to blog and get feedback.

    I have attended almost all conferences so far. Spoke at a couple. But now I am on the inside helping the program committee. This year I agreed to be a track lead for the Core Enterprise (J2EE) Track at JavaOne. I hear we get a few thousand proposals every year and yes it is daunting to read over all the proposals and pick the good ones that will get hardcore Java developers excited. It is all about making the attendees feel they got the money's worth for making the trip. To do that we need inputs from you all on what you want to hear about this year in the J2EE track.

    Track leads dont do thsi job alone. I delegate, I listen and ask advise from great people inside and outside Sun. I want to use this blog to get more feedback on what I am thinking about for this track. Chet who is leading the Desktop track had also started a java.net forum discussion for your suggestions on all the tracks.

    My list of cool topics for Core Enterprise track, not in any particular order of priority.

    - J2EE 5.0 and Ease of Development is a big theme
    - Service Oriented Architectures, MDA, Patterns, Practical Advise
    - Integration, BPEL, Biz Integration topics
    - Applied Security and Identity Management in J2EE Platform
    - Realworld experiences building solutions/apps atop J2EE
    - The top 3 or 4 cool/exciting/underexploited JSRs in the space
    - State of the art in J2EE performance tuning and advise
    - Promising frameworks that build upon or extend J2EE
    - Tools for J2EE developers


    Take a look at Casey's wonderful blog on how NOT to get your proposal accepted at Java One. This is collective distilled wisdom after scanning thousands of proposals over the years. She is spot on. Read her advise, make your own proposals or urge those folks that you do know and are great speakers, to make a proposal....

    Looking forward to your comments, a good Java One and balmy San Francsico in June...
    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