source code bean

In this post I am going to show how easy it is to create a JSON-RPC web service using the built in support in Zend Framework.

First we need to create the php-file that will handle the incoming RPC calls. It is not advised to put this inside the MVC structure of a Zend web application, since that will lead to unessesary complexity and overhead. The Zend people recommend that we create the JSON-RPC under /public/api/vX/, so lets create the file /public/api/v1/jsonrpc.php (if you haven’t setup your Zend MVC structure, read my blog post Getting started with the zend framework to get started).

We will have to do the regular bootstrapping to get our application up and running:

  1.  
  2. // Define path to application directory
  3. defined(‘APPLICATION_PATH’)
  4.     || define(‘APPLICATION_PATH’, realpath(dirname(__FILE__) . ‘/../../../application’));
  5.  
  6. // Define application environment
  7. defined(‘APPLICATION_ENV’)
  8.     || define(‘APPLICATION_ENV’, (getenv(‘APPLICATION_ENV’) ? getenv(‘APPLICATION_ENV’) : ‘production’));
  9.  
  10. // Ensure library/ is on include_path
  11. set_include_path(implode(PATH_SEPARATOR, array(
  12.     realpath(‘../../../library’),
  13. )));
  14.  
  15. /** Zend_Application */
  16. require_once ‘Zend/Application.php’;
  17.  
  18. // Create application, bootstrap, and run
  19. $application = new Zend_Application(
  20.     APPLICATION_ENV,
  21.     APPLICATION_PATH . ‘/configs/application.ini’
  22. );
  23.  
  24. $application->bootstrap();
  25.  

The next step is to create the class that will be exposed through the service. I will create a very simple class that will simply perform an addition of two ints. It is very important to describe the input parameters using the @param directive in the comment. This information is used by the Json Server when creating the SMD (Service Mapping Description).

  1.  
  2. /**
  3.  * Simple – sample class to expose via JSON-RPC
  4.  */
  5. class Simple
  6. {
  7.     /**
  8.      * Return sum of two variables
  9.      *
  10.      * @param  int $x
  11.      * @param  int $y
  12.      * @return array
  13.      */
  14.     public function add($x, $y)
  15.     {
  16.         return array(‘result’ => $x + $y);
  17.     }
  18. }
  19.  

The last step to get the JSON-RPC server running:

  1.  
  2. // Instantiate server, etc.
  3. $server = new Zend_Json_Server();
  4. $server->setClass(‘Simple’);
  5.  
  6.  
  7. if (‘GET’ == $_SERVER[‘REQUEST_METHOD’]) {
  8.     // Indicate the URL endpoint, and the JSON-RPC version used:
  9.     $server->setTarget(‘/api/v1/jsonrpc.php’)
  10.            ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
  11.  
  12.     // Grab the SMD
  13.     $smd = $server->getServiceMap();
  14.  
  15.     // Return the SMD to the client
  16.     header(‘Content-Type: application/json’);
  17.     echo $smd;
  18.     return;
  19. }
  20.  
  21. $server->handle();
  22.  

Now your JSON-RPC Server should be up running. Browsing http://{your web server}/api/v1/jsonrpc.php should result in the following SMD:

  1.  
  2. {
  3.   "transport":"POST",
  4.   "envelope":"JSON-RPC-2.0",
  5.   "contentType":"application\/json",
  6.   "SMDVersion":"2.0",
  7.   "target":"\/api\/v1\/jsonrpc.php",
  8.   "services": {
  9.       "add":{
  10.           "envelope":"JSON-RPC-2.0",
  11.           "transport":"POST",
  12.           "parameters":[
  13.               {"type":"integer","name":"x","optional":false},
  14.               {"type":"integer","name":"y","optional":false}],
  15.           "returns":"array"
  16.        }
  17.     },
  18.    "methods":{
  19.        "add":{
  20.            "envelope":"JSON-RPC-2.0",
  21.            "transport":"POST",
  22.            "parameters":[
  23.                {"type":"integer","name":"x","optional":false},
  24.                {"type":"integer","name":"y","optional":false}],
  25.            "returns":"array"}
  26.        }
  27. }
  28.  

jQuery does not support calling JSON-RPC services out of the box, but fourtenly there is plenty of plugins for jquery that fixes this. One is the JSON-RPC client found here. Download the client and put the javascript files into your /js folder. Then create a new file test.html and add the following html:

  1.  
  2. <html>
  3. <head>
  4.         <script LANGUAGE="javascript" SRC="js/jquery-1.3.min.js"></script>
  5.         <script LANGUAGE="javascript" SRC="js/json2.js"></script>
  6.         <script LANGUAGE="javascript" SRC="js/jquery.zend.jsonrpc.js"></script>
  7.         <script>
  8.                 $(document).ready(function(){
  9.                         test = jQuery.Zend.jsonrpc({url: ‘/api/v1/jsonrpc.php’});
  10.                         alert(test.add(1,1)['result']);
  11.                 });
  12.         </script>
  13. </head>
  14. <body>
  15. </body>
  16. </html>
  17.  

We are all done! Browsing test.html should result in an alert box containg the result.
result

Congratulations! You have created a JSON-RPC service!



Read more about the Zend Framework:

Today I upgraded a project we started working on last year from Zend Framework 1.7 to Zend Framework 1.9. I excepted to run into several API incompatibilities, but the only problem I got was the autoloader.

In Zend 1.7, and earlier versions, the autoloader was registered like this:

  1.  
  2. require_once "Zend/Loader.php";
  3. Zend_Loader::registerAutoload();
  4.  

In Zend Framwork 1.9 this has changed slightly, you now have to register the namespaces you want to autoload:

  1.  
  2. require_once ‘Zend/Loader/Autoloader.php’;
  3. $loader = Zend_Loader_Autoloader::getInstance();
  4. $loader->registerNamespace(‘Dqc_’);
  5.  

This was the only change we needed to do to upgrade from 1.7 to 1.9, quite impressive!

It used to be quite tricky to get started with the Zend Framework. The Zend Framework is very flexible and allows you to set it up in almost any way that fits your needs. This means for example that the directory structure and location of files is up to you, however – there is a recommended layout. When I first started using Zend I had to figure out this by looking at examples and reading the rather poor documentation available. In Zend Framework 1.9 a tool, zf.sh, was introduced. It simplifies creating a new site a lot. In this blogpost I will guide you though the process of setting up a Zend development environment in OS X. The only part that is OS X specific is MAMP. Zend Framework runs just fine under Windows and Linux as well.

Step 1 – Getting a *AMP setup (LAMP, MAMP, WAMP)
The AMP (Apache, Mysql, PHP) stack is available for almost all modern operating systems. I am writing this on my Macbook, so in this tutorial I will use MAMP. When I develop PHP in Windows I usually use WAMPServer and in Linux you can install the LAMP-stack using the packaging system in most distributions.

Setting up MAMP is pretty straightforward, download the MAMP .dmg-file and drag the MAMP folder to your Applications folder.
mamp

Start the application and press the “Open start page” button to make sure everything works. On the start page you will find information about your site, phpInfo, phpMyAdmin and SqLiteManager. We will get back to configuring the http root directory later.

Step 2 – Download and install Zend Framework
Go to the framwork download page and download the minimal distribution. In this tutorial I am using 1.9.6, but the instructions will probably apply to all 1.9 versions.

Extract the downloaded file and move the folder to a shared location, for example /usr/local/. Next step is to create an alias for the zf.sh tool. Edit your ~/.bash_profile and add the following line (change the path to where you moved the extracted files):

zf=/usr/local/ZendFramework1.9/bin/zf.sh

This will allow you execute the zf tool without using the full path. Try it out by executing zf show version, it should return the version number of the file you downloaded.


$ zf show version
Zend Framework Version: 1.9.6

Step 3 – Create your project
Go to the folder where you want to create your new project, in my case ~/Development/. Run zf create project zf-tutorial. This will setup the default directory structure and create the necessary files.

Zend Framework directory structure

The application/ folder is where the source code for your website lives. It contains separate folder for models, views and controllers. The public/ folder is the folder that is going to be your document root.

Now you need to copy the Zend library (in my case /usr/local/ZendFramework1.9/library/Zend) or create a symlink for it so your site can find the Zend files. I prefer using a symlink:


$ cd ~/Development/zf-tutorial/library
$ ln -s /usr/local/ZendFramework1.9/library/Zend/ Zend

Step 4 – Run the project
The last step before we will have running site up is to configure the step that we skipped in Step 1, configuring the Apache document root.
sitesettings

Open up MAMP and click the preferences button, under the apache tab you will find the document root. Click select and navigate to the “public” folder in your zend project. Apply the settings and restart the server.

Now open your browser and direct it to http://localhost and you should see the default welcomescreen:
zenddefault

Now open your application/controllers/IndexController.php and start hacking your code!



If you want to learn more about the Zend Framework i have some posts on some more advanced topics:

About a month ago I finished reading the book ASP.NET MVC 1.0 – Test Driven Development by Emad Ibrahim. The book weighs in only at about 300 pages, making it easily something you can read in a couple of nights. The book is written in tutorial fashion and is is probably best read with a laptop running Visual Studio on your lap, so you can follow the examples in the book. The paradigm of the book is Problem, Design, Solution. Emand gudies the reader though the full process of creating a web application in a Test Driven manner.

Besides from only presenting MVC and TTD Emand presents several very useful libraries for Test Driven Development:

  • Moq – A mocking library for .NET that uses the power of LINQ to create mocks.
  • Ninject – Dependency injection library for .NET
  • MBunit – An alternative to VSTest

I think the book gives a good kickstart in ASP.NET MVC and TTD. My favorite part of the book was actually not reading about MVC itself, it was reading about testing it – Emad shows the strengths of MVC by showing how it makes testing easier.

07 Dec, 2009

ZFS for home NAS?

Posted by: Peter In: NAS| Storage| UNIX

I have been doing some research on NASes for home use. I basically want a NAS that offers redundancy (some form of raid), the ability to add disks as I go. It should also support at least SMB as file sharing protocol (but preferable others as well), and of course not be too expensive. All home NASes I have found yet has been lacking on at least one of the above criteria.

I have read about people using ZFS on FreeBSD or OpenSolaris for their storage servers. ZFS is a open source file system developed by Sun Microsystems which has some features that makes it very compelling for a file storage server. Unfourtanly ZFS is not available on Linux at the time of writing (i think it is some licensing issues that is preventing a port of it), if it were I would definitely go for it.

To give it a try, i downloaded OpenSolaris 2009.6 and installed it as a virtual machine in VMware Fusion. Instead of having to add several virtual disks to the VM, i decided to test the features of ZFS using regular files (ZFS can use files as disk devices). An easy way to create some “disks” is to use the mkfile command, it will create a file that can be used a disk device:

# mkfile 100m /tmp/disk1
# mkfile 100m /tmp/disk2
# mkfile 100m /tmp/disk3
# mkfile 100m /tmp/disk4

ZFS has tree leveles. The highest level is a ZFS pool, which can consist of several ZFS filesystems. A ZFS filesystem consists of one or more devices. Filesystems within a pool share its resources and are not restricted to a fixed size. You can add or remove devices to a pool (for example to increase your storage space), while the pool is running. Devices in a filesystem can be configured in mirrored mode or in RAIDZ mode to offer redundancy. ZFS also supports filesystem level snapshots and cloning from existing file systems. The two main ZFS commands are:

zpool - Manages the pools and the devices within them
zfs - Manages ZFS filesystems

Ok, so lets create a pool from the disks we created earlier:

# zpool create storage /tmp/disk1 /tmp/disk2

# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
rpool 7.94G 4.28G 3.66G 53% ONLINE -
storage 191M 74.5K 191M 0% ONLINE -

As you can see we combined two disks into one pool. The filesystem automatically gets mounted on /storage (this is the default mount point, it can be changed). No volume management, configuration or formatting is needed. Lets destoy this pool to create a more interesting one.

# zpool destroy storage

# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
rpool 7.94G 4.36G 3.58G 54% ONLINE -

As you can see, it is gone. Lets create a new pool using RAIDZ (a form of raid, similar to RAID5):

# zpool create storage raidz /tmp/disk1 /tmp/disk2 /tmp/disk3

# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
rpool 7.94G 4.38G 3.56G 55% ONLINE -
storage 286M 140K 286M 0% ONLINE -

One thing that’s a little different in a ZFS raidz pool versus other RAID-5 filesystems is that the reported available disk space doesn’t subtract the space required by parity. Of course parity will take up space, so this is something to keep in mind when monitoring the disks. We can monitor the status of the pool by using the zpool status command:

# zpool status storage
pool: storage
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
storage ONLINE 0 0 0
raidz1 ONLINE 0 0 0
/tmp/disk1 ONLINE 0 0 0
/tmp/disk2 ONLINE 0 0 0
/tmp/disk3 ONLINE 0 0 0

errors: No known data errors

After some playing around with ZFS i certainly think it would be a great choice for a storage server. It is way easier to use than the software/LVM solutions i have tried on Linux. The biggest drawback would be OpenSolaris itself, I just find the GNU application userland easier to use compared to the Solaris one. Maybe I should give Nexenta (OpenSolaris Kernel, GNU application userland) a chance?

Read more:
ZFS on Wikipedia
RAID-Z

So I restored a backup from from MSSQL 2005 to a MSSQL 2008 database, which kept the database in “SQL 2005 compatibly mode”. I thought that this would mean that the database could actually be backed up from the MSSQL 2008 server to the MSSQL 2005 server, however it turns out that this is not the case. Backing it up from 2008 and trying to restore it, resulted in the the following slightly cryptic error:

An exception occurred while executing a Transact-SQL statement or batch. (Microsoft.SqlServer.Express.ConnectionInfo)
The media family on device ‘C:\Temp\db.bak’ is incorrectly formed. SQL Server cannot process this media family.
RESTORE HEADERONLY is terminating abnormally. (Microsoft SQL Server, Error: 3241)

After some googeling it turns out that MSSQL 2005 can not read backups from 2008. The solution I found to the problem was to export the database as a SQL script, and running the script on the SQL 2005 server. Maybe not the best solution, but it saved my day.

This is how you create the script file:
In Object Explorer in SQL 2008 management studio, right-click the database, select Tasks->Generate Scripts. In the options dialog enable everything, including Script Data. Make sure you select “Script for SQL 2005″ (otherwise you will export a SQL 2008 script file). Then run the script on your SQL 2005 server and hopefully you are done!

While reading the EPiServer 5 SDK documentation, i found this:

Rename a Folder

There is no Rename method on the EPiServer.Web.Hosting.UnifiedDirectory class. To rename a folder you need to call the MoveTo method as follows:

  1.  
  2. protected void RenameFolder(string path, string oldName, string name)
  3. {
  4.     if (IsFolder(path))
  5.     {
  6.         UnifiedDirectory directory =
  7.         System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetDirectory(path) as UnifiedDirectory;
  8.  
  9.         int e = -1;
  10.         while (path.IndexOf(oldName, ++e) > -1) ;
  11.  
  12.         StringBuilder sb = new StringBuilder();
  13.         sb.Append(path.Substring(0, e – 1));
  14.         sb.Append(name);
  15.         sb.Append("/");
  16.  
  17.         directory.MoveTo(sb.ToString());
  18.     }
  19. }
  20.  

What a convenient way of renaming a folder :) Good thing that you don’t have to do it too often.

03 Oct, 2009

Microsoft Web Platform Installer

Posted by: Peter In: ASP.NET| Microsoft| Web

I recently needed to setup a new ASP.NET development environment and deiced to give Microsofts Web Platform Installer 2.0 a chance. I had actually never heard about this product before, but what it does is installing .NET, the needed development libraries, and the express versions of Visual Studio and SQL Server. It required three reboots, but in total it saved me a lot of time!

10 Aug, 2009

Playing with WSGI in Python (part 1)

Posted by: Peter In: Linux| Python| Web

For the last month I have been playing around with WSGI in Python. WSGI is an interface between the web server and the web application, it is meant to simplify writing your own web framework in Python. My intention is not to write an fully fledged web framework, but rather just play around with some ideas I have and try it out.

In WSGI an application is just a callable object (remember that in Python functions are objects too!) that takes two parameters, environ and start_response. A very simple application could look like this:

  1.  
  2. def application(environ, start_response):
  3.    start_response(‘200 OK’, [(‘content-type’, ‘text/html’)])
  4.    return [‘Hello world!’]
  5.  

Not very exiting but it shows us the very basics of WSGI. The function start_response is a function that, as the name implies, starts sending out the response. This is where you give status and headers. Lastly the application returns an iterator with the body response (usually a list of strings or a list containing one string that is the entire body). As you can see WSGI lets code pass around web request in a fairly formal way.

To run this application you can either install Apache and configure it with modwsgi, this might however be slightly overkill just in order to test the application. Instead I recommend installing Python Paste (pythonpaste.com), which is kind of a framework for web frameworks. It includes a lot of functionality that can be reused, but more importantly right now, it includes a simple web server that can serve WSGI applications. In Ubuntu 9.04 (the operating system I am currently running) Paste can be installed using apt:

  1. apt-get install python-paste

To run the application, add the folowing lines to the end of your source file:

  1.  
  2. if __name__ == ‘__main__’:
  3.   from paste import httpserver
  4.   httpserver.serve(application, host=‘127.0.0.1′, port=‘8000′)
  5.  

Now it should be possible to run the application:

  1.  
  2. $ python appserver.py
  3. serving on http://127.0.0.1:8000
  4.  

Your web application is now up running! In the next part i will introduce you to a slightly more exiting application.

22 Jun, 2009

Friendly URLs in ASP.NET using URLRewriter.NET

Posted by: Peter In: ASP.NET| Web

I was having a chat the other day with Danish Peter (yes, another one) about URL rewrites in ASP.NET. In a previous post I wrote about how to use friendly URLs in the Zend framework, in this post, which is based on our discussion, I will discuss how to do this in ASP.NET.

Friendly URLs are achieved by a technique called URL-rewrite. A friendly URL is a URL that is easy to read and understand. Let me give you an example (from a site my girlfriend loves) of what is NOT a friendly URL:

http://www.bebe.com/bebe-Jersey-Knit-Apron-Dress/dp/B001UX1NBQ?ie=UTF8&asinSearchPageIndex=13&pf_rd_r=1C6TS27BZZ1CAD6WY81S&navAsinList=B001UNM3XS%2CB001OPYKKQ%2CB001UNNQ52%2CB001RPD88I%
2CB001R4NHHQ%2CB0026BM39W%2CB001QOU6TY%2CB001UX1NNY%2CB001UAA4WI
%2CB0024QP6KM%2CB0026RRN4G%2CB0027DCI6W%2CB001UX3QL6%2CB001UX1NBQ
%2CB001VROPT8%2CB00265NBKS%2CB001RPM80C%2CB001UBWNTO%2CB001RPIC1G
%2CB001PA2NMW&node=675941011&pf_rd_s=search-results&field_browse=675941011&searchSize=20&navAsinListIndex=0&pf_rd_t=101&field_availability=0&id=bebe%20Jersey%20Knit%20Apron%20Dress&searchBinNameList=null&store=core&pf_rd_p=476815091&ref=search_results_14&searchNodeID=675941011&pf_rd_i=675941011&field_launch-date=-1y&searchRank=-custom-rank&searchPage=1&pf_rd_m=A2FMOXN01TSNYY

This might be an extreme example, but there are plenty of sites which are as bad. If the above URL was transformed into a friendly URL it might look something like:

http://www.bebe.com/Apparel/Dresses/Jersey-Knit-Apron-Dress.html

The second address is easier to read. URL rewrite techniques have been around for a long time and the first time I used it was back in the early Apache 1.3 days. Today good sites use friendly URLs and if you have not adopted it yet, you need to start using it.

There are several benefits from using a friendly url scheme, the most prominent are:

  1. 1. The clear structure makes it easier for humans to read and understand the addres
  2. 2. It is easier for search engines to understand what the address is and crawler the site. URL structure that goes more than three directories deep is not always read by a spider.
  3. 3. If search engines understand the URL, it is also easier for them to help people finding what they want, giving better search results. Hence using keywords and proper titles makes life easier.

What options are there for ASP.NET?
There is no built in support for having friendly URLs in ASP.NET, but you could spend your time writing your own URL-rewrite module. Writing your own module is basically spending time reinventing the wheel. If you have the time, go ahead, but if not there are already several good ones out there (free and open source). One that I have found very useful is the URLRewriter.NET (http://urlrewriter.net/). URLRewriter.NET provides similar rewrite capabilities as the mod_rewrite does for Apache.

Using URLRewriter.NET
It is possible to use the URLRewriter.NET module without making any changes to the IIS configuration, this will however limit the functionallity the URLRewriter.NET rewriting capabilities. To use its full power, IIS should be configured to map all requests to the ASP.NET runtime (how to do this is covered in the manual). We will only be touching the surface of URLRewriter.NET so we will not have to do any modifications to the IIS configuration.

To add URLRewriter.NET to your project start out by opening Visual Studio or Visual Web Developer. Open your project and then right click the project in the solution explorer and click on Add Reference, go browse and find the folder you downloaded and unzipped. You will find the binary (.dll) file in “Loation”\urlrewriternet20rc1b6\UrlRewriterV2\bin\Release.

Before we can use the module we need to make some changes to the web.config. Add the following in the configSections:

  1. <configSections>
  2.   <section
  3.     name="rewriter"
  4.     requirePermission="false"
  5.     type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
  6. </configSections>

This will allow the URL writer to read the rewrite rules we will define later. Now we need to add this module to the httpModules section:

  1. <system.web>
  2.   <httpModules>
  3.     <add
  4.       type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"
  5.       name="UrlRewriter" />
  6.     </httpModules>
  7.  </system.web>

By adding the rewriter as a httpModule we allow it to intercept web requests and route the requests to the actual aspx file serving the page. Now we need to define the rewrite rules:

  1. <rewriter>
  2.   <rewrite url="~/(.+)/(.+)/(.+)/(.+).shtml" to="~/Default.aspx?Year=$1&amp;Month=$2&amp;Date=$3&amp;Title=$4"/>
  3.   <rewrite url="~/Article/(.+).shtml" to="~/Articles.aspx?ID=$1"/>
  4. </rewriter>

The rewrite rules are defined using regular expressions. Regular expressions are very powerful and is something every programmer should know. The syntax might be hard to remember but there are several great tools to help build advanced regular expressions, for example the RegexDesigner.NET (http://www.sellsbrothers.com/tools/#regexd) that Chris Sells has created.

The above rewrite rules are simple. The first rewrite rule will rewrite URLs like

sourcecodebean.com/2009/04/01/1.shtml

to

sourcecodebean.com/Default.aspx?Year=2009&Month=04&Date=01&Id=1



And the second rewrite rule will match requests starting with ~/Article/ so it will rewrite URLs like

sourcecodebean.com/Article/1.shtml

to

sourcecodebean.com/Articles.aspx?ID=1

Finishing up
By now you hopefully have a functioning site that uses friendly URLs. One of the common problems you might run into is broken links. To avoid this you should make sure that you reference all your pages from the root level (~) and that all your links has the runat=server tag.

Thanks for your input Peter! You can check out his Danish Peter blog over at Magic Mouse.

Categories

Adwords

Twitter Updates