Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Ray Augé
Defining the context of a service call
October 27, 2008 9:27 AM
Answer

Ray Augé

LIFERAY STAFF

Rank: Liferay Legend

Posts: 1171

Join Date: February 7, 2005

Recent Posts

Hey all,

In 5.2 we're introducing a new concept, not sure of the full extend of the change yet as we're still working out ideas, called "ServiceContext".

Background:

First, our service method calls are getting very big... some have 10-15 parameters. As we add general features to the service tier, we don't want each one to incur more and more parameters. It's enough that we're already using the entity fields as params motif.

Second, we often have objects like ThemeDisplay and/or PortletPreferences which make using these methods from the web-service perspective painful as we don't really have any good way of dealing with these, except passing null. And yet, they are so entrenched that we can't really eliminate their usage outright.

Third, many methods require values such as groupId, plid, etc.. which identify the scope to which the particular instance belongs.

Fourth, two new features we've recently added could cause the number of params to increase (which is really a subcase of First):
- ExpandoBridge (a simple API for adhoc, custom attribute definition, build on top of Expandos)
- Indexing of ExpandoBridge custom attributes

Fifth, fields like companyId, userId, addCommunityPermissions, addGuestPermissions etc... which are continuously repeated over and over throughout the service tier, should eventually be moved into the ServiceContext and dynamically evaluated based on implementation of some Interface which dictates which data to obtain from the context. For instance:
- if an entity implements Owned, then dynamically obtain userId, userName from the context
- if an entity implements Scoped, then dynamically obtain scope values from the context
- if an entity implements Permissioned, then dynamically obtain permission values from the context

Proposed Solution:

All of the above define the "context" within which a given operation is to be performed.

What we've done is defined a simple object called ServiceContext which will act as a single entry/extension point and auxiliary parameter which will (eventually) replace all of the above.

So, the result might be that a method which looked like this:

 1    public MBMessage addMessage(
 2            String uuid, long userId, String userName, long categoryId,
 3            long threadId, long parentMessageId, String subject, String body,
 4            List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
 5            double priority, String[] tagsEntries,
 6            PortletPreferences preferences, Boolean addCommunityPermissions,
 7            Boolean addGuestPermissions, String[] communityPermissions,
 8            String[] guestPermissions, ThemeDisplay themeDisplay)
 9        throws PortalException, SystemException;


may end up looking like:

1    public MBMessage addMessage(
2            String uuid, long categoryId, long threadId, long parentMessageId, String subject,
3            String body, List<ObjectValuePair<String, byte[]>> files, boolean anonymous,
4            double priority, String[] tagsEntries, ServiceContext serviceContext)
5        throws PortalException, SystemException;


and all of
- long userId
- String userName
- PortletPreferences preferences
- Boolean addCommunityPermissions
- Boolean addGuestPermissions
- String[] communityPermissions
- String[] guestPermissions
- ThemeDisplay themeDisplay

be available from the ServiceContext object, thus reducing the amount of params.. and allowing for a cleaner API as well as for extensibility without polluting the API with objects that simply make life more difficult.

Thoughts?
Ray Augé
RE: Defining the context of a service call
October 27, 2008 10:40 AM
Answer

Ray Augé

LIFERAY STAFF

Rank: Liferay Legend

Posts: 1171

Join Date: February 7, 2005

Recent Posts

Just to clarify, ServiceContext would not be a parameter that we add to every single service method.

It would mainly exist as the highest order add*|update* methods, and/or anywhere else we see fit.

The purpose of the context is to abstract features which are used across the entire array of services.

For example, there are many services which use tagging, perhaps initially they did not support... if the service had provided the facility for ServiceContext, no change may be needed to the service methods in order to implement tag support... it would simply be a matter of adding the tags into the ServiceContext and the modifying the implementation of the add* method of the *LocalServiceImpl.

A quick list I can identify as framework features which could be candidate are:

- scoping
- ownership
- permissions
- tags
- attachments
- custom attributes

Suppose for example you create a custom entity called EmploymentEntry which represents a job opening in your company.

You want that to be tagable, you might want it to support custom meta-data via ExpandoBridge and have that metadata indexed and searchable, you want to have permission support, and you might want to support scoping such that departments can maintain and manage their EmploymentEntries individually, and you might even want to support subscriptions to messaging for new entries.

Rather than writing a method:

1    public EmploymentEntry addEntry(
2            long userId, String userName, String title, String desciption, String[] tagsEntries,
3            HashMap<String, Object> customAttributes, PortletPreferences preferences,
4            Boolean addCommunityPermissions, Boolean addGuestPermissions,
5            String[] communityPermissions, String[] guestPermissions,
6            ThemeDisplay themeDisplay)
7        throws PortalException, SystemException;


you could write:

1    public EmploymentEntry addEntry(
2            String title, String desciption, ServiceContext serviceContext)
3        throws PortalException, SystemException;


with the understanding that internally, you'll get all the framework features you need to implement all of the requirements.
Jorge Ferrer
RE: Defining the context of a service call
October 28, 2008 4:51 AM
Answer

Jorge Ferrer

LIFERAY STAFF

Rank: Liferay Legend

Posts: 2757

Join Date: August 31, 2006

Recent Posts

Hey Ray,

I think this is a great idea!

From the list of candidates you propose I think all make sense as part of serviceContext, although for practical reasons I would probably leave out those that are mandatory.

In other words, I would leave out the owner userId and the scope groupId. A couple of practical benefits of doing this are:
  • That way it's easier to explain (and understand) serviceContext as an optional context for added value
  • The API is easier to invoke if you just want to provide the mandatory params. Unfortunately Java is not a good languages to create objects and pass them as attributes in a single line, so forcing the creation of a serviceContext and then passing the instance to the add/update method is a little bit cumbersome to make it mandatory.


In any case, that's just a feeling, not a strong opinion, so I'm fine with whatever is decided.
Jesper W
RE: Defining the context of a service call
December 17, 2008 8:02 AM
Answer

Jesper W

Rank: Expert

Posts: 315

Join Date: March 25, 2007

Recent Posts

So we have started porting to 5.2... and of course there are gazillions of compilation errors...

Would it be possible to have some small documentation of the ServiceContext API, and also are there any caveats etc?

(Since it is all brand new stuff for us external people....)

/j
Ray Augé
Re: [Liferay Forums][Liferay Core Developers] RE: Defining the context of a
December 17, 2008 9:38 AM
Answer

Ray Augé

LIFERAY STAFF

Rank: Liferay Legend

Posts: 1171

Join Date: February 7, 2005

Recent Posts

Hi Jesper,

The ServiceContext API is pretty simple. It essentially is a replacement
for several mundane patterns we were adding to all kinds of services.
Also it is used to solve some API problems caused by passing a couple of
none serializable parameters to methods, namely ThemeDisplay and
PortletPreferences.

The new pattern seems like a large change at the moment, but in reality
it is bringing more stability for the future as we can now hide new
features we plan to use across many services within it (maintaining API
compatibility from this point without service method changes, aside from
changes to the service itself).

Basically, the whole of the API is within these three classes:

ServiceContext.java
ServiceContextFactory.java
ServiceContextUtil.java

See the Bookmarks portlet for a usage from front to back starting at
com.liferay.portlet.bookmarks.action.EditEntryAction.

It should be very easy to migrate the code from using the old patterns
to this one because you will find you are deleting far more code than
you are adding. Jorge migrated most of our core services in about a
week, concurrently with all his other projects. While we all know Jorge
is an expert, I'm trying to instill confidence that it should not be a
hefty migration.

Also, you will be gaining access to some features to your services for
free...

Tags Categories and Entries, Custom Attributes (ExpandoBridge), gain
most critical features of ThemeDisplay, PortletPreferences access
without breaking serialization. In fact, you can even pass arbitrary
attributes dynamically at run time using service "attributes" (a la
request attributes).


Anyway, if you have any questions while your going through it... don't
hesitate to ask here. I'll do my best to fill you in, we can use the
details as a base for the Wiki or something.
Paul Timothy Preiss
RE: Defining the context of a service call
February 7, 2009 4:06 PM
Answer

Paul Timothy Preiss

Rank: New Member

Posts: 3

Join Date: September 17, 2008

Recent Posts

Ray,

I hope that you wont make ServiceContext tied to portlet request or will at least make it optional to send in a null or empty reference. We have many backend jobs that are running that call the service methods and obviously dont originate from a portlet request.

Paul
Shivansh Sharma
RE: Defining the context of a service call
February 9, 2009 5:34 AM
Answer

Shivansh Sharma

Rank: New Member

Posts: 16

Join Date: February 8, 2009

Recent Posts

Hi Ray,
I want to used liferay API for all CRUD operation, requirement is to made some sort of changes in liferay out-of-box portlet.
Can you provide some docs or links which will be helpful for me.

I have check out the latest liferay Source & downloaded the correponding liferay-tomcat bundle.

Currently i have made changes in particular java file, and placed into corresponding JAR file. then placed that updated JAR file into tomcat.

I know this not the right way to do it, rather i have to build the code & create an extension environment. But the approach is not successfully completed.

Specifically i want to know how to use services.


Other than that i wnat to know can i get the Session object in JSP.

Thanks & Regards,
Shivansh Sharma
Ray Augé
Re: [Liferay Forums][Liferay Core Development & Contributions] RE: Defining
March 4, 2009 5:58 AM
Answer

Ray Augé

LIFERAY STAFF

Rank: Liferay Legend

Posts: 1171

Join Date: February 7, 2005

Recent Posts

You can simply pass new ServiceContext() as the parameter. It's
just a simple pojo and is even handled by all our webservice APIs.

If you find you are missing things that it provides in the service,
simply use the setter methods to add those. Internally, the system is
supposed to handle any null return values.
Bernardo Riveira Faraldo
RE: Re: [Liferay Forums][Liferay Core Development & Contributions] RE:
March 31, 2009 8:08 AM
Answer

Bernardo Riveira Faraldo

Rank: Regular Member

Posts: 136

Join Date: October 30, 2008

Recent Posts

We tried today the upgrade from v5.1 to v5.2; everything was almost smooth but our external tools that use the web services API; I have just migrated that tools to use the liferay-client to connect to the web services instead of generating client stubs using the WSDL, but of course, I had to add new parameters to addUser and editUser

one of those parameters is the ServiceContext, but... I have a "big" question...

we have been importing users, groups, roles, usergroups, user membership to usergroups and the like for some time, without specifiying scope; now, I'm asked the "scopeGroupId", but... what group should the users be scoped into? :-?

I mean, my users are members of some organization, they belong to usergroups also, but... do they need to be scoped like a community content?

thanks in advance
Jorge Ferrer
RE: Re: [Liferay Forums][Liferay Core Development & Contributions] RE:
March 31, 2009 9:29 AM
Answer

Jorge Ferrer

LIFERAY STAFF

Rank: Liferay Legend

Posts: 2757

Join Date: August 31, 2006

Recent Posts

Hi Bernardo,

When adding users the scopeGroupId has no effect. That's the reason why it's not made mandatory in ServiceContext
Ray Augé
RE: Re: [Liferay Forums][Liferay Core Development & Contributions] RE:
March 31, 2009 9:36 AM
Answer

Ray Augé

LIFERAY STAFF

Rank: Liferay Legend

Posts: 1171

Join Date: February 7, 2005

Recent Posts

Exactly, you can pass new ServiceContext() and you'll be fine.
Bernardo Riveira Faraldo
RE: Re: [Liferay Forums][Liferay Core Development & Contributions] RE:
April 1, 2009 2:47 AM
Answer

Bernardo Riveira Faraldo

Rank: Regular Member

Posts: 136

Join Date: October 30, 2008

Recent Posts

Thank you very much!
Bryan Cheung
RE: Re: [Liferay Forums][Liferay Core Development & Contributions] RE:
April 7, 2009 3:45 PM
Answer

Bryan Cheung

LIFERAY STAFF

Rank: Expert

Posts: 359

Join Date: August 26, 2004

Recent Posts

Wiki Documentation can be found here.
Kyrre Myrbostad
RE: Re: [Liferay Forums][Liferay Core Developers] RE: Defining the context
June 26, 2009 12:13 AM
Answer

Kyrre Myrbostad

Rank: Junior Member

Posts: 37

Join Date: January 21, 2009

Recent Posts

I'm wondering if this ServiceContext pattern is implemented for JournalService?

To clarify, I'm trying to add an article and put in in the correct WebContent portlet through the Soap API. This is part of a migration script we are making. Here is a bit of code:

 1 ServiceContext scxt = new ServiceContext();          
 2PortletPreferencesIds portletPreferencesIds = new PortletPreferencesIds();
 3            portletPreferencesIds.setPortletId(portletID);
 4            portletPreferencesIds.setPlid(plid);
 5            portletPreferencesIds.setOwnerId(ownerId);
 6            portletPreferencesIds.setOwnerType(ownerType);
 7            scxt.setPortletPreferencesIds(portletPreferencesIds);            
 8
 9            journalService.addArticle( ...etc


I can add articles fine as long as i don't set the portletPrefencesIds on the ServiceContext, but if i run the code above I get an error implying that the portlet_id was not set. The portletId given in the code above is on the format ID_INSTANCE_RANDOM-LETTERS (e.g. "56_INSTANCE_DR4t")

Am I using the API all wrong here? As the javaDoc is somewhat lacking I'm a bit at a loss here. Using 5.2.3 tomcat bundle with mysql on ubuntu 9.04.

EDIT: Just found this Jira issue explaining it
http://issues.liferay.com/browse/LPS-2322