📄 ch11.htm
字号:
know when a model has changed. For this situation, the Observableclass and Observer interface in the java.util package offer aneffective solution. The Observable class represents the model.To create an Observable model, you need to build a subclass ofObservable. Observer objects can then attach to your model; whenthe model changes, you notify the observers.<P>In the applet portion of the chapter project, a class called ElectionTablemaintains a local cache of election results on a state-by-stateand grand-total basis; it is a direct subclass of Observable.When its data is modified, it notifies the Observer objects ofthe changes:<BLOCKQUOTE><TT>setChanged();<BR>notifyObservers();</TT></BLOCKQUOTE><P>The first method, <TT>setChanged()</TT>,tells the Observable class that the model has been modified. Whena notify method is next called (immediately afterward, in thiscase), the Observable class checks to see whether the data haschanged and, if so, broadcasts a notification to the observers.Table 11.1 lists a summary of the Observable class's methods.<BR><P><CENTER><B>Table 11.1. The Observable class's methods.</B></CENTER><P><CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%><TR VALIGN=TOP><TD WIDTH=163><I>Method</I></TD><TD WIDTH=427><I>Description</I></TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>addObserver</TT></TD><TD WIDTH=427>Add an Observer object to the list of observers.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>deleteObserver</TT></TD><TD WIDTH=427>Remove an Observer from the observer list.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>deleteObservers</TT></TD><TD WIDTH=427>Clear the observer list.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>notifyObservers</TT></TD><TD WIDTH=427>Notify all the Observers that the data has changed. One version of this method has an optional parameter to send data about what was modified.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>setChanged</TT></TD><TD WIDTH=427>Signals internally that a change has occurred.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>hasChanged</TT></TD><TD WIDTH=427>Returns whether the data has changed.</TD></TR><TR VALIGN=TOP><TD WIDTH=163><TT>countObservers</TT></TD><TD WIDTH=427>Returns a count of all the Observers.</TD></TR></TABLE></CENTER><P><P>The Observer interface has only one method, <TT>update()</TT>.It takes as its parameters the Observable object and an objectthat can be used to convey more information about what has changed.The Observer object hooks to the Observable object through the<TT>addObserver()</TT> method. Inthis chapter's project, the two observers simply repaint whenthey get an <TT>update()</TT> message.<H2><A NAME="ChapterProject"><FONT SIZE=5 COLOR=#FF0000>ChapterProject</FONT></A></H2><P>This chapter project demonstrates an applet and correspondingJava server used to show you election night returns as they comein. When you select the Election home page, the applet connectsto the server and is added to a list of registrants to be notifiedwhenever election data changes. The server uses its local databaseto check for any incoming election returns. When they occur, theserver broadcasts the results to the client applets. The applets,in turn, update themselves to show the latest totals.<P>To add a little fun to the project, the system was designed forthe likely 1996 presidential election between the incumbent andhis challenger. (Note that it wouldn't be hard to change the projectif a third-party candidate throws a monkey wrench into this mix,since the project is mostly driven by the database. However, afew assumptions about there being two candidates were made.) Figure11.1 shows the Election applet before the returns start rollingin, Figure 11.2 illustrates what the applet might look like laterin the evening, and Figure 11.3 shows the applet as the electionreaches its possible conclusion. This last figure demonstratesthe applet with its graphical view turned on.<P><A HREF="f11-1.gif" ><B>Figure 11.1 : </B><I>The Election applet before the election returns start rolling in.</I></A><P><A HREF="f11-2.gif" ><B>Figure 11.2 : </B><I>The Election applet as the evening progresses. It's a close one.</I></A><P><A HREF="f11-3.gif" ><B>Figure 11.3 : </B><I>The applet as the election reaches in climax-who is going to win?</I></A><P>You are given a database consisting of filled-in states and correspondingelectoral votes. However, the totals are left blank. If you want,you can rig the election in favor of the candidate of your choice!<H3><A NAME="GeneralArchitectureoftheProject">General Architectureof the Project</A></H3><P>The general architecture of this project is based on the projectarchitecture from <A HREF="ch10.htm" >Chapter 10</A>, "NativeMethods and Java." For the sake of clarity, a visual overviewof the architecture is repeated in Figure 11.4. Refer to <A HREF="ch10.htm" >Chapter 10</A>for a description of the general architecture and detailed serverand database implementation, but a couple of additional pointsabout the structure of the project are covered here. Furthermore,a full description of the client applet will follow in the section"Applet Client."<P><A HREF="f11-4.gif" ><B>Figure 11.4 : </B><I>The project architecture.</I></A><P>The hierarchy of the server environment is as follows: The serverclasses should be placed in the parent directory (which couldbe in a variety of places); the database (ELECT.DBF) can alsobe in this directory, but if your ODBC data source is set up properly,the database can be located elsewhere.<P>Underneath the parent is a directory called <I>htdocs</I>. Theonly file it must have is index.html, which is the HTML for theapplet at hand. Located underneath htdocs is a <I>classes</I>subdirectory. This will contain classes and any additional filesthe client applet will need.<P>To start the server, go to the parent directory and type:<BLOCKQUOTE><TT>java BasicWebServer</TT></BLOCKQUOTE><P>An additional <TT>debug 1</TT> parameterwill display debug information about the server.<H3><A NAME="ChangestotheServer">Changes to the Server</A></H3><P>As in the previous chapter, the ElectionServer class is used tosend data to multiple client applets. It does this at the behestof the BasicWebServer class because it implements the LiveDataServerinterface. The main part of this Thread class is its <TT>run()</TT>method, which constantly looks for new data and broadcasts itsresults to the client applets. This code was slightly modifiedfrom <A HREF="ch10.htm" >Chapter 10</A> for a fuller implementationof the election night project. Only the <TT>run()</TT>method was modified, as illustrated in Listing 11.1.<HR><BLOCKQUOTE><B>Listing 11.1. Changes to the </B><TT><B><FONT SIZE=1 FACE="Courier">run()</FONT></B></TT><B>method of the ElectionServer Class.<BR></B></BLOCKQUOTE><BLOCKQUOTE><TT>/**<BR> * Run method for this thread.<BR> * Recheck the database every 30 seconds<BR> * and send changed data<BR> * Resend all data every couple minutes.<BR> */<BR> public void run()<BR> {<BR> int timestamp = 0;<BR> int iterationsBeforeFull = 60; //Fifteen minutes<BR> int iteration = 0;<BR> if ( results !=null )<BR> {<BR> servThread.start();<BR> while(true)<BR> {<BR> sleep(30);<BR> try<BR> {<BR> SQLStmtnn;<BR> //After so many iterations, resend all data...<BR> if(iteration >= iterationsBeforeFull) {<BR> nn = election.sql("select * from election order by </TT><FONT FACE="ZapfDingbats">Â</FONT><TT>state,candidate");<BR> synchronized (results)<BR> {<BR> results= nn;<BR> }<BR> servThread.sendToUsers(<BR> formatResults("RESULTS",results));<BR> iteration = 0;<BR> }// end full if<BR> else{<BR> //Otherwise just check timestamps...<BR> StringpartialSQL =<BR> "select* from election where updated > '" +<BR> timestampToChar(timestamp)+<BR> "'order by state,candidate";<BR> nn= election.sql(partialSQL);<BR> //Make sure a valid number of rows is returned...<BR> if((nn.numRows() > 0) && ((nn.numRows()%2) == 0) ) {<BR> //Send data and update timestamp...<BR> servThread.sendToUsers(<BR> formatResults("RESULTS",nn));<BR> ++timestamp;<BR> }<BR> ++iteration;<BR> }<BR> }<BR> catch(DBException de)<BR> {<BR> System.out.println("Error:" + de);<BR> }<BR> }<BR> }<BR> }</TT></BLOCKQUOTE><HR><P><CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%><TR VALIGN=TOP><TD><B>Note</B></TD></TR><TR VALIGN=TOP><TD><BLOCKQUOTE>Note that the database used here does not have a "triggering" capability as many relational databases do. With triggers, the database would update the server, much like the model-view paradigm discussed earlier. This is much better than having the server query the database all the time.</BLOCKQUOTE></TD></TR></TABLE></CENTER><P><P>There were mainly two changes to the method. The first was theintroduction of partial updates. After broadcasting all the electiondata (in the <TT>NewRegistrant()</TT>method, which is not listed here), the server loops and waitsfor partial updates. The server uses the timestamp mechanism discussedin the next section, "Database," to see whether datahas changed. Every 30 seconds, the server queries the databaseto see whether any data has been added with a timestamp olderthan the current timestamp. If not, the server sleeps again andthen retries. If new data is found, the changes are broadcastto the client applets. The timestamp is then incremented and theprocess repeats itself.<P>The other change in the server's <TT>run()</TT>method is indicated by the <I>iteration</I> variable. Every 15minutes, the server rebroadcasts <I>all</I> of the data to theclients. This might seem unnecessary, but remember that the datagramprotocol used to transmit data is unreliable, and packets could
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -