SQLite and RESTFul services

 

After few months, and with some more knowledges on Android platform, #Lifedroid is being redesigned. First idea was almost like using a Liferay server as persistence through its RESTFul services in a direct way. Which is an absolutely bad idea since we will want our Android app to work even if it is not connected to internet. 
 
We need to store our data , whatever it is, somewhere in the phone (or tablet) obviously . This is so obvious that Android engineers included SQLite data bases for available for apps. cheeky
 
So now in #Lifedroid, it is being developed a very simple and generic layer over Androids SQLiteOpenHelper class which one will provide abstraction for persistence.
 
public abstract class LDSQLiteHelper<T extends LDObject> extends SQLiteOpenHelper
 
As it can be seen in the signature, LDSQLiteHelper extend Android's SQLiteOpenHelper class, which is a helper class to manage database creation and version management, and we can get access to database through it.
 
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
 
LDSQLiteHelper class is an abstract class which one only can be instantiated with a parameter type that extends LDObject. LDSQLiteHelper, based on the parameter type implements basic methods as persist, getById, delete automatically.
 
So, lets say we have a UserModel class, that extends LDObject. Creating a class which implements basic CRUD methods would be as simple as creating a class extending LDSQLiteHelper with UserModel as parameter type.
 
Right now is very basic tool and I am improving it step by step as I face the needs.
 
This all is about persistence in Terminal's local DB.
 
In previous posts, I wrote about comunication over RESTFul services wich I have to rewrite acording to Liferay 6.1 REST services. LiferayConsumer classes.
 
And finally, It would be interesting to create another layer, one to rule them all!! to perform for example synchronisation using in this case, for example UserSQLiteHelper and UserLiferayConsumer classes. This synch would be run on demand or periodically from terminal to server whenever the connetion is ready.
 
Regards!!!

JSONWS : Liferay's new JSON webservice rocks!

First, I had some problems invoking some JSON web service methods. Specially those with arguments like locales, such addUser in UserService.

Then, I got stuck, again, trying to expose a custom model service, built with the service-builder. I copied the jar to the common libs folder etc, but in the end it did not work fine.

But Liferay's new release, 6.1.0 b3 has great improvements in this way. Just have a look at this wiki page!!!

http://www.liferay.com/es/community/wiki/-/wiki/1071674/JSON+Web+Services

Firtsly, it explain how to list available JSON web services.

 

 http://localhost:8080/tunnel-web/jsonws/dump

 

I have to say it didn´t work  for me. But it's quite intuitive.

It explains how to ivoke services passing parameters as part of URL path or passing as URL query.

And it talks too about registering services. This part is really interesting in order to expose custom services.

It needs to be specified in the web.xml file of the portlet and portal will scan classes for loading the services.

 

 <servlet> <servlet-name>JSON Web Service Servlet</servlet-name> <servlet-class>com.liferay.portal.kernel.servlet.PortalClassLoaderServlet</servlet-class> <init-param> <param-name>servlet-class</param-name> <param-value>com.liferay.portal.jsonwebservice.JSONWebServiceServlet</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>JSON Web Service Servlet</servlet-name> <url-pattern>/jsonws/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>JSON Web Service Servlet</servlet-name> <url-pattern>/secure/jsonws/*</url-pattern> </servlet-mapping>

 

I tried it and it just worked!!

So,  I will have to adapt Lifedroid to 6.1. 

More JSONWS enhancements

 After writing my last post , Ray Auge contacted me via twitter. He asked me to file a ticket in jira so it could be resolved.

Here the ticket http://issues.liferay.com/browse/LPS-22606

Today, I wanted to see what was happening with the issue. It was assigned to Igor Spasic and he closed the ticket as resolved. There was another ticket asking "More JSONWS enhancements"

http://issues.liferay.com/browse/LPS-22615

This issue was resolved and close so I run to have a look to JSONServiceAction class in GitHub. And yes!!

 else if (typeNameOrClassDescriptor.equals( "java.util.Map<java.util.Locale, java.lang.String>")) { JSONObject jsonObject = JSONFactoryUtil.createJSONObject(value); return LocalizationUtil.deserialize(jsonObject); }

 

Looks  like it will work with no workarounds!

Just being able to stare at souce code, and see how bugs are fixed and new features added makes Lifedroid love open source.

Workaround!

It was taking too long but I found a solution to the problem that got me stuck! The big problem was that I could not manage to pass Locale type parameter via REST to addUser method.

I tried passing the equivalent string for a JSON serielized Locale object.

{"language":"es", "country":"ES"}

/*Can anyone tell me if it is correctly formatted? I composed the string manually.*/

Well, this did not work. This parameter was interpreted as a HashMap and this HashMap was used to invoke the "addUser" method. Obviously, this caused a NoSuchMethodException".

The other option was passing an empty string fo the locale parameter. With this option, the execution got further, but, the empty string was passed as a null, and this "value" is not valid in this case. 

When UserLocalServiceImpl class is reached, in method addUser, there is a point where locale is converted to string:

 

user.setLanguageId(locale.toString());
 
Which throws our so beloved NullPointerException
 
So, I was stuck!!!
 
But a Liferay Community project came recently to my mind. This was an "Antivirus" hook, for testing files uploaded to the document gallery. Basically, this service hook intercepts the execution before adding the file to the repository to analize the uploaded.
 
Similarly, the only thing I needed to do was to implement a user service hook, intercept the addUser method call and pass a correct locale instance.
 
 
public class UserServicePatch extends UserLocalServiceWrapper{
 
public UserServicePatch(UserLocalService userLocalService) {
super(userLocalService);
}
 
@Override
public User addUser(long creatorUserId, long companyId,
boolean autoPassword, String password1, String password2,
boolean autoScreenName, String screenName, String emailAddress,
long facebookId, String openId, Locale locale, String firstName,
String middleName, String lastName, int prefixId, int suffixId,
boolean male, int birthdayMonth, int birthdayDay, int birthdayYear,
String jobTitle, long[] groupIds, long[] organizationIds,
long[] roleIds, long[] userGroupIds, boolean sendEmail,
ServiceContext serviceContext) throws PortalException,
SystemException {
 
return super.addUser(creatorUserId, companyId, autoPassword, password1,
password2, autoScreenName, screenName, emailAddress, facebookId,
openId, new Locale("es","ES"), firstName, middleName, lastName, prefixId, suffixId,
male, birthdayMonth, birthdayDay, birthdayYear, jobTitle, null,
null, null, null, sendEmail, serviceContext);
}
 
}
 
This is not an elegant solution, as it will always create users with es_ES locale. But will just let me continue with Lifedroid. 
 
To learn more about Liferay Portal Hooks, here is the wiki page.
 
Whats next?! I will implement the basic methods needed for a registration/login form and I will test it in a small Android app against Liferay. Hopefully!

Lifedroid got Stuck!

It's been a while since the last post. And the main reason is that I have been waiting for version 6.1.0 of Liferay bacause a got stuck in a point that I thought It would be resolved in last release but it is not. Well, actually it is not very likely to be a Liferay bug but my fault. And this is what this post will talk about.  It is something like an S.O.S. call.

As it can be read in previous posts, I managed to obtain, from Android device, a user in Liferay via REST (getUserById , getUserByEmailAddress ...). So, every thing look fine and I started to implement the rest of the client-side methods that invoke the exposed service. (UserService in this case)

Functionally talking, next isteresting method was addUser. Basically, the idea was to create a basic sign-in and register dummy app having Liferay as backOffice. So, I needed to implement the ability to add a user via REST. And here is were the problem came.

UserServiceUtil has two addUser methods, and I chose the one with less parameters, just for simplicity. And this is the spec:

 

public static com.liferay.portal.model.User addUser(long companyId,
boolean autoPassword, java.lang.String password1,
java.lang.String password2, boolean autoScreenName,
java.lang.String screenName, java.lang.String emailAddress,
long facebookId, java.lang.String openId, java.util.Locale locale,
java.lang.String firstName, java.lang.String middleName,
java.lang.String lastName, int prefixId, int suffixId, boolean male,
int birthdayMonth, int birthdayDay, int birthdayYear,
java.lang.String jobTitle, long[] groupIds, long[] organizationIds,
long[] roleIds, long[] userGroupIds, boolean sendEmail,
com.liferay.portal.service.ServiceContext serviceContext)
throws com.liferay.portal.kernel.exception.PortalException,
com.liferay.portal.kernel.exception.SystemException;

 

First of all, before implementing the call in Lifedroid's UserManager I tried to invoke the service via web browser manually. With something like that making a GET call:

 

http://localhost:8080/tunnel-web/secure/json
?serviceClassName=com.liferay.portal.service.UserServiceUtil
&serviceMethodName=addUser
&serviceParameters=[companyId,autoPassword,password1,password2,autoScreenName,screenName,
emailAddress,facebookId,openId,locale,firstName,middleName,lastName,prefixId,suffixId,
male,birthdayMonth,birthdayDay,birthdayYear,jobTitle,groupIds,organizationIds,roleIds,
userGroupIds,sendEmail,serviceContext]
&serviceParameterTypes=[long,boolean,java.lang.String,java.lang.String,boolean,java.lang.String,java.lang.String,
long,java.lang.String,java.util.Locale,java.lang.String,java.lang.String,java.lang.String,int,
int,boolean,int,int,int,java.lang.String,long,long,long,long,boolean,com.liferay.portal.service.ServiceContext]
&companyId=10160
&autoPassword=true
&password1=aritz
&password2=aritz
&autoScreenName=true
&screenName=aritz
&emailAddress=aritz@mail.com
&facebookId=1
&openId=2
&locale={}
&firstName=aritz
&middleName=galdos
&lastName=otermin
&prefixId=1
&suffixId=1
&male=true
&birthdayMonth=2
&birthdayDay=2
&birthdayYear=2000
&jobTitle=1
&groupIds=1
&organizationIds=1
&roleIds={}
&userGroupIds={}
&sendEmail=false
&serviceContext={}

There is no problem with the firts marameters, as they are primitive types or Strings until we reach the locale parameter. D'oh! (Would Homer say)

I attached the source code of 6.1.0 b3 to Eclise and I started to debug/trace the code trying to figure out how to pass a locale object as parameter.

As I could read in a James Falkner's post called Yet Another Liferay JSON Service Example he passes the parameter serviceContext as "{}" and similarly I tryed it with locale.

The execution goes to JSONServiceAction class, method getArgValue. This method, in the begining, get the typeNameOrClassDescriptor for the param being evaluated, and returns the convenient class instance with the value passed as String.

The problem is that the Locale class is not contemplated and in this case and the method returns:

return JSONFactoryUtil.looseDeserialize(value); 

Where value equal {}

Which should deserialize the value to an instance of Locale class.

So at this point, I think that what I have to do is to work out how to pass a locale correctly serialiced, to be deserialiced to Locale.

In case you have any clue or tip that could help me work this out, please, spot me some light via twitter @aritzg or  @LifedroidNet. Or in the contact form.

Thanks for reading.

Mostrando el intervalo 1 - 5 de 9 resultados.
Resultados por página 5
de 2

Aritz Galdos Otermin
Mensajes: 9
Estrellas: 0
Fecha: 24/02/12