Better Faster Lighter Java [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Better Faster Lighter Java [Electronic resources] - نسخه متنی

Justin Gehtland; Bruce A. Tate

نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
افزودن یادداشت
افزودن یادداشت جدید








10.2 Replacing the Controller


First, let's replace


the
SearchProductsController. Here's
the main method of that class:

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse 
response) throws Exception {
if (request.getParameter("search") != null) {
String keyword = request.getParameter("keyword");
if (keyword == null || keyword.length( ) == 0) {
return new ModelAndView("Error", "message",
"Please enter a keyword to search for,
then press the search button.");
}
else {
PagedListHolder productList = new PagedListHolder(
this.petStore.searchProductList(keyword.toLowerCase( )));
productList.setPageSize(4);
request.getSession( ).setAttribute(
"SearchProductsController_productList", productList);
return new ModelAndView("SearchProducts", "productList",
productList);
}
}
else {
String page = request.getParameter("page");
PagedListHolder productList = (PagedListHolder)
request.getSession( ).getAttribute("SearchProductsController_productList");
if ("next".equals(page)) {
productList.nextPage( );
}
else if ("previous".equals(page)) {
productList.previousPage( );
}
return new ModelAndView("SearchProducts", "productList", productList);
}
}

The method returns a new instance of ModelAndView
and Spring uses it to determine which JSP to load and how to wire
data up to it. The method takes an
HttpServletRequest and
HttpServletResponse in order to interact directly
with the HTTP messages.

The first thing the method does is make sure the user entered a
search term. If not, it displays an error to the user; if so, it
creates a PagedListHolder called
productList with a maximum page size (number of
rows per page) set to four. Finally, it calls the
petStore instance's
searchProductList method, which calls to
ProductsDao and finally returns the
HashMap of Product instances.
The second clause is for when the user clicks the Next Page or
Previous Page buttons on the paged list.


10.2.1 Rewrite or Replace?


The next question a

conscientious programmer should ask
is, does it make more sense to rewrite this class to make use of the
Spider, or to write an entirely new controller? In order to answer
that question, we need to consider three more-specific questions
first:

Do we have access to the original source? Now that we have the
jPetStore application, do we control the source,
or is it all binary? If we don't control the source,
we can short-circuit the rest of the decision. We can only replace
the class; we can't rewrite it.

Will we ever need to use the original service again? Assuming we have
the source and can rewrite the class, can we
foresee ever needing to revert to or make use of the database-search
functionality? For the sake of flexibility, we usually want to retain
old functionality unchanged, which means we want to replace, not
rewrite. However...

Does the current class implement an easily reused interface? If we
are going to replace the class, how much work will we have to do to
get the application to recognize and accept your new class? Think of
this as an organ transplant; how much work and medication has to go
into the host body to keep it from rejecting the new organ? Will our
changes be localized around the new class or more systemic?


Here's the answer to these questions: yes, we have
the source code; yes, we'll want access to retain
the potential for using the old service; and yes, the controller
implements a very simple interface. The controller only needs to
implement a single method, handleRequest, which
takes an HttpServletRequest and a
HttpServletResponse and returns a
ModelAndView. This means the
jPetStore application doesn't
need any systemic changes in order to use our new controller, as long
as we support that interface.


10.2.2 Implementing the Interface


To replace this class, we're going

to
write our own controller class called
SearchPagesController. It must implement the
Controller interface, which defines our
handleRequest method.

public class SearchPagesController implements Controller {
...
}

Here's our controller's
handleRequest method:

public ModelAndView handleRequest(HttpServletRequest request, 
HttpServletResponse response) throws Exception {
if (request.getParameter("search") != null) {
String keyword = request.getParameter("keyword");
if (keyword == null || keyword.length( ) == 0) {
return new ModelAndView("Error", "message", "Please enter a
keyword to search for, then press the search button.");
}
else {
ConfigBean cfg = new ConfigBean( );
String indexpath = ";
try
{
indexpath = cfg.getCurIndexPath( );
}
catch(Exception ex)
{
return new ModelAndView("Error", "message",
"Could not find current index path.");
}
QueryBean qb = new QueryBean(indexpath, keyword, "contents");
qb.execute( );
HashMap hits = new HashMap(qb.getResults( ).length);
for(int i =0;i<qb.getResults( ).length;i++)
{
hits.put("hits", qb.getResults( )[i]);
}
return new ModelAndView("SearchProducts", hits);
}
}
}

For our search functionality, we won't use the paged
results. We simply list all the results on a single page; as a
result, we don't have to deal with the Next Page and
Previous Page code. Our controller again checks for null keywords and
returns an error if it finds them empty. Otherwise, the service is
used almost identically as the console application in the Chapter 9 was used. First, create an instead of
ConfigBean to find the most current index of the
site, then create a QueryBean based on that index
path. Finally, execute the query and put all the
HitBean instances into a
HashMap to return to the View.

The usage pattern is identical to that in the last chapter; the only
difference is the format of our returned data. Instead of passing the
native array of HitBeans back, the
ModelAndView object requires a
HashMap. It's easy enough to
create the one from the other, and now we have an entirely new access
point for the Spider application with almost no work.

There is one last detail we need to work out. The original
SearchProductsController has a field called
petStore of type PetStoreFacade
that the Spring framework populates for it. In order to be a complete
replacement for the original, our new controller needs to expose the
same property and accessor methods, even though they
aren't officially found on a standalone interface
anywhere in the application. You will often find examples of this
when you're extending or modifying an application.

private PetStoreFacade petStore;
public void setPetStore(PetStoreFacade petStore) {
this.petStore = petStore;
}


10.2.3 Registering Our New Class with jPetStore


Finally, we alert jPetStore to



the new
controller's existence. If
jPetStore is not coded for extensibility, we have
to modify the application code in order to get it to work. For
instance, if there are methods of jPetStore that
create instances of SearchProductsController
directly, we must change each of those lines to create a
SearchPagesController instead.

It turns out, however, that jPetStore is quite
ready for extensibilitypartly because it is based on the
Spring framework. In order to tell jPetStore about
our new controller, we modify a single configuration file
(petstore-servlets.xml). This file tells Spring
what objects to create and how to wire them together to make a
sensible application. Now, we just need to find the configuration
setting used to launch the
SearchProductsController and point it to our new
SearchPagesController instead.

<bean name="/shop/searchProducts.do" 
class="org.springframework.samples.jpetstore.web.spring.SearchPagesController">
<property name="petStore"><ref bean="petStore"/></property>
</bean>

We're telling the application to map requests for
"/shop/searchProducts.do" to a new
instance of SearchPagesController. At the same
time, we tell it, provide the
SearchPagesController with the current instance of
petStore (in a property called
petStore).


10.2.3.1 Principles in action


Keep it simple: the controller logic is a simple invocation of
Spider; the controller interface is very simple
(one method)

Choose the right tools: Spring and the Spider

Do one thing and do it well: since the Spider is so
well-encapsulated, it's easy to add to an existing
service; the controller deals with invoking the Spider and the JSP
only needs to display the resultsMVC pattern well-demonstrated

Strive for transparency: the site doesn't care how
it is indexed; it can easily switch between data-driven and
HTML-driven search technologies

Allow for extension: we quickly expanded our search capabilities by
adding a new tool with minimal code; the configuration abilities of
jPetStore allow for no-code recognition of new
service



/ 111