Refactoring the Prototype
Step 4 of 6
It’s a good practice to start with a working prototype as a proof of concept, but eventually that prototype must transform into a real application. Up to this point, you’ve made all the preparations to do that, and now it’s time to replace the prototype back-end with the real, database-driven back-end you created with Service Builder.
For the prototype, you manually created the application’s model. The first thing you want to do is remove it, because Service Builder generated a new one:
-
Find the
com.liferay.docs.guestbook.model
package in theguestbook-web
module. -
Delete it. You’ll see errors in your project, but that’s because you haven’t replaced the model yet.
Now you get to do some dependency management. For the web module to access the
generated services, you must make it aware of the API and service modules. Then
you can update the addEntry
method in GuestbookPortlet
to use the new
services:
-
First, open
guestbook-web
’sbuild.gradle
file and add these dependencies:compileOnly project(":modules:guestbook:guestbook-api") compileOnly project(":modules:guestbook:guestbook-service")
-
Right-click on the
guestbook-web
project and select Gradle → Refresh Gradle Project. -
Now you must add references to the Service Builder services you need. To do this, add them as class variables with
@Reference
annotations on their setter methods. OpenGuestbookPortlet
and add these references to the bottom of the file:@Reference(unbind = "-") protected void setEntryService(EntryLocalService entryLocalService) { _entryLocalService = entryLocalService; } @Reference(unbind = "-") protected void setGuestbookService(GuestbookLocalService guestbookLocalService) { _guestbookLocalService = guestbookLocalService; } private EntryLocalService _entryLocalService; private GuestbookLocalService _guestbookLocalService;
Note that it’s Liferay’s code style to add class variables this way. The
@Reference
annotation on the setters allows Liferay’s OSGi container to inject references to your generated services so you can use them. Theunbind
parameter tells the container there’s no method for unbinding these services: the references can die with the class during garbage collection when they’re no longer needed. -
Now you can modify the
addEntry
method to use these service references:public void addEntry(ActionRequest request, ActionResponse response) throws PortalException { ServiceContext serviceContext = ServiceContextFactory.getInstance( Entry.class.getName(), request); String userName = ParamUtil.getString(request, "name"); String email = ParamUtil.getString(request, "email"); String message = ParamUtil.getString(request, "message"); long guestbookId = ParamUtil.getLong(request, "guestbookId"); long entryId = ParamUtil.getLong(request, "entryId"); if (entryId > 0) { try { _entryLocalService.updateEntry( serviceContext.getUserId(), guestbookId, entryId, userName, email, message, serviceContext); SessionMessages.add(request, "entryAdded"); response.setRenderParameter( "guestbookId", Long.toString(guestbookId)); } catch (Exception e) { System.out.println(e); SessionErrors.add(request, e.getClass().getName()); PortalUtil.copyRequestParameters(request, response); response.setRenderParameter( "mvcPath", "/guestbookwebportlet/edit_entry.jsp"); } } else { try { _entryLocalService.addEntry( serviceContext.getUserId(), guestbookId, userName, email, message, serviceContext); SessionMessages.add(request, "entryAdded"); response.setRenderParameter( "guestbookId", Long.toString(guestbookId)); } catch (Exception e) { SessionErrors.add(request, e.getClass().getName()); PortalUtil.copyRequestParameters(request, response); response.setRenderParameter( "mvcPath", "/guestbookwebportlet/edit_entry.jsp"); } } }
This
addEntry
method gets the name, message, and email fields that the user submits in the JSP and passes them to the service to be stored as entry data. Theif-else
logic checks whether there’s an existingentryId
. If there is, the update service method is called, and if not, the add service method is called. In both cases, it sets a render parameter with the Guestbook ID so the application can display the guestbook’s entries after this one has been added. This is all done intry...catch
statements. -
Now add
deleteEntry
, which you didn’t have before:public void deleteEntry(ActionRequest request, ActionResponse response) throws PortalException { long entryId = ParamUtil.getLong(request, "entryId"); long guestbookId = ParamUtil.getLong(request, "guestbookId"); ServiceContext serviceContext = ServiceContextFactory.getInstance( Entry.class.getName(), request); try { response.setRenderParameter( "guestbookId", Long.toString(guestbookId)); _entryLocalService.deleteEntry(entryId, serviceContext); } catch (Exception e) { Logger.getLogger(GuestbookPortlet.class.getName()).log( Level.SEVERE, null, e); } }
This method retrieves the entry object (using its ID from the request) and calls the service to delete it.
-
Next you must replace the
render
method:@Override public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { try { ServiceContext serviceContext = ServiceContextFactory.getInstance( Guestbook.class.getName(), renderRequest); long groupId = serviceContext.getScopeGroupId(); long guestbookId = ParamUtil.getLong(renderRequest, "guestbookId"); List<Guestbook> guestbooks = _guestbookLocalService.getGuestbooks( groupId); if (guestbooks.isEmpty()) { Guestbook guestbook = _guestbookLocalService.addGuestbook( serviceContext.getUserId(), "Main", serviceContext); guestbookId = guestbook.getGuestbookId(); } if (guestbookId == 0) { guestbookId = guestbooks.get(0).getGuestbookId(); } renderRequest.setAttribute("guestbookId", guestbookId); } catch (Exception e) { throw new PortletException(e); } super.render(renderRequest, renderResponse); }
This new
render
method checks for any guestbooks in the current site. If there aren’t any, it creates one. Either way, it grabs the first guestbook so its entries can be displayed by your view layer. -
Remove the
parseEntries
method. It’s a remnant of the prototype application. -
Hit Ctrl-Shift-O to organize your imports.
Awesome! You’ve updated your controller to use services. Next, you’ll tackle the view.