ppt

41
Building Enterprise Applications with Mozilla, AMP, XML-RPC and JSON Jay Sheth http://www.moztips.com Presentation for NYPHP Group IBM, 590 Madison Ave New York, NY Tuesday, May 24, 2005

Post on 13-Sep-2014

9 views

Category:

Documents


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: PPT

Building Enterprise Applications with Mozilla, AMP,

XML-RPC and JSON

● Jay Sheth● http://www.moztips.com● Presentation for NYPHP Group● IBM, 590 Madison Ave● New York, NY● Tuesday, May 24, 2005

Page 2: PPT

Ajax, Ajax, Ajax!What is a Firefox + LAMP application?It's an Ajax-like application

Client-Side:

* XUL * JavaScript

Server Side:* PHP* MySQL

Data Transport:* XML-RPC* JSON

AJAX-like technologies are being used by companies such as Google in Google Suggest (http://www.google.com/webhp?complete=1&hl=en ) and Google Maps ( http://maps.google.com/ ).

AJAX: Asynchronous JavaScript + XMLhttp://www.adaptivepath.com/publications/essays/archives/000385.php

Page 3: PPT

A Bit of Architecture

Page 4: PPT

It's All About the Central Business Logic Hub

●All business logic is centralized in the form of a central PHP-driven hub

●Both administrators and end-user can access the same business hub

●Administrators use a rich web client, delivered on-demand to Firefox

●End-users use any generic HTML-based browser

Thus the same data can be accessed and modifiedby different web clients that access a single central engine.

Thus code duplication between administrator andend-user functionality is avoided.

End-user website can be displayed using PHP 4, PHP 5or even (heaven forbid) ASP.net.

Page 5: PPT

DB Abstraction at the Backend Business Hub

Putting PEAR DB to use enables easy database portability

Page 6: PPT

Enough Talk – Let's See an Example Central Business Logic Hub as Implemented at

www.brooklynandbeyond.com End-user site: directory of restaurants, real estate and other businesses in Brooklyn, Manhattan, Queens, NJ and CT

Administrator's View:

Page 7: PPT

Example, Part II

End-user site

Page 8: PPT

Recap: The Application

* Database of restaurants and other businesses in Brooklyn, Manhattan, New Jersey and Connecticut

* Two views:Rich Client for Admin (XUL + JS + PHP + MySQL)

– Status: Beta

Flat Website for end-user (HTML + CSS + PHP + MySQL) – Status: Alpha / Proof of Concept

Page 9: PPT

What's so good about a rich web client ?

● Web App + Desktop Application Hybrid● Real time response reflected in user interface● Provides 'rich', instead of 'flat' experience● Leverages Mozilla platform for improved user

interface widgets (such as editable combo boxes)

● Tabbed display paradigm enables easy editing of large number of data fields

Page 10: PPT

Recipe IngredientsMaking a nice cup of XUL, JavaScript, PHP and MySQL Noodles

* Start with some PEAR libraries as the base - http://pear.php.net HTTP RequestNet SocketNet URLXML-RPCDB

* Add in Jsolait JavaScript libraries for good measure - http://jsolait.net/ *Add in PHP JSON server library - http://mike.teczno.com/json.html

* Add some PHP code to make an XML-RPC server (stir well)* Add some PHP code to make a yummy index.php file* Add some (well a lot of, actually) XUL and JavaScript code to the index.php file so that it can 'talk to' the XML-RPC server

* Open the 'content' packet, and pour it into the MySQL DB.

You have one hot cup of Mozilla LAMP noodles there!

Page 11: PPT

Show us some code already !A basic XML-RPC transaction

HTTP Request:

POST /admintwo/mailingdbserver.php HTTP/1.1

<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>

HTTP Response:

<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><array><data><value><string>getAllEntriesBrief</string></value><value><string>getAllCategories</string></value><value><string>getTelLookupData</string></value></data></array></value></param></params></methodResponse>

Page 12: PPT

Cool Feature: Auto-address lookupusing reverse phone lookupStep 1) Enter a phone number

Page 13: PPT

Auto-address lookup (II)Step 2) Press the reverse phone lookup button

Page 14: PPT

Code for Auto-address Lookup (I)

XML-RPC Server-Side Code

require 'google_lookup.php';/*Use Google to do a reverse lookup of a telephone number, to get the contact information associated with that number.Return that information.*/function get_tel_lookup_data($params){

$tel_no = XML_RPC_decode( $params->getParam(0) );

// Check the telephone number for valid syntax before performing a lookup$tel_parts = extract_tel_digits($tel_no);

if ( ! is_array($tel_parts) ){

return new XML_RPC_Response(0, $XML_RPC_erruser + 1, "Error: phone number invalid.");}

$my_lookup = lookup_google('http://www.google.com/search', $tel_no);$retval = XML_RPC_encode($my_lookup);return new XML_RPC_Response($retval);

}

Page 15: PPT

Code for Auto-address Lookup (II)

Google lookup function (excerpt)require_once 'HTTP/Request.php'; // PEAR HTTP_Request Library to POST data (or to GET data)

function lookup_google($remote_server, $telephone){$req =& new HTTP_Request($remote_server);$req->setMethod(HTTP_REQUEST_METHOD_GET);$req->addQueryString('q', $telephone);

if (!PEAR::isError($req->sendRequest())) { $response2 = $req->getResponseBody(); } else { $response2 = 0; }

if (! empty($response2) ){

$num_lookups = 0;$our_matches_all = array();$response_no_tags = strip_tags($response2);$response_no_tags = str_replace(' & ', ' and ', $response_no_tags);

// Make space after Mapquest links so that after HTML tags have been stripped, there is a space// before the business name

$response_no_tags = str_replace('MapQuest</a>', ' ', $response_no_tags);

$num_matches = preg_match_all('/([A-Za-z\s-]+),\s\((\d{3})\)\s(\d{3})-(\d{4}),\s([0-9-]+ [\w\s.]+[.#0-9\s]*),\s([A-Za-z\s]+),\s([A-Za-z]{2})\s(\d{5})/', $response_no_tags, $our_matches_all, PREG_PATTERN_ORDER);

/*More stuff happens here ...*/

// Populate and return new array with relevant information from $our_matches_all }

}

Page 16: PPT

Code for Auto-address Lookup (III)XUL widgets population / JavaScript code

function getTelLookupData(tel_no){

set_waitbox('-- please wait --');var methods = [];try{var server = new xmlrpc.ServerProxy(globalXmlRpcServer, methods);var lookup_data = server.getTelLookupData(tel_no); // calling remote XML_RPC function here!// Automatic type conversion here from PHP assoc array to JS objectif ( lookup_data['rpc_msg'] != 'No reverse lookup matches found.' && lookup_data['rpc_msg'] !=

'Reverse Lookup: an error has occured.' ){document.getElementById('b_name').value = lookup_data['b_name'];document.getElementById('b_phone').value = lookup_data['b_phone'];last_phone_num_lookup = lookup_data['b_phone'];document.getElementById('b_street_address').value = lookup_data['b_street_address'];document.getElementById('b_city').value = lookup_data['b_city'];document.getElementById('b_state').value = lookup_data['b_state'];document.getElementById('b_zip').value = lookup_data['b_zip'];}else{

// Turn off auto lookup if no phone number has been found, or if an error has occuredtoggleReverseLookup();toggleALButton();

}set_waitbox( lookup_data['rpc_msg'] );}catch(e){set_waitbox('Error:' . e);alert(e);}

}

Page 17: PPT

Automagical zip population

Similarly, when an entry is made and both zip codes are left blank, they are looked up.

If an appropriate match could be found, this information is saved to the database.

Otherwise, an error is exposed as a JavaScript alert, and a color and text change in the notice box. (More on the notice box in a later slide.)

Page 18: PPT

Error Checking

* Centralized on the server side* Exposed on the client side as native JavaScript alerts / actions

Page 19: PPT

Nice feature: editable drop-downs

XUL has editable drop-downs – a big improvement over HTML's select tag

Page 20: PPT

XUL Code for Editable Dropdowns

<hbox><label control="b_neighborhood" value="Neighborhood:"

style="width:100px;" />

<menulist editable="true" id="b_neighborhood"><menupopup>

<menuitem label="--select--" value="--select--"/>

</menupopup></menulist>

</hbox>

Note: neighborhood values are dynamically added using the DOM viaJavaScript

Page 21: PPT

JavaScript Code for Dynamic Neighborhood Drop-down Population//Get a list of distinct neighborhoods from the entries table

function getAllNeighborhoods(){

var methods = [];try{var server = new xmlrpc.ServerProxy(globalXmlRpcServer, methods);var all_neighborhoods = server.getAllNeighborhoods(); // calling remote XML_RPC function here!

// Automatic type conversion here from PHP assoc array to JS object

var menuList = document.getElementById('b_neighborhood');var menuList2 = document.getElementById('s_near_neighborhood');

for (var i in all_neighborhoods){

aneigh = all_neighborhoods[i];neighborhood = aneigh['neighborhood'];

if (neighborhood) {

menuList.appendItem(neighborhood, neighborhood);menuList2.appendItem(neighborhood, neighborhood);

}

}

}

catch(e){alert(e);}

}

Page 22: PPT

PHP Code for Dynamic Neighborhood Drop-down Population

//Get a list of all distinct neighborhoods in the entries table

function get_all_neighborhoods(){

global $username, $password, $server, $database, $mailing_table;global $XML_RPC_erruser;

$dbh = DB::connect("mysql://$username:$password@$server/$database");

if ( DB::isError($dbh) )// CHECK PEAR DB CONNECTION ERRORS{

// Return XML-RPC faultreturn new XML_RPC_Response(0, $XML_RPC_erruser + 1, "DB Error: Could not connect to server.");

}else{

// Retrieve list of distinct neighborhoods$dbh->setFetchMode(DB_FETCHMODE_ASSOC);

$query = "SELECT DISTINCT neighborhood FROM $mailing_table ORDER BY neighborhood ASC";$mlist_neigh = $dbh->getAll($query);

if ( DB::isError($mlist_neigh) )// CHECK FOR PEAR DB / QUERY RUN ERRORS{

return new XML_RPC_Response(0, $XML_RPC_erruser + 2, "DB Error: Could not run query.");}else{

$retval = XML_RPC_encode($mlist_neigh);return new XML_RPC_Response($retval);

}}

}

Page 23: PPT

Nice feature: PEAR QF-like hier-select menus

Step 1: select category from editable-dropdown

Page 24: PPT

Step 2: select from list of subcategories pertaining to this category

Hierselect (Part II)

Page 25: PPT

Code for XUL Hierselect Menus

Code Link :http://www.moztips.com/wiki/index.pcgi?page=XuLHierMenulists

Live Demo:http://www.moztips.com/code/mozbugs/menulist/menulist_bug.php

Page 26: PPT

Capitalizing on MySQL's FULLTEXT indexingfor listings search

●Deliberate compromise in DB design: de-normalized table structure ●Category, Subcategory, Country Affiliation etc. stored in same table●These fields stored as VARCHAR(255)●Created a MySQL FULLTEXT index for these, and other fields

●MySQL is great at storing, searching through and filtering data

Sample search queries:●Bronx Italian●Bay Ridge pizza●Japanese restaurants●Vegetarian●West Village Italian

Sample FULLTEXT query (simplified):SELECT id, MATCH (title,body) AGAINST ('Tutorial') FROM articles;

More info.:http://dev.mysql.com/doc/mysql/en/fulltext-search.html

Page 27: PPT

MySQL FULLTEXT Search Example (I)

Content Administrator's View

Page 28: PPT

MySQL FULLTEXT Search Example (II)

End User's View

Page 29: PPT

Problem with rich web applications and large datasets:

things can slow down, instead of speeding up

Things slow down because:

●Large amounts of separate pieces of data are loaded on each 'event' (e.g. editing an entry)●Choosing XML-RPC as the underlying data transport is convenient but also expensive●Parsing XML on the client-side is resource-intensive

How to speed things up:

●Optimize application design for speed●Reduce the amount of requested data by using pagination●Use an alternative data transport format, such as JSON (JavaScript Object Notation)

Page 30: PPT

Techniques for Optimizing Rich Web Applications for Speed

●Intelligently cache data locally in either JavaScript arrays or XML files●Local XML file caching is more complicated, as Firefox requires local file access●Ensure that JSolait library does not request list of remote methods on each web service request●When data for one listing is retrieved, also preload data into JavaScript array for surrounding 10 listings●Only reload data from remote DB when data on the client side is stale

Case in point: reloading complete listings list takes too long

(On to-do list)

Page 31: PPT

Using JSON for Optimized Data Transport Speed

JSON: JavaScript Object Notation

●JSON is a JavaScript Object literal●JavaScript objects are the same as JavaScript associative arrays

Example:{"myname":"Jay","place":"New York"}

PHP Equivalent:array('myname' => 'Jay', 'place' => 'New York')

Page 32: PPT

How to Get Data via JSON

* Mozilla makes a GET request to page such as: http://localhost/json/test_json.php?sort=az

* That PHP page queries MySQL and lists all entries (such as weblog posts and ids) in alphabetical order in JSON format , using the JSON PHP library

* Mozilla reads this object literal string from the PHP-generated page, converts it into a JavaScript Object / Assocative Array, using the eval() function

* Mozilla loops through the JavaScript Object, and enters each title into a XUL Listbox

Using JSON results in a 600 - 700% speed increase over XML-RPC.

Page 33: PPT

Some JSON Request Code (I)

init_urllib.js

// init_urllib.jsvar urllib=null;try{ var urllib = importModule("urllib");}catch(e){ reportException(e); throw "importing of urllib module failed.";}

Page 34: PPT

Some JSON Request Code (II)HTML / PHP Page:<!-- This page is:http://localhost/json/test_json.html /http://localhost/json/test_json.php--><script type="application/x-javascript" src="jsolait/init.js"> </script><script type="application/x-javascript" src="jsolait/init_urllib.js"> </script><script type="application/x-javascript" src="jsolait/lib/urllib.js"> </script>

<script type="application/x-javascript">var rslt = urllib.sendRequest("get", "http://localhost/json/test_json.php");

if (rslt.status == '200'){jsonSerialized = rslt.responseText;

//eval( 'obj3 ={"myname":"Jay","place":"New York"};' );eval( jsonSerialized );document.write(obj3['myname']);document.write(obj3['place']);}else{

alert('Error: the server could not find the specified file.');}</script>

Page 35: PPT

Some JSON Request Code (III) PHP Script (loaded via GET HTTP Request)

<?php// test_json.php

require_once('JSON.php');$json = new JSON();

// convert a PHP value to JSON notation, and send it to the browser

$value = array('myname' => 'Jay', 'place' => 'New York');// $value is:// {"myname":"Jay","place":"New York"}$output = $json->encode($value);$output = 'obj3 =' . $output . ';';print($output);?>

Page 36: PPT

Powering the End-User Site with PEAR XML-RPC Clientand PEAR Sigma Templating System (I)

(bonus material)

Page 37: PPT

Powering the End-User Site with PEAR XML-RPC Clientand PEAR Sigma Templating System (II)

(bonus material)

<?php// Use MySQL's fulltext searching to search DB$s = $_REQUEST['s'];// Include preference file, PEAR XML-RPC Client, and PEAR Sigma Template Library // Instantiate Sigma template object. Set the templates directory to the subdirectory called 'templates'

if ( strlen($s) > 0 ){

$client = new XML_RPC_Client($xmlrpcpath, $xmlrpcserver, 80);$client->setCredentials($xmlrpcusername, $xmlrpcpassword);

$message = new XML_RPC_Message('getEntriesByKeywordgetEntriesByKeyword');$message->addParam( new XML_RPC_Value($s, 'string') );$response = $client->send($message);

$return_value = $response->value();$search_results = XML_RPC_decode($return_value);

$num_s = count($search_results);for ($j = 0; $j < $num_s; $j++){

$row = $search_results[$j];$tpl->setVariable(

array( 'name' => $name, 'id' => $row['id'], 'street_address' => $row['street_address'], 'address2' => $row['address2'], 'cross_streets' => $row['cross_streets'], 'city' => $row['city'], 'state' => $row['state'], 'neighborhood' => $row['neighborhood']) ); $tpl->parse('sitem_block');}$tpl->show(); // Display the newly created HTML file

}else {$tpl->show(); // Display the newly created HTML file}?>

PHP Fulltext Search Code Excerpt (some code omitted!)

Page 38: PPT

Powering the End-User Site with PEAR XML-RPC Clientand PEAR Sigma Templating System (III)

(bonus material)

Sigma gh

Sigma Template Code Excerpt

<html><head>

<title>Brooklyn and Beyond </title></head><body><div class="mainbody">

<h3> Search Listings </h3>

<p>{num_results_msg}</p>

<p>{no_results_msg}</p>

<p> {search_tip} </p>

<!-- BEGIN sitem_block --><ul> <li>

<strong><a href="detail.php?id={id}">{name}</a></strong> <br /> {street_address} <br /> {cross_streets} <br /> {city} <br /> {state} <br /> {neighborhood} </li>

</ul><!-- END sitem_block -->

</div></body></html>

Page 39: PPT

Conclusions

●AJAX-like applications can dramatically improve user experience●XUL + JavaScript on the client is perfect for data entry tasks●Having each component separated from the other makes for 'hot-swappable' components, and an easy-to-upgrade site

Hot-swapping components – some examples:If you (or the pointy-haired one) decide tomorrow that it would be way cool to use ASP.net to display the end-user site, you could easily do so. Simply acquire an XML-RPC client for ASP.net, and rebuild the end-user portion. The central business hub will still be powered by PHP 4 or PHP 5, and the ASP.net site will access data via the same XML-RPC API.

Suppose you would like to migrate from MySQL to PostgresQL for the datastore. Simply import your data into PostgresQL, change the PEAR DB DSN strings in the central business hub, and modify queries slightly to account for the differences between MySQL and PostgresQL.

It's as easy as that! No, really!

Page 40: PPT

Questions? Comments?

Page 41: PPT

Thank You!