Tuesday, July 01, 2008

Ringside Networks Social Application Server on Linux


This post is based on official documents from Ringside, and describes steps to set up Ringside Networks Social Application Server.
(1) Download
First, download the app server from here. In the distributed package, all dependent packages/libraries are included. Main additional components include: Apache2, PHP5 (core package and some extensions), Mysql and some unix/linux tools(e.g. curl, tidy and their libraries). So size of the whole package is sort of big. But it is an all-in-one package so that you can easily make it work without much configuration. Installation directory structure is explained here.
If you don't want the all-in-one package, check instructions here to individually set up your environment.

(2) Install
A GUI installation wizard is provided. You can get instructions here. The process is easy.

(3) Config
You can change various apache setting by modifying following files:
(*)%RNAS_ROOT%/apps/phpmyadmin/conf/phpmyadmin.conf
//This conf file is related to using of phpmyadmin. By default, users can only access phpmyadmin from IP 127.0.0.1. You can modify it
//if you want to use phpmyadmin from remote client.
(*)%RNAS_ROOT%/apps/ringside/conf/ringside.conf
//
ringside related conf. It sets where the document root is... Generally, this file should not be modified.
(*)%RNAS_ROOT%/apache2/conf/httpd.conf
//General apache http server configuration is in this file. If you want to change the port, set it here.

(4) Run
Let me assume you installed Ringside Networks Application Server into directory %RNAS_ROOT%. Under directory %RNAS_ROOT%, you should see a script called "ctlscript.sh" which can be used to start/stop/restart server components. Sample commands are shown below:
./ctlscript.sh start                    //start both apache and mysql
./ctlscript.sh stop mysql           //stop mysql
./ctlscript.sh status apache       //get status of apache server.
Official document is here which has more information.

(5) Setup/Initialization
First, you need to access http://your_ip_or_domain:port/setup.php. Default port is 8080. Then the server will carry out some setup work. For example, a database called ringside is created...
You should see following page:
image

(6) Test/Using
Main page: http://your_ip_or_domain:port
Phpmyadmin access: http://your_ip_or_domain:port/phpmyadmin.
Login: http://your_ip_or_domain:port/login.php. When you run initial setup in step (5), a user is automatically generated for you. See content in the green box in last picture.

(7) upgrades
[*] Upgrade via PEAR:
You can update Ringside source via PEAR. Instructions are described here.
[*] Check out latest code:
You can checkout latest Ringside code and build your own development/deployment environment. You should install the all-in-one package first. By following instructures here, you substitute new version of Ringside for the original one which is included in the all-in-one package.

(8) Remove
Use executable uninstall. Check instructions here.

Thursday, June 19, 2008

Client side techniques

Namespace mimic in Javascript (similar to technique used by YUI):
namespace:   function(   sNameSpace, obj   )   {  
    if   (!sNameSpace   ||   !sNameSpace.length)   {  
        return   null;  
    }  
    var   levels   =   sNameSpace.split(".");  
    var   currentNS   =   CGL;  
    //   CGL   is   implied,   so   it   is   ignored   if   it   is   included  
    for   (var   i=(levels[0]   ==   "CGL")   ?   1   :   0;   i<levels.length;   ++i)   { 
        if( arguments.length == 2 && i == levels.length - 1)
	    currentNS[levels[i]]   =   obj;
	else
	    currentNS[levels[i]]   =   currentNS[levels[i]]   ||   {};  
	currentNS   =   currentNS[levels[i]];  
    }
    return   currentNS;  
}
By default, following namespaces are supported:
CGL.mashup.resourcetype:
This object maintains resource types we support. Currently, text, image and video are supported.
CGL.mashup.addr:
This object maintains base path for our applications.
CGL.mashup.sites:
This object maintains all backend sites we support. Currently, Youtube and Flickr are supported.
CGL.mashup.log:
This object maintains request history so that in the future we can reinvoke a certain old request.
CGL.mashup.init:
All initialization work is done here.
CGL.mashup.urlbuilder:
This object provides functions which can ease construction of request URL to access various resources.
CGL.mashup.service:
This object provides functions which send various requests (e.g. get user information) to server side.
CGL.mashup.helper:
This object includes some utility functions.
GL.mashup.htmlformatter:
This object contains functions that can be used to display response in a specific format .
CGL.mashup.jsonresponse:
This object handls JSON responses from server and parses the content.
CGL.mashup.opmapper:
This object maps operation names to concrete function implementations. Callback can be specified as well.

Web2.0 Integration Summary

The server-side architecture is described here:
http://zhenhua-guo.blogspot.com/2008/05/mashup-architecture.html.

Authentication: OpenID which is described here (http://zhenhua-guo.blogspot.com/2008/05/openid.html).
Authorization: Although OAuth seems promising, it has not been supported by large web 2.0 applications. So, I make use of various authorization mechanisms of different applications.

RESTful web services are used instead of SOAP-based web services. URL pattern used to access various resources is described here(http://zhenhua-guo.blogspot.com/2008/05/url-pattern-in-mashup.html).

At client side, Ajax is used to enhance user experience. Client side functionality is described here(http://zhenhua-guo.blogspot.com/2008/06/client-side-techniques.html).

Sunday, May 25, 2008

OAuth

In my mashup framework, OpenID is used to do authentication which provides a way to make sure the users are really who they claim to be. The mechanism is that the users prove that they own/control the OpenID they provides. Here is what I wrote about OpenID.

However, OpenID just solves authentication. After users are authenticated, OpenID does not specify how the third-party apps access the protected data on service providers. And the requirement that third-party apps can access protected data stored on service providers on behalf of users is not imaginary, but real. In my mashup framework, I need to manipulate data on behalf of users which needs authorization besides authentication. Youtube and Flickr both provide ways for third-party integration. They provide similar authorization procedures (I am using this mechanism right now) which fundamentally match principles of OAuth specification.

OAuth provides a way for users to grant access to third-party apps. The procedure is pretty much the same as OpenID. What is different are parameters in requests and responses. OAuth is an independent specification which means it is not an extension of OpenID. But, in my opinion, it may be better to combine these two together because they are similar to each other. In this way, user experience can be improved because authentication and authorization can be done in the same pass instead of two. However, some sites may just support authentication service or authorization service (in terms of support of open standards like OpenID, OAuth). So how to combine them together without losing flexibility is an issue.

One problem that OAuth does not address is fine-grained access control. I think this issue must be addressed in the long run. However, nowadays, the goal is too far to reach. Actually, current version of OAuth is not supported widely.

DataPortability is a new organization which aims to promote data portability. Of course, it includes OpenID and OAuth with respect to authentication and authorization data portability. I am not sure which ones will survive and stand out  eventually, but this is a good signal that data portability is being considered as a critical issue and I hope it will be addressed in the near future.

Saturday, May 24, 2008

Authentication and Authorization in Mashup

Authentication
Currently, I don't build my own independent user authentication system. I make use of OpenID to utilize existing authentication systems, such as Yahoo Flickr, Google Blogspot, LiveJournal... You can check whether you have already had an OpenID here. I wrote a simple introduction. In essence, we delegate the task to existing authentication systems.
After a user is authenticated successfully, OpenID is used to track the user. Servlet session technique is used to associate session id and user information.

Authorization
Currently, I don't ask end users for their usernames and passwords in existing services (e.g. youtube, flickr) because it requires deep trust of end users. The user id redirected to an authorization web page hosted by the destination service(e.g. youtube). If the user accepts the request, then the user browser will be redirected to my mashup application. Generally, an auth token is appended to the URL which will be used in following requests.
Currently, for every backend service, I request the user to authorize the most powerful privilege level. For example, if the service supports READ and WRITE permission control, my application will request WRITE permission. If the service supports READ, WRITE and DELETE permission control, my application will request DELETE permission. This is not always a good strategy. But because of diversity of permission control systems, I must choose the mechanism which can be used in every possible service.
Maybe in the future, I can come up with a better framework with fine-grained access control.

URL Pattern In Mashup

URL Pattern

Note: All variables enclosed in ‘{’ and ‘}’ must be substituted with real values.
GET means HTTP GET request type and POST means HTTP POST type.

/cgl/feeds/api/{category}/{service}/users/{userid}
GET:
    Get information of a user.

/cgl/feeds/api/{category}/{service}/login
GET:
     Login the service.

/cgl/feeds/api/{category}/{service}/users/{userid}/resources
GET:
    Get all resources of the user.
POST:
    Add a new resource.

/cgl/feeds/api/{category}/{service}/users/{userid}/resources/resourceid
/cgl/feeds/api/{category}/{service}/resources/resourceid
GET:
    Get information of a specific resource.
DELETE:
    Delete the corresponding resource.
PUT:
    Update the corresponding resource.

/cgl/feeds/api/{category}/{service}/resources/resourceid/comments
GET:
    Get all comments of the resource.
POST:
    Add a new comment.

/cgl/feeds/api/{category}/{service}/resources/resourceid/rating
GET:
Get rating of the resource.

/cgl/feeds/api/{category}/{service}/tag/{tag}?perpage={perpage}&page={page}
GET:
    Get records by tag. Parameter perpage indicates how many resources you want to retrieve.Parameter page indicates which page you want to retrieve.

/cgl/feeds/api/{category}/{service}/statistics/{standard}? perpage={perpage}&page={page}
GET:
    Get records by standards.
    E.g. most viewed, most recent…

Example:

/cgl/feeds/api/videos/youtube/tag/soccer
get resources tagged as soccer.
/cgl/feeds/api/videos/youtube/statistics/most_viewed
get resources that are most viewed.
/cgl/feeds/api/pictures/flickr/users/testuser/resources
get resources belonging to user testuser.

Friday, May 23, 2008

Javascript Templates

Javascript Templates(http://code.google.com/p/trimpath/wiki/JavaScriptTemplates) is a sub project of project Trimpath. It is a client-side template engine whose functionality is similar to server-side Velocity and Smarty engines. It uses special markup syntax. Besides simple template matching and replacing, it also supports simple control flow, loop and variable declarations... Now I summarize the syntax:
Statements:
(1) Variable Declaration
Syntax Example
{var variable}
{var variable = value}
{var price}
{var price = 10}
Note: No ending ';' is needed.

(2) Control Flow

Syntax Example:
{if expression}
    {elseif expression} ...   
    {else} ...
{/if}
{if price > 10}
    {elseif price <20}...  
    {else}...
{/if}
Note: No surrounding brackets are needed in test expression. No white space between first '{' and 'if'.

(3) Loop

Syntax Example
{for varariable in list}
   statements go here
{/for}
{for price in pricelist}
    ${alert(price)}
{/for}

(4) Expression

Syntax Example
${expression} ${car.brand}
${expression|modifier} ${car.brand|capitalize}
${expression|modifier1|modifer2} ${car.brand|default:"chevy"|capitalize}
... ...

Value of the expression will be returned.

Note:
Statement for( ; ; ) is not supported.
These statements are parsed and processed by Javascript Template Library instead of javascript itself.

More:
(5) CDATA Text. Tag is cdata.
CDATA Text will be ignored and will not be processed.
(6) In-line javascript block. Tag is eval.
Multiple line javascript code can be put in a single block to evaluate.
(7) If you have multiple-line js code, you can use minify to tell processor to treat them as a whole.
For example:
<input type="button" onClick="{minify} Javascript event
handling code...
{/minify}">

Note: eval and minify are different althought they are sort of similar.

How to process templates?
API: http://code.google.com/p/trimpath/wiki/JavaScriptTemplateAPI.
Commonly used functions:
(1) TrimPath.parseDOMTemplate ( elementId, contextObject )
This function retrieves content of the element corresponding to the first parameter. It should be a textarea element and its should be hidden.
The second parameter is a context object and it will be "merged" with the template. For example, if a template refers to ${car}, then the processor tries to access contextObject.car.
(2) TrimPath.parseTemplate ( templateContentStr )
This function accepts a string as template instead of a dom element id.
You can parse a string template in this way:
TrimPath.parseTemplate( stringvariable ).process( contextObject ).

Variable Resolvation Precedence:
There are three kinds of scopes:
(1) Processor scope: it consists of all template statements.
(2) Context object scope: All properties of the context object.
(3) Local scope: local variables whic are not defined in template.

Case 1: In template expression and {eval}:
Processor scope is checked first, then context object is checked. At alst, local scope is checked.
For example:
    var data={car : "chevy"};
    var str = '${alert(car)}';
    str.process(data);        //alert "chevy"

    var str2 = '{var car = "ford"} ${alert(car)}''
    str2.process(data);      //alert "ford"

    var car = "toyota";
    var str3 = '${alert(car)}';
    str3.process();      //alert "toyota"

Case 2: All variables defined in template do not have effect in local scope.
For example:
    var str = '{var car="chevy"}${alert(car)}';
    str.process(data);        //alert "chevy"
    alert(car);                   //variable 'car' is not defined.