<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7778735617937090055</id><updated>2012-02-15T23:07:02.015-08:00</updated><title type='text'>Shahzad Bhatti</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-2161852825145115590</id><published>2010-08-13T10:04:00.000-07:00</published><updated>2010-08-13T10:07:23.727-07:00</updated><title type='text'></title><content type='html'>Popular blogs entries from &lt;a href="http://weblog.plexobject.com/"&gt;my blog&lt;/a&gt; (&lt;a href="http://weblog.plexobject.com/human_sitemap.html"&gt;sitemap&lt;/a&gt;):&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1682"&gt;Implementing a Single Sign-on solution for Wordpress (PHP) and Rails applications using Central Authentication Service (CAS)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1681"&gt;NoSql databases bring "Stored Procedures" back in fashion&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1679"&gt;Tutorial days from OSCON 2010&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1678"&gt;A few lessons from Seth Godin's book Linchpin: Are You Indispensable?&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1676"&gt;Building a stock quote server in Erlang using Ejabberd, XMPP, Bosh, Exmpp, Strophe and Yaws&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1674"&gt;Favorite fifteen tips from "Rework" book by Jason Fried and DHH&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1672"&gt;A few recipes for reprocessing messages in Dead-Letter-Queue using ActiveMQ&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1670"&gt;PlexRBAC: an open source project for providing powerful role based security (I)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1671"&gt;PlexRBAC: an open source project for providing powerful role based security (II)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1669"&gt;Building Security Systems&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1668"&gt;Dynamic Inheritance and Composition using Object Extension Pattern&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1667"&gt;Applying Adaptive Object Model using dynamic languages and schema-less databases&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1666"&gt;Quering and Indexing CouchDB documents&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1663"&gt;Introduction to CouchDB&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1660"&gt;Cut the scope and make your life easy&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1655"&gt;Day 1 at #oscon 2009&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1656"&gt;Day 2 at #oscon 2009&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1657"&gt;Day 3 at #oscon 2009&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1658"&gt;Day 4 at #oscon 2009&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1659"&gt;Day 5 at #oscon 2009&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1653"&gt;OCActiveObjects: ActiveObject based O/R Mapping framework for iPhone development&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1648"&gt;Does software quality matters?&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1647"&gt;Software Estimation&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1645"&gt;Review of Clean Code&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1644"&gt;Tips from Implementation Patterns&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1643"&gt;Tips from Effective Java&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1638"&gt;Implementing Actor-based message passing using Object-oriented methods&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1636"&gt;My gripes about REST services&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1635"&gt;Developing REST based services using JSR 311&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1634"&gt;Concurrency Constructs&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1631"&gt;Traits of good programmers&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1627"&gt;Implementing HTTP Proxy Service with XSL Transformation&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1624"&gt;Love and Hate with Java&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1622"&gt;Designing Microblogging system for Scalability&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1621"&gt;Challenges of multicore programming&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1616"&gt;Integrating with lots of Services and AJAX&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1600"&gt;Does experience matter?&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1594"&gt;Accessing SimpleDB using Java and Erlang&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1592"&gt;Starting cluster of Erlang nodes on EC2&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1577"&gt;Rosetta solution in Erlang&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1576"&gt;Performance testing C++, Java, Ruby and Erlang&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1573"&gt;Code Smells&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1572"&gt;Polymorphism in Erlang&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1570"&gt;Benchmarking Java vs Erlang&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1569"&gt;Ten Commandments for Scalable Architecture&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1568"&gt;Annotation based Caching in Java&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1566"&gt;Load and Functional Testing with Selenium and Grinder&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1562"&gt;Ten Commandments for Configuration&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1561"&gt;Ten Commandments for Writing a Service&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1556"&gt;Resource Bundle in Ruby&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1555"&gt;Working with Amazon Web Services&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1427"&gt;Agile Methodologies Under the Hood&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1393"&gt;Development in large IT Shops&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1418"&gt;Enums and Lookups in Ruby and Java&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1368"&gt;Integrating Ruby with Java using ActiveMQ and Stomp&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1403"&gt;RailsConf 2006 Day 3&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1402"&gt;RailsConf 2006 Day 2&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1401"&gt;RailsConf 2006 Day 1&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1390"&gt;Integrating ActiveMQ with JBoss&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1382"&gt;Agile Purists&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1389"&gt;Implementing Const in Java&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1407"&gt;Brainstorm Chicago April 19-20&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1420"&gt;Message-Driven-Pojos with ActiveMQ&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1435"&gt;Sudoku Solver in Ruby&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1417"&gt;Nexus for next generation languages&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1405"&gt;Scripting Flame War&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1428"&gt;Log locally and query globally&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1409"&gt;Responsibility vs Accountability&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1376"&gt;Web 2.0&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1391"&gt;Bohrbug Vs Heisenbug&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1386"&gt;Keeping the truck number low&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1424"&gt;How overwork leads to dumb workers&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1383"&gt;Best Practices 2004 (East)&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1414"&gt;What is right methodology?&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1419"&gt;Offshoring&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1369"&gt;Design by Committee&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1392"&gt;Software Development Profession is Doomed?&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1412"&gt;What's in the Title&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1430"&gt;Software Rewrites&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt; &lt;a href="http://weblog.plexobject.com/?p=1399"&gt;OO Summary&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-2161852825145115590?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/2161852825145115590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/08/popular-blogs-entries-from-my-blog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2161852825145115590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2161852825145115590'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/08/popular-blogs-entries-from-my-blog.html' title=''/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-7576568671768507709</id><published>2010-05-10T14:57:00.001-07:00</published><updated>2010-05-10T14:59:21.838-07:00</updated><title type='text'>Building a stock quote server in Erlang using Ejabberd, XMPP, Bosh, Exmpp, Strophe and Yaws</title><content type='html'>&lt;p&gt;Recently, I have been building a stock quote server at work that publishes financial data using using &lt;a href="http://www.ejabberd.im/"&gt;Ejabberd&lt;/a&gt;, &lt;a href="http://xmpp.org/"&gt;XMPP&lt;/a&gt;, &lt;a href="http://xmpp.org/extensions/xep-0060.html"&gt;PubSub&lt;/a&gt;, &lt;a href="http://github.com/processone/exmpp"&gt;Exmpp&lt;/a&gt; and &lt;a href="http://xmpp.org/extensions/xep-0124.html"&gt;Bosh&lt;/a&gt; on the server side and &lt;a href="http://code.stanziq.com/strophe/"&gt;Strophe&lt;/a&gt; library on the web application front. I will describe a simplified implementation of the quote server using &lt;a href="http://finance.yahoo.com/"&gt;Yahoo Quotes&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Installation&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Download &lt;a href="http://www.ejabberd.im/download"&gt;Ejabberd&lt;/a&gt; and go through the installation wizad. You will be asked your host name, admin account/password and whether ejabberd would be running in a clustered environment. For this tutorial, we will be running ejabberd on a single. Once installed, you can start the ejabbered server using&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; /Applications/ejabberd-2.1.3/bin/ejabberdctl start&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; As, I am using Mac, the actual path on your machine may be different. The ejabbered comes with a web baesd admin tool, that you can access using&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; http://&amp;lt;your-host-name&amp;gt;:5280/admin&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; and you would be able to see available nodes, users, etc.&lt;br&gt;&lt;br /&gt; &lt;br&gt;&lt;br&gt;&lt;br /&gt; &lt;img src="http://weblog.plexobject.com/images/ejabberd_admin.png" width="800"&gt;&lt;br&gt;&lt;br /&gt; &lt;br&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Registering Users&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; We will be creating two users: producer and consumer, where the former would be used for publishing stock quotes and latter would be used for subscribing quotes on the web side, i.e.,&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; sudo /Applications/ejabberd-2.1.3/bin/ejabberdctl register producer &lt;hostname&gt; producer&lt;br /&gt; sudo /Applications/ejabberd-2.1.3/bin/ejabberdctl register consumer &lt;hostname&gt; consumer&lt;br /&gt; &lt;/hostname&gt;&lt;/hostname&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Debuging with Psi&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; You can debug XMPP communications using a jabber client such as Psi, which you can &lt;a href="http://psi-im.org/"&gt;download&lt;/a&gt;. After you download, you can install and specify your local hostname as a server, e.g.&lt;br&gt;&lt;br /&gt; &lt;br&gt;&lt;br&gt;&lt;br /&gt; &lt;img src="http://weblog.plexobject.com/images/psi0.png"&gt;&lt;br&gt;&lt;br /&gt; &lt;br&gt;&lt;br&gt;&lt;br /&gt; You can then login using consumer@&amp;lt;your-host-name&amp;gt; with password consumer. As, we will be using PubSub protocol, you can discover available nodes or topics using General-&amp;gt;Service Discovery from the menu, e.g.&lt;br&gt;&lt;br /&gt;&lt;br /&gt; &lt;br&gt;&lt;br&gt;&lt;br /&gt; &lt;img src="http://weblog.plexobject.com/images/psi.png"&gt;&lt;br&gt;&lt;br /&gt; &lt;br&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Downloading Sample Code&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; I have stored all code needed for this example on &lt;a href="http://github.com/bhatti/FQPubSub"&gt;http://github.com/bhatti/FQPubSub&lt;/a&gt;, that you can checkout using:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; git clone git@github.com:bhatti/FQPubSub.git&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; The sample code depends on &lt;a href="http://github.com/processone/exmpp.git"&gt;exmpp&lt;/a&gt;, &lt;a href="http://github.com/oscarh/lhttpc.git"&gt;lhttpc&lt;/a&gt;, &lt;a href="http://github.com/lambder/jsonerl.git"&gt;jsonerl&lt;/a&gt;, and &lt;a href="http://github.com/klacke/yaws.git"&gt;yaws&lt;/a&gt; modules so after downloading the code, checkout dependent modules using&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; git submodule init&lt;br /&gt; git submodule update&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Above commands will checkout dependent modules in deps directory.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Building Sample Code&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Before building, ensure you have make and autoconf tools installed, then replace &amp;lt;paraclete.local&amp;gt; with your &amp;lt;your-host-name&amp;gt; in docroot/index.html and src/quote_utils.hrl. Then type following command&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; make&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; to build all sample code and dependent libraries&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Starting Web Server&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Though, the web code including Srophe library and Javascript can be run directly in the browser, but you can start Yaws to serve the application as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; erl -pa ebin deps/exmpp/ebin/ deps/lhttpc/ebin/ deps/yaws/ebin -boot start_sasl -run web_server start&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Note, that the web server will be continuously running, so you can open a separate shell before typing above command.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Publishing Quotes&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Create two separate shells and type following command in first shell:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;   erl -pa ebin deps/exmpp/ebin/ deps/lhttpc/ebin/ deps/yaws/ebin -boot start_sasl -run quote_publisher start AAPL&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; and following command in second shell&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;   erl -pa ebin deps/exmpp/ebin/ deps/lhttpc/ebin/ deps/yaws/ebin -boot start_sasl -run quote_publisher start IBM&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Above commands will start Erlang processes, that will poll &lt;a href="http://finance.yahoo.com/"&gt;Yahoo Quotes&lt;/a&gt; every second and publish the quotes on the node AAPL and IBM respectively.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Next point your browser to http://&amp;lt;your-host-name&amp;gt;:8000/, and add “IBM” and “AAPL” symbols, you would then see quotes for both symbols, e.g.&lt;br&gt;&lt;br /&gt; &lt;img src="http://weblog.plexobject.com/images/browser.png"&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Code under the hood&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Now that you are able to run the example, let’s take a look at the code how it works:&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Client library for Yahoo Finance&lt;/h4&gt;&lt;br /&gt;&lt;p&gt; Though, at work we use our own real time stock quote feed, but for this sample I implemented stock quote feed using Yahoo Finance. The src/yquote_client.hrl and src/yquote_client.erl define client API for accessing Yahoo finance service. Here is the Erlang code for requesting the quote using HTTP request and parsing it:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%-------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% File : yquote_client.erl&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Author : Shahzad Bhatti&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Purpose : Wrapper Library for Yahoo Stock Quotes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Created : May &lt;/span&gt;&lt;span class="comment"&gt;8, 2010&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%-------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt; -module(yquote_client).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt; -author('bhatti@plexobject.com').&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt; -export([&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;          quote/1&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;         ]).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt; -record(quote, {&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;         symbol,&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;         price,&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;         change,&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;         volume,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;         avg_daily_volume,&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;         stock_exchange,&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;         market_cap,&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;         book_value,&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;         ebitda,&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt;         dividend_per_share,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt;         dividend_yield,&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;         earnings_per_share,&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;         week_52_high,&lt;br /&gt; &lt;span class="line-number"&gt;30&lt;/span&gt;         week_52_low,&lt;br /&gt; &lt;span class="line-number"&gt;31&lt;/span&gt;         day_50_moving_avg,&lt;br /&gt; &lt;span class="line-number"&gt;32&lt;/span&gt;         day_200_moving_avg,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;33&lt;/span&gt;         price_earnings_ratio,&lt;br /&gt; &lt;span class="line-number"&gt;34&lt;/span&gt;         price_earnings_growth_ratio,&lt;br /&gt; &lt;span class="line-number"&gt;35&lt;/span&gt;         price_sales_ratio,&lt;br /&gt; &lt;span class="line-number"&gt;36&lt;/span&gt;         price_book_ratio,&lt;br /&gt; &lt;span class="line-number"&gt;37&lt;/span&gt;         short_ratio}).&lt;br /&gt; &lt;span class="line-number"&gt;38&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;39&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;40&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;41&lt;/span&gt; quote(&lt;span class="Var"&gt;Symbol&lt;/span&gt;) -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;42&lt;/span&gt;     inets:start(),&lt;br /&gt; &lt;span class="line-number"&gt;43&lt;/span&gt;     {ok,{&lt;span class="Var"&gt;_Status&lt;/span&gt;, &lt;span class="Var"&gt;_Headers&lt;/span&gt;, &lt;span class="Var"&gt;Response&lt;/span&gt;}} = http:request(get, {url(&lt;span class="Var"&gt;Symbol&lt;/span&gt;), []},&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;44&lt;/span&gt;         [{timeout, 5000}], [{sync, true}]),&lt;br /&gt; &lt;span class="line-number"&gt;45&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;46&lt;/span&gt;     &lt;span class="Var"&gt;Values&lt;/span&gt; = re:split(&lt;span class="Var"&gt;Response&lt;/span&gt;, &lt;span class="char"&gt;"[,\r\n]"&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;47&lt;/span&gt;     #&lt;span class="Macro"&gt;quote&lt;/span&gt;{&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;48&lt;/span&gt;         symbol = list_to_binary(&lt;span class="Var"&gt;Symbol&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;49&lt;/span&gt;         price = to_float(lists:nth(1, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;50&lt;/span&gt;         change = to_float(lists:nth(2, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;51&lt;/span&gt;         volume = to_integer(lists:nth(3, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;52&lt;/span&gt;         avg_daily_volume = to_integer(lists:nth(4, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;53&lt;/span&gt;         stock_exchange = lists:nth(5, &lt;span class="Var"&gt;Values&lt;/span&gt;), &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt; to_string&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;54&lt;/span&gt;         market_cap = to_float(lists:nth(6, &lt;span class="Var"&gt;Values&lt;/span&gt;)), &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt; B&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;55&lt;/span&gt;         book_value = to_float(lists:nth(7, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;56&lt;/span&gt;         ebitda = to_float(lists:nth(8, &lt;span class="Var"&gt;Values&lt;/span&gt;)), &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt; B&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;57&lt;/span&gt;         dividend_per_share = to_float(lists:nth(9, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;58&lt;/span&gt;         dividend_yield = to_float(lists:nth(10, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;59&lt;/span&gt;         earnings_per_share = to_float(lists:nth(11, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;60&lt;/span&gt;         week_52_high = to_float(lists:nth(12, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;61&lt;/span&gt;         week_52_low = to_float(lists:nth(13, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;62&lt;/span&gt;         day_50_moving_avg = to_float(lists:nth(14, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;63&lt;/span&gt;         day_200_moving_avg = to_float(lists:nth(15, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;64&lt;/span&gt;         price_earnings_ratio = to_float(lists:nth(16, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;65&lt;/span&gt;         price_earnings_growth_ratio = to_float(lists:nth(17, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;66&lt;/span&gt;         price_sales_ratio = to_float(lists:nth(18, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;67&lt;/span&gt;         price_book_ratio = to_float(lists:nth(19, &lt;span class="Var"&gt;Values&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;68&lt;/span&gt;         short_ratio = to_float(lists:nth(20, &lt;span class="Var"&gt;Values&lt;/span&gt;))}.&lt;br /&gt; &lt;span class="line-number"&gt;69&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;70&lt;/span&gt; url(&lt;span class="Var"&gt;Symbol&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;71&lt;/span&gt;     &lt;span class="char"&gt;"http://finance.yahoo.com/d/quotes.csv?s="&lt;/span&gt; ++ &lt;span class="Var"&gt;Symbol&lt;/span&gt; ++ &lt;span class="char"&gt;"&amp;amp;f=l1c1va2xj1b4j4dyekjm3m4rr5p5p6s7"&lt;/span&gt;.&lt;br /&gt; &lt;span class="line-number"&gt;72&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;73&lt;/span&gt; to_float(&amp;lt;&amp;lt;&lt;span class="char"&gt;"N/A"&lt;/span&gt;&amp;gt;&amp;gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;74&lt;/span&gt;     -1;&lt;br /&gt; &lt;span class="line-number"&gt;75&lt;/span&gt; to_float(&lt;span class="Var"&gt;Bin&lt;/span&gt;) -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;76&lt;/span&gt;     {&lt;span class="Var"&gt;Multiplier&lt;/span&gt;, &lt;span class="Var"&gt;Bin1&lt;/span&gt;} = &lt;span class="keyword"&gt;case&lt;/span&gt; bin_ends_with(&lt;span class="Var"&gt;Bin&lt;/span&gt;, &amp;lt;&amp;lt;&lt;span class="char"&gt;$B&lt;/span&gt;&amp;gt;&amp;gt;) &lt;span class="keyword"&gt;of&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;77&lt;/span&gt;         true -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;78&lt;/span&gt;             {1000000000, bin_replace(&lt;span class="Var"&gt;Bin&lt;/span&gt;, &amp;lt;&amp;lt;&lt;span class="char"&gt;$B&lt;/span&gt;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&amp;gt;&amp;gt;)};&lt;br /&gt; &lt;span class="line-number"&gt;79&lt;/span&gt;         false -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;80&lt;/span&gt;             &lt;span class="keyword"&gt;case&lt;/span&gt; bin_ends_with(&lt;span class="Var"&gt;Bin&lt;/span&gt;, &amp;lt;&amp;lt;&lt;span class="char"&gt;$M&lt;/span&gt;&amp;gt;&amp;gt;) &lt;span class="keyword"&gt;of&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;81&lt;/span&gt;                 true -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;82&lt;/span&gt;                     {1000000, bin_replace(&lt;span class="Var"&gt;Bin&lt;/span&gt;, &amp;lt;&amp;lt;&lt;span class="char"&gt;$M&lt;/span&gt;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&amp;gt;&amp;gt;)};&lt;br /&gt; &lt;span class="line-number"&gt;83&lt;/span&gt;                 false -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;84&lt;/span&gt;                     {1,&lt;span class="Var"&gt;Bin&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;85&lt;/span&gt;             &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;86&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;87&lt;/span&gt;     &lt;span class="Var"&gt;L&lt;/span&gt; = binary_to_list(&lt;span class="Var"&gt;Bin1&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;88&lt;/span&gt;     list_to_float(&lt;span class="Var"&gt;L&lt;/span&gt;) * &lt;span class="Var"&gt;Multiplier&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;89&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;90&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;91&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Note that I am omitting some code in above listing, as I just wanted to highlight HTTP request and parsing code.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Publishing the Stock Quote&lt;/h4&gt;&lt;br /&gt;&lt;p&gt; I used &lt;a href="http://github.com/processone/exmpp"&gt;exmpp&lt;/a&gt; library to communicate with the XMPP server in Erlang. Here is the code for publishing the quotes using Bosh/XMPP protocol:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%-------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% File : quote_publisher.erl&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Author : Shahzad Bhatti&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Purpose : OTP server for publishing quotes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%% Created : May 8, 2&lt;/span&gt;&lt;span class="comment"&gt;010&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%-------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt; -module(quote_publisher).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt; -export([&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;     start/1,&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;     start/5,&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;     stop/1]).&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt; -export([init/5]).&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt; -include_lib(&lt;span class="char"&gt;"quote_utils.hrl"&lt;/span&gt;).&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt; -record(state, {session, jid, service=?&lt;span class="Macro"&gt;TEST_XMPP_PUBSUB&lt;/span&gt;, symbol}).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% APIs&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt; &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt; start(&lt;span class="Var"&gt;Symbol&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;     start(?&lt;span class="Macro"&gt;TEST_XMPP_SERVER&lt;/span&gt;, ?&lt;span class="Macro"&gt;TEST_XMPP_PORT&lt;/span&gt;, ?&lt;span class="Macro"&gt;PRODUCER_USERNAME&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;         ?&lt;span class="Macro"&gt;PRODUCER_PASSWORD&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt; start(&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;Port&lt;/span&gt;, &lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;) -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;     spawn(?&lt;span class="Macro"&gt;MODULE&lt;/span&gt;, init, [&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;Port&lt;/span&gt;, &lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;]).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;30&lt;/span&gt; stop(&lt;span class="Var"&gt;Pid&lt;/span&gt;) -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;31&lt;/span&gt;     &lt;span class="Var"&gt;Pid&lt;/span&gt; ! stop.&lt;br /&gt; &lt;span class="line-number"&gt;32&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;33&lt;/span&gt; init(&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;Port&lt;/span&gt;, &lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;34&lt;/span&gt;     {ok, {&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;}} = quote_utils:connect(&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;Port&lt;/span&gt;, &lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;35&lt;/span&gt;     &lt;span class="Var"&gt;State&lt;/span&gt; = #&lt;span class="Macro"&gt;state&lt;/span&gt;{session=&lt;span class="Var"&gt;MySession&lt;/span&gt;, jid=&lt;span class="Var"&gt;MyJID&lt;/span&gt;, symbol = &lt;span class="Var"&gt;Symbol&lt;/span&gt;},&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;36&lt;/span&gt;     create_symbol_node(&lt;span class="Var"&gt;State&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;37&lt;/span&gt;     loop(&lt;span class="Var"&gt;State&lt;/span&gt;).&lt;br /&gt; &lt;span class="line-number"&gt;38&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;39&lt;/span&gt; loop(#&lt;span class="Macro"&gt;state&lt;/span&gt;{session=&lt;span class="Var"&gt;MySession&lt;/span&gt;, jid=&lt;span class="Var"&gt;_MyJID&lt;/span&gt;, service = &lt;span class="Var"&gt;_Service&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;40&lt;/span&gt;         symbol = &lt;span class="Var"&gt;_Symbol&lt;/span&gt;}=&lt;span class="Var"&gt;State&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;41&lt;/span&gt;     &lt;span class="keyword"&gt;receive&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;42&lt;/span&gt;         stop -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;43&lt;/span&gt;             quote_utils:disconnect(&lt;span class="Var"&gt;MySession&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;44&lt;/span&gt;         &lt;span class="Var"&gt;Record&lt;/span&gt; = #&lt;span class="Macro"&gt;received_packet&lt;/span&gt;{packet_type=message, raw_packet=&lt;span class="Var"&gt;_Packet&lt;/span&gt;} -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;45&lt;/span&gt;             loop(&lt;span class="Var"&gt;State&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt;46&lt;/span&gt;         &lt;span class="Var"&gt;Record&lt;/span&gt; -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;47&lt;/span&gt;             loop(&lt;span class="Var"&gt;State&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;48&lt;/span&gt;     &lt;span class="keyword"&gt;after&lt;/span&gt; 2000 -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;49&lt;/span&gt;         publish_quote(&lt;span class="Var"&gt;State&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;50&lt;/span&gt;         loop(&lt;span class="Var"&gt;State&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;51&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;.&lt;br /&gt; &lt;span class="line-number"&gt;52&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;53&lt;/span&gt; create_symbol_node(#&lt;span class="Macro"&gt;state&lt;/span&gt;{session=&lt;span class="Var"&gt;MySession&lt;/span&gt;, jid=&lt;span class="Var"&gt;MyJID&lt;/span&gt;, service = &lt;span class="Var"&gt;Service&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;54&lt;/span&gt;         symbol = &lt;span class="Var"&gt;Symbol&lt;/span&gt;}) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;55&lt;/span&gt;     &lt;span class="Var"&gt;IQ&lt;/span&gt; = exmpp_client_pubsub:create_node(&lt;span class="Var"&gt;Service&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;56&lt;/span&gt;     &lt;span class="Var"&gt;PacketId&lt;/span&gt; = exmpp_session:send_packet(&lt;span class="Var"&gt;MySession&lt;/span&gt;, exmpp_stanza:set_sender(&lt;span class="Var"&gt;IQ&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;57&lt;/span&gt;     &lt;span class="Var"&gt;PacketId2&lt;/span&gt; = erlang:binary_to_list(&lt;span class="Var"&gt;P&lt;/span&gt;&lt;span class="Var"&gt;acketId&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;58&lt;/span&gt;     &lt;span class="keyword"&gt;receive&lt;/span&gt; #&lt;span class="Macro"&gt;received_packet&lt;/span&gt;{id=&lt;span class="Var"&gt;PacketId2&lt;/span&gt;, raw_packet=&lt;span class="Var"&gt;Raw&lt;/span&gt;} -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;59&lt;/span&gt;       &lt;span class="keyword"&gt;case&lt;/span&gt; exmpp_iq:is_error(&lt;span class="Var"&gt;Raw&lt;/span&gt;) &lt;span class="keyword"&gt;of&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;60&lt;/span&gt;         true -&amp;gt; {error, &lt;span class="Var"&gt;Raw&lt;/span&gt;};&lt;br /&gt; &lt;span class="line-number"&gt;61&lt;/span&gt;         &lt;span class="Var"&gt;_&lt;/span&gt; -&amp;gt; ok&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;62&lt;/span&gt;       &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;63&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;.&lt;br /&gt; &lt;span class="line-number"&gt;64&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;65&lt;/span&gt; publish_quote(#&lt;span class="Macro"&gt;state&lt;/span&gt;{session=&lt;span class="Var"&gt;MySession&lt;/span&gt;, jid=&lt;span class="Var"&gt;MyJID&lt;/span&gt;, service = &lt;span class="Var"&gt;Service&lt;/span&gt;, symbol = &lt;span class="Var"&gt;Symbol&lt;/span&gt;}) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;66&lt;/span&gt;     &lt;span class="Var"&gt;Quote&lt;/span&gt; = yquote_client:quote(&lt;span class="Var"&gt;Symbol&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;67&lt;/span&gt;     &lt;span class="Var"&gt;JsonQuote&lt;/span&gt; = ?&lt;span class="Macro"&gt;record_to_json&lt;/span&gt;(quote, &lt;span class="Var"&gt;Quote&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;68&lt;/span&gt;     &lt;span class="Var"&gt;M&lt;/span&gt; = exmpp_xml:element(?&lt;span class="Macro"&gt;QUOTE_DATA&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;69&lt;/span&gt;     &lt;span class="Var"&gt;IQ&lt;/span&gt; = exmpp_client_pubsub:publish(&lt;span class="Var"&gt;Service&lt;/span&gt;, &lt;span class="Var"&gt;Symbol&lt;/span&gt;, exmpp_xml:append_cdata(&lt;span class="Var"&gt;M&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;70&lt;/span&gt;             &lt;span class="Var"&gt;JsonQuote&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;71&lt;/span&gt;     &lt;span class="Var"&gt;Xml&lt;/span&gt; = exmpp_stanza:set_id(exmpp_stanza:set_sender(&lt;span class="Var"&gt;IQ&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;), &lt;span class="Var"&gt;Symbol&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;72&lt;/span&gt;     &lt;span class="Var"&gt;PacketId&lt;/span&gt; = exmpp_session:send_packet(&lt;span class="Var"&gt;MySession&lt;/span&gt;, exmpp_stanza:set_sender(&lt;span class="Var"&gt;IQ&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;)),&lt;br /&gt; &lt;span class="line-number"&gt;73&lt;/span&gt;     &lt;span class="Var"&gt;PacketId2&lt;/span&gt; = erlang:binary_to_list(&lt;span class="Var"&gt;PacketId&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;74&lt;/span&gt;     &lt;span class="keyword"&gt;receive&lt;/span&gt; #&lt;span class="Macro"&gt;received_packet&lt;/span&gt;{id=&lt;span class="Var"&gt;PacketId2&lt;/span&gt;, raw_packet=&lt;span class="Var"&gt;Raw&lt;/span&gt;} -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;75&lt;/span&gt;       &lt;span class="keyword"&gt;case&lt;/span&gt; exmpp_iq:is_error(&lt;span class="Var"&gt;Raw&lt;/span&gt;) &lt;span class="keyword"&gt;of&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;76&lt;/span&gt;         true -&amp;gt; error;&lt;br /&gt; &lt;span class="line-number"&gt;77&lt;/span&gt;         &lt;span class="Var"&gt;_&lt;/span&gt; -&amp;gt; ok&lt;br /&gt; &lt;span class="line-number"&gt;78&lt;/span&gt;       &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;79&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;80&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;81&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;82&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; In above code, a process is created for each symbol, which periodically polls stock quote and publishes it to the XMPP node using pubsub/bosh protocol. Note that a unique node is created for each symbol and node must be created before anyone can publish or subscribe. Also, note that publish/subscribe APIs use request/ack protocol, so after sending the request, the process retrieves the acknowledgement of the request.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Here are some utility functions used by the publisher:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; -module(quote_utils).&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt; -include_lib(&lt;span class="char"&gt;"quote_utils.hrl"&lt;/span&gt;).&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; -export([&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;     init_session/2,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;     connect/4,&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;     disconnect/1]).&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt; bosh_url(&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;Port&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="char"&gt;"http://"&lt;/span&gt; ++ &lt;span class="Var"&gt;Host&lt;/span&gt; ++ &lt;span class="char"&gt;":"&lt;/span&gt; ++ integer_to_list(&lt;span class="Var"&gt;Port&lt;/span&gt;) ++ &lt;span class="char"&gt;"/http-bind"&lt;/span&gt;.&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt; connect(&lt;span class="Var"&gt;Host&lt;/span&gt;, &lt;span class="Var"&gt;_Port&lt;/span&gt;, &lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;) -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;     safe_start_apps(),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;     &lt;span class="Var"&gt;MySession&lt;/span&gt; = exmpp_session:start({1,0}),&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;     exmpp_xml:start_parser(), &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% Create XMPP ID (Session Key):&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;     &lt;span class="Var"&gt;MyJID&lt;/span&gt; = exmpp_jid:make(&lt;span class="Var"&gt;User&lt;/span&gt;, &lt;span class="Var"&gt;Host&lt;/span&gt;, random),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;     &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% Create a new session with basic (digest) authentication:&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;     exmpp_session:auth_basic_digest(&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;     &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;     {ok, &lt;span class="Var"&gt;_StreamId&lt;/span&gt;, &lt;span class="Var"&gt;_Features&lt;/span&gt;} = exmpp_session:connect_BOSH(&lt;span class="Var"&gt;MySession&lt;/span&gt;, bosh_url(&lt;span class="Var"&gt;Host&lt;/span&gt;, 5280), &lt;span class="Var"&gt;Host&lt;/span&gt;, []),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;     &lt;span class="keyword"&gt;try&lt;/span&gt; quote_utils:init_session(&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;     &lt;span class="keyword"&gt;catch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt;         &lt;span class="Var"&gt;_&lt;/span&gt;:&lt;span class="Var"&gt;Error&lt;/span&gt; -&amp;gt; io:format(&lt;span class="char"&gt;"got error: ~p~n"&lt;/span&gt;, [&lt;span class="Var"&gt;Error&lt;/span&gt;]), {error, &lt;span class="Var"&gt;Error&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;     {ok, {&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;MyJID&lt;/span&gt;}}.&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;30&lt;/span&gt; init_session(&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;31&lt;/span&gt;     &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% Login with defined JID / Authentication:&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;32&lt;/span&gt;     &lt;span class="keyword"&gt;try&lt;/span&gt; exmpp_session:login(&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="char"&gt;"PLAIN"&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;33&lt;/span&gt;     &lt;span class="keyword"&gt;catch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;34&lt;/span&gt;         throw:{auth_error, 'not-authorized'} -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;35&lt;/span&gt;         &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% Try creating a new user:&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;36&lt;/span&gt;         io:format(&lt;span class="char"&gt;"Register~n"&lt;/span&gt;,[]),&lt;br /&gt; &lt;span class="line-number"&gt;37&lt;/span&gt;         &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% In a real life client, we should trap error case here&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;38&lt;/span&gt;         &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% and print the correct message.&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;39&lt;/span&gt;         exmpp_session:register_account(&lt;span class="Var"&gt;MySession&lt;/span&gt;, &lt;span class="Var"&gt;Password&lt;/span&gt;),&lt;br /&gt; &lt;span class="line-number"&gt;40&lt;/span&gt;         &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% After registration, retry to login:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;41&lt;/span&gt;         exmpp_session:login(&lt;span class="Var"&gt;MySession&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;42&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;43&lt;/span&gt;     &lt;span class="comment"&gt;%&lt;/span&gt;&lt;span class="comment"&gt;% We explicitely send presen&lt;/span&gt;&lt;span class="comment"&gt;ce:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;44&lt;/span&gt;     exmpp_session:send_packet(&lt;span class="Var"&gt;MySession&lt;/span&gt;, exmpp_presence:set_status(exmpp_presence:available(), &lt;span class="char"&gt;"Ready to publish!!!"&lt;/span&gt;)),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;45&lt;/span&gt;     ok.&lt;br /&gt; &lt;span class="line-number"&gt;46&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;47&lt;/span&gt; disconnect(&lt;span class="Var"&gt;MySession&lt;/span&gt;) -&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;48&lt;/span&gt;     exmpp_session:stop(&lt;span class="Var"&gt;MySession&lt;/span&gt;).&lt;br /&gt; &lt;span class="line-number"&gt;49&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;50&lt;/span&gt; safe_start_apps() -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;51&lt;/span&gt;     &lt;span class="keyword"&gt;try&lt;/span&gt; start_apps()&lt;br /&gt; &lt;span class="line-number"&gt;52&lt;/span&gt;     &lt;span class="keyword"&gt;catch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;53&lt;/span&gt;         &lt;span class="Var"&gt;_&lt;/span&gt;:&lt;span class="Var"&gt;Error&lt;/span&gt; -&amp;gt; io:format(&lt;span class="char"&gt;"apps already started : ~p~n"&lt;/span&gt;, [&lt;span class="Var"&gt;Error&lt;/span&gt;]), {error, &lt;span class="Var"&gt;Error&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;54&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;.&lt;br /&gt; &lt;span class="line-number"&gt;55&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;56&lt;/span&gt; start_apps() -&amp;gt;&lt;br /&gt; &lt;span class="line-number"&gt;57&lt;/span&gt;     ok = application:start(exmpp),&lt;br /&gt; &lt;span class="line-number"&gt;58&lt;/span&gt;     ok = application:start(crypto),&lt;br /&gt; &lt;span class="line-number"&gt;59&lt;/span&gt;     ok = application:start(ssl),&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;60&lt;/span&gt;     ok = application:start(lhttpc).&lt;br /&gt; &lt;span class="line-number"&gt;61&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Note that above code auto-registers users, which is not recommended for production use. &lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Javascript code using Strophe library&lt;/h4&gt;&lt;br /&gt;&lt;p&gt; The web application depends on &lt;a href="http://docs.jquery.com/Downloading_jQuery"&gt;jQuery&lt;/a&gt;, &lt;a href="http://code.stanziq.com/strophe/"&gt;Strophe&lt;/a&gt; and &lt;a href="http://code.stanziq.com/strophe/attachment/ticket/67/strophe.pubsub.js"&gt;Strophe Pubsub&lt;/a&gt;. These libraries are included in docroot directory that are imported by index.html. The Strophe library and ejabbered 2.1.3 version supports cross domain scripting so that bosh service here doesn’t need to be on the same domain/port, but it must have a /crossdomain.xml policy file that allows access from wherever index.html lives. The Javascript initializes the connection parameter as follows (you would have to change Host):&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;  1&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;script&lt;/span&gt; &lt;span class="argument"&gt;type&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;"text/javascript"&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  2&lt;/span&gt;     &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;The&lt;/span&gt; &lt;span class="sgml-comment"&gt;BOSH_SERVICE&lt;/span&gt; &lt;span class="sgml-comment"&gt;here&lt;/span&gt; &lt;span class="sgml-comment"&gt;doesn&lt;/span&gt;&lt;span class="sgml-comment"&gt;'&lt;/span&gt;&lt;span class="sgml-comment"&gt;t&lt;/span&gt; &lt;span class="sgml-comment"&gt;need&lt;/span&gt; &lt;span class="sgml-comment"&gt;to&lt;/span&gt; &lt;span class="sgml-comment"&gt;be&lt;/span&gt; &lt;span class="sgml-comment"&gt;on&lt;/span&gt; &lt;span class="sgml-comment"&gt;the&lt;/span&gt; &lt;span class="sgml-comment"&gt;same&lt;/span&gt; &lt;span class="sgml-comment"&gt;domain&lt;/span&gt;&lt;span class="sgml-comment"&gt;/&lt;/span&gt;&lt;span class="sgml-comment"&gt;port&lt;/span&gt;&lt;span class="sgml-comment"&gt;, &lt;/span&gt;&lt;span class="sgml-comment"&gt;but&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  3&lt;/span&gt;     &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;it&lt;/span&gt; &lt;span class="sgml-comment"&gt;must&lt;/span&gt; &lt;span class="sgml-comment"&gt;have&lt;/span&gt; &lt;span class="sgml-comment"&gt;a&lt;/span&gt;&lt;span class="sgml-comment"&gt; /&lt;/span&gt;&lt;span class="sgml-comment"&gt;crossdomain&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;xml&lt;/span&gt; &lt;span class="sgml-comment"&gt;policy&lt;/span&gt; &lt;span class="sgml-comment"&gt;file&lt;/span&gt; &lt;span class="sgml-comment"&gt;that&lt;/span&gt; &lt;span class="sgml-comment"&gt;allows&lt;/span&gt; &lt;span class="sgml-comment"&gt;access&lt;/span&gt; &lt;span class="sgml-comment"&gt;from&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  4&lt;/span&gt;     &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;wherever&lt;/span&gt; &lt;span class="sgml-comment"&gt;crossdomain&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;html&lt;/span&gt; &lt;span class="sgml-comment"&gt;lives&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  5&lt;/span&gt;     &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;TODO&lt;/span&gt;&lt;span class="sgml-comment"&gt;: &lt;/span&gt;&lt;span class="sgml-comment"&gt;REPLACE&lt;/span&gt; &lt;span class="ST0"&gt;&amp;lt;paraclete.local&amp;gt;&lt;/span&gt; &lt;span class="sgml-comment"&gt;with&lt;/span&gt; &lt;span class="sgml-comment"&gt;your&lt;/span&gt; &lt;span class="ST0"&gt;&amp;lt;host-name&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  6&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; HOST = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;paraclete.l&lt;/span&gt;&lt;span class="value"&gt;ocal&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;  7&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; JID = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;consumer@&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + HOST;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;  8&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; PASSWORD = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;consumer&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;  9&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; BOSH_SERVICE = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;http://&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + HOST + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;:5280/http-bind&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;; &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;'/&lt;/span&gt;&lt;span class="sgml-comment"&gt;xmpp&lt;/span&gt;&lt;span class="sgml-comment"&gt;-&lt;/span&gt;&lt;span class="sgml-comment"&gt;httpbind&lt;/span&gt;&lt;span class="sgml-comment"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 10&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; PUBSUB = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;pubsub.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + HOST;&lt;br /&gt; &lt;span class="line-number"&gt; 11&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; connection = &lt;span class="tag"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 12&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; autoReconnect = &lt;span class="tag"&gt;true&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 13&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; hasQuotes = [];&lt;br /&gt; &lt;span class="line-number"&gt; 14&lt;/span&gt;     &lt;span class="tag"&gt;var&lt;/span&gt; subscriptions = [];&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 15&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 16&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; log(msg) {&lt;br /&gt; &lt;span class="line-number"&gt; 17&lt;/span&gt;         $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#log&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).append(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).append(document.createTextNode(msg));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 18&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 19&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 20&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; rawInput(data) {&lt;br /&gt; &lt;span class="line-number"&gt; 21&lt;/span&gt;         &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;log&lt;/span&gt;&lt;span class="sgml-comment"&gt;('&lt;/span&gt;&lt;span class="sgml-comment"&gt;RECV&lt;/span&gt;&lt;span class="sgml-comment"&gt;: ' + &lt;/span&gt;&lt;span class="sgml-comment"&gt;data&lt;/span&gt;&lt;span class="sgml-comment"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 22&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 23&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 24&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; rawOutput(data) {&lt;br /&gt; &lt;span class="line-number"&gt; 25&lt;/span&gt;         &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;log&lt;/span&gt;&lt;span class="sgml-comment"&gt;('&lt;/span&gt;&lt;span class="sgml-comment"&gt;SENT&lt;/span&gt;&lt;span class="sgml-comment"&gt;: ' + &lt;/span&gt;&lt;span class="sgml-comment"&gt;data&lt;/span&gt;&lt;span class="sgml-comment"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 26&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 27&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; onQuote(stanza) {&lt;br /&gt; &lt;span class="line-number"&gt; 28&lt;/span&gt;         &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;log&lt;/span&gt;&lt;span class="sgml-comment"&gt;('&lt;/span&gt;&lt;span class="sgml-comment"&gt;onQuote&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt;#&lt;/span&gt;&lt;span class="sgml-comment"&gt; ' + &lt;/span&gt;&lt;span class="sgml-comment"&gt;stanza&lt;/span&gt;&lt;span class="sgml-comment"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 29&lt;/span&gt;         &lt;span class="tag"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 30&lt;/span&gt;             $(stanza).find(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;event items item data&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).each(&lt;span class="tag"&gt;function&lt;/span&gt;(idx, elem) {&lt;br /&gt; &lt;span class="line-number"&gt; 31&lt;/span&gt;                 quote = jQuery.parseJSON($(elem).text());&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 32&lt;/span&gt;                 &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;{&lt;/span&gt;&lt;span class="sgml-comment"&gt;"&lt;/span&gt;&lt;span class="sgml-comment"&gt;price&lt;/span&gt;&lt;span class="sgml-comment"&gt;":235&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;86,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;change&lt;/span&gt;&lt;span class="sgml-comment"&gt;":-10&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;39,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;volume&lt;/span&gt;&lt;span class="sgml-comment"&gt;":59857756,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;a&lt;/span&gt;&lt;span class="sgml-comment"&gt;vg_daily_volume&lt;/span&gt;&lt;span class="sgml-comment"&gt;":20775600,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;stock_exchange&lt;/span&gt;&lt;span class="sgml-comment"&gt;":[78,97,115,100,97,113,78,77],"&lt;/span&gt;&lt;span class="sgml-comment"&gt;market_cap&lt;/span&gt;&lt;span class="sgml-comment"&gt;":2&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;146&lt;/span&gt;&lt;span class="sgml-comment"&gt;e&lt;/span&gt;&lt;span class="sgml-comment"&gt;+11,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 33&lt;/span&gt;                 &lt;span class="sgml-comment"&gt;//"&lt;/span&gt;&lt;span class="sgml-comment"&gt;book_value&lt;/span&gt;&lt;span class="sgml-comment"&gt;":43&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;257,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;ebitda&lt;/span&gt;&lt;span class="sgml-comment"&gt;":1&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;5805&lt;/span&gt;&lt;span class="sgml-comment"&gt;e&lt;/span&gt;&lt;span class="sgml-comment"&gt;+10,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;dividend_per_share&lt;/span&gt;&lt;span class="sgml-comment"&gt;":0&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;0,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;dividend_yield&lt;/span&gt;&lt;span class="sgml-comment"&gt;":-1,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;earnings_per_share&lt;/span&gt;&lt;span class="sgml-comment"&gt;":11&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;7&lt;/span&gt;&lt;span class="sgml-comment"&gt;96,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;week_52_high&lt;/span&gt;&lt;span class="sgml-comment"&gt;":272&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;46,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;week_52_low&lt;/span&gt;&lt;span class="sgml-comment"&gt;":119&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;38,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 34&lt;/span&gt;                 &lt;span class="sgml-comment"&gt;//"&lt;/span&gt;&lt;span class="sgml-comment"&gt;day_50_moving_avg&lt;/span&gt;&lt;span class="sgml-comment"&gt;":245&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;206,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;day_200_moving_avg&lt;/span&gt;&lt;span class="sgml-comment"&gt;":214&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;119,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;price_earnings_ratio&lt;/span&gt;&lt;span class="sgml-comment"&gt;":20&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;88,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;price_earnings_growth_r&lt;/span&gt;&lt;span class="sgml-comment"&gt;atio&lt;/span&gt;&lt;span class="sgml-comment"&gt;":1&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;05,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;price_sales_ratio&lt;/span&gt;&lt;span class="sgml-comment"&gt;":4&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;38,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 35&lt;/span&gt;                 &lt;span class="sgml-comment"&gt;//"&lt;/span&gt;&lt;span class="sgml-comment"&gt;price_book_ratio&lt;/span&gt;&lt;span class="sgml-comment"&gt;":5&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;69,"&lt;/span&gt;&lt;span class="sgml-comment"&gt;short_ratio&lt;/span&gt;&lt;span class="sgml-comment"&gt;":0&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;7&lt;/span&gt;&lt;span class="sgml-comment"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 36&lt;/span&gt;                 &lt;span class="tag"&gt;if&lt;/span&gt; (hasQuotes[quote.symbol] != &lt;span class="tag"&gt;undefined&lt;/span&gt;) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 37&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;price_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol).innerHTML = quote.price;&lt;br /&gt; &lt;span class="line-number"&gt; 38&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;change_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol).innerHTML = quote.change;&lt;br /&gt; &lt;span class="line-number"&gt; 39&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;volume_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol).innerHTML = quote.volume;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 40&lt;/span&gt;                 } &lt;span class="tag"&gt;else&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 41&lt;/span&gt;                     hasQuotes[quote.symbol] = &lt;span class="tag"&gt;true&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 42&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#quotesTable &amp;gt; tbody:last&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).append(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;tr id="quote_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; +&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 43&lt;/span&gt;                         quote.symbol + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;"&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol +&lt;br /&gt; &lt;span class="line-number"&gt; 44&lt;/span&gt;                         &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;/td&amp;gt;&amp;lt;td id="price_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.price +&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 45&lt;/span&gt;                         &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;/td&amp;gt;&amp;lt;td id="change_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;" class="class_change_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; +&lt;br /&gt; &lt;span class="line-number"&gt; 46&lt;/span&gt;                         quote.change + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;/td&amp;gt;&amp;lt;td id="volume_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; +&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 47&lt;/span&gt;                         quote.symbol + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; +&lt;br /&gt; &lt;span class="line-number"&gt; 48&lt;/span&gt;                         quote.volume + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 49&lt;/span&gt;                 }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 50&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 51&lt;/span&gt;                 &lt;span class="tag"&gt;if&lt;/span&gt;(quote.change &amp;lt; 0) {&lt;br /&gt; &lt;span class="line-number"&gt; 52&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;.class_change_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol).css(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;color&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;, &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;red&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 53&lt;/span&gt;                 } &lt;span class="tag"&gt;else&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 54&lt;/span&gt;                     $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;.cla&lt;/span&gt;&lt;span class="value"&gt;ss_change_&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + quote.symbol).css(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;color&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;, &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;green&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 55&lt;/span&gt;                 }&lt;br /&gt; &lt;span class="line-number"&gt; 56&lt;/span&gt;             });&lt;br /&gt; &lt;span class="line-number"&gt; 57&lt;/span&gt;         } &lt;span class="tag"&gt;catch&lt;/span&gt; (e) {&lt;br /&gt; &lt;span class="line-number"&gt; 58&lt;/span&gt;             log(e)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 59&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt; 60&lt;/span&gt;         &lt;span class="tag"&gt;return&lt;/span&gt; &lt;span class="tag"&gt;true&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 61&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 62&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 63&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; handleSubscriptionChange (stanza) {&lt;br /&gt; &lt;span class="line-number"&gt; 64&lt;/span&gt;         &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;log&lt;/span&gt;&lt;span class="sgml-comment"&gt;("***&lt;/span&gt;&lt;span class="sgml-comment"&gt;handleSubscriptionChange&lt;/span&gt; &lt;span class="sgml-comment"&gt;Received&lt;/span&gt;&lt;span class="sgml-comment"&gt;: " + &lt;/span&gt;&lt;span class="sgml-comment"&gt;stanza&lt;/span&gt;&lt;span class="sgml-comment"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 65&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 66&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 67&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; onConnect(status) {&lt;br /&gt; &lt;span class="line-number"&gt; 68&lt;/span&gt;         &lt;span class="tag"&gt;if&lt;/span&gt; (status == Strophe.Status.CONNECTING) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 69&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;Strophe is connecting.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 70&lt;/span&gt;         } &lt;span class="tag"&gt;else&lt;/span&gt; &lt;span class="tag"&gt;if&lt;/span&gt; (status == Strophe.Status.CONNFAIL) {&lt;br /&gt; &lt;span class="line-number"&gt; 71&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;Strophe fail&lt;/span&gt;&lt;span class="value"&gt;ed to connect.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 72&lt;/span&gt;             $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#connect&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).get(0).value = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;connect&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 73&lt;/span&gt;         } &lt;span class="tag"&gt;else&lt;/span&gt; &lt;span class="tag"&gt;if&lt;/span&gt; (status == Strophe.Status.DISCONNECTING) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 74&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;Strophe is disconnecting.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 75&lt;/span&gt;         } &lt;span class="tag"&gt;else&lt;/span&gt; &lt;span class="tag"&gt;if&lt;/span&gt; (status == Strophe.Status.DISCONNECTED) {&lt;br /&gt; &lt;span class="line-number"&gt; 76&lt;/span&gt;             &lt;span class="tag"&gt;if&lt;/span&gt; (autoReconnect) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 77&lt;/span&gt;                 log( &lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;Streaming dis&lt;/span&gt;&lt;span class="value"&gt;connected. Trying to reconnect...&lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt;, METHODNAME );&lt;br /&gt; &lt;span class="line-number"&gt; 78&lt;/span&gt;                 connection.connect($(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#jid&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).get(0).value, $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#pass&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).get(0).value, onConnect);&lt;br /&gt; &lt;span class="line-number"&gt; 79&lt;/span&gt;                 log( &lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;Streaming &lt;/span&gt;&lt;span class="value"&gt;reconnected.&lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt;, METHODNAME );&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 80&lt;/span&gt;             } &lt;span class="tag"&gt;else&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 81&lt;/span&gt;                 log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;Strophe is disconnected.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 82&lt;/span&gt;                 $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#connect&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).get(0).value = &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;connect&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 83&lt;/span&gt;                 &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;publishEvent&lt;/span&gt;&lt;span class="sgml-comment"&gt;( "&lt;/span&gt;&lt;span class="sgml-comment"&gt;streamingDisconnected&lt;/span&gt;&lt;span class="sgml-comment"&gt;" );&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 84&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt; 85&lt;/span&gt;         } &lt;span class="tag"&gt;else&lt;/span&gt; &lt;span class="tag"&gt;if&lt;/span&gt; (status == Strophe.Status.CONNECTED) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 86&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;Strophe is connected.&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 87&lt;/span&gt;             &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;l&lt;/span&gt;&lt;span class="sgml-comment"&gt;og&lt;/span&gt;&lt;span class="sgml-comment"&gt;('&lt;/span&gt;&lt;span class="sgml-comment"&gt;QUOTE_BOT&lt;/span&gt;&lt;span class="sgml-comment"&gt;: &lt;/span&gt;&lt;span class="sgml-comment"&gt;Send&lt;/span&gt; &lt;span class="sgml-comment"&gt;a&lt;/span&gt; &lt;span class="sgml-comment"&gt;message&lt;/span&gt; &lt;span class="sgml-comment"&gt;to&lt;/span&gt;&lt;span class="sgml-comment"&gt; ' + &lt;/span&gt;&lt;span class="sgml-comment"&gt;connection&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;jid&lt;/span&gt;&lt;span class="sgml-comment"&gt; + ' &lt;/span&gt;&lt;span class="sgml-comment"&gt;to&lt;/span&gt; &lt;span class="sgml-comment"&gt;talk&lt;/span&gt; &lt;span class="sgml-comment"&gt;to&lt;/span&gt; &lt;span class="sgml-comment"&gt;me&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;');&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 88&lt;/span&gt;             connection.addHandler(onMessage, &lt;span class="tag"&gt;null&lt;/span&gt;, &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;message&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;, &lt;span class="tag"&gt;null&lt;/span&gt;, &lt;span class="tag"&gt;null&lt;/span&gt;, &lt;span class="tag"&gt;null&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 89&lt;/span&gt;             connection.send($pres().tree());&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 90&lt;/span&gt;             publishEvent( &lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;streamingConnected&lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt; );&lt;br /&gt; &lt;span class="line-number"&gt; 91&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt; 92&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 93&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 94&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; subscribe(symbol) {&lt;br /&gt; &lt;span class="line-number"&gt; 95&lt;/span&gt;         &lt;span class="tag"&gt;if&lt;/span&gt; (subscriptions[symbol]) &lt;span class="tag"&gt;return&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 96&lt;/span&gt;         &lt;span class="tag"&gt;try&lt;/span&gt; {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 97&lt;/span&gt;             connection.pubsub.subscribe(JID, PUBSUB, symbol, [], onQuote, handleSubscriptionChange);&lt;br /&gt; &lt;span class="line-number"&gt; 98&lt;/span&gt;             subscriptions[symbol] = &lt;span class="tag"&gt;true&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt; 99&lt;/span&gt;             log(&lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;Subscribed to &lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt; + symbol);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;100&lt;/span&gt;         } &lt;span class="tag"&gt;catch&lt;/span&gt; (e) {&lt;br /&gt; &lt;span class="line-number"&gt;101&lt;/span&gt;             alert(e)&lt;br /&gt; &lt;span class="line-number"&gt;102&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt;103&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;104&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; unsubscribe(symbol) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;105&lt;/span&gt;         &lt;span class="tag"&gt;if&lt;/span&gt; (!subscriptions[symbol]) &lt;span class="tag"&gt;return&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;106&lt;/span&gt;         &lt;span class="tag"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;107&lt;/span&gt;             connection.pubsub.unsubscribe(JID, PUBSUB, symbol, handleSubscriptionChange);&lt;br /&gt; &lt;span class="line-number"&gt;108&lt;/span&gt;             subscriptions[symbol] = &lt;span class="tag"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;109&lt;/span&gt;             log(&lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;Unsubscribed from &lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt; + symbol);&lt;br /&gt; &lt;span class="line-number"&gt;110&lt;/span&gt;         } &lt;span class="tag"&gt;catch&lt;/span&gt; (e) {&lt;br /&gt; &lt;span class="line-number"&gt;111&lt;/span&gt;             alert(e)&lt;br /&gt; &lt;span class="line-number"&gt;112&lt;/span&gt;         }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;113&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;114&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;115&lt;/span&gt;     &lt;span class="tag"&gt;function&lt;/span&gt; onMessage(msg) {&lt;br /&gt; &lt;span class="line-number"&gt;116&lt;/span&gt;         &lt;span class="tag"&gt;var&lt;/span&gt; to = msg.getAttribute(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;to&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;117&lt;/span&gt;         &lt;span class="tag"&gt;var&lt;/span&gt; from = msg.getAttribute(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;f&lt;/span&gt;&lt;span class="value"&gt;rom&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt;118&lt;/span&gt;         &lt;span class="tag"&gt;var&lt;/span&gt; type = msg.getAttribute(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;type&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt;119&lt;/span&gt;         &lt;span class="tag"&gt;var&lt;/span&gt; elems = msg.getElementsByTagName(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;body&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;120&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;121&lt;/span&gt;         &lt;span class="tag"&gt;if&lt;/span&gt; (type == &lt;span class="value"&gt;"&lt;/span&gt;&lt;span class="value"&gt;chat&lt;/span&gt;&lt;span class="value"&gt;"&lt;/span&gt; &amp;amp;&amp;amp; elems.length &amp;gt; 0) {&lt;br /&gt; &lt;span class="line-number"&gt;122&lt;/span&gt;             &lt;span class="tag"&gt;var&lt;/span&gt; body = elems[0];&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;123&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;QUOTE_BOT: I got a message from &lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + from + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;: &lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + Strophe.getText(body));&lt;br /&gt; &lt;span class="line-number"&gt;124&lt;/span&gt;             &lt;span class="tag"&gt;var&lt;/span&gt; reply = $msg({to: from, from: to, type: &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;chat&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;}).cnode(Strophe.copyElement(body));&lt;br /&gt; &lt;span class="line-number"&gt;125&lt;/span&gt;             connection.send(reply.tree());&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;126&lt;/span&gt;             log(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;QUOTE_BOT: I sent &lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + from + &lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;: &lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; + Strophe.getText(body));&lt;br /&gt; &lt;span class="line-number"&gt;127&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt;128&lt;/span&gt;         &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;we&lt;/span&gt; &lt;span class="sgml-comment"&gt;must&lt;/span&gt; &lt;span class="sgml-comment"&gt;return&lt;/span&gt; &lt;span class="sgml-comment"&gt;true&lt;/span&gt; &lt;span class="sgml-comment"&gt;to&lt;/span&gt; &lt;span class="sgml-comment"&gt;keep&lt;/span&gt; &lt;span class="sgml-comment"&gt;the&lt;/span&gt; &lt;span class="sgml-comment"&gt;handler&lt;/span&gt; &lt;span class="sgml-comment"&gt;alive&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;129&lt;/span&gt;         &lt;span class="sgml-comment"&gt;// &lt;/span&gt;&lt;span class="sgml-comment"&gt;returning&lt;/span&gt; &lt;span class="sgml-comment"&gt;false&lt;/span&gt; &lt;span class="sgml-comment"&gt;would&lt;/span&gt; &lt;span class="sgml-comment"&gt;remove&lt;/span&gt; &lt;span class="sgml-comment"&gt;it&lt;/span&gt; &lt;span class="sgml-comment"&gt;after&lt;/span&gt; &lt;span class="sgml-comment"&gt;it&lt;/span&gt; &lt;span class="sgml-comment"&gt;finishes&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;130&lt;/span&gt;         &lt;span class="tag"&gt;return&lt;/span&gt; &lt;span class="tag"&gt;true&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;131&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;132&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;133&lt;/span&gt;     $(document).ready(&lt;span class="tag"&gt;function&lt;/span&gt; () {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;134&lt;/span&gt;         connection = &lt;span class="tag"&gt;new&lt;/span&gt; Strophe.Connection(BOSH_SERVICE);&lt;br /&gt; &lt;span class="line-number"&gt;135&lt;/span&gt;         connection.rawInput = rawInput;&lt;br /&gt; &lt;span class="line-number"&gt;136&lt;/span&gt;         connection.rawOutput = rawOutput;&lt;br /&gt; &lt;span class="line-number"&gt;137&lt;/span&gt;         connection.connect(JID, PASSWORD, onConnect);&lt;br /&gt; &lt;span class="line-number"&gt;138&lt;/span&gt;         &lt;span class="sgml-comment"&gt;//&lt;/span&gt;&lt;span class="sgml-comment"&gt;connection&lt;/span&gt;&lt;span class="sgml-comment"&gt;.&lt;/span&gt;&lt;span class="sgml-comment"&gt;disconnect&lt;/span&gt;&lt;span class="sgml-comment"&gt;(&lt;/span&gt;&lt;span class="sgml-comment"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;139&lt;/span&gt;         $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#add_symbol&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).bind(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;click&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;, &lt;span class="tag"&gt;function&lt;/span&gt; () {&lt;br /&gt; &lt;span class="line-number"&gt;140&lt;/span&gt;             &lt;span class="tag"&gt;var&lt;/span&gt; symbol = $(&lt;span class="value"&gt;'&lt;/span&gt;&lt;span class="value"&gt;#symbol&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt;).get(0).value;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;141&lt;/span&gt;             subscribe(symbol);&lt;br /&gt; &lt;span class="line-number"&gt;142&lt;/span&gt;         });&lt;br /&gt; &lt;span class="line-number"&gt;143&lt;/span&gt;     });&lt;br /&gt; &lt;span class="line-number"&gt;144&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;145&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;script&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;146&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; When the document is loaded, the connection to the ejabberd server is established. Here is the form and table that is used to add subscription and display current quote information for the symbols:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;form&lt;/span&gt; &lt;span class="argument"&gt;name&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'symbols'&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;label&lt;/span&gt; &lt;span class="argument"&gt;for&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'symbol'&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;Symbol:&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;label&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;input&lt;/span&gt; &lt;span class="argument"&gt;type&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'text'&lt;/span&gt; &lt;span class="argument"&gt;id&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'symbol'&lt;/span&gt;&lt;span class="tag"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;input&lt;/span&gt; &lt;span class="argument"&gt;type&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'button'&lt;/span&gt; &lt;span class="argument"&gt;id&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'add_symbol'&lt;/span&gt; &lt;span class="argument"&gt;value&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'add&lt;/span&gt;&lt;span class="value"&gt;'&lt;/span&gt; &lt;span class="tag"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;form&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;hr&lt;/span&gt; &lt;span class="tag"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;div&lt;/span&gt; &lt;span class="argument"&gt;id&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;'log'&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;div&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;table&lt;/span&gt; &lt;span class="argument"&gt;id&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;"quotesTable"&lt;/span&gt; &lt;span class="argument"&gt;width&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;"600"&lt;/span&gt; &lt;span class="argument"&gt;border&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;"2"&lt;/span&gt; &lt;span class="argument"&gt;bordercolor&lt;/span&gt;&lt;span class="argument"&gt;=&lt;/span&gt;&lt;span class="value"&gt;"#333333"&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;thead&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;         &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;t&lt;/span&gt;&lt;span class="tag"&gt;r&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;             &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;Symbol&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;             &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;Price&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;             &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;Change&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;             &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;Volume&lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;th&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;         &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;tr&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;thead&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;tbody&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;     &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;tbody&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt; &lt;span class="tag"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;table&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; When the form is submitted, it calls subscribe method, which in turn sends request to the ejabbered server for subscription. When a new quote is received, it calls onQuote function, which inserts a row in the table when a new symbol is added or updates the quote information if it already exists.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The ejabberd, XMPP, exmpp, Bosh and Strophe provides a robust and mature solution for messaging and are especially suitable for web applications that want to build highly scalable and interactive applications. Though, above code is fairly simple, but same design principles can be used to support large number of stock quotes updates. As, we need to send stock quotes from tens of thousands symbols for every tick within a fraction of a second, the Erlang provides very scalable solution, where each symbol is simply served by an Erlang process. Finally, I am still learning more about Ejabberd’s clustering, security, and other features so that it can truly survive the production load, so I would love to hear any feedback you might have with similar solution.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-7576568671768507709?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/7576568671768507709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/05/building-stock-quote-server-in-erlang.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/7576568671768507709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/7576568671768507709'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/05/building-stock-quote-server-in-erlang.html' title='Building a stock quote server in Erlang using Ejabberd, XMPP, Bosh, Exmpp, Strophe and Yaws'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-2600708408272951238</id><published>2010-04-24T13:26:00.000-07:00</published><updated>2010-04-24T13:27:23.445-07:00</updated><title type='text'>Favorite fifteen tips from “Rework” book by Jason Fried and DHH</title><content type='html'>&lt;p&gt;I have been a long admirer of Jason Fried of 37Signals and read his first book &lt;a href="http://gettingreal.37signals.com/"&gt;Getting Real&lt;/a&gt;. Jason along with DHH have put forth many of the ideas from that book along with other ideas from their blog &lt;a href="http://37signals.com/svn/"&gt;Signal vs. Noise&lt;/a&gt; into a new book &lt;a href="http://37signals.com/rework/"&gt;Rework&lt;/a&gt;. I just finished reading it and though it reiterates many ideas from the earlier book “Getting Real” and their blogs, it’s worth re-reading those ideas as many of business companies today still runs on old fallacies. The book consists of thirteen sections and over eighty ideas, here are my favorite ideas from the book:&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Failure is not a rite of passage&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm2.static.flickr.com/1279/1350612855_72abb6dbd0.jpg"&gt;&lt;br&gt;&lt;br /&gt; I have heared the advice from startup folks about “Fail early and fail often.” On the contrary, this book shows people who learn from mistakes will make new mistakes, instead success shows what actually works. Another related avice in the book is “Reason to quit”, which shows when you can quit and choose something else. When I read &lt;a href="http://www.amazon.com/Founders-Work-Stories-Startups-Problem-Solution/dp/1430210788/ref=sr_1_2?ie=UTF8&amp;amp;s=books&amp;amp;qid=1272130595&amp;amp;sr=8-2"&gt;Founders at Work: Stories of Startups’ Early Days&lt;/a&gt;, it also showed that most startups don’t stick to their original ideas and move to other ideas based on early feedback. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Planning is Guessing&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.construx.com/File.ashx?cid=1650"&gt;&lt;br&gt;&lt;br /&gt; This is related to another advice from the book “Your estimates suck” as Planning and Estimation is hard especially in software business. I have written about &lt;a href="http://weblog.plexobject.com/?p=1647"&gt;Software Estimation&lt;/a&gt; in my &lt;a href="http://weblog.plexobject.com/?p=1647"&gt;earlier blogs&lt;/a&gt;, however most places still equate estimates with commitments. Jason and DHH reminds us again that estimates are just guesses that were made based on the best information available at the time. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Workaholism&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm3.static.flickr.com/2695/4445000495_80b5b35bf7.jpg"&gt;&lt;br&gt;&lt;br /&gt; This is another unorthodox advice that is contradictory to how most software projects are run. Most companies measure workers’ dedication on how many hours he/she put even when they are not actually producing. This is also common when managers treat estimates as commitments and refuse to admit reality when things change. We are all familiar with iron triangle of schedule/cost/functionality or sometime referred to as cost/quality/schedule or cost/resourcs/schedule. Often business folks are unwilling to change schedule and functionality, which often requires working late hours. This is also related to &lt;a href="http://weblog.plexobject.com/?p=1422"&gt;Heroism&lt;/a&gt;, which I have &lt;a href="http://weblog.plexobject.com/?p=1422"&gt;blogged&lt;/a&gt; before and go to sleep, as workholism can result in sleep deprivation, which reduces creativity and productivity.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Scratch your own itch&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Most successful businesses started with hobbies or personal interests or problems and there are tons of examples of this. This advice is also related to eat your own dog food, though not mentioned in this book.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Start making something&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm5.static.flickr.com/4048/4405944644_af6c744b30.jpg"&gt;&lt;br&gt;&lt;br /&gt; Jason and DHH reminds us another great point that ideas are cheap and the real question is how well you execute them.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Draw a line in the sand&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm2.static.flickr.com/1199/553466023_1373c87ad9.jpg"&gt;&lt;br&gt;&lt;br /&gt; One of the key characteristics of Ruby on Rails software that DHH produced is having strong opinions that limits variations. Similarly, 37Signals is known for their simple design and limited features. You can differentiate yourself from others by standing for something. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Outside money is Plan Z&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm4.static.flickr.com/3169/2964576939_ceec642c23.jpg"&gt;&lt;br&gt;&lt;br /&gt; Both DHH and Jason often talked about downside of getting money from venture capitalists and I agree that these days you can start most software startups with minimal money and raising money can be very distracting. Another related tip that “building a flip is building to flop”, which is often what startup founders hope to get out.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Start at the epicenter&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm1.static.flickr.com/29/100772750_f13a773c13.jpg"&gt;&lt;br&gt;&lt;br /&gt; This book advices you to focus on your core product. Though, this book briefly mentiosn this topic but there is a great presentation of &lt;a href="http://blog.businessofsoftware.org/2010/03/video-of-geoffrey-moore-at-business-of-software-2009.html"&gt; Video of Geoffrey Moore at Business of Software 2009 &lt;/a&gt; that talks about similar topic. This advice is also reated to other tips from the book such as “don’t copy”, “decommoditize your product”, “focus on you instead of they”, i.e., focus on your core strengths and not your competitors.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Focus on what won’t change&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm1.static.flickr.com/151/374852588_c848117565.jpg"&gt;&lt;br&gt;&lt;br /&gt; This is great advice for building business that will last. I remember when I started working at Amazon, we were told the core values of Amazon that included having a large selection, cheap prices, customer service and everything we built started from outside-in focus, i.e., it started with customers. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Get it out here&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm3.static.flickr.com/2568/4054766770_8ba3856c00.jpg"&gt;&lt;br&gt;&lt;br /&gt; This is similar to common advice from the startup and agile community, i.e. release early and release often.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Interruption is the enemy of productivity&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm4.static.flickr.com/3105/2474695970_d5603c5854.jpg"&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt; More and more research is showing that our brain can’t focus on onething at a time, and constant interruption and multi-tasking hampers your productivity. This is also somewhat related to office space is setup as many agile practices encourage more open space with pair programming and I have found that it prevents concentration. I found that private office offered from &lt;a href="http://www.amazon.com/Organizational-Patterns-Agile-Software-Development/dp/0131467409"&gt;Organizational Patterns of Agile Software Development&lt;/a&gt; provides less interruption. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Meetings are toxic&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm4.static.flickr.com/3032/2860972937_d64064742e.jpg"&gt;&lt;br&gt;&lt;br /&gt; This is another hallmark idea of 37Signals and the book contains a number of tips on making your productive such as fixed time, fewer people, clear agenda, beginning with a specific problem and ending with action items and making someone responsible for them.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Good enough is fine&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm4.static.flickr.com/3049/2956887402_4086dc1c25.jpg"&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt; 37Signals is known for their simple design and fewer features.  This is related other advice in the book such as “embrace the constraints”, “throw less at the problem”, “underdo your competitor”, “say no” and “be a curator”. When you have limited resources, you can become more creative. Also, you are better off building half a product, not a half assed product.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Make tiny decisions&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm4.static.flickr.com/3490/3306777491_a5d628ea32.jpg"&gt;&lt;br&gt;&lt;br /&gt; The authors encourage to make tiny decisions as big decisions are hard to make and hard to change. This advice is related to other tips such as “decisions are progress”, which encourages you to always make progress and “quick wins”, which encourages you to build momentum by accomplishing small tasks.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Build an audience&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://farm5.static.flickr.com/4025/4331658431_defc34a4bd.jpg"&gt;&lt;br&gt;&lt;br /&gt; The authors encourage to build audience that come back to you by writing blogs, tweets and speaking. This is also reated to “sell your by-products”, “emulate chefs”, “emulate drug dealers” and “out-teach your competitors”.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Though, I skipped many gems of advice on hiring, culture and marketing but I suggest you read the book to build long lasting and successful business.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-2600708408272951238?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/2600708408272951238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/04/favorite-fifteen-tips-from-rework-book.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2600708408272951238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2600708408272951238'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/04/favorite-fifteen-tips-from-rework-book.html' title='Favorite fifteen tips from “Rework” book by Jason Fried and DHH'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm2.static.flickr.com/1279/1350612855_72abb6dbd0_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-1229526920849424907</id><published>2010-03-18T14:00:00.000-07:00</published><updated>2010-03-18T14:19:11.820-07:00</updated><title type='text'>Smarter Email appender for Log4j with support of duplicate-removal, summary-report and JMX</title><content type='html'>I have been using SMTPAppender for a while to notify developers when something breaks on the production site and for most part it works well. However, due to some misconfiguration or service crash it can result in large number of emails. I was struck by similar problem at work when my email box suddently got tons of emails from the production site. So I decided to write a bit intelligent email appender. My goals for the appender were:&lt;br /&gt;&lt;br /&gt;* Throttle emails based on some configured time&lt;br /&gt;* Remove duplicate emails&lt;br /&gt;* Support JMX for dynamic configuration&lt;br /&gt;* Provide summary report with count of errors and their timings&lt;br /&gt;&lt;br /&gt;I created FilteredSMTPAppender class that extends SMTPAppender. The FilteredSMTPAppender defines a nested class Stats for keeping track of errors. For each unique exception, it creates an instance of Stats, that stores the first and last occurrence of this exception as well as count. The Stats class uses hash of stack trace to identify unique exceptions, however it ignores first line, which often stores some dynamic information. FilteredSMTPAppender registers iteslf as MBean so that it can be configured at runtime. It overrides append method to capture the event and overrides checkEntryConditions to add filtering. It also changes the layout so that the summary count of error messages are added to the footer of email message.&lt;br /&gt;&lt;br /&gt;The FilteredSMTPAppender uses a number of helper classes such as ServiceJMXBeanImpl for MBean definition, LRUSortedList to keep fixed cache of exceptions. Here is listing of LRUSortedList and ServiceJMXBeanImpl.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Listing of FilteredSMTPAppender.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1 package com.plexobject.log;&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;3 import java.beans.PropertyChangeEvent;&lt;br /&gt;4 import java.beans.PropertyChangeListener;&lt;br /&gt;5 import java.util.Comparator;&lt;br /&gt;&lt;br /&gt;6 import java.util.Date;&lt;br /&gt;7&lt;br /&gt;8 import javax.mail.MessagingException;&lt;br /&gt;9&lt;br /&gt;&lt;br /&gt;10 import org.apache.commons.lang.builder.EqualsBuilder;&lt;br /&gt;11 import org.apache.commons.lang.time.FastDateFormat;&lt;br /&gt;12&lt;br /&gt;13 import org.apache.log4j.Layout;&lt;br /&gt;&lt;br /&gt;14 import org.apache.log4j.net.SMTPAppender;&lt;br /&gt;15 import org.apache.log4j.spi.LoggingEvent;&lt;br /&gt;16&lt;br /&gt;17 import com.plexobject.jmx.JMXRegistrar;&lt;br /&gt;&lt;br /&gt;18 import com.plexobject.jmx.impl.ServiceJMXBeanImpl;&lt;br /&gt;19 import com.plexobject.metrics.Metric;&lt;br /&gt;20 import com.plexobject.metrics.Timer;&lt;br /&gt;&lt;br /&gt;21 import com.plexobject.util.Configuration;&lt;br /&gt;22 import com.plexobject.util.LRUSortedList;&lt;br /&gt;23&lt;br /&gt;24 public class FilteredSMTPAppender extends SMTPAppender {&lt;br /&gt;&lt;br /&gt;25&lt;br /&gt;26     private static final String SMTP_FILTER_MIN_DUPLICATE_INTERVAL_SECS = "smtp.filter.min.duplicate.interval.secs";&lt;br /&gt;27     private static final int MAX_STATS = Configuration.getInstance().getInteger("smtp.filter.max", 100);&lt;br /&gt;&lt;br /&gt;28     private static int MIN_DUPLICATE_EMAILS_INTERVAL = Configuration.getInstance().getInteger(SMTP_FILTER_MIN_DUPLICATE_INTERVAL_SECS,&lt;br /&gt;29             60); // 1 minute&lt;br /&gt;30     private static final Date STARTED = new Date();&lt;br /&gt;&lt;br /&gt;31     private static final FastDateFormat DATE_FMT = FastDateFormat.getInstance("MM/dd/yy HH:mm");&lt;br /&gt;32&lt;br /&gt;33     final static class Stats implements Comparable&lt;stats&gt; {&lt;br /&gt;&lt;br /&gt;34&lt;br /&gt;35         final int checksum;&lt;br /&gt;36         final long firstSeen;&lt;br /&gt;&lt;br /&gt;37         long lastSeen;&lt;br /&gt;38         long lastSent;&lt;br /&gt;39         int numSeen;&lt;br /&gt;&lt;br /&gt;40         int numEmails;&lt;br /&gt;41&lt;br /&gt;42         Stats(LoggingEvent event) {&lt;br /&gt;43             StringBuilder sb = new StringBuilder();&lt;br /&gt;&lt;br /&gt;44             String[] trace = event.getThrowableStrRep();&lt;br /&gt;45             for (int i = 1; i &lt; checksum =" sb.toString().hashCode();" firstseen =" lastSeen" numseen =" 1;" current =" System.currentTimeMillis();" elapsed =" current" lastseen =" current;"&gt; MIN_DUPLICATE_EMAILS_INTERVAL * 1000) {&lt;br /&gt;62                 lastSent = current;&lt;br /&gt;&lt;br /&gt;63                 numEmails++;&lt;br /&gt;64                 return true;&lt;br /&gt;65             } else {&lt;br /&gt;&lt;br /&gt;66                 return false;&lt;br /&gt;67             }&lt;br /&gt;68         }&lt;br /&gt;69&lt;br /&gt;&lt;br /&gt;70         @Override&lt;br /&gt;71         public boolean equals(Object object) {&lt;br /&gt;72             if (!(object instanceof Stats)) {&lt;br /&gt;&lt;br /&gt;73                 return false;&lt;br /&gt;74             }&lt;br /&gt;75             Stats rhs = (Stats) object;&lt;br /&gt;76             return new EqualsBuilder().append(this.checksum, rhs.checksum).isEquals();&lt;br /&gt;&lt;br /&gt;77&lt;br /&gt;78         }&lt;br /&gt;79&lt;br /&gt;80         @Override&lt;br /&gt;81         public int hashCode() {&lt;br /&gt;&lt;br /&gt;82             return checksum;&lt;br /&gt;83         }&lt;br /&gt;84&lt;br /&gt;85         @Override&lt;br /&gt;&lt;br /&gt;86         public String toString() {&lt;br /&gt;87             return " (" + checksum + ") occurred " + numSeen + " times, " + numEmails + " # of emails, first @" + DATE_FMT.format(new Date(firstSeen)) + ", last @" + DATE_FMT.format(new Date(lastSeen)) + " since server started @" + DATE_FMT.format(STARTED);&lt;br /&gt;&lt;br /&gt;88         }&lt;br /&gt;89&lt;br /&gt;90         @Override&lt;br /&gt;91         public int compareTo(Stats other) {&lt;br /&gt;&lt;br /&gt;92             return checksum - other.checksum;&lt;br /&gt;93         }&lt;br /&gt;94     }&lt;br /&gt;95&lt;br /&gt;&lt;br /&gt;96     final static class StatsCmp implements Comparator&lt;stats&gt; {&lt;br /&gt;97&lt;br /&gt;&lt;br /&gt;98         @Override&lt;br /&gt;99         public int compare(Stats first, Stats second) {&lt;br /&gt;100             return first.checksum - second.checksum;&lt;br /&gt;&lt;br /&gt;101         }&lt;br /&gt;102     }&lt;br /&gt;103     private static final LRUSortedList&lt;stats&gt; STATS_LIST = new LRUSortedList&lt;stats&gt;(&lt;br /&gt;&lt;br /&gt;104             MAX_STATS, new StatsCmp());&lt;br /&gt;105     private LoggingEvent event;&lt;br /&gt;106     private ServiceJMXBeanImpl mbean;&lt;br /&gt;107     private Layout layout;&lt;br /&gt;&lt;br /&gt;108&lt;br /&gt;109     public FilteredSMTPAppender() {&lt;br /&gt;110         mbean = JMXRegistrar.getInstance().register(getClass());&lt;br /&gt;111         mbean.addPropertyChangeListener(new PropertyChangeListener() {&lt;br /&gt;112&lt;br /&gt;&lt;br /&gt;113             @Override&lt;br /&gt;114             public void propertyChange(PropertyChangeEvent event) {&lt;br /&gt;115                 try {&lt;br /&gt;116                     if (event != null &amp;amp;&amp;amp; SMTP_FILTER_MIN_DUPLICATE_INTERVAL_SECS.equalsIgnoreCase(event.getPropertyName())) {&lt;br /&gt;&lt;br /&gt;117                         MIN_DUPLICATE_EMAILS_INTERVAL = Integer.parseInt((String) event.getNewValue());&lt;br /&gt;118                     }&lt;br /&gt;119                 } catch (Exception e) {&lt;br /&gt;120                     e.printStackTrace();&lt;br /&gt;121                 }&lt;br /&gt;&lt;br /&gt;122             }&lt;br /&gt;123         });&lt;br /&gt;124&lt;br /&gt;125     }&lt;br /&gt;126&lt;br /&gt;127     public void append(LoggingEvent event) {&lt;br /&gt;&lt;br /&gt;128         this.event = event;&lt;br /&gt;129         if (layout == null) {&lt;br /&gt;130             layout = getLayout();&lt;br /&gt;131         }&lt;br /&gt;&lt;br /&gt;132         super.append(event);&lt;br /&gt;133     }&lt;br /&gt;134&lt;br /&gt;135     protected boolean checkEntryConditions() {&lt;br /&gt;136         final Timer timer = Metric.newTimer(getClass().getSimpleName() + ".checkEntryConditions");&lt;br /&gt;&lt;br /&gt;137         try {&lt;br /&gt;138             boolean check = true;&lt;br /&gt;139             if (event != null) {&lt;br /&gt;&lt;br /&gt;140                 Stats newStats = new Stats(event);&lt;br /&gt;141                 Stats stats = STATS_LIST.get(newStats);&lt;br /&gt;142                 if (stats == null) {&lt;br /&gt;143                     stats = newStats;&lt;br /&gt;&lt;br /&gt;144                     STATS_LIST.add(stats);&lt;br /&gt;145                 } else {&lt;br /&gt;146                     check = stats.check();&lt;br /&gt;147                 }&lt;br /&gt;148                 if (check) {&lt;br /&gt;&lt;br /&gt;149                     setMessageFooter(stats);&lt;br /&gt;150                 }&lt;br /&gt;151             }&lt;br /&gt;152             return check &amp;amp;&amp;amp; super.checkEntryConditions();&lt;br /&gt;&lt;br /&gt;153         } finally {&lt;br /&gt;154             timer.stop();&lt;br /&gt;155         }&lt;br /&gt;156     }&lt;br /&gt;157&lt;br /&gt;&lt;br /&gt;158     private void setMessageFooter(Stats stats) {&lt;br /&gt;159         String message = event.getMessage().toString();&lt;br /&gt;160&lt;br /&gt;161         final String footer = "\n\n-------------------------\n" + message + " - " + stats;&lt;br /&gt;&lt;br /&gt;162&lt;br /&gt;163         if (layout != null) {&lt;br /&gt;164             setLayout(new Layout() {&lt;br /&gt;165&lt;br /&gt;&lt;br /&gt;166                 @Override&lt;br /&gt;167                 public void activateOptions() {&lt;br /&gt;168                     layout.activateOptions();&lt;br /&gt;169&lt;br /&gt;170                 }&lt;br /&gt;&lt;br /&gt;171&lt;br /&gt;172                 @Override&lt;br /&gt;173                 public String format(LoggingEvent evt) {&lt;br /&gt;174                     return layout.format(evt);&lt;br /&gt;175                 }&lt;br /&gt;&lt;br /&gt;176&lt;br /&gt;177                 @Override&lt;br /&gt;178                 public String getFooter() {&lt;br /&gt;179                     return footer;&lt;br /&gt;180                 }&lt;br /&gt;&lt;br /&gt;181&lt;br /&gt;182                 @Override&lt;br /&gt;183                 public boolean ignoresThrowable() {&lt;br /&gt;184                     return layout.ignoresThrowable();&lt;br /&gt;&lt;br /&gt;185                 }&lt;br /&gt;186             });&lt;br /&gt;187         }&lt;br /&gt;188     }&lt;br /&gt;189 }&lt;br /&gt;190&lt;br /&gt;&lt;br /&gt;191&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/pre&gt;&lt;h3&gt;Listing of ServiceJMXBeanImpl.java&lt;/h3&gt;&lt;pre&gt;&lt;br /&gt;&lt;stats&gt;&lt;stats&gt;&lt;stats&gt;&lt;stats&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/stats&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1 package com.plexobject.util;&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;3 import java.util.ArrayList;&lt;br /&gt;4 import java.util.Collection;&lt;br /&gt;5 import java.util.Collections;&lt;br /&gt;&lt;br /&gt;6 import java.util.Comparator;&lt;br /&gt;7 import java.util.Iterator;&lt;br /&gt;8 import java.util.List;&lt;br /&gt;&lt;br /&gt;9 import java.util.ListIterator;&lt;br /&gt;10&lt;br /&gt;11 import org.apache.log4j.Logger;&lt;br /&gt;12&lt;br /&gt;&lt;br /&gt;13&lt;br /&gt;14 public class LRUSortedList&lt;t&gt; implements List&lt;t&gt; {&lt;br /&gt;&lt;br /&gt;15     private static final Logger LOGGER = Logger.getLogger(LRUSortedList.class);&lt;br /&gt;16     private final int max;&lt;br /&gt;&lt;br /&gt;17     private final Comparator&lt;t&gt; comparator;&lt;br /&gt;18&lt;br /&gt;19     private final List&lt;pair&gt;&lt;long, t=""&gt;&gt; list = new ArrayList&lt;pair&gt;&lt;long, t=""&gt;&gt;();&lt;br /&gt;&lt;br /&gt;20     private final List&lt;pair&gt;&lt;long, integer=""&gt;&gt; timestamps = new ArrayList&lt;pair&gt;&lt;long, integer=""&gt;&gt;();&lt;br /&gt;&lt;br /&gt;21&lt;br /&gt;22     // comparator to sort by timestamp&lt;br /&gt;23     private static final Comparator&lt;pair&gt;&lt;long, integer=""&gt;&gt; CMP = new Comparator&lt;pair&gt;&lt;long, integer=""&gt;&gt;() {&lt;br /&gt;&lt;br /&gt;24         @Override&lt;br /&gt;25         public int compare(Pair&lt;long, integer=""&gt; first, Pair&lt;long, integer=""&gt; second) {&lt;br /&gt;&lt;br /&gt;26             if (first.getFirst() &lt;&gt; second.getFirst()) {&lt;br /&gt;&lt;br /&gt;29                 return 1;&lt;br /&gt;30             } else {&lt;br /&gt;31                 return 0;&lt;br /&gt;&lt;br /&gt;32             }&lt;br /&gt;33         }&lt;br /&gt;34     };&lt;br /&gt;35&lt;br /&gt;36     public LRUSortedList(int max, Comparator&lt;t&gt; comparator) {&lt;br /&gt;&lt;br /&gt;37         this.max = max;&lt;br /&gt;38         this.comparator = comparator;&lt;br /&gt;39     }&lt;br /&gt;40&lt;br /&gt;&lt;br /&gt;41     @Override&lt;br /&gt;42     public boolean add(T e) {&lt;br /&gt;43         if (list.size() &gt; max) {&lt;br /&gt;&lt;br /&gt;44             removeOldest();&lt;br /&gt;45         }&lt;br /&gt;46         // add object&lt;br /&gt;47         long timestamp = System.nanoTime();&lt;br /&gt;&lt;br /&gt;48         int insertionIdx = Collections.binarySearch(this, e, comparator);&lt;br /&gt;49         if (insertionIdx &lt; insertionidx =" (-insertionIdx)" t=""&gt;(timestamp, e));&lt;br /&gt;52         } else {&lt;br /&gt;&lt;br /&gt;53             // found&lt;br /&gt;54             list.set(insertionIdx, new Pair&lt;long, t=""&gt;(timestamp, e));&lt;br /&gt;55         }&lt;br /&gt;&lt;br /&gt;56&lt;br /&gt;57         // as timestamps are sorted, we just remove the oldest (first)&lt;br /&gt;58         if (timestamps.size() &gt; max) {&lt;br /&gt;&lt;br /&gt;59             timestamps.remove(0);&lt;br /&gt;60         }&lt;br /&gt;61         // update timestamp&lt;br /&gt;62         Pair&lt;long, integer=""&gt; t = new Pair&lt;long, integer=""&gt;(timestamp, insertionIdx);&lt;br /&gt;&lt;br /&gt;63         timestamps.add(t);&lt;br /&gt;64         return true;&lt;br /&gt;65     }&lt;br /&gt;66&lt;br /&gt;&lt;br /&gt;67     @Override&lt;br /&gt;68     public void add(int index, T element) {&lt;br /&gt;69         throw new UnsupportedOperationException(&lt;br /&gt;&lt;br /&gt;70                 "can't add element at arbitrary index, must use add to keep sorted order");&lt;br /&gt;71     }&lt;br /&gt;72&lt;br /&gt;73     @Override&lt;br /&gt;&lt;br /&gt;74     public boolean addAll(Collection c) {&lt;br /&gt;75         for (T e : c) {&lt;br /&gt;&lt;br /&gt;76             add(e);&lt;br /&gt;77         }&lt;br /&gt;78         return c.size() &gt; 0;&lt;br /&gt;79     }&lt;br /&gt;&lt;br /&gt;80&lt;br /&gt;81     @Override&lt;br /&gt;82     public boolean addAll(int index, Collection c) {&lt;br /&gt;&lt;br /&gt;83         throw new UnsupportedOperationException(&lt;br /&gt;84                 "can't add element at arbitrary index, must use addAll to keep sorted order");&lt;br /&gt;85     }&lt;br /&gt;&lt;br /&gt;86&lt;br /&gt;87     @Override&lt;br /&gt;88     public void clear() {&lt;br /&gt;89         list.clear();&lt;br /&gt;&lt;br /&gt;90     }&lt;br /&gt;91&lt;br /&gt;92     @SuppressWarnings("unchecked")&lt;br /&gt;93     @Override&lt;br /&gt;&lt;br /&gt;94     public boolean contains(Object e) {&lt;br /&gt;95         if (e == null) {&lt;br /&gt;96             return false;&lt;br /&gt;&lt;br /&gt;97         }&lt;br /&gt;98         try {&lt;br /&gt;99             return Collections.binarySearch(this, (T) e, comparator) &gt;= 0;&lt;br /&gt;&lt;br /&gt;100         } catch (ClassCastException ex) {&lt;br /&gt;101             LOGGER.error("Unexpected type for contains "&lt;br /&gt;102                     + e.getClass().getName() + ": " + e);&lt;br /&gt;&lt;br /&gt;103             return false;&lt;br /&gt;104         }&lt;br /&gt;105     }&lt;br /&gt;106&lt;br /&gt;107     @Override&lt;br /&gt;&lt;br /&gt;108     public boolean containsAll(Collection c) {&lt;br /&gt;109         for (Object e : c) {&lt;br /&gt;110             if (!contains(e)) {&lt;br /&gt;&lt;br /&gt;111                 return false;&lt;br /&gt;112             }&lt;br /&gt;113         }&lt;br /&gt;114         return true;&lt;br /&gt;&lt;br /&gt;115     }&lt;br /&gt;116&lt;br /&gt;117     @Override&lt;br /&gt;118     public T get(int index) {&lt;br /&gt;119         Pair&lt;long, t=""&gt; e = list.get(index);&lt;br /&gt;&lt;br /&gt;120         return e != null ? e.getSecond() : null;&lt;br /&gt;121     }&lt;br /&gt;122&lt;br /&gt;123     public T get(Object e) {&lt;br /&gt;&lt;br /&gt;124         int ndx = indexOf(e);&lt;br /&gt;125         if (ndx &gt;= 0) {&lt;br /&gt;126             return get(ndx);&lt;br /&gt;127         }&lt;br /&gt;&lt;br /&gt;128         return null;&lt;br /&gt;129     }&lt;br /&gt;130&lt;br /&gt;131     @SuppressWarnings("unchecked")&lt;br /&gt;132     @Override&lt;br /&gt;&lt;br /&gt;133     public int indexOf(Object e) {&lt;br /&gt;134         try {&lt;br /&gt;135             return Collections.binarySearch(this, (T) e, comparator);&lt;br /&gt;&lt;br /&gt;136         } catch (ClassCastException ex) {&lt;br /&gt;137             LOGGER.error("Unexpected type for get " + e.getClass().getName()&lt;br /&gt;138                     + ": " + e);&lt;br /&gt;&lt;br /&gt;139             return -1;&lt;br /&gt;140         }&lt;br /&gt;141     }&lt;br /&gt;142&lt;br /&gt;143     @Override&lt;br /&gt;144     public boolean isEmpty() {&lt;br /&gt;&lt;br /&gt;145         return list.isEmpty();&lt;br /&gt;146     }&lt;br /&gt;147&lt;br /&gt;148     @Override&lt;br /&gt;149     public Iterator&lt;t&gt; iterator() {&lt;br /&gt;&lt;br /&gt;150         final Iterator&lt;pair&gt;&lt;long, t=""&gt;&gt; it = list.iterator();&lt;br /&gt;151         return new Iterator&lt;t&gt;() {&lt;br /&gt;&lt;br /&gt;152&lt;br /&gt;153             @Override&lt;br /&gt;154             public boolean hasNext() {&lt;br /&gt;155                 return it.hasNext();&lt;br /&gt;&lt;br /&gt;156             }&lt;br /&gt;157&lt;br /&gt;158             @Override&lt;br /&gt;159             public T next() {&lt;br /&gt;160                 Pair&lt;long, t=""&gt; e = it.next();&lt;br /&gt;&lt;br /&gt;161                 return e.getSecond();&lt;br /&gt;162             }&lt;br /&gt;163&lt;br /&gt;164             @Override&lt;br /&gt;165             public void remove() {&lt;br /&gt;&lt;br /&gt;166                 it.remove();&lt;br /&gt;167             }&lt;br /&gt;168         };&lt;br /&gt;169     }&lt;br /&gt;170&lt;br /&gt;171     @Override&lt;br /&gt;&lt;br /&gt;172     public int lastIndexOf(Object o) {&lt;br /&gt;173         for (int i = list.size() - 1; i &gt;= 0; i--) {&lt;br /&gt;174             T e = get(i);&lt;br /&gt;&lt;br /&gt;175             if (e.equals(o)) {&lt;br /&gt;176                 return i;&lt;br /&gt;177             }&lt;br /&gt;178         }&lt;br /&gt;179         return -1;&lt;br /&gt;&lt;br /&gt;180     }&lt;br /&gt;181&lt;br /&gt;182     @Override&lt;br /&gt;183     public ListIterator&lt;t&gt; listIterator() {&lt;br /&gt;184         final ListIterator&lt;pair&gt;&lt;long, t=""&gt;&gt; it = list.listIterator();&lt;br /&gt;&lt;br /&gt;185         return buildListIterator(it);&lt;br /&gt;186     }&lt;br /&gt;187&lt;br /&gt;188     @Override&lt;br /&gt;189     public ListIterator&lt;t&gt; listIterator(int index) {&lt;br /&gt;&lt;br /&gt;190         final ListIterator&lt;pair&gt;&lt;long, t=""&gt;&gt; it = list.listIterator(index);&lt;br /&gt;191         return buildListIterator(it);&lt;br /&gt;192     }&lt;br /&gt;&lt;br /&gt;193&lt;br /&gt;194     @SuppressWarnings("unchecked")&lt;br /&gt;195     @Override&lt;br /&gt;196     public boolean remove(Object e) {&lt;br /&gt;&lt;br /&gt;197         try {&lt;br /&gt;198             int ndx = Collections.binarySearch(this, (T) e, comparator);&lt;br /&gt;199             if (ndx &gt;= 0) {&lt;br /&gt;&lt;br /&gt;200                 remove(ndx);&lt;br /&gt;201                 return true;&lt;br /&gt;202             } else {&lt;br /&gt;203                 return false;&lt;br /&gt;&lt;br /&gt;204             }&lt;br /&gt;205&lt;br /&gt;206         } catch (ClassCastException ex) {&lt;br /&gt;207             LOGGER.error("Unexpected type for remove " + e.getClass().getName()&lt;br /&gt;&lt;br /&gt;208                     + ": " + e);&lt;br /&gt;209             return false;&lt;br /&gt;210         }&lt;br /&gt;211     }&lt;br /&gt;&lt;br /&gt;212&lt;br /&gt;213     @Override&lt;br /&gt;214     public T remove(int index) {&lt;br /&gt;215         Pair&lt;long, t=""&gt; e = list.remove(index);&lt;br /&gt;&lt;br /&gt;216         Pair&lt;long, integer=""&gt; t = new Pair&lt;long, integer=""&gt;(e.getFirst(), 0);&lt;br /&gt;217&lt;br /&gt;218         int insertionIdx = Collections.binarySearch(timestamps, t, CMP);&lt;br /&gt;&lt;br /&gt;219         if (insertionIdx &gt;= 0) {&lt;br /&gt;220             timestamps.remove(insertionIdx);&lt;br /&gt;221         }&lt;br /&gt;222         return e != null ? e.getSecond() : null;&lt;br /&gt;&lt;br /&gt;223     }&lt;br /&gt;224&lt;br /&gt;225     @Override&lt;br /&gt;226     public boolean removeAll(Collection c) {&lt;br /&gt;&lt;br /&gt;227         boolean all = true;&lt;br /&gt;228         for (Object e : c) {&lt;br /&gt;229             all = all &amp;amp;&amp;amp; remove(e);&lt;br /&gt;&lt;br /&gt;230         }&lt;br /&gt;231         return all;&lt;br /&gt;232     }&lt;br /&gt;233&lt;br /&gt;234     @Override&lt;br /&gt;235     public boolean retainAll(Collection c) {&lt;br /&gt;&lt;br /&gt;236         boolean changed = false;&lt;br /&gt;237         Iterator it = c.iterator();&lt;br /&gt;238         while (it.hasNext()) {&lt;br /&gt;&lt;br /&gt;239             Object e = it.next();&lt;br /&gt;240             if (!contains(e)) {&lt;br /&gt;241                 it.remove();&lt;br /&gt;242                 changed = true;&lt;br /&gt;243             }&lt;br /&gt;&lt;br /&gt;244         }&lt;br /&gt;245         return changed;&lt;br /&gt;246     }&lt;br /&gt;247&lt;br /&gt;248     @Override&lt;br /&gt;&lt;br /&gt;249     public T set(int index, T element) {&lt;br /&gt;250         throw new UnsupportedOperationException();&lt;br /&gt;251     }&lt;br /&gt;&lt;br /&gt;252&lt;br /&gt;253     @Override&lt;br /&gt;254     public int size() {&lt;br /&gt;255         return list.size();&lt;br /&gt;&lt;br /&gt;256     }&lt;br /&gt;257&lt;br /&gt;258     @Override&lt;br /&gt;259     public List&lt;t&gt; subList(int fromIndex, int toIndex) {&lt;br /&gt;&lt;br /&gt;260         List&lt;t&gt; tlist = new ArrayList&lt;t&gt;();&lt;br /&gt;261         List&lt;pair&gt;&lt;long, t=""&gt;&gt; plist = list.subList(fromIndex, toIndex);&lt;br /&gt;&lt;br /&gt;262         for (Pair&lt;long, t=""&gt; e : plist) {&lt;br /&gt;263             tlist.add(e.getSecond());&lt;br /&gt;264         }&lt;br /&gt;265         return tlist;&lt;br /&gt;&lt;br /&gt;266     }&lt;br /&gt;267&lt;br /&gt;268     @Override&lt;br /&gt;269     public Object[] toArray() {&lt;br /&gt;270         return subList(0, list.size()).toArray();&lt;br /&gt;&lt;br /&gt;271     }&lt;br /&gt;272&lt;br /&gt;273     @SuppressWarnings("hiding")&lt;br /&gt;274     @Override&lt;br /&gt;275     public &lt;t&gt; T[] toArray(T[] a) {&lt;br /&gt;&lt;br /&gt;276         return subList(0, list.size()).toArray(a);&lt;br /&gt;277     }&lt;br /&gt;278&lt;br /&gt;279     @Override&lt;br /&gt;280     public String toString() {&lt;br /&gt;&lt;br /&gt;281         StringBuilder sb = new StringBuilder();&lt;br /&gt;282         Iterator&lt;t&gt; it = iterator();&lt;br /&gt;283         while (it.hasNext()) {&lt;br /&gt;&lt;br /&gt;284             sb.append(it.next() + ", ");&lt;br /&gt;285         }&lt;br /&gt;286         return sb.toString();&lt;br /&gt;287     }&lt;br /&gt;288&lt;br /&gt;&lt;br /&gt;289     private void removeOldest() {&lt;br /&gt;290         timestamps.remove(timestamps.size() - 1);&lt;br /&gt;291     }&lt;br /&gt;292&lt;br /&gt;293     private ListIterator&lt;t&gt; buildListIterator(&lt;br /&gt;&lt;br /&gt;294             final ListIterator&lt;pair&gt;&lt;long, t=""&gt;&gt; it) {&lt;br /&gt;295         return new ListIterator&lt;t&gt;() {&lt;br /&gt;&lt;br /&gt;296&lt;br /&gt;297             @Override&lt;br /&gt;298             public void add(T e) {&lt;br /&gt;299                 it.add(new Pair&lt;long, t=""&gt;(System.nanoTime(), e));&lt;br /&gt;&lt;br /&gt;300             }&lt;br /&gt;301&lt;br /&gt;302             @Override&lt;br /&gt;303             public boolean hasNext() {&lt;br /&gt;304                 return it.hasNext();&lt;br /&gt;&lt;br /&gt;305&lt;br /&gt;306             }&lt;br /&gt;307&lt;br /&gt;308             @Override&lt;br /&gt;309             public boolean hasPrevious() {&lt;br /&gt;&lt;br /&gt;310                 return it.hasPrevious();&lt;br /&gt;311&lt;br /&gt;312             }&lt;br /&gt;313&lt;br /&gt;314             @Override&lt;br /&gt;315             public T next() {&lt;br /&gt;&lt;br /&gt;316                 Pair&lt;long, t=""&gt; e = it.next();&lt;br /&gt;317                 return e.getSecond();&lt;br /&gt;318             }&lt;br /&gt;319&lt;br /&gt;320             @Override&lt;br /&gt;&lt;br /&gt;321             public int nextIndex() {&lt;br /&gt;322                 return it.nextIndex();&lt;br /&gt;323&lt;br /&gt;324             }&lt;br /&gt;&lt;br /&gt;325&lt;br /&gt;326             @Override&lt;br /&gt;327             public T previous() {&lt;br /&gt;328                 Pair&lt;long, t=""&gt; e = it.previous();&lt;br /&gt;&lt;br /&gt;329                 return e.getSecond();&lt;br /&gt;330             }&lt;br /&gt;331&lt;br /&gt;332             @Override&lt;br /&gt;333             public int previousIndex() {&lt;br /&gt;&lt;br /&gt;334                 return it.previousIndex();&lt;br /&gt;335&lt;br /&gt;336             }&lt;br /&gt;337&lt;br /&gt;338             @Override&lt;br /&gt;339             public void remove() {&lt;br /&gt;&lt;br /&gt;340                 it.remove();&lt;br /&gt;341&lt;br /&gt;342             }&lt;br /&gt;343&lt;br /&gt;344             @Override&lt;br /&gt;345             public void set(T e) {&lt;br /&gt;&lt;br /&gt;346                 it.set(new Pair&lt;long, t=""&gt;(System.nanoTime(), e));&lt;br /&gt;347&lt;br /&gt;348             }&lt;br /&gt;349         };&lt;br /&gt;350     }&lt;br /&gt;&lt;br /&gt;351&lt;br /&gt;352 }&lt;br /&gt;353&lt;br /&gt;354&lt;br /&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/t&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/long,&gt;&lt;/pair&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Listing of LRUSortedList.java&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1 package com.plexobject.jmx.impl;&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;3 import java.beans.PropertyChangeListener;&lt;br /&gt;4 import java.beans.PropertyChangeSupport;&lt;br /&gt;5 import java.util.Map;&lt;br /&gt;&lt;br /&gt;6 import java.util.concurrent.ConcurrentHashMap;&lt;br /&gt;7 import java.util.concurrent.atomic.AtomicLong;&lt;br /&gt;8&lt;br /&gt;9 import javax.management.AttributeChangeNotification;&lt;br /&gt;&lt;br /&gt;10 import javax.management.MBeanNotificationInfo;&lt;br /&gt;11 import javax.management.Notification;&lt;br /&gt;12 import javax.management.NotificationBroadcasterSupport;&lt;br /&gt;&lt;br /&gt;13 import javax.management.NotificationListener;&lt;br /&gt;14&lt;br /&gt;15 import org.apache.commons.lang.builder.EqualsBuilder;&lt;br /&gt;16 import org.apache.commons.lang.builder.HashCodeBuilder;&lt;br /&gt;&lt;br /&gt;17 import org.apache.commons.lang.builder.ToStringBuilder;&lt;br /&gt;18 import org.apache.log4j.Logger;&lt;br /&gt;19&lt;br /&gt;20 import com.plexobject.jmx.ServiceJMXBean;&lt;br /&gt;&lt;br /&gt;21 import com.plexobject.metrics.Metric;&lt;br /&gt;22 import com.plexobject.util.TimeUtils;&lt;br /&gt;23&lt;br /&gt;24 public class ServiceJMXBeanImpl extends NotificationBroadcasterSupport&lt;br /&gt;&lt;br /&gt;25         implements ServiceJMXBean, NotificationListener {&lt;br /&gt;26     private static final Logger LOGGER = Logger&lt;br /&gt;27             .getLogger(ServiceJMXBeanImpl.class);&lt;br /&gt;&lt;br /&gt;28     private Map&lt;string, string=""&gt; properties = new ConcurrentHashMap&lt;string, string=""&gt;();&lt;br /&gt;29     private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);&lt;br /&gt;&lt;br /&gt;30&lt;br /&gt;31     private final String serviceName;&lt;br /&gt;32     private AtomicLong totalErrors;&lt;br /&gt;&lt;br /&gt;33     private AtomicLong totalRequests;&lt;br /&gt;34&lt;br /&gt;35     private AtomicLong sequenceNumber;&lt;br /&gt;36     private String state;&lt;br /&gt;&lt;br /&gt;37&lt;br /&gt;38     public ServiceJMXBeanImpl(final String serviceName) {&lt;br /&gt;39         this.serviceName = serviceName;&lt;br /&gt;&lt;br /&gt;40         this.totalErrors = new AtomicLong();&lt;br /&gt;41         this.totalRequests = new AtomicLong();&lt;br /&gt;42         this.sequenceNumber = new AtomicLong();&lt;br /&gt;&lt;br /&gt;43     }&lt;br /&gt;44&lt;br /&gt;45     @Override&lt;br /&gt;46     public double getAverageElapsedTimeInNanoSecs() {&lt;br /&gt;&lt;br /&gt;47         return Metric.getMetric(getServiceName())&lt;br /&gt;48                 .getAverageDurationInNanoSecs();&lt;br /&gt;49     }&lt;br /&gt;50&lt;br /&gt;&lt;br /&gt;51     public String getProperty(final String name) {&lt;br /&gt;52         return properties.get(name);&lt;br /&gt;53     }&lt;br /&gt;&lt;br /&gt;54&lt;br /&gt;55     public void setProperty(final String name, final String value) {&lt;br /&gt;&lt;br /&gt;56         final String oldValue = properties.put(name, value);&lt;br /&gt;57         final Notification notification = new AttributeChangeNotification(this,&lt;br /&gt;&lt;br /&gt;58                 sequenceNumber.incrementAndGet(), TimeUtils&lt;br /&gt;59                         .getCurrentTimeMillis(), name + " changed", name,&lt;br /&gt;60                 "String", oldValue, value);&lt;br /&gt;61         sendNotification(notification);&lt;br /&gt;&lt;br /&gt;62         handleNotification(notification, null);&lt;br /&gt;63     }&lt;br /&gt;64&lt;br /&gt;65     @Override&lt;br /&gt;&lt;br /&gt;66     public String getServiceName() {&lt;br /&gt;67         return serviceName;&lt;br /&gt;68     }&lt;br /&gt;69&lt;br /&gt;&lt;br /&gt;70     @Override&lt;br /&gt;71     public long getTotalDurationInNanoSecs() {&lt;br /&gt;72         return Metric.getMetric(getServiceName()).getTotalDurationInNanoSecs();&lt;br /&gt;&lt;br /&gt;73     }&lt;br /&gt;74&lt;br /&gt;75     @Override&lt;br /&gt;76     public long getTotalErrors() {&lt;br /&gt;&lt;br /&gt;77         return totalErrors.get();&lt;br /&gt;78     }&lt;br /&gt;79&lt;br /&gt;80     public void incrementError() {&lt;br /&gt;&lt;br /&gt;81         final long oldErrors = totalErrors.getAndIncrement();&lt;br /&gt;82         final Notification notification = new AttributeChangeNotification(this,&lt;br /&gt;&lt;br /&gt;83                 sequenceNumber.incrementAndGet(), TimeUtils&lt;br /&gt;84                         .getCurrentTimeMillis(), "Errors changed", "Errors",&lt;br /&gt;85                 "long", oldErrors, oldErrors + 1);&lt;br /&gt;&lt;br /&gt;86         sendNotification(notification);&lt;br /&gt;87     }&lt;br /&gt;88&lt;br /&gt;89     @Override&lt;br /&gt;90     public long getTotalRequests() {&lt;br /&gt;&lt;br /&gt;91         return totalRequests.get();&lt;br /&gt;92     }&lt;br /&gt;93&lt;br /&gt;94     public void incrementRequests() {&lt;br /&gt;&lt;br /&gt;95         final long oldRequests = totalRequests.getAndIncrement();&lt;br /&gt;96         final Notification notification = new AttributeChangeNotification(this,&lt;br /&gt;&lt;br /&gt;97                 sequenceNumber.incrementAndGet(), TimeUtils&lt;br /&gt;98                         .getCurrentTimeMillis(), "Requests changed",&lt;br /&gt;99                 "Requests", "long", oldRequests, oldRequests + 1);&lt;br /&gt;&lt;br /&gt;100         sendNotification(notification);&lt;br /&gt;101     }&lt;br /&gt;102&lt;br /&gt;103     @Override&lt;br /&gt;104     public MBeanNotificationInfo[] getNotificationInfo() {&lt;br /&gt;105         String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE };&lt;br /&gt;&lt;br /&gt;106         String name = AttributeChangeNotification.class.getName();&lt;br /&gt;107         String description = "An attribute of this MBean has changed";&lt;br /&gt;108         MBeanNotificationInfo info = new MBeanNotificationInfo(types, name,&lt;br /&gt;&lt;br /&gt;109                 description);&lt;br /&gt;110&lt;br /&gt;111         return new MBeanNotificationInfo[] { info };&lt;br /&gt;112     }&lt;br /&gt;113&lt;br /&gt;&lt;br /&gt;114     @Override&lt;br /&gt;115     public String getState() {&lt;br /&gt;116         return state;&lt;br /&gt;117     }&lt;br /&gt;118&lt;br /&gt;&lt;br /&gt;119     /**&lt;br /&gt;120      * @param state&lt;br /&gt;121      *            the state to set&lt;br /&gt;&lt;br /&gt;122      */&lt;br /&gt;123     public void setState(String state) {&lt;br /&gt;124         this.state = state;&lt;br /&gt;125     }&lt;br /&gt;&lt;br /&gt;126&lt;br /&gt;127     /**&lt;br /&gt;128      * @see java.lang.Object#equals(Object)&lt;br /&gt;&lt;br /&gt;129      */&lt;br /&gt;130     @Override&lt;br /&gt;131     public boolean equals(Object object) {&lt;br /&gt;132         if (!(object instanceof ServiceJMXBeanImpl)) {&lt;br /&gt;&lt;br /&gt;133             return false;&lt;br /&gt;134         }&lt;br /&gt;135         ServiceJMXBeanImpl rhs = (ServiceJMXBeanImpl) object;&lt;br /&gt;136         return new EqualsBuilder().append(this.serviceName, rhs.serviceName)&lt;br /&gt;&lt;br /&gt;137                 .isEquals();&lt;br /&gt;138     }&lt;br /&gt;139&lt;br /&gt;140     /**&lt;br /&gt;141      * @see java.lang.Object#hashCode()&lt;br /&gt;&lt;br /&gt;142      */&lt;br /&gt;143     @Override&lt;br /&gt;144     public int hashCode() {&lt;br /&gt;145         return new HashCodeBuilder(786529047, 1924536713).append(&lt;br /&gt;&lt;br /&gt;146                 this.serviceName).toHashCode();&lt;br /&gt;147     }&lt;br /&gt;148&lt;br /&gt;149     /**&lt;br /&gt;150      * @see java.lang.Object#toString()&lt;br /&gt;&lt;br /&gt;151      */&lt;br /&gt;152     @Override&lt;br /&gt;153     public String toString() {&lt;br /&gt;154         return new ToStringBuilder(this)&lt;br /&gt;&lt;br /&gt;155                 .append("serviceName", this.serviceName).append("totalErrors",&lt;br /&gt;156                         this.totalErrors).append("totalRequests",&lt;br /&gt;157                         this.totalRequests).append("totalRequests",&lt;br /&gt;&lt;br /&gt;158                         this.totalRequests).append("state", this.state).append(&lt;br /&gt;159                         "properties", this.properties).toString();&lt;br /&gt;160     }&lt;br /&gt;&lt;br /&gt;161&lt;br /&gt;162     public void addPropertyChangeListener(PropertyChangeListener pcl) {&lt;br /&gt;163         pcs.addPropertyChangeListener(pcl);&lt;br /&gt;164     }&lt;br /&gt;165&lt;br /&gt;&lt;br /&gt;166     public void removePropertyChangeListener(PropertyChangeListener pcl) {&lt;br /&gt;167         pcs.removePropertyChangeListener(pcl);&lt;br /&gt;168&lt;br /&gt;169     }&lt;br /&gt;170&lt;br /&gt;&lt;br /&gt;171     @Override&lt;br /&gt;172     public void handleNotification(Notification notification, Object handback) {&lt;br /&gt;173         LOGGER.info("Received notification: ClassName: "&lt;br /&gt;174                 + notification.getClass().getName() + ", Source: "&lt;br /&gt;&lt;br /&gt;175                 + notification.getSource() + ", Type: "&lt;br /&gt;176                 + notification.getType() + ", tMessage: "&lt;br /&gt;177                 + notification.getMessage());&lt;br /&gt;178         if (notification instanceof AttributeChangeNotification) {&lt;br /&gt;&lt;br /&gt;179             AttributeChangeNotification acn = (AttributeChangeNotification) notification;&lt;br /&gt;180             pcs.firePropertyChange(acn.getAttributeName(), acn.getOldValue(),&lt;br /&gt;181                     acn.getNewValue());&lt;br /&gt;182&lt;br /&gt;183         }&lt;br /&gt;184     }&lt;br /&gt;&lt;br /&gt;185 }&lt;br /&gt;186&lt;br /&gt;187&lt;br /&gt;&lt;br /&gt;&lt;/string,&gt;&lt;/string,&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Testing&lt;/h3&gt; &lt;p&gt; Finally, here is how you can test this filter:&lt;/p&gt; &lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1 package com.plexobject;&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;3 import java.net.InetAddress;&lt;br /&gt;4 import java.util.Date;&lt;br /&gt;5&lt;br /&gt;&lt;br /&gt;6 import org.apache.log4j.Logger;&lt;br /&gt;7 import org.apache.log4j.PatternLayout;&lt;br /&gt;8 import org.apache.log4j.net.SMTPAppender;&lt;br /&gt;&lt;br /&gt;9&lt;br /&gt;10 import com.plexobject.log.FilteredSMTPAppender;&lt;br /&gt;11&lt;br /&gt;12 public class Main {&lt;br /&gt;&lt;br /&gt;13     private static final Logger LOGGER = Logger.getLogger(Main.class);&lt;br /&gt;14     public static void main(String[] args) {&lt;br /&gt;&lt;br /&gt;15         SMTPAppender appender = new FilteredSMTPAppender();&lt;br /&gt;16         try {&lt;br /&gt;17             appender.setTo("bhatti@xxx.com");&lt;br /&gt;18             appender.setFrom("bhatti@xxx.com");&lt;br /&gt;&lt;br /&gt;19             appender.setSMTPHost("smtp.xxx.net");&lt;br /&gt;20             appender.setLocationInfo(true);&lt;br /&gt;21             appender.setSubject("Error from " + InetAddress.getLocalHost());&lt;br /&gt;22&lt;br /&gt;&lt;br /&gt;23             appender.setLayout(new PatternLayout());&lt;br /&gt;24             appender.activateOptions();&lt;br /&gt;25             LOGGER.addAppender(appender);&lt;br /&gt;26         } catch (Exception e) {&lt;br /&gt;&lt;br /&gt;27             LOGGER.error("Failed to register smtp appender", e);&lt;br /&gt;28         }&lt;br /&gt;29         while (true) {&lt;br /&gt;30             try {&lt;br /&gt;&lt;br /&gt;31                 throw new Exception("throwing exception at " + new Date());&lt;br /&gt;32             } catch (Exception e) {&lt;br /&gt;&lt;br /&gt;33                 LOGGER.error("Logging error at " + new Date(), e);&lt;br /&gt;34             }&lt;br /&gt;35             try {&lt;br /&gt;&lt;br /&gt;36                 Thread.sleep(1000);&lt;br /&gt;37             } catch (InterruptedException e) {&lt;br /&gt;38                 Thread.interrupted();&lt;br /&gt;39             }&lt;br /&gt;40         }&lt;br /&gt;&lt;br /&gt;41     }&lt;br /&gt;42 }&lt;br /&gt;43&lt;br /&gt;44&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Above code simulates error generation every second, but it sends email based on the throttling level defined in the configuration. Obviously you can use log4j properties file to define all this configuration, e.g.&lt;/p&gt; &lt;p&gt;      &lt;!--– Send email when error happens –--&gt;&lt;br /&gt;    &lt;br /&gt;&lt;p&gt;      &amp;lt;!– Send email when error happens –&amp;gt;&lt;br&gt;&lt;br /&gt;     &amp;lt;appender name=”APP-EMAIL”  class=”com.plexobject.log.FilteredSMTPAppender”&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;param name=”BufferSize” value=”256″ /&amp;gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;         &amp;lt;param name=”SMTPHost” value=”smtp.xxx.net” /&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;param name=”From” value=”bhatti@xxx.com” /&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;param name=”To” value=”bhatti@xxx.com” /&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;param name=”Subject” value=”Production Error” /&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;layout class=”org.apache.log4j.PatternLayout”&amp;gt;&lt;br&gt;&lt;br /&gt;             &amp;lt;param name=”ConversionPattern”&lt;br&gt;&lt;br /&gt;&lt;br /&gt;               value=”[%d{ISO8601}]%n%n%-5p%n%n%c%n%n%m%n%n” /&amp;gt;&lt;br&gt;&lt;br /&gt;         &amp;lt;/layout&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;            &amp;lt;filter class=”org.apache.log4j.varia.StringMatchFilter”&amp;gt;&lt;br&gt;&lt;br /&gt;                 &amp;lt;param name=”StringToMatch” value=”My Error”/&amp;gt;&lt;br&gt;&lt;br /&gt;                 &amp;lt;param name=”AcceptOnMatch” value=”false” /&amp;gt;&lt;br&gt;&lt;br /&gt;            &amp;lt;/filter&amp;gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;/appender&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;          &lt;br /&gt;    &lt;p&gt;&lt;/p&gt; &lt;h2&gt;Summary&lt;/h2&gt; &lt;p&gt; I am skipping other classes, but you can download entire code from &lt;a href="http://weblog.plexobject.com/FilteredSMTPAppender.zip"&gt;FilteredSMTPAppender.zip&lt;/a&gt;. This solution seems to be working from me but feel free to share your experience with similar problems.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-1229526920849424907?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/1229526920849424907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/03/smarter-email-appender-for-log4j-with.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/1229526920849424907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/1229526920849424907'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/03/smarter-email-appender-for-log4j-with.html' title='Smarter Email appender for Log4j with support of duplicate-removal, summary-report and JMX'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-3156692482967190108</id><published>2010-02-03T13:55:00.000-08:00</published><updated>2010-02-03T13:56:29.694-08:00</updated><title type='text'>A few recipes for reprocessing messages in Dead-Letter-Queue using ActiveMQ</title><content type='html'>&lt;h2&gt;A few recipes for reprocessing messages in Dead-Letter-Queue using ActiveMQ&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;p&gt;Messaging based asynchronous processing is a key component of any complexed software especially in transactional environment. There are a number of solutions that provide high performance and reliable messaging in Java space such as ActiveMQ, FUSE broker, JBossMQ, SonicMQ, Weblogic, Websphere, Fiorano, etc. These providers support &lt;a href="http://java.sun.com/products/jms/docs.html"&gt;JMS specification&lt;/a&gt;, which provides abstraction for queues, message providers and message consumers. In this blog, I will go over some recipes for recovering messages from dead letter queue when using ActiveMQ.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;What is Dead Letter Queue&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Generally, when a consumer fails to process a message within a transaction or does not send acknowledgement back to the broker, the message is put back to the queue. The message is then delivered upto certain number of times based on configuration and finally the message is put to dead letter queue when that limit is exceeded. The &lt;a href="http://activemq.apache.org/message-redelivery-and-dlq-handling.html"&gt;ActiveMQ documentation&lt;/a&gt; recommends following settings for defining dead letter queues:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt;broker...&amp;gt;&lt;br /&gt;   &amp;lt;destinationPolicy&amp;gt;&lt;br /&gt;     &amp;lt;policyMap&amp;gt;&lt;br /&gt;       &amp;lt;policyEntries&amp;gt;&lt;br /&gt;         &amp;lt;!-- Set the following policy on all queues using the '&amp;gt;' wildcard --&amp;gt;&lt;br /&gt;         &amp;lt;policyEntry queue="&amp;gt;"&amp;gt;&lt;br /&gt;&lt;br /&gt;           &amp;lt;deadLetterStrategy&amp;gt;&lt;br /&gt;             &amp;lt;individualDeadLetterStrategy&lt;br /&gt;               queuePrefix="DLQ." useQueueForQueueMessages="true" /&amp;gt;&lt;br /&gt;           &amp;lt;/deadLetterStrategy&amp;gt;&lt;br /&gt;         &amp;lt;/policyEntry&amp;gt;&lt;br /&gt;       &amp;lt;/policyEntries&amp;gt;&lt;br /&gt;     &amp;lt;/policyMap&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;/destinationPolicy&amp;gt;&lt;br /&gt;   ...&lt;br /&gt; &amp;lt;/broker&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; and you can control redlivery policy as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; RedeliveryPolicy policy = connection.getRedeliveryPolicy();&lt;br /&gt; policy.setInitialRedeliveryDelay(500);&lt;br /&gt; policy.setBackOffMultiplier(2);&lt;br /&gt; policy.setUseExponentialBackOff(true);&lt;br /&gt; policy.setMaximumRedeliveries(2);&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; It is important that you create dlq per queue, otherwise ActiveMQ puts them into a single dead letter queue.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Getting the QueueViewMBean Handle&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; ActiveMQ provides QueueViewMBean to invoke administration APIs on the queues. The easiest way to get this handle is to use BrokerFacadeSupport class, which is extended by RemoteJMXBrokerFacade and LocalBrokerFacade. You can use RemoteJMXBrokerFacade if you are connecting to remote ActiveMQ server, e.g. here is Spring configuration for setting it up:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;     &amp;lt;bean id="brokerQuery" class="org.apache.activemq.web.RemoteJMXBrokerFacade" autowire="constructor" destroy-method="shutdown"&amp;gt;&lt;br /&gt;             &amp;lt;property name="configuration"&amp;gt;&lt;br /&gt;             &amp;lt;bean class="org.apache.activemq.web.config.SystemPropertiesConfiguration"/&amp;gt;&lt;br /&gt;         &amp;lt;/property&amp;gt;&lt;br /&gt;&lt;br /&gt;             &amp;lt;property name="brokerName"&amp;gt;&amp;lt;null/&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;     &amp;lt;/bean&amp;gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Alternatively, you can use LocalBrokerFacade if you are running embedded ActiveMQ server, e.g. below is Spring configuration for it:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;     &amp;lt;bean id="brokerQuery" class="org.apache.activemq.web.LocalBrokerFacade" autowire="constructor" scope="prototype"/&amp;gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Getting number of messages from the queue&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Once you got handle to QueueViewMBean, you can use following API to find the number of messages in the queue:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;long&lt;/span&gt; getQueueSize(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; String dest) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;         &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;             &lt;span class="keyword-directive"&gt;return&lt;/span&gt; brokerQuery.getQueue(dest).getQueueSize();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;             &lt;span class="keyword-directive"&gt;throw&lt;/span&gt; &lt;span class="keyword-directive"&gt;ne&lt;/span&gt;&lt;span class="keyword-directive"&gt;w&lt;/span&gt; RuntimeException(e);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Copying Messages using JMS APIs&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The JMS specification provides APIs to browse queue in read mode and then you can send the messages to another queue, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.Enumeration;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.Connection;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.ConnectionFactory;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.JMSException;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.Message;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;impor&lt;/span&gt;&lt;span class="keyword-directive"&gt;t&lt;/span&gt; javax.jms.Queue;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.QueueBrowser;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.Session;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.jms.TextMessage;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; javax.management.openmbean.CompositeData;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.apache.activemq.broker.jmx.QueueViewMBean;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.apache.activemq.web.BrokerFacadeSupport;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.springframework.jms.core.BrowserCallback;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.springframework.jms.core.JmsTemplate;&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; org.springframework.jms.core.MessageCreator;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; DlqReprocessor {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;     @Autowired&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; JmsTemplate jmsTemplate;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;     @Autowired&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;     BrokerFacadeSupport brokerQuery;&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt;     @Autowired&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;     ConnectionFactory connectionFactory;&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;30&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;31&lt;/span&gt;     @SuppressWarnings(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;unchecked&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;32&lt;/span&gt;     &lt;span class="keyword-directive"&gt;void&lt;/span&gt; redeliverDLQUsingJms(&lt;span class="keyword-directive"&gt;fina&lt;/span&gt;&lt;span class="keyword-directive"&gt;l&lt;/span&gt; String brokerName, &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String from,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;33&lt;/span&gt;             &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String to) {&lt;br /&gt; &lt;span class="line-number"&gt;34&lt;/span&gt;         Connection connection = &lt;span class="keyword-directive"&gt;null&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;35&lt;/span&gt;         Session session = &lt;span class="keyword-directive"&gt;null&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;36&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;37&lt;/span&gt;         &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;38&lt;/span&gt;             connection = connectionFactory.createConnection();&lt;br /&gt; &lt;span class="line-number"&gt;39&lt;/span&gt;             connection.start();&lt;br /&gt; &lt;span class="line-number"&gt;40&lt;/span&gt;             session = connection.createSession(&lt;span class="keyword-directive"&gt;false&lt;/span&gt;, Session.AUTO_ACKNOWLEDGE);&lt;br /&gt; &lt;span class="line-number"&gt;41&lt;/span&gt;             Queue dlq = session.createQueue(from);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;42&lt;/span&gt;             QueueBrowser browser = session.createBrowser(dlq);&lt;br /&gt; &lt;span class="line-number"&gt;43&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;44&lt;/span&gt;             Enumeration&amp;lt;Message&amp;gt; e = browser.getEnumeration();&lt;br /&gt; &lt;span class="line-number"&gt;45&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;46&lt;/span&gt;             &lt;span class="keyword-directive"&gt;while&lt;/span&gt; (e.hasMoreElements()) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;47&lt;/span&gt;                 Message message = e.nextElement();&lt;br /&gt; &lt;span class="line-number"&gt;48&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String messageBody = ((TextMessage) message).getText();&lt;br /&gt; &lt;span class="line-number"&gt;49&lt;/span&gt;                 jmsTemplate.send(to, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; MessageCreator() {&lt;br /&gt; &lt;span class="line-number"&gt;50&lt;/span&gt;                     @Override&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;51&lt;/span&gt;                     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Message createMessage(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Session session)&lt;br /&gt; &lt;span class="line-number"&gt;52&lt;/span&gt;                             &lt;span class="keyword-directive"&gt;throws&lt;/span&gt; JMSException {&lt;br /&gt; &lt;span class="line-number"&gt;53&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; session.createTextMessage(messageBody);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;54&lt;/span&gt;                     }&lt;br /&gt; &lt;span class="line-number"&gt;55&lt;/span&gt;                 });&lt;br /&gt; &lt;span class="line-number"&gt;56&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt;57&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt; &lt;span class="line-number"&gt;58&lt;/span&gt;             &lt;span class="keyword-directive"&gt;throw&lt;/span&gt; &lt;span class="keyword-directive"&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;59&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;finally&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;60&lt;/span&gt;             &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;61&lt;/span&gt;                 session.close();&lt;br /&gt; &lt;span class="line-number"&gt;62&lt;/span&gt;             } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;63&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt;64&lt;/span&gt;             &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt;65&lt;/span&gt;                 connection.close();&lt;br /&gt; &lt;span class="line-number"&gt;66&lt;/span&gt;             } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;67&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt;68&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt;69&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;70&lt;/span&gt;     &lt;span class="comment"&gt;// . . .&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;71&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;72&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt; The downside of above approach is that it leaves the original messages in the dead letter queue.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Copying Messages using Spring’s JmsTemplate APIs&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; You can effectively do the same thing with JmsTemplate provided by Spring with a bit less code, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;    &lt;span class="keyword-directive"&gt;void&lt;/span&gt; redeliverDLQUsingJmsTemplateBrowse(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; String from, &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String to) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;         &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;             jmsTemplate.browse(from, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; BrowserCallback() {&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;                 @SuppressWarnings(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;unchecked&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;                 @Override&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object doInJms(Session session, QueueBrowser browser)&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;throws&lt;/span&gt; JMSException {&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;                     Enumeration&amp;lt;Message&amp;gt; e = browser.getEnumeration();&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;                     &lt;span class="keyword-directive"&gt;while&lt;/span&gt; (e.hasMoreElements()) {&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;                         Message message = e.nextElement();&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String messageBody = ((TextMessage) message)&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;                                 .getText();&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;                         jmsTemplate.send(to, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; MessageCreator() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;                             @Override&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;                             &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Message createMessage(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Session session)&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;                                     &lt;span class="keyword-directive"&gt;throws&lt;/span&gt; JMSException {&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;                                 &lt;span class="keyword-directive"&gt;return&lt;/span&gt; session.createTextMessage(messageBody);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;                             }&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;                         });&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;                     }&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;                     &lt;span class="keyword-directive"&gt;return&lt;/span&gt; &lt;span class="keyword-directive"&gt;null&lt;/span&gt;;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;                 }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;             });&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt;             &lt;span class="keyword-directive"&gt;throw&lt;/span&gt; &lt;span class="keyword-directive"&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt;         }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Moving Messages using receive/send APIs&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; As I mentioned, the above approaches leave messages in the DLQ, which may not be what you want. Thus, another simple approach would be to consume messages from the dead letter queue and send it to another,e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;   &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; redeliverDLQUsingJmsTemplateReceive(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; String from,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;             &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String to) {&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;         &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;             jmsTemplate.setReceiveTimeout(100);&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;             Message message = &lt;span class="keyword-directive"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;             &lt;span class="keyword-directive"&gt;while&lt;/span&gt; ((message = jmsTemplate.receive(from)) != &lt;span class="keyword-directive"&gt;null&lt;/span&gt;) {&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String messageBody = ((TextMessage) message).getText();&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;                 jmsTemplate.send(to, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; MessageCreator() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;                     @Override&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;                     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Message createMessage(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Session session)&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;                             &lt;span class="keyword-directive"&gt;throws&lt;/span&gt; JMSException {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; session.createTextMessage(messageBody);&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;                     }&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;                 });&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;             &lt;span class="keyword-directive"&gt;throw&lt;/span&gt; &lt;span class="keyword-directive"&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Moving Messages using ActiveMQ’s API&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Finally, the best approach I found waas to use ActiveMQ’s APIs to move messags, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; redeliverDLQUsingJMX(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; String brokerName, &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String from,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;             &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String to) {&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;         &lt;span class="keyword-directive"&gt;try&lt;/span&gt; {&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;             &lt;span class="keyword-directive"&gt;final&lt;/span&gt; QueueViewMBean queue = brokerQuery.getQueue(from);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;             &lt;span class="keyword-directive"&gt;fo&lt;/span&gt;&lt;span class="keyword-directive"&gt;r&lt;/span&gt; (&lt;span class="keyword-directive"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10 &amp;amp;&amp;amp; queue.getQueueSize() &amp;gt; 0; i++) {&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;                 CompositeData[] compdatalist = queue.browse();&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;for&lt;/span&gt; (CompositeData cdata : compdatalist) {&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;                     String messageID = (String) cdata.get(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;JMSMessageID&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;                     queue.moveMessageTo(messageID, to);&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;                 }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;             }&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;         } &lt;span class="keyword-directive"&gt;catch&lt;/span&gt; (Exception e) {&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;             &lt;span class="keyword-directive"&gt;throw&lt;/span&gt; &lt;span class="keyword-directive"&gt;new&lt;/span&gt; RuntimeException(e);&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;         }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; I have been using this approach and have found to be reliable for reprocessing dead letter queue, though these techniques an also be used for general queues. I am sure there are tons of alternatives including using full-fledged enterprise service bus route. Let me know if you have interesting solutions to this problem.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-3156692482967190108?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/3156692482967190108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/02/few-recipes-for-reprocessing-messages.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/3156692482967190108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/3156692482967190108'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/02/few-recipes-for-reprocessing-messages.html' title='A few recipes for reprocessing messages in Dead-Letter-Queue using ActiveMQ'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-5816276616170847138</id><published>2010-01-20T14:06:00.000-08:00</published><updated>2010-01-20T14:07:05.212-08:00</updated><title type='text'>PlexRBAC: an open source project for providing powerful role based security (II)</title><content type='html'>This is continuation of my &lt;a href="http://weblog.plexobject.com/?p=1670"&gt;previous blog&lt;/a&gt; on my open source project &lt;a href="http://github.com/bhatti/PlexRBAC"&gt;PlexRBAC&lt;/a&gt; for managing role based access control. Last time, I covered REST APIs and in this blog I will cover internal domain model, RBAC APIs in Java and examples of instance or dynamic based security. &lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Layers&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; PlexRBAC consists of following layers&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Business Domain Layer&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; This layer defines core classes that are part of the RBAC based security domain such as:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Domain – As described previously, the domain allows you to support multiple applications or realms.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Subject – The subject represents users who are defined in an application.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Role – A role represents job title or function.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Permission – A permission is composed of operation, target and an expression that is used for dynamic or instance based security.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SecurityError – Upon a permission failure, you can choose to store them in the database using SecurityError.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Repository Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer is responsible for accessing or storing above objects in the database. PlexRBAC uses Berkley DB for persistence and each domain is stored as a separate database, which allows you to segregate permissions and roles for distinct domains. Following are list of repositories supported by PlexRBAC:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;DomainRepository – provides database access for Domains.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;PermissionRepository – provides database access for Permissions.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SubjectRepository – provides database access for Subjects.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SecurityErrorRepository – provides database access for SecurityErrors.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;RoleRepository – provides database access for Roles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SecurityMappingRepository – provides APIs to map permissions with roles and to map subject with roles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;RepositoryFactory – provides factory methods to create above repositories.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Security Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This class defines PermissionManager for authorizing permissions.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Evaluation Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer proivdes evaluation engine for instance based security.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Service Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer defines REST services such as:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;DomainService – this service provides REST APIs for accessing Domains.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;PermissionService – this service provides REST APIs for accessing Permissions.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SubjectService – this service provides REST APIs for accessing Subjects.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;RoleService – this service provides REST APIs for accessing Roles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;AuthenticationService – this service provides REST APIs for authenticating users.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;AuthorizationService – this service provides REST APIs for authorizing permissions.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;RolePermissionService – this service provides REST APIs for mapping permissions with roles.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SubjectRolesService – this service provides REST APIs for mapping subjects with roles.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;JMX Layer&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; This layer defines JMX helper classes for managing services and configuration remotely.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Caching Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer provides caching security permissions to improve performance.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Metrics Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer provides performance measurement classes such as Timing class to measure method invocation benchmarks.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Utility Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer provides helper classes.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Web Layer&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; This layer provides filters for enforcing authentication and authorization when accessing REST APIs.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Example&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Let’s use the same example that we described last time but with addition of instance based security.  Let’s assume there are five roles: Teller, Customer-Service-Representative (CSR), Account, AccountingManager and LoanOfficer, where&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A teller can modify customer deposit accounts — but only if customer and teller live in same region&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A customer service representative can create or delete customer deposit accounts — but only if customer and teller live in same region&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An accountant can create general ledger reports — but only if year is == current year&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An accounting manager can modify ledger-posting rules  — but only if year is == current year&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A loan officer can create and modify loan accounts – but only if account balance is &amp;lt; 10000&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; In addition, following classes will be used to add domain specific security:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; User {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String id;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String region;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;     User() {&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; User(String id, String region) {&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.id = id;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.region = region;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; setRegion(String region) {&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.region = region;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getRegion() {&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; region;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; setId(String id) {&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.id = id;&lt;br /&gt; &lt;span class="line-number"&gt;25&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;27&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getId() {&lt;br /&gt; &lt;span class="line-number"&gt;28&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; id;&lt;br /&gt; &lt;span class="line-number"&gt;29&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;30&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;31&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;32&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Customer &lt;span class="keyword-directive"&gt;extends&lt;/span&gt; User {&lt;br /&gt; &lt;span class="line-number"&gt;33&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;34&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Customer(String id, String region) {&lt;br /&gt; &lt;span class="line-number"&gt;35&lt;/span&gt;         &lt;span class="keyword-directive"&gt;super&lt;/span&gt;(id, region);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;36&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;37&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;38&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;39&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Employee &lt;span class="keyword-directive"&gt;extends&lt;/span&gt; User {&lt;br /&gt; &lt;span class="line-number"&gt;40&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;41&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Employee(String id, String region) {&lt;br /&gt; &lt;span class="line-number"&gt;42&lt;/span&gt;         &lt;span class="keyword-directive"&gt;super&lt;/span&gt;(id, region);&lt;br /&gt; &lt;span class="line-number"&gt;43&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;44&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;45&lt;/span&gt; &lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;46&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Account {&lt;br /&gt; &lt;span class="line-number"&gt;47&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;48&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String id;&lt;br /&gt; &lt;span class="line-number"&gt;49&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; &lt;span class="keyword-directive"&gt;double&lt;/span&gt; balance;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;50&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;51&lt;/span&gt;     Account() {&lt;br /&gt; &lt;span class="line-number"&gt;52&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;53&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;54&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Account(String id, &lt;span class="keyword-directive"&gt;double&lt;/span&gt; balance) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;55&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.id = id;&lt;br /&gt; &lt;span class="line-number"&gt;56&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.balance = balance;&lt;br /&gt; &lt;span class="line-number"&gt;57&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;58&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;59&lt;/span&gt;     &lt;span class="comment"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;60&lt;/span&gt; &lt;span class="comment"&gt;     * &lt;/span&gt;&lt;span class="ST0"&gt;@return&lt;/span&gt; &lt;span class="comment"&gt;the&lt;/span&gt; &lt;span class="comment"&gt;id&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;61&lt;/span&gt;      &lt;span class="comment"&gt;*/&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;62&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getId() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;63&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; id;&lt;br /&gt; &lt;span class="line-number"&gt;64&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;65&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;66&lt;/span&gt;     &lt;span class="comment"&gt;/**&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;67&lt;/span&gt; &lt;span class="comment"&gt;     * &lt;/span&gt;&lt;span class="ST0"&gt;@param&lt;/span&gt; &lt;span class="comment"&gt;id&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;68&lt;/span&gt; &lt;span class="comment"&gt;     *            &lt;/span&gt;&lt;span class="comment"&gt;the&lt;/span&gt; &lt;span class="comment"&gt;id&lt;/span&gt; &lt;span class="comment"&gt;to&lt;/span&gt; &lt;span class="comment"&gt;set&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;69&lt;/span&gt;      &lt;span class="comment"&gt;*/&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;70&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; setId(String id) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;71&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.id = id;&lt;br /&gt; &lt;span class="line-number"&gt;72&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;73&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;74&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; setBalance(&lt;span class="keyword-directive"&gt;double&lt;/span&gt; balance) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;75&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.balance = balance;&lt;br /&gt; &lt;span class="line-number"&gt;76&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;77&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;78&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;double&lt;/span&gt; getBalance() {&lt;br /&gt; &lt;span class="line-number"&gt;79&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; balance;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;80&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;81&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;82&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;83&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Bootstrapping&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Let’s create handle to repository-factory as:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; &lt;span class="keyword-directive"&gt;static&lt;/span&gt; &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String TEST_DB_DIR = &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;test_db_dir_perms&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;     RepositoryFactory repositoryFactory = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; RepositoryFactoryImpl(TEST_DB_DIR);&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; And instance of permission manager as:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt; PermissionManager permissionManager = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionManagerImpl(repositoryFactory,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;             &lt;span class="keyword-directive"&gt;new&lt;/span&gt; JavascriptEvaluator());&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Creating a domain&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Now, let’s create a domain for banking:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; &lt;span class="keyword-directive"&gt;static&lt;/span&gt; &lt;span class="keyword-directive"&gt;final&lt;/span&gt; String BANKING = &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;banking&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     repositoryFactory.getDomainRepository().save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Domain(BANKING, &lt;span class="character"&gt;""&lt;/span&gt;));&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Creating Users&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Next step is to create users for the domain or application so let’s define accounts for tom, cassy, ali, mike and larry, i.e.,&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;         &lt;span class="keyword-directive"&gt;final&lt;/span&gt; SubjectRepository subjectRepo = repositoryFactory&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;                 .getSubjectRepository(BANKING);&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         Subject tom = subjectRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Subject(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;tom&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;pass&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         Subject cassy = subjectRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Subject(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;cassy&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;pass&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;         Subject ali = subjectRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Subject(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;ali&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;pass&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;         Subject mike = subjectRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Subject(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;mike&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;pass&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;         Subject larry = subjectRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Subject(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;larry&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;pass&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Creating Roles&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Now, we will create roles for Teller, CSR, Accountant, AccountManager and LoanManager:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;         &lt;span class="keyword-directive"&gt;final&lt;/span&gt; RoleRepository roleRepo = repositoryFactory&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;                 .getRoleRepository(BANKING);&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;         Role employee = roleRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;Employee&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;));&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;         Role teller = roleRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;Teller&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, employee));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;         Role csr = roleRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;CSR&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, teller));&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;         Role accountant = roleRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;Accountant&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, employee));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;         Role accountantMgr = roleRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;AccountingManager&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;                 accountant));&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;         Role loanOfficer = roleRepo&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;                 .save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Role(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;LoanOfficer&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, accountantMgr));&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Creating Permissions&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; We can then create new permissions and save them in the database as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;         &lt;span class="keyword-directive"&gt;final&lt;/span&gt; PermissionRepository permRepo = repositoryFactory&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;                 .getPermissionRepository(BANKING);&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;         Permission cdDeposit = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(create|delete)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;DepositAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;employee.getRegion().equals(customer.getRegion())&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;         Permission ruDeposit = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(read|modify)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;DepositAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;employee.getRegion().equals(customer.getRegion())&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;         Permission cdLoan = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(create|delete)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;LoanAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account.getBalance() &amp;lt; 10000&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;         Permission ruLoan = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(read|modify)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;LoanAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account.getBalance() &amp;lt; 10000&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;         Permission rdLedger = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(read|create)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedger&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year == new Date().getFullYear()&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt;         Permission rGlpr = permRepo&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;                 .save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;read&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedgerPostingRules&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt;                         &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year == new Date().getFullYear()&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;         Permission cmdGlpr = permRepo.save(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Permission(&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;(create|modify|delete)&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedgerPostingRules&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year == new Date().getFullYear()&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;)); &lt;span class="comment"&gt;// 7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;24&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Mapping Subjects/Permissions to Roles&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Now we will map subjects to roles as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;         &lt;span class="keyword-directive"&gt;final&lt;/span&gt; SecurityMappingRepository smr = repositoryFactory&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;                 .getSecurityMappingRepository(BANKING);&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         &lt;span class="comment"&gt;// Mapping Users to Roles&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;         smr.addRolesToSubject(tom, teller);&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;         smr.addRolesToSubject(cassy, csr);&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;         smr.addRolesToSubject(ali, accountant);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;         smr.addRolesToSubject(mike, accountantMgr);&lt;br /&gt; &lt;span class="line-number"&gt;9&lt;/span&gt;         smr.addRolesToSubject(larry, loanOfficer);&lt;br /&gt; &lt;span class="line-number"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we will map permissions to roles as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;         smr.addPermissionsToRole(teller, ruDeposit);&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;         smr.addPermissionsToRole(csr, cdDeposit);&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         smr.addPermissionsToRole(accountant, rdLedger);&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         smr.addPermissionsToRole(accountant, ruLoan);&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;         smr.addPermissionsToRole(accountantMgr, cdLoan);&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;         smr.addPermissionsToRole(accountantMgr, rGlpr);&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;         smr.addPermissionsToRole(loanOfficer, cmdGlpr);&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Authorization&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Now the fun part of authorization, let’s check if user “tom” can view deposit-accounts, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt;    &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;static&lt;/span&gt; Map&amp;lt;String, Object&amp;gt; toMap(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Object... keyValues) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;         Map&amp;lt;String, Object&amp;gt; map = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; HashMap&amp;lt;String, Object&amp;gt;();&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;         &lt;span class="keyword-directive"&gt;for&lt;/span&gt; (&lt;span class="keyword-directive"&gt;int&lt;/span&gt; i = 0; i &amp;lt; keyValues.length - 1; i += 2) {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;             map.put(keyValues[i].toString(), keyValues[i + 1]);&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;         }&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; map;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;     @Test&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testReadDepositByTeller() {&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;tom&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;read&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;DepositAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;employee&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Employee(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;tom&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;                         &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;), &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;customer&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Customer(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;))));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Note that above test method builds a PermissionRequest that encapsulates domain, subject, operation, target and context and then calls check method of SecurityManager, which throws SecurityException if permission fails.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Then we check if tom, the teller can delete deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test(expected = SecurityException.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testDeleteByTeller() {&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;t&lt;/span&gt;&lt;span class="character"&gt;om&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;delete&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;DepositAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;employee&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Employee(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;tom&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;), &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;customer&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Customer(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;))));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which would throw security exception.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; Now let’s check if cassy, the CSR can delete deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testDeleteByCsr() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;cass&lt;/span&gt;&lt;span class="character"&gt;y&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;delete&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;DepositAccount&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;employee&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Employee(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;cassy&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;), &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;customer&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Customer(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;west&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;))));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which works as CSR have permissions for deleting deposit-account. Now, let’s check if ali, the accountant can view general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;    @Test&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testReadLedgerByAccountant() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;ali&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;read&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedger&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 2010, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Account(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 500))));&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;9&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which works as expected. Next we check if ali can delete general-ledger:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test(expected = SecurityException.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testDeleteLedgerByAccountant() {&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;ali&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;delete&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedger&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 2010, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Account(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 500))));&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;9&lt;/span&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which would fail as only account-manager can delete. Next we check if mike, the account-manager can create general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testCreateLedgerByAccountantManager() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;mike&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;create&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedger&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 2010,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Account(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 500))));&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which works as expected. Now we check if mike can create posting-rules of general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test(expected = SecurityException.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testPostLedgingRulesByAccountantManager() {&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;mike&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;create&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedgerPostingRules&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         2010, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Account(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 500))));&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which fails authorization. Then we check if larry, the loan officer can create posting-rules of general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testPostLedgingRulesByLoanManager() {&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;larry&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;create&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedgerPostingRules&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         2010, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;account&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Account(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;zak&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, 500))));&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which works as expected. Now, let’s check the same permission but with different year, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &lt;span class="line-number"&gt;1&lt;/span&gt;     @Test(expected = SecurityException.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; testPostLedgingRulesByLoanManagerWithExceededAmount() {&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt;         initDatabase();&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;         permissionManager.check(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PermissionRequest(BANKING, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;larry&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;                 &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;create&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, &lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;GeneralLedgerPostingRules&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;, IDUtils.toMap(&lt;span class="character"&gt;"&lt;/span&gt;&lt;span class="character"&gt;year&lt;/span&gt;&lt;span class="character"&gt;"&lt;/span&gt;,&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;                         2011)));&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Which fails as year doesn’t match.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Above examples demonstrate how PlexRBAC API can be used along with instance or dynamic based security. In next post, I will describe caching and how PlexRBAC can be integrated with J2EE and Spring security.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-5816276616170847138?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/5816276616170847138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/01/plexrbac-open-source-project-for_20.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/5816276616170847138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/5816276616170847138'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/01/plexrbac-open-source-project-for_20.html' title='PlexRBAC: an open source project for providing powerful role based security (II)'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-9209100224680415385</id><published>2010-01-10T20:35:00.000-08:00</published><updated>2010-01-10T20:36:27.707-08:00</updated><title type='text'>PlexRBAC: an open source project for providing powerful role based security (I)</title><content type='html'>&lt;h2&gt;Overview&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; In my &lt;a href="http://weblog.plexobject.com/?p=1669"&gt;last blog&lt;/a&gt; I described core pieces of a security system and mentioned a new open source project &lt;a href="http://github.com/bhatti/PlexRBAC"&gt;PlexRBAC&lt;/a&gt; I recently started to provide Role Based Security both as a REST service and Java library. In this post, I will go over the some of the features that are now available. This project is based on my experience with a number of home built solutions for RBAC and standard J2EE solutions. However, a key differentiator is that it adds instance based security or context based security that adds dynamic access control. The role based security consists of following components:&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Domain&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Though, domain is strictly not part of role based security but RBAC provides segregation of security policies by domains, where a domain can represent a security realm or an application.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Subject&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The subject represents users who are defined in an application.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Role&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; A role represents job title or function. A subject or user belongs to one or more roles. One of key feature of PlexRBAC is that roles support inheritance where a role can have one or more roles. This helps define security policies that follow “don’t repeat yourself” or DRY.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Permission&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; A permission consists of two sub parts: operation and target, where operation is a “verb” that describes action and target represents “object” that is acted upon. All permissions are assigned to roles. In PlexRBAC, permissions also contains an expression which is evaluated to check dynamic security. PlexRBAC allows Javascript based expressions and provides access to runtime request parameters. Finally, PlexRBAC offers &lt;b&gt;regular expressions&lt;/b&gt; for both operations and target, so you can define operations like “(read|write|create|delete)” or “read*”, etc.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; Following diagram shows the relationship between these components:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; &lt;img src="http://www.gliffy.com/pubdoc/1951045/M.jpg"&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;h2&gt;Getting Started&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; &lt;a href="http://github.com/bhatti/PlexRBAC"&gt;PlexRBAC&lt;/a&gt; depends on Java 1.6+ and Maven 2.0+. You can download the project using git:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; git clone git@github.com:bhatti/PlexRBAC.git&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Then you can start the REST based web service within Jetty by typing:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; mvn jetty:run-war&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; The service will listen on port 8080 and you can test it with curl.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Authentication&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Though, PlexRBAC is not designed for authentication but it provides Basic authentication and all administration APIs are protected with the authentication. By default, it uses an account “super_admin” with password “changeme”, which you can modify with configurations. Also, as PlexRBAC supports domains to segregates security policies, subjects are also restricted to the domains where they are defined.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;REST APIs&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Following are APIs defined in PlexRBAC:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Domains&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;GET /api/security/domains – returns list of all domains in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;GET /api/security/domains/{domain-id} – returns details of given domain in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;PUT /api/security/domains/{domain-id} with body of domain details in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/domains – deletes all domains.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/domains/{domain-id} – deletes domain identified by domain-id.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Subjects&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;GET /api/security/subjects/{domain-id} – returns list of all subjects in domain identified by domain-id in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;GET /api/security/subjects/{domain-id}/{id} – returns details of given subject identified by id in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;PUT /api/security/subjects/{domain-id}/{id} with body of subject details in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/subjects/{domain-id} – deletes all subjects in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/subjects/{domain-id}/{id} – deletes subject identified by id.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Roles&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;GET /api/security/roles/{domain-id} – returns list of all roles in domain identified by domain-id in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;GET /api/security/roles/{domain-id}/{id} – returns details of given role identified by id in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;PUT /api/security/roles/{domain-id}/{id} with body of role details in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/roles/{domain-id} – deletes all roles in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/roles/{domain-id}/{id} – deletes role identified by id.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Permissions&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;GET /api/security/permissions/{domain-id} – returns list of all permissions in domain identified by domain-id in JSON format.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;GET /api/security/permissions/{domain-id}/{id} – returns details of given permission identified by id in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;POST /api/security/permissions/{domain-id} with body of permission details in JSON format. Note that this API uses POST instead of PUT as the id will be assigned by the server.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/permissions/{domain-id} – deletes all permissions in given domain.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/permissions/{domain-id}/{id} – deletes permission identified by id.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Mapping of Roles and Permissions&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;PUT /api/security/role_perms/{domain-id}/{role-id} – adds permissions identified by permissionIds that stores list of permission-ids in JSON format. Note that permissionIds is passed as a form parameter.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/role_perms/{domain-id}/{role-id} – removes permissions identified by permissionIds that stores list of permission-ids in JSON format. Note that permissionIds is passed as a form parameter.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Mapping of Subjects and Roles&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;PUT /api/security/subject_roles/{domain-id}/{subject-id} – adds roles identified by rolenames that stores list of role-ids in JSON format. Note that rolenames is passed as a form parameter.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;DELETE /api/security/subject_roles/{domain-id}/{subject-id} – removes roles identified by rolenames that stores list of role-ids in JSON format. Note that rolenames is passed as a form parameter.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Authorization&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;GET /api/security/authorize/{domain-id} – with query parameter of operation and target.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Example&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Let’s start with a banking example where a bank-object can be account, general-ledger-report or ledger-posting-rules and account is further grouped into customer account or loan account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; &lt;img src="http://www.gliffy.com/pubdoc/1951059/M.jpg"&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; Let’s assume there are five roles: Teller, Customer-Service-Representative (CSR), Account, AccountingManager and LoanOfficer, where&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A teller can modify customer deposit accounts.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A customer service representative can create or delete customer deposit accounts.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An accountant can create general ledger reports.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An accounting manager can modify ledger-posting rules.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A loan officer can create and modify loan accounts.&lt;br /&gt; &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Creating a domain&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The first thing is to create a security domain for your application. As we are dealing with banking domain, let’s call our domain “banking”. &lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/domains/banking" -d '{"id":"banking"}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; It will return response:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"banking","ownerSubjectNames":"super_admin"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; The first thing to note that we are passing user and password using Basic authentication as all accesses to administration APIs require login. Now, you can find out available domains via&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "super_admin:changeme" "http://localhost:8080/api/security/domains"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which would return something like:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; [{"id":"banking","ownerSubjectNames":"super_admin"},{"description":"default","id":"default","ownerSubjectNames":"super_admin"}]&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Creating Users&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Next step is to create users for the domain or application so let’s define accounts for tom, cassy, ali, mike and larry, i.e.,&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"tom","credentials":"pass"}'&lt;br /&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"cassy","credentials":"pass"}'&lt;br /&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"ali","credentials":"pass"}'&lt;br /&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"mike","credentials":"pass"}'&lt;br /&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subjects/banking" -d '{"id":"larry","credentials":"pass"}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Note that each user is identified by an id or username and credentials and in above examples usernames or subject-ids are prefixed with domain-ids, e.g. “ddefault:super_admin”. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Creating Roles&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; As I mentioned, a role represents job title or responsibilities and each role can have one or more parents. By default, PlexRBAC defines an “anonymous” role, which is used for users who are not logged in and all user-defined roles extend “anonymous” role.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; &lt;img src="http://www.gliffy.com/pubdoc/1951572/M.jpg"&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; First, we create a role for bank employee called “Employee”:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Employee"}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; which returns&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"Employee","parentIds":["anonymous"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; As you can see the “Employee” role is created with parent of “anonymous”. Next, we create “Teller” role:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Teller","parentIds":["Employee"]}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"Teller","parentIds":["Employee"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Then we create a role for customer-service-representative called “CSR” that is extended by Teller e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"CSR","parentIds":["Teller"]}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"CSR","parentIds":["Teller"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we create a role for “Accountant”:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"Accountant","parentIds":["Employee"]}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"Accountant","parentIds":["Employee"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we create a role for “AccountingManager”, which is extended by “Accountant”, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"AccountingManager","parentIds":["Accountant"]}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"AccountingManager","parentIds":["Accountant"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Finally, we create a role for “LoanOfficer”, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/roles/banking" -d '{"id":"LoanOfficer","parentIds":["Employee"]}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"id":"LoanOfficer","parentIds":["Employee"]}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Creating Permissions&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; As described above, a permission is composed of operation, target and expression, where an operation and target can be any regular expression and expression can be any Javascript expression. However following permissions don’t define any expressions for simplicity. First, we create a permission to create or delete deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(create|delete)","target":"DepositAccount","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"1","operation":"(create|delete)","target":"DepositAccount"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Each permission is automatically assigned a unique numeric id. Next, we create a permission to read or modify deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|modify)","target":"DepositAccount","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"2","operation":"(read|modify)","target":"DepositAccount"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then, we create a permission to create or delete loan-account&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(create|delete)","target":"LoanAccount","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"3","operation":"(create|delete)","target":"LoanAccount"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we create a permission to read or modify loan-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|modify)","target":"LoanAccount","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"4","operation":"(read|modify)","target":"LoanAccount"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we create a role to view and create general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|create)","target":"GeneralLedger","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"5","operation":"(read|create)","target":"GeneralLedger"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Finally, we create a permission for modifying posting rules of general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X POST "http://localhost:8080/api/security/permissions/banking" -d '{"operation":"(read|create|modify|delete)","target":"GeneralLedgerPostingRules","expression":""}'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; {"expression":"","id":"6","operation":"(read|create|modify|delete)","target":"GeneralLedgerPostingRules"}&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Mapping Permissions to Roles&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Next task is to map permissions to roles. First we assign permission to view or modify customer deposit accounts to Teller role:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/Teller" -d 'permissionIds=["2"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns all permission-ids for given role, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; ["2"]&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we assign permission to view, create, modify or delete customer deposit accounts to CSR (as CSR extends Teller it will automatically will get all permissions of Teller):&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/CSR" -d 'permissionIds=["1"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Then we assign permissions to create general ledger to Accountant:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/Accountant" -d 'permissionIds=["5"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we assign permission to modify ledger-posting rules to AccountingManager:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/role_perms/banking/AccountingManager" -d 'permissionIds=["6"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Mapping Users to Roles&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; A role is associated with one or more permissions and each user is assigned one or more role. First, we assign subject “tom” to Teller role:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/tom" -d 'rolenames=["Teller"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns list of all roles for given subject or user, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; ["Teller"]&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we assign subject “cassy” to CSR role:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/cassy" -d 'rolenames=["CSR"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Next we assign subject “ali” to role of Accountant:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/ali" -d 'rolenames=["Accountant"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we assign role AccountingManager to “mike”:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/mike" -d 'rolenames=["AccountingManager"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Finally we assign subject “larry” to LoanOfficer role:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -H "Content-Type: application/json" --user "default:super_admin:changeme" -X PUT "http://localhost:8080/api/security/subject_roles/banking/larry" -d 'rolenames=["LoanOfficer"]'&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Authorization&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Now we are ready to validate authorization based on above security policies. For example, let’s check if user “tom” can view deposit-accounts, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:tom:pass" "http://localhost:8080/api/authorize/banking?operation=read&amp;amp;target=DepositAccount"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; On successful authorization, the API returns 200 http responose-code and on failure it returns 401 http response-code, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 200 OK&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we check if tom, the teller can delete deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:tom:pass" "http://localhost:8080/api/authorize/banking?operation=delete&amp;amp;target=DepositAccount"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns http-response-code 401, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 401 Unauthorized&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we create if cassy, the CSR can delete deposit-account, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:cassy:pass" "http://localhost:8080/api/authorize/banking?operation=delete&amp;amp;target=DepositAccount"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 200 OK&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Then we check if ali, the accountant can view general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:ali:pass" "http://localhost:8080/api/authorize/banking?operation=read&amp;amp;target=GeneralLedger"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 200 OK&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Next we check if mike, the accounting-manager can create general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:mike:pass" "http://localhost:8080/api/authorize/banking?operation=create&amp;amp;target=GeneralLedger"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 200 OK&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; Then we check if larry, the loan officer can create posting-rules of general-ledger, e.g.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:mike:pass" "http://localhost:8080/api/authorize/banking?operation=create&amp;amp;target=GeneralLedgerPostingRules"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which returns:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 200 OK&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; Next, ali tries to create posting rules via&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; curl -v --user "banking:ali:pass" "http://localhost:8080/api/authorize/banking?operation=create&amp;amp;target=GeneralLedgerPostingRules"&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;p&gt; which is denied:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt; &amp;lt; HTTP/1.1 401 Unauthorized&lt;br /&gt; &lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Above examples demonstrate how PlexRBAC can be used to define and enforce flexible security policies. In next post, I will describe instance based security, regular expressions and Java APIs for PlexRBAC.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-9209100224680415385?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/9209100224680415385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2010/01/plexrbac-open-source-project-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/9209100224680415385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/9209100224680415385'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2010/01/plexrbac-open-source-project-for.html' title='PlexRBAC: an open source project for providing powerful role based security (I)'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-1979025896034833123</id><published>2009-12-28T09:45:00.000-08:00</published><updated>2009-12-28T09:46:13.701-08:00</updated><title type='text'>Building Security Systems</title><content type='html'>&lt;p&gt;Being software developer for over eighteen years, I have observed a number of recurring problems and one of those recurring problems is security system. Most systems you build will require some kind of security so in this post I will go over core concepts when adding security to your system. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;User Registration&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; A pre-requisite for any security system is to allow users to register to the system and store those users in some database, LDAP, Active Directory, or storage system. Though, for an internal application this step may be unnecessary.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Authentication&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The authentication allows systems to validate users based on password or other form of verification. For internal applications within a company, users may have to use multiple applications with their own authentication and each external website would also require unique authentication. This quickly becomes burdensome for both users and applications as users have to remember the passwords and systems have to maintain them. Thus, many companies employ some form of Single-Sign-On and I have used many solutions such as &lt;a href="http://www.ca.com/us/internet-access-control.aspx"&gt;SiteMinder&lt;/a&gt;, &lt;a href="http://www.novell.com/products/accessmanager/"&gt;IChain&lt;/a&gt;, &lt;a href="http://web.mit.edu/Kerberos/"&gt;Kerberos&lt;/a&gt;, &lt;a href="https://opensso.dev.java.net/"&gt;Open SSO&lt;/a&gt;, &lt;a href="http://www.jasig.org/cas"&gt;Central Authentication Service (CAS)&lt;/a&gt;, or other home built solutions. These Single-Sign-On systems use &lt;a href="http://en.wikipedia.org/wiki/Reverse_proxy"&gt;reverse proxy servers&lt;/a&gt; that sit in front of the application and intercepts all requests and automatically redirects users to login page if the users are not authenticated. When an internal system consists of multiple tiers such as services, it is often required to pass authentication tokens to those services. In J2EE systems, you can Common Secure Interoperability (CSIv2) protocol to pass the authentication to other tiers, which uses Security Attribute Service (SAS) protocol to perform client authentication and impersonation.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; For external systems, &lt;a href="http://openid.net/"&gt;Open ID&lt;/a&gt; is a way to go and I have used &lt;a href="https://rpxnow.com/"&gt;RPX&lt;/a&gt; to integrate Open ID for a number of sites I have developed such as &lt;a href="http://wazil.com/"&gt;http://wazil.com/&lt;/a&gt;, &lt;a href="http://dealredhot.com/"&gt;http://dealredhot.com/&lt;/a&gt;, etc.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; There are a number of factors that make authentication a bit tricky such as when part of your system does not require authentication, you have to ensure the authentication policy is being used correctly. Also, in general authentication requires https instead of http, so you have to ensure that the site use those protocols consistently. In generaly, static contents such as css, javascript and images do not require authentication but often they are also put behind authentication by mistake. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; Another factor related to authentication is session management. A session determines how long the user can access the system without login. Though, many systems provide remember-me feature, but often sessions require system resources on the server. It’s essential to keep the session short as it can effect scalability if it’s stored on the server. I generally prefer keeping the session very short and storing only user-id and a couple of other database-ids such as shopping-cart-id, request-id, etc. If they are short, they can also be stored in cookies that makes a stateless system so you can scale easily.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Authorization&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Not all users are same in most systems, thus authorization allows you to provide access control to limit the usage based on permissions and access control. There are a number of ways to define authorization such as &lt;a href="http://en.wikipedia.org/wiki/Access_control_list"&gt;Access control list&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Role-based_access_control"&gt;Role-based access control&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Capability-based_security"&gt;Capability-based security&lt;/a&gt;, etc. In most systems, I have used J2EE/EJB Security, Java Web Security, &lt;a href="http://java.sun.com/javase/6/docs/technotes/guides/security/"&gt;JAAS&lt;/a&gt;, &lt;a href="http://www.acegisecurity.org/"&gt;Acegi&lt;/a&gt;, which is now part of Spring and home built systems. As security is a cross cutting concern, I prefer to define those declaratively in a common security file or with annotations. There is nothing worse than sporadic security code mixed with your business logic.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; One of feature I have found lacked in most of open source and commercial tools is support for instance based security or dynamic security that verifies runtime properties. For example, in most RBAC systems you can define rule that a purchase order can be approved by a role “POApprover”, but it does not allow you to say that “POApprover” can only approve if the user is from the same department or if amount is less than $10,000, etc. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;UI or Resource Protection&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; When users have various level of access, it is essential to hide the UI elements and resources that are not accessible. Though, I have seen some systems employ security by obscurity that only hide the resources without actually enforcing the permissions, but it’s a bad idea. This can be complicated when the access level is very fine grained such as when a single form has fields based on role and permissions.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Database Security&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The security must be enforced in depth, ranging from the UI, business and database tier. The database operations must use security to prevent access to unauthorized data. For example, let’s assume a user can post and edit blogs, it is essential that the database only allows the user to modify his/her blog. Also, it is critical that any kind of sensitive data such as passwords or personal identification with encryption. This is another reason I like OpenId or SSO solution because you don’t need to maintain them. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Method/Message Security&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The message security ensures that a user only invokes the operations that he/she is authorized. For example, Acegi provides an annotation based mechanism to protect unauthorized methods.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Data Integrity&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Any communication based systems may need to use message authentication check (MAC) to detect changes to the data.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Confidentiality&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; Any communication based systems may need to encrypt sensitive data with HTTPS.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Non-repudiation&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The system must audit users action so that they cannot repudiate them.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt; As achieving high level of security can be difficult and expensive so you need to treat security as a risk and employ the level of security that suits the underlying system. Finally, as I have found most RBAC systems lack, I have started my own open source project &lt;a href="http://github.com/bhatti/PlexRBAC"&gt;PlexRBAC&lt;/a&gt; to provide instance based security. Of course if you hare interested in assisting with the effort, you are welcome to join the project.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-1979025896034833123?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/1979025896034833123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2009/12/building-security-systems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/1979025896034833123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/1979025896034833123'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2009/12/building-security-systems.html' title='Building Security Systems'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-2179653086159760268</id><published>2009-12-14T19:42:00.000-08:00</published><updated>2009-12-14T19:45:06.896-08:00</updated><title type='text'>Dynamic Inheritance and Composition using Object Extension Pattern</title><content type='html'>&lt;h2&gt;Static Inheritance&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; Inheritance is a core feature of object oriented languages that has been used to simulate real world by modeling closely related objects and to build reusable code. The inheritance relationship is defined statically in class specifications and it comes in various flavors such as:&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Single Inheritance&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; It allows a class to be extended by just one other class.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Multiple Inheritance&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; It allows a class to be derived from multiple classes and historically has been difficult to maintain and has been source of diamond inheritance in C++, though other languages use order such as Method Resolution Order (MRO) in Python to avoid those issues.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Interfaces&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The interfaces are used in C# and Java to define methods without implementation and a class can implement multiple interfaces without the downsides of multiple inheritance. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Mixins&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The mixins are available in Ruby and D, that use mixins for code reuse. The mixins are similar to interfaces with implementations except they aggregate methods and attributes at runtime.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Traits&lt;/h3&gt;&lt;br /&gt;&lt;p&gt; The traits are available in Squeak and Scala and are conceptually similar to Mixins except &lt;a href="http://scg.unibe.ch/archive/papers/Scha02bTraits.pdf"&gt;traits&lt;/a&gt; do not allow attributes. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Dynamic Inheritance&lt;/h2&gt;&lt;br /&gt;&lt;p&gt; As opposed to static inheritance, dynamic inheritance can be added at runtime using &lt;a href="http://www.cse.buffalo.edu/%7Ealphonce/KillerExamples/OOPSLA2004/ExtensionObjectsPattern.pdf"&gt;Object Extension Pattern&lt;/a&gt;, which I first learned in Erich Gamma, et al’s Gof patterns. In late 90s, I used &lt;a href="http://www.inf.fu-berlin.de/lehre/WS99/VS/Misc/Voyager/API/"&gt;Voyager ORB&lt;/a&gt; for building distributed systems, which used this pattern. Following example shows how this pattern can be used:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt; Let’s define a marker interface Extension in Java such as:&lt;/p&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt;1&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; ext;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;interface&lt;/span&gt; Extension {&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; Then create a factory class such as &lt;/p&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt;1&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; ext;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; ExtensionsFactory {&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; register(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Class subject, &lt;span class="keyword-directive"&gt;final&lt;/span&gt; Extension ... exts) {&lt;span class="comment"&gt;/* ... */&lt;/span&gt;}&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &amp;lt;T&amp;gt; T get(&lt;span class="keyword-directive"&gt;final&lt;/span&gt; Object subject, &lt;span class="keyword-directive"&gt;final&lt;/span&gt; Class&amp;lt;T&amp;gt; extClass) { &lt;span class="comment"&gt;/* ... */&lt;/span&gt; &lt;span class="keyword-directive"&gt;retu&lt;/span&gt;&lt;span class="keyword-directive"&gt;rn&lt;/span&gt; &lt;span class="keyword-directive"&gt;…&lt;/span&gt;;}&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt; The subject is object that needs to extend extensions, e.g. let’s assume you have a User class and you need to add hobbies, you can do it as follows:&lt;/p&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt;1&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; domain;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; User {&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;     &lt;span class="comment"&gt;//...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt; And you then define Hobbies as follows:&lt;/p&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt;1&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; domain;&lt;br /&gt; &lt;span class="line-number"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;3&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Hobbies implements ext.Extension {&lt;br /&gt; &lt;span class="line-number"&gt;4&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Hobbies(User user) {&lt;br /&gt; &lt;span class="line-number"&gt;5&lt;/span&gt;         &lt;span class="comment"&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;6&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;7&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;8&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;9&lt;/span&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt; At runtime, you can register Hobbies to User and use it as follows&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; test;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Main {&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;static&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; main(String[] args) {&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt;         ExtensionsFactory f = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; ExtensionsFactory();&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt;         f.register(User.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;, Hobbies.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt;         &lt;span class="comment"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;         User user = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; User();&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt;         Hobbies hobbies = f.get(user, Hobbies.&lt;span class="keyword-directive"&gt;class&lt;/span&gt;);&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;     }&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt; }&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt; The dynamic inheritance allows you to follow open-closed principle by extending classes without modifying existing classes and allows you to choose features that you need at runtime.  Of course, dynamic languages such as Ruby make this a lot easier as you can extend classes or objects with modules at runtime, e.g.&lt;/p&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;# defining Hobbies extension&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="ST0"&gt;Hobbies&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 3&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; hobbies&lt;br /&gt; &lt;span class="line-number"&gt; 4&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 6&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;# defining User class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="ST0"&gt;User&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;10&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;11&lt;/span&gt; user = &lt;span class="ST0"&gt;User&lt;/span&gt;.new.extend(&lt;span class="ST0"&gt;Hobbies&lt;/span&gt;)&lt;br /&gt; &lt;span class="line-number"&gt;12&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;13&lt;/span&gt; puts user.singleton_methods   &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;["hobbies"]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;14&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;15&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;# or&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;16&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;# binding Hobbies with User at runtime&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;17&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="ST0"&gt;User&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;18&lt;/span&gt;   include &lt;span class="ST0"&gt;Hobbies&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;19&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;20&lt;/span&gt; puts &lt;span class="ST0"&gt;User&lt;/span&gt;.singleton_methods   &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt; ["hobbies"]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="line-number"&gt;21&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;22&lt;/span&gt;&lt;br /&gt; &lt;span class="line-number"&gt;23&lt;/span&gt;&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;p&gt; In real life, the inheritance relationship can be difficult to get right and often you have to use Liskov Substitution Principle to ensure base class can be replaced by derived class in all uses of the base class. However, dynamic inheritance acts more like Composition feature so above technique can also be used to implement dynamic composition. The dynamic inheritance or composition allows you to mix and match features you need at runtime and build extendable systems. This technique has been success key of evolution of Eclipse IDE. Also, this technique goes nicely with the Adaptive Object Modeling technique I described in my &lt;a href="http://weblog.plexobject.com/?p=1667"&gt;last post&lt;/a&gt; to build easily extendable systems.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-2179653086159760268?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/2179653086159760268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2009/12/dynamic-inheritance-and-composition.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2179653086159760268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/2179653086159760268'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2009/12/dynamic-inheritance-and-composition.html' title='Dynamic Inheritance and Composition using Object Extension Pattern'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-4689245274578086669</id><published>2009-11-16T14:18:00.000-08:00</published><updated>2009-11-16T14:28:23.807-08:00</updated><title type='text'>Applying Adaptive Object Model using dynamic languages and schema-less databases</title><content type='html'>&lt;style type="text/css"&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;.line-number {background-color: #e9e8e2}&lt;br /&gt;.keyword-directive {color: #0000e6}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Introduction to Adaptive/Active Object Model&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Adaptive or Active Object Model is a design pattern used in domains that requires dynamic manipulation of meta information.&lt;br /&gt;Though, it is quite extensive topic of research, but general idea from original paper of&lt;br /&gt;&lt;a href="http://st-www.cs.illinois.edu/users/johnson/papers/dom/DynamicObjectModel.pdf"&gt;Ralph Johnson&lt;/a&gt; is to treat meta information such as attributes, &lt;br /&gt;rules and relationships as a data. It is usually used when the number of sub-classes is huge or unknown upfront and the system requires adding new functionality without downtime.&lt;br /&gt;For example, let's say we are working in automobile domain and we need to model different type of vehicles. Using an object oriented design would result in vehicle hierarchy such as follows:&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;img src="http://www.gliffy.com/pubdoc/1895386/M.jpg"/&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;In above example, all type hierarchy is predefined and each class within the hierarchy defines attributes and operations. Adaptive Object Modeling on the other hand use Object Type pattern, which treats classes like objects. The basic Adaptive Object Model uses type square model such as:&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;img src="http://www.gliffy.com/pubdoc/1893675/M.jpg"/&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;In above diagram, EntityType class represents all classes and instance of this class defines actual attributes and operations supported by the class. Similarly, PropertyType defines names and types of all attributes. Finally, instance of Entity class will actual be real object instance that would store collection of properties and would refer to the EntityType. &lt;br /&gt;&lt;h3&gt;Java Implementation&lt;/h3&gt;&lt;br /&gt;Let's assume we only need to model Vehicle class from above vehicle hierarchy. In a typical object oriented language such as Java, the &lt;a href="http://weblog.plexobject.com/aom/Vehicle.java"&gt;Vehicle&lt;/a&gt; class would be defined as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * Simple Vehicle class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;im&lt;/span&gt;&lt;span class="keyword-directive"&gt;port&lt;/span&gt; java.util.Date;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Vehicle {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String maker;&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String model;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; Date yearCreated;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; &lt;span class="keyword-directive"&gt;double&lt;/span&gt; speed;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; &lt;span class="keyword-directive"&gt;long&lt;/span&gt; miles;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt;     &lt;span class="comment"&gt;//... other attributes, accessors, setters&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; drive() {&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;         &lt;span class="comment"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;v&lt;/span&gt;&lt;span class="keyword-directive"&gt;oid&lt;/span&gt; stop() {&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;         &lt;span class="comment"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; performMaintenance() {&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;         &lt;span class="comment"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt;     &lt;span class="comment"&gt;//... other methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt; }&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see all attributes and operations are defined within the Vehicle class. The Adaptive Object Model would use meta classes such as Entity, EntityType, Property and PropertyType to build the Vehicle metaclass. Following Java code defines core classes of type square model:&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The &lt;a href="http://weblog.plexobject.com/aom/Property.java"&gt;Property&lt;/a&gt; class defines type and value for each attribute of class:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * Property class defines attribute type and value&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;pu&lt;/span&gt;&lt;span class="keyword-directive"&gt;blic&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Property {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; PropertyType propertyType;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; Object value;&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Property(PropertyType propertyType, Object value) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.propertyType = propertyType;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.value = value;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; PropertyType getPropertyType() {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; propertyType;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object getValue() {&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; value;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;     &lt;span class="comment"&gt;//... other methods&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; }&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The &lt;a href="http://weblog.plexobject.com/aom/PropertyType.java"&gt;PropertyType&lt;/a&gt; class defines type information for each attribute of class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * PropertyType class defines type information&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; PropertyType {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String propertyName;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String type;&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; PropertyType(String propertyName, String type) {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.propertyName = propertyName;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.type = type;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getPropertyName() {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; propertyName;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getType() {&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; type;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;     &lt;span class="comment"&gt;//... other methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The &lt;a href="http://weblog.plexobject.com/aom/EntityType.java"&gt;EntityType&lt;/a&gt; class defines type of entity:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * EntityType class defines attribute types and operations&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.Collection;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.HashMap;&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.Map;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; EntityType {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; String typeName;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; Map&amp;lt;String, PropertyType&amp;gt; propertyTypes = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; HashMap&amp;lt;String, PropertyType&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; Map&amp;lt;String, Operation&amp;gt; operations = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; HashMap&amp;lt;String, Operation&amp;gt;();&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; EntityType(String typeName) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.typeName = typeName;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; String getTypeName() {&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;         &lt;span class="keyword-directive"&gt;ret&lt;/span&gt;&lt;span class="keyword-directive"&gt;urn&lt;/span&gt; typeName;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; addPropertyType(PropertyType propertyType) {&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt;         propertyTypes.put(propertyType.getPropertyName(),&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;                 propertyType);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Collection&amp;lt;PropertyType&amp;gt; getPropertyTypes() {&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; propertyTypes.values();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; PropertyType getPropertyType(String propertyName) {&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; propertyTypes.get(propertyName);&lt;br /&gt;&lt;span class="line-number"&gt;36&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;37&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;38&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; addOperation(String operationName, Operation operation) {&lt;br /&gt;&lt;span class="line-number"&gt;39&lt;/span&gt;         operations.put(operationName, operation);&lt;br /&gt;&lt;span class="line-number"&gt;40&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;41&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;42&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;43&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Operation getOperation(String name) {&lt;br /&gt;&lt;span class="line-number"&gt;44&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; operations.get(name);&lt;br /&gt;&lt;span class="line-number"&gt;45&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;46&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;47&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Collection&amp;lt;Operation&amp;gt; getOperations() {&lt;br /&gt;&lt;span class="line-number"&gt;48&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; operations.values();&lt;br /&gt;&lt;span class="line-number"&gt;49&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;50&lt;/span&gt;     &lt;span class="comment"&gt;//... other methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;51&lt;/span&gt; }&lt;br /&gt;&lt;span class="line-number"&gt;52&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;53&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The &lt;a href="http://weblog.plexobject.com/aom/Entity.java"&gt;Entity&lt;/a&gt; class defines entity itself:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * Entity class represents instance of actual metaclass&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.Collection;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;span class="keyword-directive"&gt;import&lt;/span&gt; java.util.Collections;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Entity {&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;private&lt;/span&gt; EntityType entityType;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     &lt;span class="keyword-directive"&gt;priva&lt;/span&gt;&lt;span class="keyword-directive"&gt;te&lt;/span&gt; Collection&amp;lt;Property&amp;gt; properties;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Entity(EntityType entityType) {&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt;         &lt;span class="keyword-directive"&gt;this&lt;/span&gt;.entityType = entityType;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; EntityType getEntityType() {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; entityType;&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; addProperty(Property property) {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;         properties.add(property);&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Collection&amp;lt;Property&amp;gt; getProperties() {&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; Collections.unmodifiableCollection(properties);&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object perform(String operationName, Object[] args) {&lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; entityType.getOperation(operationName).perform(&lt;span class="keyword-directive"&gt;this&lt;/span&gt;, args);&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;     &lt;span class="comment"&gt;//... other methods&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The &lt;a href="http://weblog.plexobject.com/aom/Operation.java"&gt;Operation&lt;/a&gt; interface is used for implementing behavior using Command pattern:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * Operation interface defines behavior&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;interface&lt;/span&gt; Operation {&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;     Object perform(Entity entity, Object[] args);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Above meta classes would be used to create classes and objects. For example, the type information of Vehicle class would be defined in EntityType and PropertyType and the instance would be defined using Entity and Property classes as follows. Though, in real applications, type binding would be stored in XML configuration or will be defined in some DSL, but I am binding programmatically below:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * an example of binding attributes and operations of Vehicle&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;im&lt;/span&gt;&lt;span class="keyword-directive"&gt;port&lt;/span&gt; java.util.Date;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;class&lt;/span&gt; Initializer {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; &lt;span class="keyword-directive"&gt;void&lt;/span&gt; bind() {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;         EntityType vehicleType = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; EntityType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;Vehicle&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;         vehicleType.addPropertyType(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;maker&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;java.lang.String&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt;         vehicleType.addPropertyType(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;model&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;java.lang.S&lt;/span&gt;&lt;span class="character"&gt;tring&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;         vehicleType.addPropertyType(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;yearCreated&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;java.util.Date&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;         vehicleType.addPropertyType(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;speed&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;java.lang.Double&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;         vehicleType.addPropertyType(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; PropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;miles&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;java.lang.L&lt;/span&gt;&lt;span class="character"&gt;ong&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;         vehicleType.addOperation(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;drive&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Operation() {&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt;             &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object perform(Entity entity, Object[] args) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;return&lt;/span&gt; &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;driving&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;             }&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt;         });&lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt;         vehicleType.addOperation(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;stop&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Operation() {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;             &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object perform(Entity entity, Object[] args) {&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;return&lt;/span&gt; &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;stoping&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;             }&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt;         });&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;36&lt;/span&gt;         vehicleType.addOperation(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;performMaintenance&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="keyword-directive"&gt;new&lt;/span&gt; VehicleMaintenanceOperation());&lt;br /&gt;&lt;span class="line-number"&gt;37&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;38&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;39&lt;/span&gt;         &lt;span class="comment"&gt;// now creating instance of Vehicle&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;40&lt;/span&gt;         Entity vehicle = &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Entity(vehicleType);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;41&lt;/span&gt;         vehicle.addProperty(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Property(vehicleType.getPropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;maker&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;),&lt;br /&gt;&lt;span class="line-number"&gt;42&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;Toyota&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;span class="line-number"&gt;43&lt;/span&gt;         vehicle.addProperty(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Property(vehicleType.getPropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;model&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;44&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;High&lt;/span&gt;&lt;span class="character"&gt;lander&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;));&lt;br /&gt;&lt;span class="line-number"&gt;45&lt;/span&gt;         vehicle.addProperty(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Property(vehicleType.getPropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;yearCreated&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;),&lt;br /&gt;&lt;span class="line-number"&gt;46&lt;/span&gt;                 &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Date(2003, 0, 1)));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;47&lt;/span&gt;         vehicle.addProperty(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Property(vehicleType.getPropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;speed&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;), &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Double(120)));&lt;br /&gt;&lt;span class="line-number"&gt;48&lt;/span&gt;         vehicle.addProperty(&lt;span class="keyword-directive"&gt;new&lt;/span&gt; Property(vehicleType.getPropertyType(&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;miles&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;), &lt;span class="keyword-directive"&gt;new&lt;/span&gt; Long(3000)));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;49&lt;/span&gt;         vehicle.perform(&lt;br /&gt;&lt;span class="line-number"&gt;50&lt;/span&gt;                 &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;drive&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;, &lt;span class="keyword-directive"&gt;null&lt;/span&gt;);&lt;br /&gt;&lt;span class="line-number"&gt;51&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;52&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;53&lt;/span&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;54&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;55&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;The operations define runtime behavior of the class and can be defined as closures (anonymous classes) or external implementation such as &lt;a href="http://weblog.plexobject.com/aom/Operation.java"&gt;VehicleMaintenanceOperation&lt;/a&gt; as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;span class="comment"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="comment"&gt; * an example of operation&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="comment"&gt; * &lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt; &lt;span class="comment"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt; &lt;span class="keyword-directive"&gt;package&lt;/span&gt; com.plexobject.aom;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;span class="keyword-directive"&gt;cl&lt;/span&gt;&lt;span class="keyword-directive"&gt;ass&lt;/span&gt; VehicleMaintenanceOperation &lt;span class="keyword-directive"&gt;implements&lt;/span&gt; Operation {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; VehicleMaintenanceOperation() {&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword-directive"&gt;public&lt;/span&gt; Object perform(Entity entity, Object[] args) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;         &lt;span class="keyword-directive"&gt;return&lt;/span&gt; &lt;span class="character"&gt;&amp;quot;&lt;/span&gt;&lt;span class="character"&gt;mai&lt;/span&gt;&lt;span class="character"&gt;ntenance&lt;/span&gt;&lt;span class="character"&gt;&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt; }&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In real applications, you would also have meta classes for business rules, relationships, strategies, validations, etc as instances. As, you can see AOM provides powerful way to adopt new business requirements and I have seen it used successfully while working as &lt;br /&gt;consultant. On the downside, it requires a lot of plumbing and tooling support such as XML based configurations or GUI tools to manipulate meta data. I have also found it difficult to optimize with relational databases as each attribute and operation are stored in separate rows in the databases, which results in excessive joins when building the object. There are a number of alternatives of Adaptive Object &lt;br /&gt;Model such as code generators, generative techniques, metamodeling, and table-driven systems. These techniques are much easier with dynamic languages due to their support of metaprogramming, higher order functions and generative programming. Also, over the last &lt;br /&gt;few years, a number of schema less databases such as &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt;, &lt;a href="http://mongodb.org/"&gt;MongoDB&lt;/a&gt;, &lt;a href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt;, &lt;a href="http://incubator.apache.org/cassandra/"&gt;Cassendra&lt;/a&gt;, &lt;a href="http://1978th.net/"&gt;Tokyo Cabinet&lt;/a&gt;, &lt;a href="http://riak.basho.com/"&gt;Riak&lt;/a&gt;, etc. have become popular due to their ease of use and scalability. These new databases solve excessive join limitation of relational databases and allow evolution of applications similar to Adaptive Object Model. They are also much more scalable than traditional databases. &lt;br /&gt;The combination of dynamic languages and schema less databases provides a simple way to add Adaptive Object Model features without a lot of plumbing code.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;h3&gt;Javascript Implementation&lt;/h3&gt;&lt;br /&gt;Let's try above example in Javascript due to its supports of higher order functions, and prototype based inheritance capabilities. First, we will need to add some &lt;a href="http://weblog.plexobject.com/aom/js_helper.js"&gt;helper methods&lt;/a&gt; to Javascript (adopted from Douglas Crockford's "Javascript: The Good Parts"), e.g.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="keyword"&gt;typeof&lt;/span&gt; Object.beget !== &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;function&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt;     Object.beget = &lt;span class="keyword"&gt;function&lt;/span&gt;(o) {&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt;         &lt;span class="keyword"&gt;var&lt;/span&gt; F = &lt;span class="keyword"&gt;function&lt;/span&gt;() {};&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt;         F.prototype = o;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;new&lt;/span&gt; F();&lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; }&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; Function.prototype.method = &lt;span class="keyword"&gt;function&lt;/span&gt; (name, func) {&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.prototype[name] = func;&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt; };&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; Function.method(&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;new&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;, &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="LINE_COMMENT"&gt;// &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;creating&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;new&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;object&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;that&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;inherits&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;from&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;constructor&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;&amp;#39;&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;s&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;prototype&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; that = Object.beget(&lt;span class="keyword"&gt;this&lt;/span&gt;.prototype);&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     &lt;span class="LINE_COMMENT"&gt;// &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;invoke&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;the&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;constructor&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;, &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;binding&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt; -&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;this&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;- &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;to&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;new&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; other = &lt;span class="keyword"&gt;this&lt;/span&gt;.apply(that, arguments);&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     &lt;span class="LINE_COMMENT"&gt;// &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;if&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;its&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;return&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;va&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;lue&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;isn&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;&amp;#39;&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;t&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;an&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;object&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;substitute&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;the&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;new&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;     &lt;span class="keyword"&gt;return&lt;/span&gt; (&lt;span class="keyword"&gt;typeof&lt;/span&gt; other === &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;object&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; &amp;amp;&amp;amp; other) || that;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt; });&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; Function.method(&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;inherits&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;, &lt;span class="keyword"&gt;function&lt;/span&gt;(Parent) {&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.prototype = &lt;span class="keyword"&gt;new&lt;/span&gt; Parent();&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;     &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt; });&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt; Function.method(&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;bind&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;, &lt;span class="keyword"&gt;function&lt;/span&gt;(that) {&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; method = &lt;span class="keyword"&gt;this&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; slice = Array.prototype.slice;&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; args = slice.apply(arguments, [1]);&lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;     &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; method.apply(that, args.concat(slice.apply(arguments,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;36&lt;/span&gt;             [0])));&lt;br /&gt;&lt;span class="line-number"&gt;37&lt;/span&gt;     };&lt;br /&gt;&lt;span class="line-number"&gt;38&lt;/span&gt; });&lt;br /&gt;&lt;span class="line-number"&gt;39&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;40&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;// &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;as&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;typeof&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;is&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;broken&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;in&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;Javascript&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;, &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;trying&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;to&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;get&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;type&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;from&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;the&lt;/span&gt; &lt;span class="LINE_COMMENT"&gt;constructor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;41&lt;/span&gt; Object.prototype.typeName = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;42&lt;/span&gt;     &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;typeof&lt;/span&gt;(&lt;span class="keyword"&gt;this&lt;/span&gt;) === &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;object&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; ? &lt;span class="keyword"&gt;this&lt;/span&gt;.constructor.toString().split(&lt;span class="mod-regexp"&gt;/&lt;/span&gt;&lt;span class="mod-regexp"&gt;[\s\(]&lt;/span&gt;&lt;span class="mod-regexp"&gt;/&lt;/span&gt;)[1] : &lt;span class="keyword"&gt;typeof&lt;/span&gt;(&lt;span class="keyword"&gt;this&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;43&lt;/span&gt; };&lt;br /&gt;&lt;span class="line-number"&gt;44&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;45&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There is no need to define Operation interface, Property and PropertyType due to higher order function and dynamic language support. Following &lt;a href="http://weblog.plexobject.com/aom/entity.js"&gt;Javascript code&lt;/a&gt; defines core functionality of Entity and EntityType classes, e.g.:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="keyword"&gt;var&lt;/span&gt; EntityType = &lt;span class="keyword"&gt;function&lt;/span&gt;(typeName, propertyNamesAndTypes) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.typeName = typeName;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.propertyNamesAndTypes = propertyNamesAndTypes;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt;     &lt;span class="keyword"&gt;th&lt;/span&gt;&lt;span class="keyword"&gt;is&lt;/span&gt;.getPropertyTypesAndNames = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;.propertyNamesAndTypes;&lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt;     };&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.getPropertyType = &lt;span class="keyword"&gt;fu&lt;/span&gt;&lt;span class="keyword"&gt;nction&lt;/span&gt;(propertyName) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;.propertyNamesAndTypes[propertyName];&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;     };&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.getTypeName = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;.typeName;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     };&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; that = &lt;span class="keyword"&gt;this&lt;/span&gt;;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="keyword"&gt;for&lt;/span&gt; (propertyTypesAndName &lt;span class="keyword"&gt;in&lt;/span&gt; propertyNamesAndTypes) {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt;         that[propertyTypesAndName] = &lt;span class="keyword"&gt;funct&lt;/span&gt;&lt;span class="keyword"&gt;ion&lt;/span&gt;(name) {&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;             &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;                 &lt;span class="keyword"&gt;return&lt;/span&gt; propertyNamesAndTypes[name];&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;             };&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;         }(propertyTypesAndName);&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;         &lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;     }&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt; };&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt; &lt;span class="keyword"&gt;var&lt;/span&gt; Entity = &lt;span class="keyword"&gt;function&lt;/span&gt;(entityType, properties) {&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.entityType = entityType;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.properties = properties;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt;     &lt;span class="keyword"&gt;this&lt;/span&gt;.getEntityType = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt;         &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;this&lt;/span&gt;.entityType;&lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;     };&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt;     &lt;span class="keyword"&gt;var&lt;/span&gt; that = &lt;span class="keyword"&gt;this&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;     &lt;span class="keyword"&gt;for&lt;/span&gt; (propertyTypesAndName &lt;span class="keyword"&gt;in&lt;/span&gt; entityType.getPropertyTypesAndNames()) {&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt;         that[propertyTypesAndName] = &lt;span class="keyword"&gt;function&lt;/span&gt;(name) {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;36&lt;/span&gt;             &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;37&lt;/span&gt;                 &lt;span class="keyword"&gt;if&lt;/span&gt; (arguments.length == 0) {&lt;br /&gt;&lt;span class="line-number"&gt;38&lt;/span&gt;                     &lt;span class="keyword"&gt;return&lt;/span&gt; that.properties[name];&lt;br /&gt;&lt;span class="line-number"&gt;39&lt;/span&gt;                 } &lt;span class="keyword"&gt;else&lt;/span&gt; {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;40&lt;/span&gt;                     &lt;span class="keyword"&gt;var&lt;/span&gt; oldValue = that.properties[name];&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;41&lt;/span&gt;                     that.properties[name] = arguments[0];&lt;br /&gt;&lt;span class="line-number"&gt;42&lt;/span&gt;                     &lt;span class="keyword"&gt;return&lt;/span&gt; oldValue;&lt;br /&gt;&lt;span class="line-number"&gt;43&lt;/span&gt;                 }&lt;br /&gt;&lt;span class="line-number"&gt;44&lt;/span&gt;             };&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;45&lt;/span&gt;         }(propertyTypesAndName);&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;46&lt;/span&gt;         &lt;br /&gt;&lt;span class="line-number"&gt;47&lt;/span&gt;     }&lt;br /&gt;&lt;span class="line-number"&gt;48&lt;/span&gt; };&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Following &lt;a href="http://weblog.plexobject.com/aom/bind.js"&gt;Javascript code&lt;/a&gt; shows binding and example of usage (again in real application binding will be stored in configurations):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; &lt;span class="keyword"&gt;var&lt;/span&gt; vehicleType = &lt;span class="keyword"&gt;new&lt;/span&gt; EntityType(&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Vehicle&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;, {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;maker&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;String&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,              &lt;span class="LINE_COMMENT"&gt;// &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;name&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="LINE_COMMENT"&gt;typeName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;model&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;String&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;yearCreated&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Date&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;speed&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Number&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;miles&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Number&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; });&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt; &lt;span class="keyword"&gt;var&lt;/span&gt; vehicle = &lt;span class="keyword"&gt;new&lt;/span&gt; Entity(vehicleType, {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;maker&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Toyota&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;model&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;Highlander&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;yearCreated&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : &lt;span class="keyword"&gt;new&lt;/span&gt; Date(2003, 0, 1),&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;speed&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : 120,&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt;     &lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;miles&lt;/span&gt;&lt;span class="STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; : 3000&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; });&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt; vehicle.drive = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;     }.bind(vehicle);&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt; vehicle.stop = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;     }.bind(vehicle);&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt; vehicle.performMaintenance = &lt;span class="keyword"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt;     }.bind(vehicle);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see, a lot of plumbing code disappears with dynamic languages. &lt;br /&gt;&lt;h3&gt;Ruby Implementation&lt;/h3&gt;&lt;br /&gt;Similarly, &lt;a href="http://weblog.plexobject.com/aom/aom.rb"&gt;above example in Ruby&lt;/a&gt; may look like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; require &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;date&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt; require &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;forwardable&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="ST0"&gt;EntityType&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt;   attr_accessor &lt;span class="TYPE_SYMBOL"&gt;:&lt;/span&gt;&lt;span class="TYPE_SYMBOL"&gt;type_name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt;   attr_accessor &lt;span class="TYPE_SYMBOL"&gt;:&lt;/span&gt;&lt;span class="TYPE_SYMBOL"&gt;property_names_and_types&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; initialize(type_name, property_names_and_types)&lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt;     &lt;span class="INSTANCE_VAR"&gt;@type_name&lt;/span&gt; = type_name&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt;     &lt;span class="INSTANCE_VAR"&gt;@property_names_and_types&lt;/span&gt; = property_names_and_types&lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; property_type(property_name)&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="INSTANCE_VAR"&gt;@property_names_and_types&lt;/span&gt;[property_name]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="ST0"&gt;Entity&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;   attr_accessor &lt;span class="TYPE_SYMBOL"&gt;:&lt;/span&gt;&lt;span class="TYPE_SYMBOL"&gt;entity_type&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;   attr_accessor &lt;span class="TYPE_SYMBOL"&gt;:&lt;/span&gt;&lt;span class="TYPE_SYMBOL"&gt;properties&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; initialize(entity_type, attrs = {})&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;     &lt;span class="INSTANCE_VAR"&gt;@entity_type&lt;/span&gt; = entity_type&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;     bind_properties(entity_type.property_names_and_types)&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;     attrs.each &lt;span class="keyword"&gt;do&lt;/span&gt; |name, value|&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;       instance_variable_set(&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;@&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;#{&lt;/span&gt;name&lt;span class="QUOTED_STRING_LITERAL"&gt;}&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;, value)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; bind_properties(property_names_and_types)&lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt;     (&lt;span class="keyword"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="keyword"&gt;self&lt;/span&gt;; &lt;span class="keyword"&gt;self&lt;/span&gt;; &lt;span class="keyword"&gt;end&lt;/span&gt;).module_eval &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;28&lt;/span&gt;       property_names_and_types.each &lt;span class="keyword"&gt;do&lt;/span&gt; |name, type|&lt;br /&gt;&lt;span class="line-number"&gt;29&lt;/span&gt;         define_method name.to_sym &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;30&lt;/span&gt;           instance_variables_get(&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;@&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;#{&lt;/span&gt;name&lt;span class="QUOTED_STRING_LITERAL"&gt;}&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;31&lt;/span&gt;         &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;32&lt;/span&gt;         define_method name.to_sym &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;33&lt;/span&gt;           instance_variables_set(&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;@&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;#{&lt;/span&gt;name&lt;span class="QUOTED_STRING_LITERAL"&gt;}&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;, value)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;34&lt;/span&gt;         &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;35&lt;/span&gt;       &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;36&lt;/span&gt;     &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;37&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;38&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;39&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;66&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;67&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;68&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We can then use Singleton, Lambdas and metaprogramming features of Ruby to add &lt;a href="http://weblog.plexobject.com/aom/vehicle.rb"&gt;Adaptive Object Model&lt;/a&gt; support, e.g.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 1&lt;/span&gt; vehicle_type = &lt;span class="ST0"&gt;EntityType&lt;/span&gt;.new(&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Vehicle&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;, {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 2&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;maker&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;String&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,             &lt;span class="LINE_COMMENT"&gt;#&lt;/span&gt;&lt;span class="LINE_COMMENT"&gt; class.name&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 3&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;model&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;String&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 4&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;yearCreated&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Time&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt; 5&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;speed&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Fixnum&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt; 6&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;miles&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Float&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;});&lt;br /&gt;&lt;span class="line-number"&gt; 7&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 8&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt; 9&lt;/span&gt; vehicle = &lt;span class="ST0"&gt;Entity&lt;/span&gt;.new(vehicle_type, {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;10&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;maker&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Toyota&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt;11&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;model&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Highlander&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span class="line-number"&gt;12&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;year&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;Created&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span class="ST0"&gt;DateTime&lt;/span&gt;.parse(&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;1-1-2003&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;13&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;speed&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; 120,&lt;br /&gt;&lt;span class="line-number"&gt;14&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;miles&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;#39;&lt;/span&gt; =&amp;gt; 3000});&lt;br /&gt;&lt;span class="line-number"&gt;15&lt;/span&gt; &lt;span class="keyword"&gt;class&lt;/span&gt; &amp;lt;&amp;lt; vehicle&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;16&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; drive&lt;br /&gt;&lt;span class="line-number"&gt;17&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;driving&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;18&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;19&lt;/span&gt;   &lt;span class="keyword"&gt;def&lt;/span&gt; stop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;20&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;stopping&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;21&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;22&lt;/span&gt;   &lt;span class="keyword"&gt;de&lt;/span&gt;&lt;span class="keyword"&gt;f&lt;/span&gt; perform_maintenance&lt;br /&gt;&lt;span class="line-number"&gt;23&lt;/span&gt;     &lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;performing maintenance&lt;/span&gt;&lt;span class="QUOTED_STRING_LITERAL"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="line-number"&gt;24&lt;/span&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;25&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="line-number"&gt;26&lt;/span&gt; &lt;br /&gt;&lt;span class="line-number"&gt;27&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see Ruby makes it even more succint and provides a lot more options for higher order functions such as monkey patching, lambdas/procs/methods, send, delegates/forwardables, etc.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Schema-less Databases&lt;/h3&gt;&lt;br /&gt;Now, the second half of the equation for Adaptive Object Model is persisting, which I have found to be challenge with relational databases. However, as I have been using schemaless databases such as CouchDB, it makes it trivial to store meta information as part of the plain data. For example, if I have to store this vehicle in CouchDB, all I have to do is create a table such as vehicles (I could use Single Table Inheritance to store all types of vehicles in same table):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;curl -XPUT http://localhost:5984/vehicles&lt;br /&gt;curl -XPUT http://localhost:5984/vehicle_types&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and then add vehicle-type as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;curl -XPOST http://localhost:5984/vehicle_types/ -d '{"maker":"String", "model":"String", "yearCreated":"Date", "speed":"Number", "miles":"Number"}'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which returns&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{"ok":true,"id":"bb70f95e43c3786f72cb46b372a2808f","rev":"1-3976038079"}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, we can use the id of vehicle-type and add vehicle a follows&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;curl -XPOST http://localhost:5984/vehicles/ -d '{"vehicle_type_id":"bb70f95e43c3786f72cb46b372a2808f", "maker":"Toyota", "model":"Highlander", "yearCreated":"2003", "speed":120, "miles":3000}'&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which returns id of newly created vehicle as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{"ok":true,"id":"259237d7c041c405f0671d6774bfa57a","rev":"1-367618940"}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;&lt;br /&gt;Adaptive Object Model based on dynamic languages with support metaprogramming and generative programming provide powerful techniques to meet increasingly changing requirements and it can be used build systems that can be easily evolved with minimum changes and downtime. Also, Schema-less databases eliminates drawbacks of many implementations of AOM that suffer from poor performance due to excessive joins in the relational databases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-4689245274578086669?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/4689245274578086669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2009/11/applying-adaptive-object-model-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/4689245274578086669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/4689245274578086669'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2009/11/applying-adaptive-object-model-using.html' title='Applying Adaptive Object Model using dynamic languages and schema-less databases'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-5002604417404401781</id><published>2009-07-31T14:56:00.000-07:00</published><updated>2009-07-31T15:11:36.767-07:00</updated><title type='text'>Day 1 at #oscon 2009</title><content type='html'>The first day of OSCon 2009 covered a number of tutorials and I decided to attend Google App Engine tutorial for the first half of the day. Google App Engine API follows CGI model of web development, i.e., it uses stdin and stdout files and assumes stateless applications. There is limit of 10MB response size and 30 requests per second, but it does not allow streaming. The tutorial started pretty slow and we spent first hour just installing the SDK and tutorial. The Google App Engine SDK is available from &lt;a href="http://code.google.com/appengine/downloads.html"&gt;http://code.google.com/appengine/downloads.html&lt;/a&gt;. I downloaded Mac image and then dragged the image to my hard drive. I then double clicked the app icon for Google Appe Engine SDK, which installed the SDK under /usr/local/google_appengine. Once the SDK is installed, you have to install Google App Engine tutorials from &lt;a href="http://code.google.com/p/app-engine-tutorial/"&gt;http://code.google.com/p/app-engine-tutorial/&lt;/a&gt;. &lt;br /&gt; &lt;p&gt;&lt;br /&gt;&lt;br /&gt; After installing SDK and tutorial, I copied all files named tutorial? under the SDK. The rest of session covered those tutorials one by one, though we ran out of time in the end and completed only upto tutorial7. In order to install first tutorial, I went into tutorial1 directory, e.g.&lt;br /&gt; &lt;/p&gt;&lt;code&gt; cd /usr/local/google_appengine/tutorial1&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; Then started local app server as follows:&lt;br /&gt; &lt;code&gt; python ../dev_appserver.py .&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; &lt;br /&gt; When I pointed my browser to the http://localhost:8080, I was able to see ‚ÄúHello World!‚Äù.&lt;br /&gt; &lt;p&gt;&lt;br /&gt; Next, I registered myself to &lt;a href="http://appengine.google.com/"&gt;http://appspot.com&lt;/a&gt;. After registering, I received an SMS message for confirmation and was able to fully register after entering the confirmation number. Next, I created an application-id on Google App Engine. You can only create 10 app-ids and you cannot delete app-ids, so be careful with ids. Also, you can also use your own domain instead appspot.com. For my testing purpose, I chose the id ‚Äúshahbhat‚Äù.&lt;br /&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt; Next, I changed app.yaml inside my local tutorial1 directory that describes how your application is configured. You may also notice index.yaml, which describes list of indices in the database, though Google App Engine can figure out what queries are being used and creates indices automatically. I changed application name in app.yaml to ‚Äúshahbhat‚Äù, e.g.&lt;br /&gt; &lt;/p&gt;&lt;code&gt; application: shahbhat&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; I then pushed my application to the Google App Engine by typing&lt;br /&gt; &lt;code&gt; python ../appcfg.py update .&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; I was then able to go to &lt;a href="http://shahbhat.appspot.com/"&gt;http://shahbhat.appspot.com/&lt;/a&gt; and see my application, Voila. You can also see your application usage from &lt;a href="http://appengine.google.com/dashboard?app_id=shahbhat"&gt;http://appengine.google.com/dashboard?app_id=shahbhat&lt;/a&gt; (you will have to change app_id parameter in your application).&lt;br /&gt; &lt;p&gt;&lt;br /&gt;&lt;br /&gt; Unfortunately, a lot of people had problems getting to that state so we wasted another half hour in break where other folks sort out configuration and deployment issues.&lt;br /&gt; Next, I went through another tutorial to turn on authentication by setting:&lt;br /&gt; &lt;/p&gt;&lt;code&gt; login: required&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; in app.yaml file. Next I added caching by adding expires options in the app.yaml. I was also able to use curl to test my applications and see headers to verify caching, e.g.&lt;br /&gt; &lt;code&gt; curl --include http://localhost:8080&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; Which showed following when caching was not configured:&lt;br /&gt; &lt;code&gt; Cache-Control: no-cache&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; When I configured the caching to 2d, I was able to see:&lt;br /&gt; &lt;br /&gt; &lt;code&gt; Cache-Control: public, max-age=172800&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; The Google App Engine SDK also includes development that you can view by going to:&lt;br /&gt; &lt;code&gt; http://localhost:8080/_ah/admin&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; &lt;br /&gt; The Google App Engine supports Django based templates, e.g.&lt;br /&gt; &lt;code&gt; #!/usr/bin/env python&lt;br /&gt;   &lt;br /&gt;   import os&lt;br /&gt;   from google.appengine.ext.webapp import template&lt;br /&gt;   &lt;br /&gt;   def main():&lt;br /&gt;       template_values = {"foo" : [1,2,3]}&lt;br /&gt;       template_file = os.path.join(&lt;br /&gt;                    os.path.dirname(__file__), ‚Äúindex.html‚Äù)&lt;br /&gt;       body = template.render(&lt;br /&gt;         template_file, template_values)&lt;br /&gt;       print ‚ÄúStatus: 200 OK‚Äù&lt;br /&gt;       print ‚ÄúContent-type: text/html‚Äù&lt;br /&gt;       print&lt;br /&gt;       print body&lt;br /&gt;   &lt;br /&gt;   if __name__ == ‚Äò__main__‚Äô:&lt;br /&gt;     main()&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; &lt;br /&gt; In addition, Google App Engine supports WSGI standard (PEP 333), e.g.&lt;br /&gt; &lt;br /&gt; &lt;code&gt;   import os&lt;br /&gt;   import wsgiref.handlers&lt;br /&gt;   &lt;br /&gt;   from google.appengine.ext import webapp&lt;br /&gt;   from google.appengine.ext.webapp import template&lt;br /&gt;   &lt;br /&gt;   class IndexHandler(webapp.RequestHandler):&lt;br /&gt;   &lt;br /&gt;     def get(self):&lt;br /&gt;       template_values = {"foo" : 1}&lt;br /&gt;   &lt;br /&gt;       template_file = os.path.join(os.path.dirname(__file__), "index.html")&lt;br /&gt;       self.response.out.write(template.render(template_file, template_values))&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;   def main():&lt;br /&gt;     application = webapp.WSGIApplication([('/', IndexHandler)], debug=True)&lt;br /&gt;     wsgiref.handlers.CGIHandler().run(application)&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;   if __name__ == ‚Äò__main__‚Äô:&lt;br /&gt;     main()&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; Other tutorials included authentication APIs such as&lt;br /&gt; &lt;code&gt; create_login_url(dest_url)&lt;br /&gt; create_logout_url(dest_url)&lt;br /&gt; get_current_user()&lt;br /&gt; is_current_user_admin()&lt;br /&gt; &lt;/code&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; The SDK also includes decorator to add authentication automitcally using &lt;br /&gt; &lt;code&gt; from gogole.appengine.ext.webapp.util import login_required&lt;br /&gt; ...&lt;br /&gt;     @login_required&lt;br /&gt;     def get(self):&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; &lt;br /&gt; Finally, we went over datastore APIs for persistence support, e.g.&lt;br /&gt; &lt;code&gt;   import os&lt;br /&gt;   import wsgiref.handlers&lt;br /&gt;   &lt;br /&gt;   from google.appengine.ext import webapp&lt;br /&gt;   from google.appengine.ext.webapp import template&lt;br /&gt;   from google.appengine.ext import db&lt;br /&gt;   &lt;br /&gt;   class ToDoModel(db.Model):&lt;br /&gt;     description = db.StringProperty()&lt;br /&gt;     created = db.DateTimeProperty(auto_now_add=True)&lt;br /&gt;     foo = db.FloatProperty(default=3.14)&lt;br /&gt;     bar = db.IntegerProperty()&lt;br /&gt;     baz = db.BooleanProperty(default=False)&lt;br /&gt;     N = db.IntegerProperty()&lt;br /&gt;     l = db.ListProperty(str, default=["foo", "bar"])&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;   class IndexHandler(webapp.RequestHandler):&lt;br /&gt;   &lt;br /&gt;     def get(self):&lt;br /&gt;       todo = ToDoModel(description = ‚ÄúHello World‚Äù, bar=1, baz=True)&lt;br /&gt;       todo.put()&lt;br /&gt;   &lt;br /&gt;   def main():&lt;br /&gt;     application = webapp.WSGIApplication([('/', IndexHandler)], debug=True)&lt;br /&gt;     wsgiref.handlers.CGIHandler().run(application)&lt;br /&gt;   &lt;br /&gt;   if __name__ == ‚Äò__main__‚Äô:&lt;br /&gt;     main()&lt;br /&gt; &lt;/code&gt;&lt;br /&gt; &lt;br /&gt; You can view the model by going to http://localhost:8080/_ah/admin/datastore. The data store supports a number of types such as string, boolean, blob, list, time, text. However, there are some limitations, &lt;br /&gt; e.g. TextProperty can only store upto 500 bytes and Google App Engine will create index if needed, however it won‚Äôt create index on TextProperty. For each row, the datastore assigns a numeric id and UUID based key, &lt;br /&gt; though you can provide your own key. Also, a row cannot exceed 1MB.  &lt;br /&gt; Unfortunately, we ran out of time At this time, so I had to go to &lt;a href="http://code.googlecom/appengne/docs"&gt;http://code.googlecom/appengne/docs&lt;/a&gt; for further documentation. Overall, I thought it was good introduction to Google App Engine, but I was disappointed that instructor wasted a lot of time with setup that could have been used to cover rest of the tutorials.&lt;br /&gt; &lt;br /&gt; &lt;p&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; For the second half of the day, I attended session on ‚ÄúBuilding applications with XMPP‚Äù. This was interesting session that showed usage of XMPP for a number of usecases such as IM, gaming, real-time social networking, , monitoring, etc. The session started with history of XMPP (Extensible Messaging and Presnce Protocol), its Jabber roots and its use of streaming XML. A number of factors contributed to the popularity of XMPP such as open source, XML, federeated network, low latency, etc. The XMPP is also very extensible and supports audio/video via jingle, geo location, TLS, SASL, etc. XMPP architecture is based on client server, where servers are decentralized and federated. XMPP identifies a user with jabber id that looks like email address and consists of local part,  domain and resource, e.g.  alise@wonderland.lit/TeaParty, where domain is mandatory, but local-part and resource are optional. There are three types of XMPP message stanzas,  i.e., presence, IQ, message. The presence-stanza is asynchronous, but IQ stanza requires response. As opposed to web architecture that is based on short lived connections and stateless architecture, XMPP uses one long lived session and events are received asynchronously.&lt;br /&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt; Next, the tutorial showed how to build a javascript client for jabber using sleekxmpp and Strophe library (alternatively you can use twistedword). The example used Bosh protocol to wrap XMPP protocol with HTTP protocol. Unfortunately, there was a lot of fast typing and I could not follow all that. I am waiting for the presenters to post the slides online so that I can use those examples in my own applications.&lt;br /&gt;                &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Blog copy: &lt;a href="http://weblog.plexobject.com/?p=1655"&gt;&lt;br /&gt;Day 1 at #oscon 2009&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-5002604417404401781?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/5002604417404401781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2009/07/day-1-at-oscon-2009.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/5002604417404401781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/5002604417404401781'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2009/07/day-1-at-oscon-2009.html' title='Day 1 at #oscon 2009'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7778735617937090055.post-3382638683810075650</id><published>2009-07-30T16:54:00.000-07:00</published><updated>2009-07-30T16:58:06.752-07:00</updated><title type='text'>Cut the scope and make your life easy</title><content type='html'>I have been developing software for over twenty years and in every project you have to grapple with iron triangle of schedule/cost/functionality or sometime referred to as cost/quality/schedule or cost/resources/schedule. In my experience, curtailing the scope produces better results than adding more resources or extending deadline. In addition, slashing the scope also produces other side effects such as reducing the complexity of the software, easier learning curve for users, less training/support cost and better communication among team members.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;You can reduce the scope by focusing on essential features using Pareto principle (80-20 rule) and companies like like Apple or 37Signals produce great products that are not only more useful but are much simpler to use. However, this is not easy as project manager or product owner have to say NO. Too often, I see project managers say YES to anything to please upper management and users. In the end, the team is overwhelmed and under stress. Also, a big pile of features where all features are of same importance (priority) is biggest reason for death-march projects.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;Working with a small number of features reduces complexity such as essential complexity, cyclomatic complexity or accidental complexity because your codebase is smaller. Though, you still have to apply good software engineering principles such as domain driven design, unit testing, refactoring, etc, but maintenance becomes easier with smaller codebase. When you have a small codebase you have fewer bugs as they are no bugs for zero code. Fewer bugs means less support cost when some user complains of a bug or when system crashes in the middle of the night.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;With a small set of features, the user interface becomes simpler, which in turn provides better usability to the users. Often, I have seen users get confuse when they have to work with a complex software that has a lot of features. This often is remedied by providing training or adding support that adds a lot more overhead to the projects. Again, better user interface does not come free automatically with a small set of features, but the usability problem becomes easier with fewer features.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Finally, small number of features and small code means your team size will remain small so communication among team members becomes easier. I like to work with team with &lt;a href="http://www.infoq.com/news/2009/04/agile-optimal-team-size"&gt;size of 5 plus/minus 2&lt;/a&gt;, as number of communication links increase exponentially when you add more members. Also, with smaller teams that are colocated, you have better&lt;br /&gt;&lt;a href="http://alistair.cockburn.us/Osmotic+communication"&gt;Osmotic communication&lt;/a&gt; that Alistair Cockburn talks about. At Amazon, we have “2-Pizza” teams, i.e., teams are small enough to have team lunch with just two pizzas. Another factor when building teams is whether they are cross functional (vertical) or focus on single expertise such as systems, database, UI, etc. I prefer working with cross functional teams that focus on a single service or an application as communication and priorities within a single team is much easier to manage than between different teams.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;In nutshell, reducing scope not only helps you deliver the software in time and delight your users but prepares you better to maintain and support the software. The complexity is number one killer for the software and results in buggy and bloated software. You should watch out when someone says “Wouldn’t it be cool if it did X?” kind of feature requests and often I see developers see this as a challenge or an opportunity to learn or apply new technology. However, each new feature takes a toll on your existing features, software maintenance and your team.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;  &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;My other weblog: &lt;a href="http://weblog.plexobject.com/?p=1660"&gt;Cut the scope and make your life easy&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7778735617937090055-3382638683810075650?l=shahbhat.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shahbhat.blogspot.com/feeds/3382638683810075650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://shahbhat.blogspot.com/2009/07/cut-scope-and-make-your-life-easy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/3382638683810075650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7778735617937090055/posts/default/3382638683810075650'/><link rel='alternate' type='text/html' href='http://shahbhat.blogspot.com/2009/07/cut-scope-and-make-your-life-easy.html' title='Cut the scope and make your life easy'/><author><name>Shahzad Bhatti</name><uri>http://www.blogger.com/profile/15145385191948959926</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_FcylJ2PCxvk/SnJi5cjTdkI/AAAAAAAAAAM/vhfVCMvxltI/s1600-R/sshahbhat.jpg'/></author><thr:total>0</thr:total></entry></feed>
