Tuesday, June 15, 2010

RESTful on Google App Engine in 5

 RESTful on Google App Engine in 5

Quick prototyping and publishing is very useful in developing RESTful services.  It's essential that consumers can access and experiment with a service while it's being developed.  The Google App Engine (GAE) platform is free at the entry level, and provides sufficient capabilities to deploy RESTful applications with a public URI.

Prepare the Environment
  1. Obtain a free GAE account by visiting: appengine.google.com.
  2. From the "My Applications" view on the appengine page, create a new application ID.
  3. Install the Eclipse plugin .
Creating & Deploying a RESTful App on GAE
  1. In Eclipse, create a new web application (File / New / Web Application Project), notice the Google logo next to this option.
  2. Modify the appengine-web.xml file to reflect your new application ID:
    <application>your-app-id</application>



  3. Create a package for your REST classes


  4. Update web.xml with the following:


  5.     <servlet>
    <servlet-name>jersey</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>zpylx.restful</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>jersey</servlet-name>
    <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>



  6. Download JAXB 2.1 ; note that 2.2 does not run on GAE at this time; unpack the file or, if your systems is unix-based, run:

    java -jar JAXB2_20081030.jar



  7. Download the JAX-RS reference implementation (jersey), and unpack.


  8. Place the JAXB and JAX-RS jars in the Eclipse project under /war/WEB-INF/lib.  Also, add the jars to the Java build path of the project.


  9. package zpylx.restful.action;

    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;


    @Path("/activitieslist")
    public class MapActivities {

    @GET
    @Produces("text/plain")
    public String getItems() {
    return "restful web service example";
    }



  10. Create RESTful classes, e.g.: Deploy to app engine from Eclipse, by clicking on the "Deploy App Engine Project" icon in the toolbar (installed by the GAE plugin).


  11. The application, based on the configuration above, would be accessible from this URI:  your-app-id.appspot.com/rest/activitieslist


  12. Manage application versions and view logs from the admin dashbord: appengine.google.com/dashboard?&app_id=your-app-id





example link: http://zhoupengylx.appspot.com/rest/activitieslist

Thursday, June 3, 2010

Seamless Java RDP client

(I had done this two years ago and posted on my personal website. I never thought someone still sent email to me for this, even ask for source code. I think maybe more people want to know it. Posting on blogger is absolutely much popular than on my personal website).

It is built base on properJavaRDP, which is an open source Java RDP client for Windows Terminal Services. The idea of "seamless" is come from rdesktop, which is a open source RDP client on unix platform. "seamless" can make remote running application looks like running locally. I upgrad properJavaRDP code from AWT to Swing, and add the functionality to handle "seamless" message in a special rdp vchannel.

 new update(2010.06): support window 2008 now (solve problem of “wrong modulus size! expected64+8got:264”)

new update(2010.06.17): support seamless mode applet

Seamless Java RDP client

It is a general Java RDP client for Windows Terminal Services with "seamless" feature. It is built base on properJavaRDP.

Product details


To use seamless feature, you need seamlessRDP server extension. A SeamlessRDP server extension is available to support integration of individual applications with the client desktop. Precompiled binaries are available from Cendio (If you want Connetion sharing feature, you have to get patch from http://www.fontis.com.au/rdesktop). My contribution is updated properJavaRDP code from AWT to Swing, and add the functionality to handle "seamless" message in a special rdp vchannel. jdk1.6.0-10 is needed, since shaping jframe is a new feature of jdk1.6.0-10.

To download the client jar file: javaRDP16-1.1.jar. A usage document is here:HowTo.

I also write a Adito extension: adito-application-seamlessjavardp.zip. Just for you convenience, i upload service side exe package here:seamlessrdp_server.zip.

(05/12/2009) Recently, i got chance to take a look at "rdesktop session connection-sharing" from http://www.fontis.com.au/rdesktop. It is a very interesting feature which can save TS session. I think it is good to port this feature to my seamless JavaRDPClient. It took me one day to do this. I have updated all above link with the new update. Welcome you to try this cool feature.

"Connection sharing - allows a single rdesktop connection to launch multiple applications. When run in seamless mode, rdesktop creates and listens on a control socket. A new option allows rdesktop to be run in slave mode, which notifies the master rdesktop instance of a new command to be run and then exits. The master instance sends a client-to-server message to the SeamlessRDP server component, which runs the new command".

see the difference of "seamless rdp" from normal rdp client with following screenshot:

1. nornal properJavaRdp client: ie and notepad is running on a remote server. you can see there is always a "frame" around the remote application.(My OS is english version XP, remote server is a chinese version windows 2003)

2. Seamless rdp client: ie and notepad is running on a remote server. you can are running like "local" application. (My OS is english version XP, remote server is a chinese version windows 2003)

The usage:

First, On windows as server

download seamlessrdp_server.zip and upzip it to C:\seamlessrdp

Then, on client side (windows or unix support jdk1.6u10),

Run the pure seamless client:

c:\>java -jar JavaRDP16-1.1.jar -u administrator -p 111111 -fs -s "C:\seamlessrdp\seamlessrdpshell.exe C:\Program Files\Internet Explorer\iexplore.exe" 192.168.1.135:3389

Run as seamless client with Connection-sharing feature:

1. start the firt client :

c:\>java -jar JavaRDP16-1.1.jar -u administrator -p 111111 -fm -s "C:\seamlessrdp\seamlessrdpshell.exe C:\Program Files\Internet Explorer\iexplore.exe" 192.168.1.135:3389

2. start more client but share the same connection with above one:

c:\>java -jar JavaRDP16-1.1.jar -fc -s "C:\Program Files\Internet Explorer\iexplore.exe"

------------------------------------------------------------------------------------------------------------------------

How to run as applet:  

(take a look at exampleHtml to be aware of how to fill the params.)

First, the JavaRDP16-1.1.jar should be signed, and make sure it is in the right directory. I wrote a html(javaRdpApplet.html) and “sign.bat” in case you do not know how to sign and run the RDP jar.

Step by step:

1. create self certification and sign the jar package. In “sign.bat”, there are four commands to be executed:

keytool -genkey -dname "cn=BeanSoft Studio, ou=Java Software, o=BeanSoft Studio, c=China" -alias beansoft -keypass beansoft -storepass beansoft -validity 365 -keystore .\beansoft

keytool -list -keystore .\beansoft -storepass beansoft

keytool -export -keystore .\beansoft -storepass beansoft -file beansoft.cer -alias beansoft

jarsigner -verbose -keystore .\beansoft javaRDP16-1.1.jar beansoft

If you already have your certification file, you may just need to run the command in last line.

Before running sign.bat, the file list is as below:

clip_image002

2. run the sign.bat, you will get a window as below, input your password, in my case, it is “beansoft”.

clip_image004

3. Now, you got file list should like:

clip_image006

Notice that the size of javaRDP16-1.1.jar is bigger than original one. (in my testing, it is from 352KB to 374KB). It is becase it is signed. “jarsigner” add some file to META-INF.

4. Now you can try javaRdpApplet.html with IE explorer. I got message like below and it work well if you input correct IP address.

clip_image008

Wednesday, June 2, 2010

Flex tips

 

1. fileReference.load undefined - wrong SDK:

1061: Call to a possibly undefined method load through a reference with static type flash.net:FileReference

solution:

in Flex Bulider 3/4:
Project > Properties > Flex compiler
Change "HTML wrapper" --> "Require Flash Player version" from 9.x.x to 10.x.x where x is some numbers (In my case, I just change 9.0.124 to 10.0.0)

Sunday, March 28, 2010

Adito standalone agent client



(I had done this one and half year ago and posted on my personal website. I never thought someone still sent email to me for this. I think maybe more people want to know it. Posting on blogger is absolutely much popular than on my personal website).





Adito is an open-source, browser-based SSL VPN solution. It’s a remote access solution that provides users and businesses alike with a means of securely accessing network resources from outside the network perimeter using only a standard web browser.



What is my contribute?


I go throught almost all the code of Adito and debug it in Eclipse. Base on Agent code, i add a swing wrapper to it and run it as a standalone client. Related technology is java swing GUI, TLS socket. You can download it from here. Any bugs, please leave your comments below.



Adito


It is an open-source, browser-based SSL VPN solution. It’s a remote access solution that provides users and businesses alike with a means of securely accessing network resources from outside the network perimeter using only a standard web browser. For more information regarding Adito go here



Background


This is the open-source clone of SSL-Explorer after it went biz-o-matic.





What is standalone agent client






Generally, agent client is a systray and used like a applet. I notice that someone like to use it as a standalone application that you do not need to access web site each time and can run it from even console (of cause, you have to have jre), and it is convenient for debug agent server. I like the idea, so i add a Java Swing Wrapper base on original Adito agent code. Only Swing is supported, no swt.



Screenshots





login GUI





Main board



To download: agent.zip (new updated usage document, 2010.05)



the source code is at : https://sourceforge.net/projects/aditoagentclien/

Wednesday, February 3, 2010

how to use JExcel with spring 3 on google app engine

 

First, i tried org.apache.poi. It works in local but throw exception when i upload it to google app engine. Then i have to to JExcel, it works well till now.

step 1: setup your spring environment for your google app engine, please refer my previous article for this.

step 2: download jexcelapi, what i used is jexcelapi_2_6_12. Then copy jxl.jar into war/WEB-INF/lib/ and add it to build path.

step 3: configure web.xml to add spring configuration as below

    <servlet>
<servlet-name>web-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>web-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>



step 4: create web-dispatcher-servlet.xml which is required by spring looks like below:



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>

<context:component-scan base-package="com.zpylxapp.controller.html" />

<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views" />
</bean>
</beans>



step 5: create views.properties file under your “src” directory and add following configuration



xl.(class)=com.zpylxapp.excel.HomePage



step 6: create com.zpylxapp.excel.HomePage view class



package com.zpylxapp.excel;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jxl.*;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.springframework.web.servlet.view.document.AbstractJExcelView;
public class HomePage extends AbstractJExcelView {

protected void buildExcelDocument(Map model, WritableWorkbook wb,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
WritableSheet sheet = wb.createSheet("Spring", 0);
sheet.addCell(new Label(0, 0, "Spring-Excel jexcel"));
List words = (List) model.get("wordList");
for (int i = 0; i < words.size(); i++) {
sheet.addCell(new Label(2 + i, 0, (String) words.get(i)));
}
}
}

step 7: create your controller use “return new ModelAndView("xl", map);” as return

@Controller
@RequestMapping("/inventory")
public class InventoryController {

@RequestMapping(value = "/{item}", method = RequestMethod.GET)
public ModelAndView getxls(Inventory item) {

Map map = new HashMap();
List wordList = new ArrayList();
wordList.add("hello");
wordList.add("world");
map.put("wordList", wordList);
return new ModelAndView("xl", map);
}
}



step 8: done! try it in your google app engine.

Monday, February 1, 2010

Iphone NSDate and NSDateComponents

 

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/DatesAndTimes/Articles/dtCalendars.html#//apple_ref/doc/uid/TP40003470-SW1

1. use components:fromDate:toDate:options: to determine the temporal difference between two dates in units other than seconds (which you could calculate with the NSDate method timeIntervalSinceDate

NSDate *startDate = ...; 
NSDate *endDate = ...;

NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];

NSUInteger unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;

NSDateComponents *components = [gregorian components:unitFlags
fromDate:startDate
toDate:endDate options:0];
NSInteger months = [components month];
NSInteger days = [components day];




2. use the dateByAddingComponents:toDate:options: method to add components of a date (such as hours or months) to an existing date



NSDate *today = [[NSDate alloc] init]; 
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setHour:1];
[offsetComponents setMinutes:30];
// Calculate when, according to Tom Lehrer, World War III will end
NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:comps toDate:today options:0];

Thursday, January 14, 2010

Goolge app engine +JPA+ java + spring + REST + JSON + Iphone

 

I have been inching to try out google app engine and its capabilities with "app engine + java + BlazeDS + Flex", it works well on my personal website. But "remote object data accessing" is not suitable for client platform like Iphone and Android. I happend find a great topic talking about "app engine + java + spring + REST + JSON", it does help me with my Planned Iphone preject.

The end product will be spring mvc app running in google app engine handling GET, POST, PUT and DELETE http requests with JSON objects in and out utilizing JDO and seesions. And you can access it from you Iphone App.
So here you have it. Step by step.

Part One: Once you are finished with this article, you will be able to implement REST services in Google Apps Engine using JAVA, Spring 3.0 and JSON.

  1. Eclipse with google App engine. I am using Eclipse, which is my favorite IDE. There is a lot of article about how to install Google App Engine on eclipse, and google also have great help doc here: http://code.google.com/eclipse/docs/download.html. I believe you can get it done easily and finally you will got something like:

  2. Create a new google Web Application Project: File -> new -> Web Application Project (google), and named it like "gae-json-iphone"
  3. Add Spring Support.

    Go Download the latest version of Spring 3 from http://www.springsource.org/download. For this tutorial we have downloaded spring-framework-3.0.0.RELEASE-with-docs.zip, which contains the documentation also. unzip it into a folder where you keep your java libs. Copy the following Jars into war\WEB-INF\llib directory:
    1.   org.springframework.asm-3.0.0.RELEASE.jar
    2.   org.springframework.beans-3.0.0.RELEASE.jar
    3.   org.springframework.context-3.0.0.RELEASE.jar
    4.   org.springframework.core-3.0.0.RELEASE.jar
    5.   org.springframework.expression-3.0.0.RELEASE.jar
    6.   org.springframework.oxm-3.0.0.RELEASE.jar
    7.   org.springframework.web-3.0.0.RELEASE.jar
    8.   org.springframework.web.servlet-3.0.0.RELEASE.jar :
    Also grab your favorite version of log4j.jar and commons-logging-1.1.1.jar. Remember to rename commons-logging-1.1.1.jar to something like commons-logging-1.1.jar, google app engine replaces this jar with its own version with crippled packages, by providing different name we keep both versions and make spring happy. see more why . Once you copied the jars, open project preferences and add those jars to the build library path:

  4. configuring spring.
    The final version should look like this:
    <?xml version="1.0" encoding="utf-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

    version="2.5">
    <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>
    <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

    <servlet>
    <servlet-name>rest-json</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>rest-json</servlet-name>
    <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    </web-app>



  5. Add JSON support. -- Jackson JSON.Grab the library from here and put jackson-core-1.4.jar and jackson-mapper-1.4.jar file into projects WEB-INF/lib directory


  6. Configure Spring

    To configure Spring servlet we need to create servletname-servlet.xml file for spring bean configuration. Our file has to be named rest-json-servlet.xml.



    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd"
    >

    <!--
    tell String to scan “com.zpylxapp.iphone” package for any bean
    annotations
    -->
    <context:component-scan base-package="com.zpylxapp.iphone" />

    <!--
    define message converter to convert messages sent to the server into
    beans using MappingJacksonHttpMessageConverter
    -->
    <bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
    <list>
    <ref bean="jsonHttpMessageConverter" />
    </list>
    </property>
    </bean>

    <bean id="jsonHttpMessageConverter"
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />

    <!--
    tells spring to render messages sent from the server to the client
    using JsonView
    -->
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
    <map>
    <entry key="json" value="application/json" />
    </map>
    </property>
    <property name="defaultContentType" value="application/json" />
    <property name="defaultViews">
    <list>
    <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
    </list>
    </property>
    </bean>

    </beans>




Part Two: Using JPA with App Engine. GAE support both JDO and JPA. I use JPA here. see detail of GAE JPA here.




  1. Creating the persistence.xml File. The JPA interface needs a configuration file named persistence.xml . You can create this file in /src/META-INF/persistence.xml :

    <?xml version="1.0" encoding="UTF-8" ?> 
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">

    <persistence-unit name="transactions-optional">
    <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
    <properties>
    <property name="datanucleus.NontransactionalRead" value="true"/>
    <property name="datanucleus.NontransactionalWrite" value="true"/>
    <property name="datanucleus.ConnectionURL" value="appengine"/>
    </properties>
    </persistence-unit>

    </persistence>



  2. Getting an EntityManager Instance.

    An app interacts with JPA using an instance of the EntityManager class. You get this instance by instantiating and calling a method on an instance of the EntityManagerFactory class. The factory uses the JPA configuration (identified by the name "transactions-optional") to create EntityManager instances.



    Because an EntityManagerFactory instance takes time to initialize, it's a good idea to reuse a single instance as much as possible. An easy way to do this is to create a singleton wrapper class with a static instance, as follows:



    EMF.java



    import javax.persistence.EntityManagerFactory; 
    import javax.persistence.Persistence;

    public final class EMF {
    private static final EntityManagerFactory emfInstance =
    Persistence.createEntityManagerFactory("transactions-optional");

    private EMF() {}

    public static EntityManagerFactory get() {
    return emfInstance;
    }
    }



  3. User bean to support permissions.
    package com.zpylxapp.iphone;

    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;

    @Entity
    public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String name;
    private String password;


    public long getId() {
    return id;
    }
    public void setId(long id) {
    this.id = id;
    }
    public String getEmail() {
    return email;
    }
    public void setEmail(String email) {
    this.email = email;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public void setPassword(String password) {
    this.password = password;
    }
    public String getPassword() {
    return password;
    }
    }



  4. Implement Login Controller. (for POST request “/login”)
    package com.zpylxapp.iphone;

    import java.io.IOException;
    import java.util.List;

    import javax.persistence.EntityManager;
    import javax.servlet.http.HttpServletRequest;

    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;

    import com.zpylxapp.jpa.*;

    @Controller
    @RequestMapping("/login")
    public class LoginController {

    private static Logger logger = Logger.getLogger( LoginController.class );

    @SuppressWarnings("unchecked")
    @ModelAttribute("user")
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public User login( @RequestBody User user, HttpServletRequest request ) throws IOException {
    logger.debug(user);

    // Hardcoded for demo website
    if( user.getName().equalsIgnoreCase("user1") && user.getPassword().equals("password1") ) {
    user.setId(1001);
    user.setEmail("fake@email.com");
    //set user session to check if user login or not.Even it is RESTful, we still need "Session"
    request.getSession(true).setAttribute( Constants.SESSION_USER , user);
    return user;
    }

    EntityManager em = EMF.get().createEntityManager();
    List<User> users;
    try {
    javax.persistence.Query query = em.createQuery("select p from User p ");
    users = (List<User>)query.getResultList();
    if(users.size()>0)
    return users.get(0);
    } finally {
    em.close();
    }
    return null;
    }
    }



  5. Add a preHandle interceptor, to check only if the user is present in the session. If no user is present and user is not trying to log in, send back an error. lets code our interceptor. I named it SessionInerceptor:
    package com.zpylxapp.iphone;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

    public class SessionInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
    User user = (User) request.getSession().getAttribute(
    Constants.SESSION_USER);
    String uri = request.getRequestURI();
    String base = request.getContextPath();
    uri = uri.substring(base.length());
    if (user == null && !uri.startsWith("/api/login")) {
    request.getSession().invalidate();
    response.setContentType("application/json");
    response.getWriter().write("{\"error\":\"SESSION-EXPIRED\"}");
    return false;
    }
    return true;
    }

    }



    Now lets add this interceptor to the Spring MVC stack by adding these 5 lines to our rest-json-flex-servlet.xml file.



    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
    <bean class="com.lureto.rjf.SessionInterceptor"/>
    </property>
    </bean>



    One more thing – we need to enable session in google app engine. Add this line to your appengine-web.xml.



    <sessions-enabled>true</sessions-enabled>



    sessions are backed up by the datastore, you should be able to see the session data using the Data Viewer in the Admin Console.



    work on java part is already done. Let us move to Iphone client.





Part Three: Using JPA with App Engine.




  1. To use JSON in Iphone, you need third part library like json-framework. Download JSON_2.2.2.dmg and open it, then drag the JSON directory into your project.

    Picture_7 




  2. Create a view based iphone project, add button and textfield as following:

     Picture_8



     




  3. Handler to the “login” button is as below. which will get user/password from user input and encapsulate them in a JSON post request. If the user is invalid, give an alert window. If it is valid, the response is a NSDictionary type. It will be display in another TableView based page.
    -(IBAction)sendLogin:(id)sender{

    //prepare json data
    NSString *username = tfUsername.text;
    NSString *password = tfPassword.text;

    NSDictionary *data = [[NSDictionary alloc] initWithObjectsAndKeys:
    username, USERNAMEKEY,
    password, PASSWORDKEY,
    nil];
    SBJsonWriter *json = [SBJsonWriter alloc];
    NSString *jsonString = [json stringWithObject:data];
    NSLog(jsonString);

    [data release];
    [json release];

    //create/send http post request
    NSData *postData = [jsonString dataUsingEncoding:NSASCIIStringEncoding];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:@"http://zpylxrealtors.appspot.com/api/login/"]];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postData];

    NSURLResponse *urlResponse;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:nil];
    [request release];
    NSString *jsonData = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    NSLog(jsonData);

    //parse response json data
    // Create a dictionary from the JSON string
    @try {
    NSDictionary *response = [jsonData JSONValue];
    id user = [response objectForKey:@"user"];
    if(user != nil && [user isKindOfClass:[NSDictionary class]]){
    //go to next view
    UserListViewController *nextview = [[UserListViewController alloc] initWithStyle:UITableViewStyleGrouped];
    nextview.user = user;
    [self presentModalViewController:nextview animated:YES];
    [nextview release];
    }
    else{
    //alert
    UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:@"Error"
    message:@"invalid user/password!" delegate:nil
    cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
    [myAlert show];
    [myAlert release];

    }
    }
    @catch (NSException * e) {
    //nothing to do here, just provent to crash when google location search does not work
    NSLog(@"NSException: ....");
    }
    @finally {
    [jsonData release];
    }
    }



  4. delegation code for the table view:
    @interface UserListViewController : UITableViewController {
    NSDictionary *user;
    }
    @property(nonatomic, retain) NSDictionary *user;


    ……………

    #pragma mark Table view methods


    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
    }



    // Customize the number of rows in the table view.
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 3;
    }



    // Customize the appearance of table view cells.
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];
    }

    // Set up the cell...
    if(indexPath.row == 0){
    cell.textLabel.text = @"name";
    cell.detailTextLabel.text = [user objectForKey:@"name"];
    }
    else if(indexPath.row == 1){
    cell.textLabel.text = @"id";
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", [user objectForKey:@"id"]];
    }
    else{
    cell.textLabel.text = @"email";
    cell.detailTextLabel.text = [user objectForKey:@"email"];
    }
    return cell;
    }



  5. result page:

    Picture_9 Picture_10