DevOps Zone is brought to you in partnership with:

Bill Digman is a Java EE / Servlet enthusiast and Open Source enthusiast who loves working with Caucho's Resin Servlet Container, a Java EE Web Profile Servlet Container. Bill has posted 12 posts at DZone. You can read more from them at their website. View Full User Profile

Resin Proxy Cache Support and REST Support Explained

02.21.2013
| 1733 views |
  • submit to reddit

Contents

Resin provides real DevOps support

Resin is an end to end solution from load balancer, to http proxy cache, to cloud deployment.  This is not to say that you could not use Resin with NginX or Varnish or XYZ, because you can. This is to say that Resin's built in support is typically the fastest most scalable, most supportable option. To demonstrate this, let's show how we can use Resin built-in proxy cache (similar to Varnish or Squid) with Resin's REST admin support.

This article will not only help you with using our Proxy Cache Support, but also with learning about our REST administrations, the envy of DevOps who have to support Java everywhere.

JMX REST support

Resin has a nice API for managing Resin that is exposed via JMX (Java Management Extensions). But in this day of interoperability, cloud, REST and DevOps, it is not good enough to have a JMX interface, one must have a server that can  be managed as a service via a REST interface.

All JMX operations and quite a few other operations are available via our REST admin interface as well as JMX and CLI.

Let's create a simple page to demonstrate how the cache works

Let's create a really simple JSP file so we can focus more on the REST, JMX, etc. setup. Using a standard Resin 4.0.32 install, I place this file under /var/resin/webapps/ROOT/cache.jsp.

view source print? 1.<%@ page session="false" %> 2.<%! intcounter; %> 3.<% 4.response.addHeader("Cache-Control", "max-age=150"); 5.%> 6.Count: <%= counter++ %>

The above says cache the page for 150 seconds. If you enable Resin http proxy caching, Resin will cache this page for every client for 150 seconds. Let's say, we changed the data that backs this page, and we want a faster update, how would we tell Resin to evict this page out of cache.

(Side note: Since Resin http proxy cache is built into Resin, it knows about every Java web resource and can cache them all without the need to use a cache providers special server side includes. Your cache includes can just be jsp:include and <%@include, etc.)

When you load this page, it gets put into the Resin cache. With just the above, it does not matter if the end users hits shift refresh from their browser or whatever, this page is going to stay in the cache. (There are ways to enable some cache validation checking to be triggered from client, but that is for another lesson as it involves more cache controls like ETag, etc.)

But first lets setup the http proxy cache

To enable the cache, you just need to modify /etc/resin/resin.properties and make sure the following two properties get set:

view source print? 1.# Enable the proxy-cache - forcaching staticcontent in memory 2.proxy_cache_enable : true 3.  4.  5.  6.  7.# Sets the proxy cache memory size 8.proxy_cache_size : 256m cache

Now the cache is setup, but like we mentioned earlier, there is no way to invalidate it. What if we know some process just happened and a certain page is invalid. What if you just did a data import or ran some batch job or received a new product xml file or whatever. Perhaps you have some backend script that stages this data, and now you need to kill this page out of the cache. Now in the Java world we have JMX, and it is a nice way to interface with such things like caching, but what if these scripts were written in Ruby, Perl, Bash, or whatever. This is where the REST Admin service comes into play.

Turning on REST support

view source print? 1.To turn on the REST admin support, you guessed it, modify /etc/resin/resin.properties file as follows: view source print? 1.# Enable Resin REST Admin 2.rest_admin_enable : true 3.  4.  5.  6.  7.# Require SSL forREST Admin 8.# rest_admin_ssl : true

If you are not on an internal safe network, you should install open ssl support from the get go, and set rest_admin_ssl to true (it is commented out now). For now, I am going to assume that you are just messing around or you really trust your network's security and we will leave SSL support off. (We should come back and add it and change the examples accordingly.)

Setting up a user for the rest calls

Run the generate-password command to create a new password.

view source print? 1.$ resinctl generate-password --user foobar --password foobar

Output

view source print? 1.admin_user : foobar 2.admin_password : {SSHA}MW8h/2zwAk4Oqa3yfObDEKMcht3OKvil

Modify /etc/resin/resin.properties and put those two  entries in there. Now you have an admin user called foobar with the password foobar. You can add more users just search /etc/resin/*.xml and see where $admin_user is getting used. 

Invalidating the page from the command line with Curl

If you don't see a Curl call to a REST example, then you should be suspicious.  Thus without further ado, let's show using Curl to invalidate our proxy cache via a REST call to the Resin REST admin.

The easier way to invalidate a page is to you use the curl command as follows:

view source print? 1.curl --user foobar:foobar  2.       --data "values=.* .*cache.jsp"  3.         "http://localhost:8080/resin-rest/jmx-call?pattern=resin:type=ProxyCache&operation=clearCacheByPattern"

(Newlines added for clarity). This is the return, which is just JSON. 

view source print? 1.{"bean":"resin:type=ProxyCache","operation":"clearCacheByPattern(java.lang.String, java.lang.String)","return-value":"null"}

All Resin jmx beans are exposed. Thus all of Resin jmx support is open to REST calls.

The --data "values=*. *cache.jsp" passes two arguments to the jmx method ProxyCache::clearCacheByPattern. The URL starts with the URI: /resin-rest/ where you will find all of the Resin admin support. The URI under this /resin-rest/jmx-call (jmx-call) means we want to invoke a JMX method. The query param pattern=resin:type=ProxyCache means we want to call a method on the JMX bean resin:ProxyCache The query param operation=clearCacheByPattern means we want to call the clearCacheByPattern method.

You can also use curl to submit SSL/TLS requests. After you run this from a bash script or Perl you can go the test cache.jsp and it will reload as expected.

(see http://javadoc4.caucho.com/com/caucho/management/server/ProxyCacheMXBean.html)

REST calls from other languages

Here are some other example from other languages making REST calls.

Ruby Rest call to Resin JMX

view source print? 01.require "net/http" 02.require "uri" 03.  04.  05.  06.  07.$values = ".* .*cache.jsp" 08.$clearCacheByPatternURL = "http://localhost:8080/resin-rest/jmx-call?pattern=resin:type=ProxyCache&operation=clearCacheByPattern" 09.$connected=false 10.  11.  12.  13.  14.def main 15.  16.  17.  18.  19.    begin 20.    response = Net::HTTP.get_response(URI.parse("http://localhost:8080/")) 21.        puts response.body 22.        connected=true 23.    rescue Net::HTTPExceptions => ex 24.        connected=false 25.        puts ("The error was "+  ex) 26.    ensure 27.        #conn.close() unless conn.nil? 28.    end 29.  30.  31.  32.  33.    ifconnected 34.        invalidateCache() 35.    else 36.        puts ("Resin does not appear to be up") 37.    end 38.end 39.  40.  41.  42.  43.  44.  45.  46.  47.def invalidateCache() 48.    begin 49.    uri = URI.parse($clearCacheByPatternURL) 50.      http = Net::HTTP.new(uri.host, uri.port) 51.      request = Net::HTTP::Post.new(uri.request_uri) 52.      request.basic_auth("foobar", "foobar") 53.        request.set_form_data({"values"=> $values}) 54.      response = http.request(request) 55.    puts response.body 56.    puts "No error "+ response.code 57.    rescue Net::HTTPExceptions => ex 58.        connected=false 59.        puts ("The error was "+  ex) 60.    ensure 61.        #http.close() unless http.nil? 62.    end 63.   64.end 65.  66.  67.  68.  69.if__FILE__ == $0 70.   main 71.end

Python Rest call to Resin REST Admin

view source print? 01.importhttplib 02.importbase64  03.  04.  05.  06.  07.requestBody = "values=.* .*cache.jsp" 08.host = "localhost" 09.clearCacheByPatternURI = "/resin-rest/jmx-call?pattern=resin:type=ProxyCache&operation=clearCacheByPattern" 10.connected=False 11.  12.  13.  14.  15.def main(): 16.    global connected 17.    try: 18.        conn = httplib.HTTPConnection(host, port=8080 19.        conn.request("GET", "/") 20.        response = conn.getresponse() 21.        data = response.read()  22.        print (data) 23.        connected=True 24.    except httplib.HTTPException, ex: 25.        connected=False 26.        print ("The error was %s" % ex) 27.    finally: 28.        ifconn: 29.            conn.close() 30.  31.  32.  33.  34.    ifconnected: 35.        invalidateCache() 36.    else: 37.        print ("Resin does not appear to be up") 38.  39.  40.  41.  42.def invalidateCache(): 43.    auth = base64.encodestring("foobar:foobar" 44.    headers = {"Authorization" : "Basic %s" % auth,   45.               "Content-Type": "application/x-www-form-urlencoded" 46.  47.  48.  49.  50.    try: 51.        conn = httplib.HTTPConnection(host, port=8080 52.        conn.request("POST", clearCacheByPatternURI, requestBody, headers)  53.        response = conn.getresponse()  54.        data = response.read()  55.        print (data) 56.        print ("No error %s " % response.status) 57.    except httplib.HTTPException, ex: 58.        print ("err was %s" % ex) 59.    finally: 60.        ifconn: 61.            conn.close() 62.      63.if  __name__ =='__main__': 64.    main()

PERL Rest call to Resin REST Admin

view source print? 1.coming soon

Java Rest call to Resin REST Admin

view source print? 1.coming soon

Go programming Rest call to Resin REST Admin

view source print? 01.packagemain 02.  03.  04.  05.  06.import( 07.    "fmt" 08.    "net/http" 09.    "io/ioutil" 10.    "bytes" 11.) 12.  13.  14.  15.  16.var ( 17.    connected bool 18.    client *http.Client = &http.Client{} 19.    requestBody *bytes.Buffer = bytes.NewBufferString("values=.* .*cache.jsp" 20.    clearCacheByPatternURL string = "http://localhost:8080/resin-rest/jmx-call"+ 21.                                 "?pattern=resin:type=ProxyCache&operation=clearCacheByPattern" 22.) 23.  24.  25.  26.  27.func main() { 28.  29.  30.  31.  32.    ifresp, err := http.Get("http://localhost:8080/"); err==nil { 33.  34.  35.  36.  37.            ifbody, err := ioutil.ReadAll(resp.Body); err==nil { 38.                    fmt.Println(string(body)) 39.            connected = true 40.                } 41.  42.  43.  44.  45.    } else{ 46.           fmt.Println("The error was", err) 47.    } 48.  49.  50.  51.  52.    ifconnected { 53.       invalidateCache(); 54.    } else{ 55.           fmt.Println("Resin does not appear to be up"); 56.    } 57.} 58.  59.  60.  61.  62.func invalidateCache() { 63.     ifrequest, err := http.NewRequest("POST", clearCacheByPatternURL, requestBody); err==nil { 64.         fmt.Println(request.Method) 65.    request.SetBasicAuth("foobar", "foobar") 66.        request.Header.Add("Content-Type", "application/x-www-form-urlencoded") 67.    response, err := client.Do(request) 68.  69.  70.  71.  72.        ifbody, err := ioutil.ReadAll(response.Body); err==nil { 73.                    fmt.Println(string(body)) 74.            connected = true 75.        } 76.    iferr==nil{ 77.       fmt.Println("No error "+ response.Status) 78.    } else{ 79.       fmt.Println("err was", err) 80.    } 81.     } 82.}

Further reading

Bill Digman is a Java EE / Servlet enthusiast and Open Source enthusiast who loves working with Caucho's Resin Servlet Container, a Java EE Web Profile Servlet Container.

Caucho's Resin OpenSource Servlet Container

Resin REST support

Resin Proxy Cache support and REST support explained

Published at DZone with permission of its author, Bill Digman.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)