Wednesday, 30 September 2009

Persisting Users - Yikes! I Had To Think About Transactionality

A SwagItem has a JDO 1-to-1 owned relationship with a SwagImage. A User can own many SwagItems. However, I decided not to let JDO manage that relationship. Instead I simply use the user email as an (informal) foreign key in SwagItem.

This means that SwagItem and User are not in the same JDO entity group which means they may not be mutated in the same transaction.

In order for my service method overcome this, I had to think about transactionality. Let's take a look at ItemService.save():

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void save(SwagItem swagItem) {
if (swagItem.isNew()) {
String currentUserEmail = googleUserService.getCurrentUser().getEmail();
swagItem.setOwnerEmail(currentUserEmail);
String currentUserNickName = googleUserService.getCurrentUser().getNickname();
swagItem.setOwnerNickName(currentUserNickName);
itemDao.insert(swagItem);
// insert user if they don't exist (this only happens when creating a new item
// since only existing users can update
SwagSwapUser swagSwapUser = swagSwapUserService.findByEmail(currentUserEmail);
if (swagSwapUser==null) { //add them
swagSwapUserService.insert(new SwagSwapUser(currentUserEmail,currentUserNickName));
}
}
else { //update
checkPermissions(swagItem.getKey());
itemDao.update(swagItem);
}
}


You'll notice that I'm inserting the user if they don't exist. This caused an exception since User is in a different entity group than SwagItem (not allowed to be committed in the same transaction). To fix this I added the spring transaction annotation Propagation.REQUIRES_NEW to the swagSwapUserService.insert() method:


@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void insert(SwagSwapUser swagSwapUser) throws UserAlreadyExistsException {
if (findByEmail(swagSwapUser.getEmail()) !=null) {
throw new UserAlreadyExistsException(swagSwapUser);
}
userDao.insert(swagSwapUser);
}

And it works fine.

Full Blown Google Accounts API Authentication plus some Authorization

In my last post I protected some resources in web.xml to force users to login for CRUD operations on swagItems.

Now I've come as far as getting the logged in user's email and nickName using the Google UserService.

When a swagItem is added, I associate an email with it so that only the owner (or admins) can perform CRUD operations on it. I check authorization on the server side and using a custom tag library in the JSPs. See the checkPermissions() method in ItemServiceImpl. Note the googleUserService here is injected using spring.

The taglib I use in the JSP is called IsAllowedTag. It's used in listSwagItems.jsp to show or hide the action buttons.

Another tag that takes advantage of the Google Accoutns AOI is the LoginLogoutTag. I'll let you guess what that does (also used in listSwagItems.jsp)

Saturday, 26 September 2009

Authentication in 3 minutes

I knew that security in GAE/J was easy so I gave myself 15 minutes to add it. I was able to do it in 3 minutes including testing it locally and deploying it to The Cloud.

The goal was to allow anyone to list or search swagItems but make them log in to add/edit/delete them. Here's the XML I had to add:

<security-constraint>
<web-resource-collection>
<url-pattern>/swag/delete/*</url-pattern>
<url-pattern>/swag/add/*</url-pattern>
<url-pattern>/swag/edit/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>

The next step will be to save user profiles in the DB, save owner information when a SwagItem is uploaded, and only allow the owner to edit or delete his own items. Admins can do anything.

Thursday, 24 September 2009

swagswap: see it, browse it, or even install and run it

Hi Sam here. While Scott has been bla bla blogging up a storm, I've actually been ticking out the application. I'm proud to announce that in record time it's ready for public consumption.

Currently (version 0,1) the included technology features:
  • RESTful Spring MVC controllers with annotations
  • A service layer with annotated Spring transactions
  • Spring JDO DAOs
  • Unit tests galore
  • An advanced ant script
  • Eclipse ready

You can now:

I'll report on some appengine difficulties I've had in my next post.

Sunday, 20 September 2009

Welcome!

Welcome to cloudMouth! This is the Blog of Sam Brodkin and Scott Stevenson, two freelance Java technologists, and their voyage into the world of Cloud Computing. The Blog will track our progress in developing a Google App Engine application and presenting it at the Devoxx conference in Antwerp.