Added code
This commit is contained in:
parent
8d2771ef74
commit
a4e7295bcb
94
build/build.xml
Normal file
94
build/build.xml
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="suncertify" default="doSubmissionBuild" basedir="../." >
|
||||
|
||||
<property name="dir_build" value="dist" />
|
||||
<property name="dir_src" value="src" />
|
||||
<property name="dir_classes" value="bin" />
|
||||
<property name="dir_resources" value="resources" />
|
||||
|
||||
<property name="file_submission" value="submission.jar"/>
|
||||
<property name="file_program" value="runme.jar"/>
|
||||
<property name="file_version" value="version.txt"/>
|
||||
<property name="file_choices" value="choices.txt"/>
|
||||
<property name="file_db" value="db-1x3.db"/>
|
||||
<property name="file_instructions" value="instructions.html"/>
|
||||
|
||||
|
||||
<!-- Task execution order list -->
|
||||
<target name="doSubmissionBuild" depends="cleanDist,createDist,compile,createHelpDocs,packProgram,createJavaDocs" />
|
||||
|
||||
<!-- Cleanup the dist directory -->
|
||||
<target name="cleanDist">
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${dir_build}" includes="**/*" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<!-- copy most requirements into dist dir -->
|
||||
<target name="createDist">
|
||||
<mkdir dir="${dir_build}/code"/>
|
||||
<mkdir dir="${dir_build}/docs"/>
|
||||
<mkdir dir="${dir_build}/help"/>
|
||||
<mkdir dir="${dir_build}/javadoc"/>
|
||||
|
||||
<copy todir="${dir_build}/code"> <fileset dir="${dir_src}"/></copy>
|
||||
<copy todir="${dir_build}/code/resources"> <fileset dir="${dir_resources}"/></copy>
|
||||
<copy todir="${dir_build}" file="doc/${file_version}"/>
|
||||
<copy todir="${dir_build}/docs" file="doc/${file_choices}"/>
|
||||
<copy todir="${dir_build}" file="doc/submission/${file_db}"/>
|
||||
<copy todir="${dir_build}/docs" file="doc/submission/${file_instructions}"/>
|
||||
</target>
|
||||
|
||||
<!-- Compile the java src -->
|
||||
<target name="compile">
|
||||
<javac srcdir="${dir_src}"
|
||||
destdir="${dir_classes}"
|
||||
debug="on"
|
||||
source="1.5"
|
||||
/>
|
||||
</target>
|
||||
|
||||
<target name="packProgram" >
|
||||
<jar destfile="${dir_build}/${file_program}" basedir="${dir_classes}" includes="suncertify/**/*"></jar>
|
||||
</target>
|
||||
|
||||
<target name="createJavaDocs">
|
||||
<javadoc
|
||||
destdir="${dir_build}/docs/javadoc"
|
||||
author="true"
|
||||
version="true"
|
||||
use="true"
|
||||
windowtitle="Suncertify Application Submission"
|
||||
|
||||
packagenames="suncertify.**/*"
|
||||
sourcepath="${dir_src}"
|
||||
defaultexcludes="yes"
|
||||
>
|
||||
<doctitle><![CDATA[<h1>Suncertify Application Submission (Version 1.1.3)</h1>]]></doctitle>
|
||||
<bottom><![CDATA[<i>Copyright © 2008 Willem Cazander All Rights Reserved.</i>]]></bottom>
|
||||
|
||||
<!--
|
||||
<tag name="todo" scope="all" description="To do:"/>
|
||||
<group title="Group 1 Packages" packages="com.dummy.test.a*"/>
|
||||
<group title="Group 2 Packages" packages="com.dummy.test.b*:com.dummy.test.c*"/>
|
||||
|
||||
Geeft error:
|
||||
<link href="http://developer.java.sun.com/developer/products/xml/docs/api/"/>
|
||||
-->
|
||||
<link href="http://java.sun.com/j2se/1.5.0/docs/api/"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<target name="createHelpDocs">
|
||||
<!-- Note: this requires docbook the be installed -->
|
||||
<property name="sheet" value="/usr/share/xml/docbook/stylesheet/nwalsh/javahelp/javahelp.xsl" />
|
||||
<property name="loc_help" value="dist/docs/help/" />
|
||||
<property name="loc_help_src" value="doc/help/" />
|
||||
<xslt basedir="${loc_help_src}" destdir="${loc_help}" extension=".xml" style="${sheet}" force="true">
|
||||
<factory name="com.icl.saxon.TransformerFactoryImpl" lib="build/lib/saxon6.jar"/>
|
||||
<param name="base.dir" expression="../${loc_help}"/>
|
||||
<param name="use.id.as.filename" expression="1"/>
|
||||
<param name="toc.section.depth" expression="4"/>
|
||||
</xslt>
|
||||
</target>
|
||||
</project>
|
BIN
build/lib/saxon6.jar
Normal file
BIN
build/lib/saxon6.jar
Normal file
Binary file not shown.
29
doc/choices.txt
Normal file
29
doc/choices.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
|
||||
** fully NIO based:
|
||||
|
||||
The database server and the network layer are both based
|
||||
on an implemention on the java nio libary.
|
||||
|
||||
I've choices NIO because I had no real experiance with it
|
||||
so it was a nice opertunty to learn it.
|
||||
|
||||
Working with it is real harder then it seems at first hand.
|
||||
To get all details right is even working around jvm bugs.
|
||||
|
||||
|
||||
** Proxy classes
|
||||
|
||||
I see proxy classes heavly used in modren (ee) server based
|
||||
applictions, mostly even without the programmer noticing it.
|
||||
|
||||
It provides a nice layer to dynamicly plugin the networking layer
|
||||
between the database and the client.
|
||||
|
||||
|
||||
** Bean bases server
|
||||
|
||||
Made a simple implemention of how EE containers manages the backend
|
||||
beans and depecicies.
|
||||
|
||||
|
519
doc/submission/instructions.html
Normal file
519
doc/submission/instructions.html
Normal file
|
@ -0,0 +1,519 @@
|
|||
/**DO NOT DELETE Security Code: 706-US24 Form: form-113.html ****/
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79C-CCK-MCD [en] (X11; U; SunOS 5.8 sun4u) [Netscape]">
|
||||
<title>Sun Certified Developer for the Java 2 Platform: Application Submission (Version 1.1.3)</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
<a NAME="top"></a>Sun Certified Developer for the Java 2 Platform: Application
|
||||
Submission (Version 1.1.3)</h1>
|
||||
<h2>
|
||||
Introduction and Index</h2>
|
||||
This document tells you what you need, and what you must do, to submit
|
||||
your solution to the Sun Certified Developer for the Java 2 Platform programming
|
||||
assignment. Read it carefully before you begin work on the solution. This
|
||||
document contains strict guidelines about the way the work is to be performed.
|
||||
These guidelines ensure consistency and fairness.
|
||||
<p>The application distribution is composed of:
|
||||
<ul>
|
||||
<li>
|
||||
This document</li>
|
||||
<li>
|
||||
A non-relational database file</li>
|
||||
</ul>
|
||||
Be sure to maintain a backup copy of all files related to your project,
|
||||
including the distribution files, until you receive your certificate in
|
||||
case one or more is corrupted, lost, or becomes unusable. You must not
|
||||
use any materials issued to other certification candidates even if you
|
||||
believe they are identical.
|
||||
<p>This document is divided into the following sections:
|
||||
<ul>
|
||||
<li>
|
||||
<b><a href="#what_this">Application Overview</a></b> - A general description
|
||||
of the application you will write</li>
|
||||
<li>
|
||||
<b><a href="#arch">Architecture</a></b> - The parts of the application
|
||||
and how they fit together</li>
|
||||
<li>
|
||||
<b><a href="#UI">User Interface</a></b> - GUI specification</li>
|
||||
<li>
|
||||
<b><a href="#database">Server</a></b> - The data server and its network
|
||||
connection</li>
|
||||
<li>
|
||||
<b><a href="#data">Data file format</a></b> The format and schema of the database file</li>
|
||||
<li>
|
||||
<b><a href="#Deliverables">Deliverables</a></b> - The components you must
|
||||
deliver, and how you should package them.</li>
|
||||
<li>
|
||||
<b><a href="#marking">Marking</a></b> - How your assignment will be graded</li>
|
||||
<li>
|
||||
<b><a href="#whattodo">What to do if you have a question</a></b></li>
|
||||
</ul>
|
||||
<h3>
|
||||
Important Note About Automatic Failure</h3>
|
||||
<i>Where this document uses the word "must" an absolute requirement is
|
||||
being described. If you fail to adhere to such a requirement, your assignment
|
||||
will be failed automatically, and without further evaluation. It is therefore
|
||||
imperative that you pay close attention to any statement using the word
|
||||
"must" in this document. Portions of your submission will be analyzed
|
||||
by software; where a specific spelling or structure is required, even a
|
||||
slight deviation could result in automatic failure. </i>
|
||||
<hr>
|
||||
<h2>
|
||||
<a NAME="what_this"></a>Application Overview</h2>
|
||||
<H3>Background</H3>
|
||||
URLyBird is a broker of discount hotel rooms. They sell
|
||||
accomodations for business and pleasure travellers at short notice,
|
||||
helping hotels to fill rooms that would otherwise be left empty. They
|
||||
take bookings only within 48 hours of the start of room occupancy.
|
||||
Curently, URLyBird sells the rooms over the phone using a team of
|
||||
customer service representatives (CSRs). The CSRs interact with an
|
||||
aging custom-written application that has been drawing increasing criticism
|
||||
from the CSRs. In the future, URLyBird wants to move into
|
||||
Internet-based marketing, and hopes to be able to accept bookings
|
||||
direct from customers over the web.
|
||||
<P>The company's IT director has decided to migrate the existing
|
||||
application to a Java technology based system. Initially, the system
|
||||
will support only the CSRs, although the hope is that this interim
|
||||
step will give them a starting point for migrating the system to the
|
||||
web. The IT director does not anticipate much reuse of the first Java
|
||||
technology system, but intends to use that system as a learning
|
||||
exercise before going on to a web based system.
|
||||
<P>The company's IT department has a data file that contains the
|
||||
essential information for the company, but because the data must
|
||||
continue to be manipulated for reports using another custom-written
|
||||
application, the new system must reimplement the database code from
|
||||
scratch without altering the data file format.
|
||||
<P>The new application, using the existing data file format, must
|
||||
allow the CSRs to generate a list of accomodations that match a
|
||||
customer's criteria. This is the project that you have been
|
||||
commissioned to implement.
|
||||
<h3>
|
||||
What you must do</h3>
|
||||
The following are the "top level" features that must be implemented:
|
||||
<ul>
|
||||
<li>
|
||||
A client program with a graphical user interface that connects to the database</li>
|
||||
<li>
|
||||
A data access system that provides record locking and a flexible search
|
||||
mechanism</li>
|
||||
<li>
|
||||
Network server functionality for the database system</li>
|
||||
</ul>
|
||||
The work involves a number of design choices that have to be made. In all
|
||||
such cases, the following principles should be applied.
|
||||
<h4>
|
||||
Clarity and Maintainability</h4>
|
||||
<dl>
|
||||
<dd>
|
||||
A clear design, such as will be readily understood by junior programmers,
|
||||
will be preferred to a complex one, even if the complex one is a little
|
||||
more efficient. Code complexity, including nesting depth, argument passing,
|
||||
and the number of classes and interfaces, should be reasonable.</dd>
|
||||
<dd>
|
||||
</dd>
|
||||
</dl>
|
||||
<h4>
|
||||
Documentation</h4>
|
||||
<dl>
|
||||
<dd>
|
||||
The code itself should be as clear as possible; do not provide comments
|
||||
that do not add to the comprehensibility of the code. Awkward or complex
|
||||
code should have descriptive comments, and javadoc style comments must
|
||||
be used for each element of the public interface of each class. You must
|
||||
create a full suite of documentation for the classes of the completed project.
|
||||
This must be generated using the tool "javadoc" and must be in HTML format.
|
||||
Provide javadoc documentation for all classes you write.</dd>
|
||||
<dd>
|
||||
</dd>
|
||||
<dd>
|
||||
You must provide basic user documentation. This should be sufficient to
|
||||
allow a user who is familiar with the broad purpose of the project to use
|
||||
the application. This documentation must be in one of these three formats:</dd>
|
||||
</dl>
|
||||
<ul>
|
||||
<li>
|
||||
HTML</li>
|
||||
<li>
|
||||
Plain text (not a wordprocessor format)</li>
|
||||
<li>
|
||||
Within the application as a help system.</li>
|
||||
</ul>
|
||||
<h4>
|
||||
Correctness</h4>
|
||||
<dt>
|
||||
Your project must conform to this specification. Features that deviate
|
||||
from specification will not receive full credit. You will not receive
|
||||
extra credit points for work beyond the requirements of the specification.</dt>
|
||||
<h4>
|
||||
Use of Standard Elements</h4>
|
||||
<dl>Use of functionality provided by the core Java classes will be preferred
|
||||
to your own implementation of that functionality, unless there is a specific
|
||||
advantage to providing your own implementation.</dl>
|
||||
<i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<h2>
|
||||
<a NAME="arch"></a>Overall Architecture</h2>
|
||||
<h3>
|
||||
Major Components</h3>
|
||||
The main architecture of the application must be a traditional client-server
|
||||
system. There are three key parts: the server-side data management
|
||||
system, the client-side GUI, and the network connection between the two.
|
||||
<h3>
|
||||
Non-Networked Mode</h3>
|
||||
The program must be able to work in a non-networked mode. In this mode,
|
||||
the database and GUI must run in the same VM and must perform no networking,
|
||||
must not use loopback networking, and must not involve the serialization
|
||||
of any objects when communicating between the GUI and database elements.
|
||||
<p>The operating mode is selected using the single command line argument
|
||||
that is permitted. Architecturally, this mode must use the database and
|
||||
GUI from the networked form, but must not use the network server code at
|
||||
all.
|
||||
<h3>
|
||||
Network Communication Approach</h3>
|
||||
You have a choice regarding the network connection protocol. You must use
|
||||
either serialized objects over a simple socket connection, or RMI.
|
||||
Both options are equally acceptable. Keep in mind that networking
|
||||
must be entirely bypassed in the non-networked mode.
|
||||
<h3>
|
||||
Restrictions on RMI</h3>
|
||||
To avoid unnecessary complexity in the marking environment certain restrictions
|
||||
are placed on solutions that use RMI. Specifically:
|
||||
<br>
|
||||
<li>
|
||||
You must not require the use of an HTTP server.</li>
|
||||
<li>
|
||||
You must not require the installation of a security manager.</li>
|
||||
<li>
|
||||
You must provide all classes pre-installed so that no dynamic class
|
||||
downloading occurs.</li>
|
||||
<li>
|
||||
You must use RMI over JRMP (do not use IIOP)</li>
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<h2>
|
||||
<a NAME="UI"></a>The User Interface</h2>
|
||||
The user interface for this assignment must satisfy the following criteria:
|
||||
<ul>
|
||||
<li>
|
||||
It must be composed exclusively with components from the Java Foundation
|
||||
Classes (Swing components).</li>
|
||||
<li>
|
||||
It must allow the user to search the data for all records, or for records
|
||||
where the name and/or location fields exactly match values specified by
|
||||
the user.</li>
|
||||
<li>
|
||||
It must present search results in a JTable.</li>
|
||||
<li>
|
||||
It must allow the user to book a selected record, updating the database
|
||||
file accordingly.</li>
|
||||
</ul>
|
||||
Your user interface should be designed with the expectation of future functionality
|
||||
enhancements, and it should establish a framework that will support this
|
||||
with minimal disruption to the users when this occurs.
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<h2>
|
||||
<a NAME="database"></a>Server</h2>
|
||||
<H3>Required Interface</H3>
|
||||
Your data access class must be called "Data.java", must be in a package called "suncertify.db", and must implement the following interface:
|
||||
<P><PRE>
|
||||
package suncertify.db;
|
||||
public interface DB
|
||||
{
|
||||
// Reads a record from the file. Returns an array where each
|
||||
// element is a record value.
|
||||
public String[] read(int recNo) throws RecordNotFoundException;
|
||||
// Modifies the fields of a record. The new value for field n
|
||||
// appears in data[n]. Throws SecurityException
|
||||
// if the record is locked with a cookie other than lockCookie.
|
||||
public void update(int recNo, String[] data, long lockCookie)
|
||||
throws RecordNotFoundException, SecurityException;
|
||||
// Deletes a record, making the record number and associated disk
|
||||
// storage available for reuse.
|
||||
// Throws SecurityException if the record is locked with a cookie
|
||||
// other than lockCookie.
|
||||
public void delete(int recNo, long lockCookie)
|
||||
throws RecordNotFoundException, SecurityException;
|
||||
// Returns an array of record numbers that match the specified
|
||||
// criteria. Field n in the database file is described by
|
||||
// criteria[n]. A null value in criteria[n] matches any field
|
||||
// value. A non-null value in criteria[n] matches any field
|
||||
// value that begins with criteria[n]. (For example, "Fred"
|
||||
// matches "Fred" or "Freddy".)
|
||||
public int[] find(String[] criteria);
|
||||
// Creates a new record in the database (possibly reusing a
|
||||
// deleted entry). Inserts the given data, and returns the record
|
||||
// number of the new record.
|
||||
public int create(String[] data) throws DuplicateKeyException;
|
||||
// Locks a record so that it can only be updated or deleted by this client.
|
||||
// Returned value is a cookie that must be used when the record is unlocked,
|
||||
// updated, or deleted. If the specified record is already locked by a different
|
||||
// client, the current thread gives up the CPU and consumes no CPU cycles until
|
||||
// the record is unlocked.
|
||||
public long lock(int recNo) throws RecordNotFoundException;
|
||||
// Releases the lock on a record. Cookie must be the cookie
|
||||
// returned when the record was locked; otherwise throws SecurityException.
|
||||
public void unlock(int recNo, long cookie)
|
||||
throws RecordNotFoundException, SecurityException;
|
||||
}
|
||||
</PRE>
|
||||
<P>Any unimplemented exceptions in this interface must all be created as member classes of the
|
||||
<tt>suncertify.db</tt> package. Each must have a zero argument constructor and a second
|
||||
constructor that takes a String that serves as the exception's description.
|
||||
<p>Any methods that throw RecordNotFoundException should do so if a specified
|
||||
record does not exist or is marked as deleted in the database file.
|
||||
<h3>
|
||||
<font size=+0>Network Approaches</font></h3>
|
||||
Your choice of RMI or serialized objects will not affect your grade, but
|
||||
no other approach is acceptable. In either case, the program must allow
|
||||
the user to specify the location of the database, and it must also accept
|
||||
an indication that a local database is to be used, in which case, the networking
|
||||
must be bypassed entirely. No authentication is required for database access.
|
||||
<h3>
|
||||
Locking</h3>
|
||||
Your server must be capable of handling multiple concurrent requests, and
|
||||
as part of this capability, must provide locking functionality as specified
|
||||
in the interface provided above. You may assume that at any moment,
|
||||
at most one program is accessing the database file; therefore your locking
|
||||
system only needs to be concerned with multiple concurrent clients of your
|
||||
server. Any attempt to lock a resource that is already locked should
|
||||
cause the current thread to give up the CPU, consuming no CPU cycles until
|
||||
the desired resource becomes available.
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<h2> <a NAME="data"></a> Data file Format</h2>
|
||||
The format of data in the database file is as follows:
|
||||
<p>Start of file
|
||||
<br>4 byte numeric, magic cookie value. Identifies this as a data file
|
||||
<br>2 byte numeric, number of fields in each record
|
||||
<p>Schema description section.
|
||||
<br>Repeated for each field in a record:
|
||||
<br>1 byte numeric, length in bytes of field name
|
||||
<br>n bytes (defined by previous entry), field name
|
||||
<br>1 byte numeric, field length in bytes
|
||||
<br>end of repeating block
|
||||
<p>Data section.
|
||||
<br>Repeat to end of file:
|
||||
<br>1 byte flag. 00 implies valid record, 0xFF implies deleted record
|
||||
<br>Record containing fields in order specified in schema section, no separators
|
||||
between fields, each field fixed length at maximum specified in schema
|
||||
information
|
||||
<p>End of file
|
||||
<p>All numeric values are stored in the header information use the formats
|
||||
of the DataInputStream and DataOutputStream classes. All text values, and
|
||||
all fields (which are text only), contain only 8 bit characters, null terminated
|
||||
if less than the maximum length for the field. The character encoding is
|
||||
8 bit US ASCII.
|
||||
<H3>Database schema</H3>
|
||||
The database that URLyBird uses contains the following fields:
|
||||
<table>
|
||||
<tr>
|
||||
<td>Field descriptive name</td>
|
||||
<td>Database field name</td>
|
||||
<td>Field length</td>
|
||||
<td>Detailed description</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hotel Name</td>
|
||||
<td>name</td>
|
||||
<td>64</td>
|
||||
<td>The name of the hotel this vacancy record relates to</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>City</td>
|
||||
<td>location</td>
|
||||
<td>64</td>
|
||||
<td>The location of this hotel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum occupancy of this room</td>
|
||||
<td>size</td>
|
||||
<td>4</td>
|
||||
<td>The maximum number of people permitted in this room, not including infants</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is the room smoking or non-smoking</td>
|
||||
<td>smoking</td>
|
||||
<td>1</td>
|
||||
<td>Flag indicating if smoking is permitted. Valid values are "Y" indicating a smoking room,
|
||||
and "N" indicating a non-smoking room</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Price per night</td>
|
||||
<td>rate</td>
|
||||
<td>8</td>
|
||||
<td>Charge per night for the room. This field includes the currency symbol</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Date available</td>
|
||||
<td>date</td>
|
||||
<td>10</td>
|
||||
<td>The single night to which this record relates, format is yyyy/mm/dd.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Customer holding this record</td>
|
||||
<td>owner</td>
|
||||
<td>8</td>
|
||||
<td>The id value (an 8 digit number) of the customer who has booked this.
|
||||
Note that for this application, you should assume that customers and CSRs
|
||||
know their customer ids. The system you are writing does not interact with
|
||||
these numbers, rather it simply records them. If this field is all blanks, the
|
||||
record is available for sale.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<h2>
|
||||
<a NAME="Deliverables"></a>Deliverables</h2>
|
||||
<h3>
|
||||
Target Platform and Execution</h3>
|
||||
Throughout this exercise, you must use exclusively the Java 2 platform.
|
||||
You may develop your code using any implementation of the Java 2 platform,
|
||||
but the submission that you return must have been tested and shown to work
|
||||
under a production (not development) version of the Sun Microsystems' Java
|
||||
2 platform and that platform must not have been superseded by a new production
|
||||
version for more than 18 months by the time you make your submission.
|
||||
<p>You are permitted to use any IDE tool you choose, but you must not submit
|
||||
any code that is not your own work. The final program must have no dependencies
|
||||
on any libraries other than those of the Java 2 Platform.
|
||||
<p>When you submit your assignment, each part (client and server) must
|
||||
be executable using a command of this exact form:
|
||||
<blockquote><tt>java -jar <path_and_filename> [<mode>]</tt></blockquote>
|
||||
Your programs must not require use of command line arguments other than
|
||||
the single mode flag, which must be supported. Your programs must
|
||||
not require use of command line property specifications. All configuration
|
||||
must be done via a GUI, and must be persistent between runs of the program.
|
||||
Such configuration information must be stored in a file called suncertify.properties
|
||||
which must be located in the current working directory.
|
||||
<p>The mode flag must be either "server", indicating the server program
|
||||
must run, "alone", indicating standalone mode, or left out entirely, in
|
||||
which case the network client and gui must run.
|
||||
<p>You must not require manual editing of any files by the examiners.
|
||||
<h3>
|
||||
Packaging of Submissions</h3>
|
||||
All elements of your submission must be packaged in a single JAR file.
|
||||
The JAR file must have the following layout and contents in its root:
|
||||
<ul>
|
||||
<li>
|
||||
The executable JAR containing the programs. This must be called <tt>runme.jar</tt>.</li>
|
||||
<li>
|
||||
The original, <i>unchanged</i> database file that was supplied to you.
|
||||
Note that you must keep a copy of the original database file supplied to
|
||||
you, and this must be the file you submit. The marking process will expect
|
||||
the exact same data without any changes.</li>
|
||||
<li>
|
||||
A directory called <tt>code</tt>, containing all the source code and related
|
||||
parts of your project. You must create subdirectories within this to reflect
|
||||
your package structure and distribute your source files within those directories.</li>
|
||||
<li>
|
||||
A file called <tt>version.txt.</tt> This must contain pure ASCII (not a
|
||||
word processor format) indicating the exact version of JDK you used, and
|
||||
the host platform you worked on.</li>
|
||||
<li>
|
||||
A directory called <tt>docs</tt>, containing the following items at the
|
||||
top level:</li>
|
||||
<ul>
|
||||
<li>
|
||||
This html file.</li>
|
||||
<li>
|
||||
A subdirectory called javadoc, containing HTML/Javadoc documentation for
|
||||
all classes and interfaces you are submitting.</li>
|
||||
<li>
|
||||
A file called <tt>choices.txt</tt> that containing pure ASCII (not a word
|
||||
processor format) text describing the significant design choices you made.
|
||||
Detail the problems you perceived, the issues surrounding them, your value
|
||||
judgments, and the decisions that you made. This document should also describe
|
||||
any uncertainties you had regarding the project, and the decisions you
|
||||
made when resolving them.</li>
|
||||
<li>
|
||||
User documentation for the database server and the gui client. If your
|
||||
user documentation is online then you may omit this file. However, if the
|
||||
documentation is not online, you must provide either a single plain ASCII
|
||||
(not word processor format) text document, which must be called <tt>userguide.txt</tt>,
|
||||
or multiple HTML files which must all be accessible from a starting point
|
||||
document that must be called <tt>userguide.html</tt>.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<center>
|
||||
<h2>
|
||||
<a NAME="marking"></a>Marking</h2></center>
|
||||
This section describes how your submission will be marked, and the marking
|
||||
criteria which govern allocation of marks for the Sun Certified Developer
|
||||
for the Java 2 platform application submission. The first part describes
|
||||
the marking process, and the second describes how the marks are allocated.
|
||||
<p><b>How The Assignment is Marked</b>
|
||||
<p>The marking is done in three phases. First, software checks that
|
||||
overall structure and nomenclature conform to specification. Second
|
||||
the examiner runs the code ensuring that it functions correctly through
|
||||
the specified operations. If any automatic failures are noted at this stage,
|
||||
the marking process terminates and the assignment is failed.
|
||||
<p>Provided the essential behavioral requirements of the assignment have
|
||||
been correctly implemented, the examiner proceeds to investigate the design
|
||||
and implementation of your assignment. This process is time consuming,
|
||||
and it is because this is done carefully and thoroughly that submissions
|
||||
take time to grade. The grading process is closely controlled to ensure
|
||||
consistency and fairness, and it is performed according to criteria detailed
|
||||
in the next section. At any time during this process, if an automatic failure
|
||||
is noted, the marking process terminates, and the assignment is failed.
|
||||
For any design choice concerning topics not specifically described in the
|
||||
requirements, marks are awarded for a clear and consistent approach, rather
|
||||
than for any particular solution. Design decisions must be described <i>briefly
|
||||
but clearly</i> in your comments.
|
||||
<p>In addition to the submission, you will be required to take a written
|
||||
examination. This exam tests your understanding of your submission and
|
||||
asks you to justify a number of design choices embodied in that submission.
|
||||
<h3>
|
||||
Automatic Failures</h3>
|
||||
<i>As noted at the beginning of this document, where this document uses
|
||||
the word "must" an absolute requirement is being described. If you fail
|
||||
to adhere to such a requirement, your assignment will be failed automatically,
|
||||
and without further evaluation. It is therefore imperative that you pay
|
||||
close attention to any statement using the word "must" in this document.</i>
|
||||
<h3>
|
||||
<b>Marking Criteria</b></h3>
|
||||
Your work will be evaluated based on the following criteria. The minimum
|
||||
passing score is 320 out of a possible 400 points.
|
||||
<p>General Considerations (100 points)
|
||||
<br>Documentation (70 points)
|
||||
<br>Object-orietned design (30 points)
|
||||
<br>User Interface (40 points)
|
||||
<br>Locking (80 points)
|
||||
<br>Data class (40 points)
|
||||
<br>Server (40 points)
|
||||
<br>
|
||||
<br>
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
<hr>
|
||||
<center>
|
||||
<h2>
|
||||
<a NAME="whattodo"></a>What to do if you have a question</h2></center>
|
||||
You might find that you want to ask for further explanation of some part
|
||||
of this document, perhaps to seek permission to solve a problem in a particular
|
||||
way. This document deliberately leaves some issues unspecified, and some
|
||||
problems unraised. Your ability to think through these issues, in the face
|
||||
of realistically imperfect specifications, and come to a tenable solution
|
||||
is something upon which you are being graded.
|
||||
<p>In general, you should <i>not</i> ask your question; rather you should
|
||||
consider the options available and make a decision about how to address
|
||||
the problem yourself. This decision-making process is part of the marking
|
||||
scheme, and as such it is crucially important that you provide documentation
|
||||
of your choice. Be sure to describe the options you considered, the perceived
|
||||
benefits and weaknesses of each, and why you chose the solution you did.
|
||||
Provided you do not contravene any specification in this document you will
|
||||
not be marked on the particular choice that you made, but rather on the
|
||||
consistency of your decision making process and your adherence to other
|
||||
aspects of these notes during that decision making process.
|
||||
<p>If you feel you must ask your question, you should address it to who2contact@sun.com.
|
||||
Clearly indicate that the question relates to the Sun Certified Developer
|
||||
Exam, provide your candidate ID number, name, and include your return email
|
||||
address in the <i>body</i> of your message. Describe your issue as briefly
|
||||
as reasonably possible; you will be asked for more information if necessary.
|
||||
<p><i><a href="#top">Return to top</a></i>
|
||||
</body>
|
||||
</html>
|
3
doc/todo.txt
Normal file
3
doc/todo.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
- on high load client network lib locks.
|
26
doc/version.txt
Normal file
26
doc/version.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
JAVA VERSION:
|
||||
|
||||
willemc@battleship:~/devv/jdk1.6.0_10/bin$ ./java -version
|
||||
java version "1.6.0_10"
|
||||
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
|
||||
Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode)
|
||||
|
||||
|
||||
|
||||
PLATFORM VERSION:
|
||||
|
||||
willemc@battleship:~$ uname -a
|
||||
Linux battleship 2.6.26-1-686 #1 SMP Wed Nov 26 19:14:11 UTC 2008 i686 GNU/Linux
|
||||
|
||||
willemc@battleship:~$ cat /etc/apt/sources.list | grep main
|
||||
deb http://ftp.nl.debian.org/debian/ unstable main non-free contrib
|
||||
|
||||
|
||||
|
||||
IDE VERSION:
|
||||
|
||||
Eclipse SDK
|
||||
Version: 3.3.2
|
||||
Build id: M20080221-1800
|
||||
|
5
resources/i18n-suncertify.properties
Normal file
5
resources/i18n-suncertify.properties
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# A properties file for i18n keys
|
||||
#
|
||||
|
||||
test = i18n_test
|
17
resources/suncertify-default.properties
Normal file
17
resources/suncertify-default.properties
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Default suncertify application key properties file.
|
||||
#
|
||||
|
||||
# The default modes for startup
|
||||
startup_mode = client
|
||||
|
||||
# The default server and port to connect to as client
|
||||
# in server mode only server_port is used to bind
|
||||
server_host = localhost
|
||||
server_port = 9000
|
||||
|
||||
# Cache this amount of rows.
|
||||
db_cache_size = 1000;
|
||||
|
||||
# default timeout of lock is 2min.
|
||||
db_lock_timeout = 15000
|
30
src/suncertify/client/ClientController.java
Normal file
30
src/suncertify/client/ClientController.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.client;
|
||||
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
|
||||
public class ClientController {
|
||||
|
||||
|
||||
|
||||
private HotelRoomManagerRemote hotelRoomManager = null;
|
||||
|
||||
/**
|
||||
* @return the hotelRoomManager
|
||||
*/
|
||||
public HotelRoomManagerRemote getHotelRoomManager() {
|
||||
return hotelRoomManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hotelRoomManager the hotelRoomManager to set
|
||||
*/
|
||||
public void setHotelRoomManager(HotelRoomManagerRemote hotelRoomManager) {
|
||||
this.hotelRoomManager = hotelRoomManager;
|
||||
}
|
||||
}
|
106
src/suncertify/client/HotelRoomTableModel.java
Normal file
106
src/suncertify/client/HotelRoomTableModel.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import suncertify.models.HotelRoom;
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class HotelRoomTableModel extends AbstractTableModel {
|
||||
|
||||
private List<HotelRoom> data = new ArrayList<HotelRoom>(0);
|
||||
|
||||
private HotelRoomManagerRemote hotelRoomManager = null;
|
||||
|
||||
public HotelRoomTableModel(HotelRoomManagerRemote hotelRoomManager) {
|
||||
if (hotelRoomManager==null) {
|
||||
throw new NullPointerException("Can't get data from null hotelRoomManager");
|
||||
}
|
||||
this.hotelRoomManager=hotelRoomManager;
|
||||
}
|
||||
|
||||
public void updateByCriteria(HotelRoom room) {
|
||||
try {
|
||||
data = hotelRoomManager.findByCriteria(room);
|
||||
System.out.println("Got size from search: "+data.size());
|
||||
this.fireTableDataChanged();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Could not get init all rooms: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
public HotelRoom getHotelRoom(int rowIndex) {
|
||||
return data.get(rowIndex);
|
||||
}
|
||||
|
||||
|
||||
// ============ TableModel
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableModel#getColumnCount()
|
||||
*/
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableModel#getRowCount()
|
||||
*/
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.AbstractTableModel#getColumnName(int)
|
||||
*/
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return "Name";
|
||||
case 1:
|
||||
return "Location";
|
||||
case 2:
|
||||
return "Size";
|
||||
case 3:
|
||||
return "Date";
|
||||
default:
|
||||
return "<DEFAULT>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableModel#getValueAt(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
HotelRoom room = data.get(rowIndex);
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return room.getName();
|
||||
case 1:
|
||||
return room.getLocation();
|
||||
case 2:
|
||||
return room.getSize();
|
||||
case 3:
|
||||
return room.getDateAvailable();
|
||||
default:
|
||||
return "<DEFAULT>";
|
||||
}
|
||||
}
|
||||
}
|
181
src/suncertify/client/MainView.java
Normal file
181
src/suncertify/client/MainView.java
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
|
||||
package suncertify.client;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author willemc
|
||||
*
|
||||
*/
|
||||
public class MainView {
|
||||
|
||||
private HotelRoomManagerRemote hotelRoomManagerRemote = null;
|
||||
private JFrame frame = null;
|
||||
|
||||
public MainView(HotelRoomManagerRemote hotelRoomManagerRemote) {
|
||||
if (hotelRoomManagerRemote==null) {
|
||||
throw new NullPointerException("Can't create MainView with null HotelRoomManager.");
|
||||
}
|
||||
this.hotelRoomManagerRemote=hotelRoomManagerRemote;
|
||||
|
||||
frame = new JFrame();
|
||||
|
||||
frame.setTitle("URLyBird HotelRoom Manager");
|
||||
//frame.setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getResource("/resources/images/logos/gabelfresser.gif")));
|
||||
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowListener() {
|
||||
public void windowActivated(WindowEvent e) { }
|
||||
public void windowClosed(WindowEvent e) { }
|
||||
public void windowClosing(WindowEvent e) { System.exit(0); }
|
||||
public void windowDeactivated(WindowEvent e) { }
|
||||
public void windowDeiconified(WindowEvent e) { }
|
||||
public void windowIconified(WindowEvent e) { }
|
||||
public void windowOpened(WindowEvent e) { }
|
||||
});
|
||||
frame.pack();
|
||||
frame.setBounds(50,50,900,700);
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
|
||||
|
||||
JMenuItem item3 = new JMenuItem("Connect");
|
||||
item3.setEnabled(false);
|
||||
fileMenu.add(item3);
|
||||
|
||||
JMenuItem item2 = new JMenuItem("Preferences");
|
||||
item2.setEnabled(false);
|
||||
fileMenu.add(item2);
|
||||
|
||||
fileMenu.addSeparator();
|
||||
|
||||
JMenuItem item = new JMenuItem();
|
||||
item.setText("Quit");
|
||||
item.addActionListener(new ActionListener() {
|
||||
/**
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
fileMenu.add(item);
|
||||
|
||||
JMenu helpMenu = new JMenu("Help");
|
||||
JMenuItem help = new JMenuItem();
|
||||
help.setText("Help");
|
||||
help.setEnabled(false);
|
||||
helpMenu.add(help);
|
||||
|
||||
helpMenu.addSeparator();
|
||||
|
||||
JMenuItem itemAbout = new JMenuItem("About");
|
||||
itemAbout.setEnabled(false);
|
||||
helpMenu.add(itemAbout);
|
||||
|
||||
menuBar.add(fileMenu);
|
||||
menuBar.add(helpMenu);
|
||||
frame.setJMenuBar(menuBar);
|
||||
|
||||
HotelRoomTableModel model = new HotelRoomTableModel(hotelRoomManagerRemote);
|
||||
SearchPanel searchPanel = new SearchPanel(model);
|
||||
|
||||
frame.getContentPane().add(searchPanel.getJComponent(), BorderLayout.NORTH);
|
||||
|
||||
JPanel southSide = new JPanel();
|
||||
southSide.setLayout(new BoxLayout(southSide, BoxLayout.LINE_AXIS));
|
||||
|
||||
JButton searchButton = new JButton("Search [F1]");
|
||||
JButton addButton = new JButton("Add [F2]");
|
||||
JButton delButton = new JButton("Del [F3]");
|
||||
JButton editButton = new JButton("Edit [F4]");
|
||||
JButton bookButton = new JButton("Book [F5]");
|
||||
JButton exportButton = new JButton("Export [F6]");
|
||||
JButton helpButton = new JButton("Next [F7]");
|
||||
JButton printButton = new JButton("Print [F8]");
|
||||
|
||||
searchButton.setEnabled(false);
|
||||
addButton.setEnabled(false);
|
||||
delButton.setEnabled(false);
|
||||
editButton.setEnabled(false);
|
||||
bookButton.setEnabled(false);
|
||||
exportButton.setEnabled(false);
|
||||
helpButton.setEnabled(false);
|
||||
printButton.setEnabled(false);
|
||||
|
||||
southSide.add(searchButton);
|
||||
southSide.add(addButton);
|
||||
southSide.add(delButton);
|
||||
southSide.add(editButton);
|
||||
southSide.add(bookButton);
|
||||
southSide.add(exportButton);
|
||||
southSide.add(helpButton);
|
||||
southSide.add(printButton);
|
||||
|
||||
frame.getContentPane().add(southSide, BorderLayout.SOUTH);
|
||||
|
||||
// center
|
||||
|
||||
final JTable table = new JTable(model);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
TableRowSorter sorter = new TableRowSorter(model);
|
||||
table.setRowSorter(sorter);
|
||||
|
||||
table.getSelectionModel().addListSelectionListener(
|
||||
new ListSelectionListener() {
|
||||
public void valueChanged(ListSelectionEvent event) {
|
||||
int viewRow = table.getSelectedRow();
|
||||
if (viewRow < 0) {
|
||||
//Selection got filtered away.
|
||||
//statusText.setText("");
|
||||
} else {
|
||||
System.out.println("Selected; "+viewRow+" ... ");
|
||||
//details.updateHotelRoom(model.getHotelRoom(viewRow));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JScrollPane mainPanel = new JScrollPane();
|
||||
mainPanel.setWheelScrollingEnabled(true);
|
||||
mainPanel.setViewportView(table);
|
||||
mainPanel.getVerticalScrollBar().setUnitIncrement(10);
|
||||
mainPanel.getHorizontalScrollBar().setUnitIncrement(10);
|
||||
frame.getContentPane().add(mainPanel,BorderLayout.CENTER);
|
||||
|
||||
}
|
||||
|
||||
public void openView() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
310
src/suncertify/client/SearchPanel.java
Normal file
310
src/suncertify/client/SearchPanel.java
Normal file
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
|
||||
package suncertify.client;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.Spring;
|
||||
import javax.swing.SpringLayout;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.PlainDocument;
|
||||
|
||||
import suncertify.models.HotelRoom;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author willemc
|
||||
*
|
||||
*/
|
||||
public class SearchPanel implements ActionListener,DocumentListener {
|
||||
|
||||
private JPanel searchPanel = null;
|
||||
private JButton searchButton = null;
|
||||
private JButton clearButton = null;
|
||||
private HotelRoomTableModel model = null;
|
||||
private JTextField f0;
|
||||
private JTextField f1;
|
||||
private JTextField f2;
|
||||
private JTextField f3;
|
||||
|
||||
public SearchPanel(HotelRoomTableModel model) {
|
||||
this.model=model;
|
||||
searchPanel = new JPanel();
|
||||
searchPanel.setLayout(new SpringLayout());
|
||||
TitledBorder titledBorder = BorderFactory.createTitledBorder("Search");
|
||||
titledBorder.setTitleJustification(TitledBorder.LEFT);
|
||||
titledBorder.setTitlePosition(TitledBorder.TOP);
|
||||
searchPanel.setBorder(titledBorder);
|
||||
createPanel();
|
||||
}
|
||||
|
||||
public JComponent getJComponent() {
|
||||
return searchPanel;
|
||||
}
|
||||
|
||||
|
||||
private void createPanel() {
|
||||
|
||||
JPanel leftPanel = searchPanel;
|
||||
|
||||
JLabel l0 = new JLabel();
|
||||
l0.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l0.setText("Custumber Number:");
|
||||
leftPanel.add(l0);
|
||||
|
||||
f0 = new JTextField(15);
|
||||
f0.getDocument().addDocumentListener(this);
|
||||
leftPanel.add(f0);
|
||||
|
||||
JLabel l1 = new JLabel();
|
||||
l1.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l1.setText("Name:");
|
||||
leftPanel.add(l1);
|
||||
|
||||
f1 = new JTextField(15);
|
||||
f1.getDocument().addDocumentListener(this);
|
||||
leftPanel.add(f1);
|
||||
|
||||
JLabel l2 = new JLabel();
|
||||
l2.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l2.setText("Location:");
|
||||
leftPanel.add(l2);
|
||||
|
||||
f2 = new JTextField(15);
|
||||
f2.getDocument().addDocumentListener(this);
|
||||
leftPanel.add(f2);
|
||||
|
||||
//searchPanel.add(leftPanel,BorderLayout.LINE_START);
|
||||
|
||||
// === Center
|
||||
|
||||
JPanel centerPanel = searchPanel;
|
||||
|
||||
JLabel l3 = new JLabel();
|
||||
l3.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l3.setText("Size:");
|
||||
centerPanel.add(l3);
|
||||
|
||||
class IntTextDocument extends PlainDocument {
|
||||
private static final long serialVersionUID = 7151907649485446049L;
|
||||
|
||||
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
|
||||
if (str == null) {
|
||||
return;
|
||||
}
|
||||
String oldString = getText(0, getLength());
|
||||
String newString = oldString.substring(0, offs) + str + oldString.substring(offs);
|
||||
try {
|
||||
Integer.parseInt(newString + "0");
|
||||
super.insertString(offs, str, a);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f3 = new JTextField(new IntTextDocument(),null,15);
|
||||
f3.getDocument().addDocumentListener(this);
|
||||
centerPanel.add(f3);
|
||||
|
||||
|
||||
JLabel l4 = new JLabel();
|
||||
l4.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l4.setText("Smoking:");
|
||||
centerPanel.add(l4);
|
||||
|
||||
JCheckBox c1 = new JCheckBox();
|
||||
centerPanel.add(c1);
|
||||
|
||||
JLabel l5 = new JLabel();
|
||||
l5.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l5.setText("Price:");
|
||||
centerPanel.add(l5);
|
||||
|
||||
//JTextField f4 = new JTextField(15);
|
||||
//f4.getDocument().addDocumentListener(this);
|
||||
|
||||
String labels[] = { "10", "20", "50", "100","150", "200", "300", "400","500", "800" };
|
||||
JComboBox comboBox = new JComboBox(labels);
|
||||
comboBox.setMaximumRowCount(5);
|
||||
comboBox.setEditable(true);
|
||||
|
||||
centerPanel.add(comboBox);
|
||||
|
||||
|
||||
JLabel l6 = new JLabel();
|
||||
l6.setHorizontalAlignment(JLabel.TRAILING);
|
||||
l6.setText("Date:");
|
||||
centerPanel.add(l6);
|
||||
|
||||
JTextField f5 = new JTextField(15);
|
||||
//f4.getDocument().addDocumentListener(this);
|
||||
centerPanel.add(f5);
|
||||
|
||||
//searchPanel.add(centerPanel,BorderLayout.CENTER);
|
||||
|
||||
|
||||
// South
|
||||
|
||||
JLabel l7 = new JLabel();
|
||||
centerPanel.add(l7);
|
||||
JLabel l8 = new JLabel();
|
||||
centerPanel.add(l8);
|
||||
|
||||
JPanel buttonPane = searchPanel;
|
||||
//buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||
//buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
|
||||
//buttonPane.add(Box.createHorizontalGlue());
|
||||
|
||||
|
||||
searchButton = new JButton();
|
||||
searchButton.setText("Search");
|
||||
searchButton.addActionListener(this);
|
||||
|
||||
buttonPane.add(searchButton);
|
||||
//buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
|
||||
clearButton = new JButton();
|
||||
clearButton.setText("Clear");
|
||||
clearButton.addActionListener(this);
|
||||
|
||||
buttonPane.add(clearButton);
|
||||
|
||||
//searchPanel.add(buttonPane,BorderLayout.SOUTH);
|
||||
|
||||
//Layout the panel.
|
||||
makeCompactGrid(searchPanel,
|
||||
3, 6, //rows, cols
|
||||
6, 6, //initX, initY
|
||||
6, 6); //xPad, yPad
|
||||
}
|
||||
|
||||
private void updateSearch() {
|
||||
HotelRoom room = new HotelRoom();
|
||||
room.setName(f1.getText());
|
||||
room.setLocation(f2.getText());
|
||||
|
||||
model.updateByCriteria(room);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getSource()==searchButton) {
|
||||
updateSearch();
|
||||
}
|
||||
if (e.getSource()==clearButton) {
|
||||
f0.setText(null);
|
||||
f1.setText(null);
|
||||
f2.setText(null);
|
||||
f3.setText(null);
|
||||
updateSearch();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.event.DocumentListener#changedUpdate(javax.swing.event.DocumentEvent)
|
||||
*/
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
//updateSearch();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent)
|
||||
*/
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
updateSearch();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.event.DocumentListener#removeUpdate(javax.swing.event.DocumentEvent)
|
||||
*/
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
updateSearch();
|
||||
}
|
||||
|
||||
|
||||
public static void makeCompactGrid(Container parent,
|
||||
int rows, int cols,
|
||||
int initialX, int initialY,
|
||||
int xPad, int yPad) {
|
||||
SpringLayout layout;
|
||||
try {
|
||||
layout = (SpringLayout)parent.getLayout();
|
||||
} catch (ClassCastException exc) {
|
||||
System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
|
||||
return;
|
||||
}
|
||||
|
||||
//Align all cells in each column and make them the same width.
|
||||
Spring x = Spring.constant(initialX);
|
||||
for (int c = 0; c < cols; c++) {
|
||||
Spring width = Spring.constant(0);
|
||||
for (int r = 0; r < rows; r++) {
|
||||
width = Spring.max(width,getConstraintsForCell(r, c, parent, cols).getWidth());
|
||||
}
|
||||
for (int r = 0; r < rows; r++) {
|
||||
SpringLayout.Constraints constraints =
|
||||
getConstraintsForCell(r, c, parent, cols);
|
||||
constraints.setX(x);
|
||||
constraints.setWidth(width);
|
||||
}
|
||||
x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
|
||||
}
|
||||
|
||||
//Align all cells in each row and make them the same height.
|
||||
Spring y = Spring.constant(initialY);
|
||||
for (int r = 0; r < rows; r++) {
|
||||
Spring height = Spring.constant(0);
|
||||
for (int c = 0; c < cols; c++) {
|
||||
height = Spring.max(height,getConstraintsForCell(r, c, parent, cols).getHeight());
|
||||
}
|
||||
for (int c = 0; c < cols; c++) {
|
||||
SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols);
|
||||
constraints.setY(y);
|
||||
constraints.setHeight(height);
|
||||
}
|
||||
y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
|
||||
}
|
||||
|
||||
//Set the parent's size.
|
||||
SpringLayout.Constraints pCons = layout.getConstraints(parent);
|
||||
pCons.setConstraint(SpringLayout.SOUTH, y);
|
||||
pCons.setConstraint(SpringLayout.EAST, x);
|
||||
}
|
||||
|
||||
private static SpringLayout.Constraints getConstraintsForCell(
|
||||
int row, int col,
|
||||
Container parent,
|
||||
int cols) {
|
||||
SpringLayout layout = (SpringLayout) parent.getLayout();
|
||||
Component c = parent.getComponent(row * cols + col);
|
||||
return layout.getConstraints(c);
|
||||
}
|
||||
}
|
32
src/suncertify/client/package.html
Normal file
32
src/suncertify/client/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The GUI of the application.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
67
src/suncertify/core/LoadHotelRoomDB.java
Normal file
67
src/suncertify/core/LoadHotelRoomDB.java
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import suncertify.db.DataBaseManager;
|
||||
import suncertify.db.data.Table;
|
||||
import suncertify.db.data.column.BooleanObjectConverter;
|
||||
import suncertify.db.data.column.Column;
|
||||
import suncertify.db.data.column.DateObjectConverter;
|
||||
import suncertify.db.data.column.IntegerObjectConverter;
|
||||
import suncertify.db.data.column.LongObjectConverter;
|
||||
import suncertify.db.data.column.StringColumnSearcher;
|
||||
import suncertify.db.data.column.StringObjectConverter;
|
||||
|
||||
|
||||
/**
|
||||
* LoadHotelRoomDB loads the db-1x3.db database file.
|
||||
* And fills in some meta data in the Table model which is missing in the db file.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class LoadHotelRoomDB {
|
||||
|
||||
|
||||
/**
|
||||
* Loads the database and configs the fields acouring the file specefications.
|
||||
* @param dbm
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Table loadTable(DataBaseManager dbm) throws IOException {
|
||||
|
||||
File f = new File("db-1x3.db");
|
||||
dbm.openTable(f);
|
||||
|
||||
Table table = dbm.getTable(f.getName());
|
||||
// manual config for data safe type
|
||||
for (Column c:table.getColumns()) {
|
||||
if (1==c.getColumnIndex() | 2==c.getColumnIndex()) {
|
||||
c.setObjectConverter(new StringObjectConverter());
|
||||
c.setColumnSearcher(new StringColumnSearcher());
|
||||
}
|
||||
if (3==c.getColumnIndex() | 7==c.getColumnIndex()) {
|
||||
c.setObjectConverter(new IntegerObjectConverter());
|
||||
}
|
||||
if (4==c.getColumnIndex()) {
|
||||
c.setObjectConverter(new BooleanObjectConverter());
|
||||
}
|
||||
if (5==c.getColumnIndex()) {
|
||||
c.setObjectConverter(new LongObjectConverter());
|
||||
}
|
||||
if (6==c.getColumnIndex()) {
|
||||
c.setObjectConverter(new DateObjectConverter());
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
}
|
43
src/suncertify/core/LoadServerBeans.java
Normal file
43
src/suncertify/core/LoadServerBeans.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import suncertify.db.DataBaseManager;
|
||||
import suncertify.models.HotelRoomDBConverter;
|
||||
import suncertify.server.ServerManager;
|
||||
import suncertify.server.beans.BookingLogManager;
|
||||
import suncertify.server.beans.BookingLogManagerRemote;
|
||||
import suncertify.server.beans.HotelRoomManager;
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
|
||||
|
||||
/**
|
||||
* Loads the application needed beans into the ServerManager
|
||||
*
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class LoadServerBeans {
|
||||
|
||||
/**
|
||||
* Loads the application backend beans into the ServerManager
|
||||
* @param server The server to initation with beans.
|
||||
* @param dataBaseManager The databaseManager is needed for injection into beans.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void loadBeans(ServerManager server,DataBaseManager dataBaseManager) throws IOException {
|
||||
|
||||
server.putServerInitBean("hotelRoom.tableBackend", dataBaseManager.getHotelRoomDB());
|
||||
server.putServerInitBean("hotelRoom.beanConverter", new HotelRoomDBConverter(dataBaseManager.getHotelRoomTable()));
|
||||
|
||||
server.putServerBean(HotelRoomManagerRemote.class,HotelRoomManager.class);
|
||||
server.putServerBean(BookingLogManagerRemote.class,BookingLogManager.class);
|
||||
}
|
||||
}
|
108
src/suncertify/core/NetworkServerWorker.java
Normal file
108
src/suncertify/core/NetworkServerWorker.java
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
|
||||
package suncertify.core;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import suncertify.net.NetworkRequest;
|
||||
import suncertify.net.NetworkResponse;
|
||||
import suncertify.net.NetworkServer;
|
||||
import suncertify.net.NetworkNIOConnector.ObjectHandler;
|
||||
import suncertify.server.ServerManager;
|
||||
|
||||
/**
|
||||
* The NetworkServerWorker
|
||||
*
|
||||
* This Runnable worker handlers the data from the nio server and decode it.
|
||||
* Then it will invoke the bean methode and return the result to the nio server.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
|
||||
public class NetworkServerWorker implements Runnable {
|
||||
|
||||
private Logger logger = Logger.getLogger(NetworkServerWorker.class.getName());
|
||||
NetworkServer server = null;
|
||||
SocketChannel socket = null;
|
||||
private ServerManager serverManager = null;
|
||||
private ByteBuffer data = ByteBuffer.allocate(8192);
|
||||
|
||||
/**
|
||||
* Creates an new NetworkServerWorker which can handle requests from the server and executes them on the serverManager.
|
||||
* @param serverManager
|
||||
* @param server
|
||||
* @param socket
|
||||
* @param data
|
||||
*/
|
||||
public NetworkServerWorker(ServerManager serverManager,NetworkServer server,SocketChannel socket,byte[] data) {
|
||||
this.socket=socket;
|
||||
this.server=server;
|
||||
this.data.put(data);
|
||||
this.data.limit(data.length);
|
||||
this.serverManager=serverManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an chuck of data from server and process an response to it.
|
||||
*/
|
||||
public void run() {
|
||||
String tName = Thread.currentThread().getName();
|
||||
long startTime = System.currentTimeMillis();
|
||||
logger.fine("Starting exec in "+tName);
|
||||
try {
|
||||
ByteBuffer leftOver = server.receiveObject(socket,data, new ObjectHandler() {
|
||||
public void processObject(Object object) {
|
||||
NetworkRequest request = (NetworkRequest)object;
|
||||
NetworkResponse response = new NetworkResponse(request.getRequestId());
|
||||
try {
|
||||
Object bean = serverManager.getServerBean(request.getBeanName());
|
||||
|
||||
int pS = 0;
|
||||
if (request.getMethodArgs()!=null) {
|
||||
pS = request.getMethodArgs().length;
|
||||
}
|
||||
Class<?>[] para = new Class[pS];
|
||||
for (int i=0;i<pS;i++) {
|
||||
para[i] = request.getMethodArgs()[i].getClass();
|
||||
}
|
||||
Method mm = bean.getClass().getMethod(request.getMethodName(), para);
|
||||
Object resultObject = mm.invoke(bean,request.getMethodArgs());
|
||||
|
||||
response.setResult(resultObject);
|
||||
server.send(socket,response);
|
||||
|
||||
} catch (Exception e) {
|
||||
response.setResult(e);
|
||||
e.printStackTrace();
|
||||
try {
|
||||
server.send(socket,response);
|
||||
} catch (Exception ee) {
|
||||
logger.log(Level.WARNING,"Error while sending back request: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},0);
|
||||
if (leftOver==null) {
|
||||
return; // all oke
|
||||
} else {
|
||||
// should/will not happen in server mode ... but anyway
|
||||
throw new RuntimeException("Server can't handle leftOver data.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING,"Error while handling request: "+e.getMessage(),e);
|
||||
} finally {
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.fine("Helped client"+tName+" in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
}
|
||||
}
|
81
src/suncertify/core/PropertiesManager.java
Normal file
81
src/suncertify/core/PropertiesManager.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.core;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The PropertiesManager
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Jan 5, 2009
|
||||
*/
|
||||
public class PropertiesManager {
|
||||
|
||||
/** The filename we may use to save the properties of the application. */
|
||||
static final String FILENAME = "suncertify.properties";
|
||||
/** The properties managed by this manager. */
|
||||
private Properties properties = new Properties();
|
||||
|
||||
/**
|
||||
* Reads in the properties.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(FILENAME);
|
||||
properties.load(in);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
// we discard this one because one first startup we don't have a file.
|
||||
} finally {
|
||||
if (in!=null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the properties.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void stop() throws IOException {
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(FILENAME);
|
||||
properties.store(out, "Created by: "+PropertiesManager.class.getSimpleName());
|
||||
} finally {
|
||||
if (out!=null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an properties.
|
||||
* @param key The key of the property.
|
||||
* @param value The value of the property.
|
||||
*/
|
||||
public void setProperty(String key,String value) {
|
||||
properties.setProperty(key,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property.
|
||||
* @param key The key of the property.
|
||||
* @return The value of the property.
|
||||
*/
|
||||
public String getProperty(String key) {
|
||||
return properties.getProperty(key);
|
||||
}
|
||||
}
|
168
src/suncertify/core/SunCertifyStarter.java
Normal file
168
src/suncertify/core/SunCertifyStarter.java
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import suncertify.client.MainView;
|
||||
import suncertify.db.DataBaseManager;
|
||||
import suncertify.net.NIOConnector;
|
||||
import suncertify.net.NetworkClient;
|
||||
import suncertify.net.NetworkServer;
|
||||
import suncertify.net.NetworkServer.ServerBackendProvider;
|
||||
import suncertify.server.ServerManager;
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
|
||||
|
||||
/**
|
||||
* The Main methode to start the SUN Certify UrlBurd submission
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class SunCertifyStarter {
|
||||
|
||||
/**
|
||||
* The startup modes.
|
||||
* Which can be used as startup argument.
|
||||
*/
|
||||
public enum StartupMode {
|
||||
server,
|
||||
alone,
|
||||
client
|
||||
}
|
||||
|
||||
/** The current mode we are started with. */
|
||||
private StartupMode mode = null;
|
||||
|
||||
/** The default mode if no arguments are given. */
|
||||
static public final StartupMode DEFAULT_MODE = StartupMode.client;
|
||||
|
||||
/** The server manager */
|
||||
private ServerManager serverManager = null;
|
||||
|
||||
/** The database manager */
|
||||
private DataBaseManager dataBaseManager = null;
|
||||
|
||||
/** The network manager (server or client) */
|
||||
private NIOConnector networkManager = null;
|
||||
|
||||
/**
|
||||
* Constructor with the startup mode.
|
||||
* @param mode The mode to startup the software.
|
||||
*/
|
||||
public SunCertifyStarter(StartupMode mode) {
|
||||
this.mode=mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all managers with are needed in the selected mode.
|
||||
* And opens the mainview if nessery.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
|
||||
if (mode!=StartupMode.client) {
|
||||
// do startup for server and alone
|
||||
dataBaseManager = new DataBaseManager();
|
||||
dataBaseManager.start();
|
||||
serverManager = new ServerManager();
|
||||
serverManager.start();
|
||||
|
||||
// loading
|
||||
new LoadHotelRoomDB().loadTable(dataBaseManager);
|
||||
new LoadServerBeans().loadBeans(serverManager,dataBaseManager);
|
||||
}
|
||||
|
||||
|
||||
switch(mode) {
|
||||
case alone:
|
||||
HotelRoomManagerRemote local = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
serverManager.getLocalInvocationHandler());
|
||||
MainView aloneView = new MainView(local);
|
||||
aloneView.openView();
|
||||
break;
|
||||
case client:
|
||||
NetworkClient client = new NetworkClient(InetAddress.getByName("localhost"), 9090);
|
||||
client.start();
|
||||
HotelRoomManagerRemote remote = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
client.getInvocationHandler(HotelRoomManagerRemote.class));
|
||||
MainView clientView = new MainView(remote);
|
||||
clientView.openView();
|
||||
networkManager = client;
|
||||
|
||||
PropertiesManager propertiesManager = new PropertiesManager();
|
||||
propertiesManager.start();
|
||||
|
||||
break;
|
||||
case server:
|
||||
ServerBackendProvider serverBackendProvider = new ServerBackendProvider() {
|
||||
public void executeWorker(Runnable runable) {
|
||||
serverManager.execute(runable);
|
||||
}
|
||||
public Runnable dataWorker(NetworkServer server,SocketChannel socket,byte[] data) {
|
||||
return new NetworkServerWorker(serverManager,server,socket,data);
|
||||
}
|
||||
};
|
||||
networkManager = new NetworkServer(null, 9090, serverBackendProvider);
|
||||
break;
|
||||
}
|
||||
|
||||
if (networkManager!=null) {
|
||||
networkManager.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all not null Managers.
|
||||
*/
|
||||
public void stop() throws IOException {
|
||||
try {
|
||||
if (networkManager!=null) {
|
||||
networkManager.stop();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (serverManager!=null) {
|
||||
serverManager.stop();
|
||||
}
|
||||
} finally {
|
||||
if (dataBaseManager!=null) {
|
||||
dataBaseManager.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main startup method of SunCertify Software Application
|
||||
* @param args The mode to startup with.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
StartupMode mode = null;
|
||||
if (args.length<1) {
|
||||
mode = DEFAULT_MODE;
|
||||
} else if (args.length==1) {
|
||||
mode = StartupMode.valueOf(args[0]);
|
||||
} else if (args.length>1) {
|
||||
System.err.println("To many arguments given, only one optionale argument supperted with values: "+StartupMode.values());
|
||||
System.exit(1);
|
||||
}
|
||||
SunCertifyStarter starter = new SunCertifyStarter(mode);
|
||||
try {
|
||||
starter.start();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Could not start SunCertify: "+e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
33
src/suncertify/core/package.html
Normal file
33
src/suncertify/core/package.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The core classes.<br/>
|
||||
These bind the different object layers of the application toghter to form the application.
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
91
src/suncertify/db/DB.java
Normal file
91
src/suncertify/db/DB.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
/**
|
||||
* File provided by the Application Submission
|
||||
*
|
||||
* @author suncertify.db
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public interface DB {
|
||||
|
||||
/**
|
||||
* Reads a record from the file. Returns an array where each
|
||||
* element is a record value.
|
||||
*/
|
||||
public String[] read(int recNo) throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
* Modifies the fields of a record. The new value for field n
|
||||
* appears in data[n]. Throws SecurityException
|
||||
* if the record is locked with a cookie other than lockCookie.
|
||||
*/
|
||||
public void update(int recNo, String[] data, long lockCookie) throws RecordNotFoundException, SecurityException;
|
||||
|
||||
/**
|
||||
* Deletes a record, making the record number and associated disk
|
||||
* storage available for reuse.
|
||||
* Throws SecurityException if the record is locked with a cookie
|
||||
* other than lockCookie.
|
||||
*
|
||||
* @param recNo
|
||||
* @param lockCookie
|
||||
* @throws RecordNotFoundException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void delete(int recNo, long lockCookie) throws RecordNotFoundException, SecurityException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns an array of record numbers that match the specified
|
||||
* criteria. Field n in the database file is described by
|
||||
* criteria[n]. A null value in criteria[n] matches any field
|
||||
* value. A non-null value in criteria[n] matches any field
|
||||
* value that begins with criteria[n]. (For example, "Fred"
|
||||
* matches "Fred" or "Freddy".)
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
public int[] find(String[] criteria);
|
||||
|
||||
/**
|
||||
* Creates a new record in the database (possibly reusing a
|
||||
* deleted entry). Inserts the given data, and returns the record
|
||||
* number of the new record.
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
* @throws DuplicateKeyException
|
||||
*/
|
||||
public int create(String[] data) throws DuplicateKeyException;
|
||||
|
||||
/**
|
||||
* Locks a record so that it can only be updated or deleted by this client.
|
||||
* Returned value is a cookie that must be used when the record is unlocked,
|
||||
* updated, or deleted. If the specified record is already locked by a different
|
||||
* client, the current thread gives up the CPU and consumes no CPU cycles until
|
||||
* the record is unlocked.
|
||||
*
|
||||
* @param recNo
|
||||
* @return
|
||||
* @throws RecordNotFoundException
|
||||
*/
|
||||
public long lock(int recNo) throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
* Releases the lock on a record. Cookie must be the cookie
|
||||
* returned when the record was locked; otherwise throws SecurityException.
|
||||
*
|
||||
* @param recNo
|
||||
* @param cookie
|
||||
* @throws RecordNotFoundException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void unlock(int recNo, long cookie) throws RecordNotFoundException, SecurityException;
|
||||
}
|
86
src/suncertify/db/Data.java
Normal file
86
src/suncertify/db/Data.java
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
import suncertify.db.data.Table;
|
||||
|
||||
/**
|
||||
* Wrapper class for interface DB , to Table object.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class Data implements DB {
|
||||
|
||||
/** The table we wrap. */
|
||||
final private Table table;
|
||||
|
||||
/**
|
||||
* Creates an Data wrapper for an Table object.
|
||||
* @param table
|
||||
*/
|
||||
public Data(Table table) {
|
||||
this.table=table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#read(int)
|
||||
*/
|
||||
@Override
|
||||
public String[] read(int row) throws RecordNotFoundException {
|
||||
return table.getInterfaceRow(row);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#find(java.lang.String[])
|
||||
*/
|
||||
@Override
|
||||
public int[] find(String[] criteria) {
|
||||
return table.searchByInterfaceCriteria(criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#lock(int)
|
||||
*/
|
||||
@Override
|
||||
public long lock(int row) throws RecordNotFoundException {
|
||||
return table.lock(row).getLockId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#unlock(int, long)
|
||||
*/
|
||||
@Override
|
||||
public void unlock(int row, long lockId) throws RecordNotFoundException,SecurityException {
|
||||
table.unlock(row, lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#update(int, java.lang.String[], long)
|
||||
*/
|
||||
@Override
|
||||
public void update(int row, String[] data, long lockId) throws RecordNotFoundException, SecurityException {
|
||||
table.update(row, data, lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#delete(int, long)
|
||||
*/
|
||||
@Override
|
||||
public void delete(int row, long lockId) throws RecordNotFoundException, SecurityException {
|
||||
table.delete(row, lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.DB#create(java.lang.String[])
|
||||
*/
|
||||
@Override
|
||||
public int create(String[] data) throws DuplicateKeyException {
|
||||
return table.create(data);
|
||||
}
|
||||
}
|
88
src/suncertify/db/DataBaseManager.java
Normal file
88
src/suncertify/db/DataBaseManager.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import suncertify.db.data.Table;
|
||||
|
||||
/**
|
||||
* Manages all open database files in the application.
|
||||
*
|
||||
* At the moment this is only one.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class DataBaseManager {
|
||||
|
||||
private Logger logger = Logger.getLogger(DataBaseManager.class.getName());
|
||||
private Map<String,Table> tables = null;
|
||||
|
||||
/**
|
||||
* Creates the DataBaseManager.
|
||||
*/
|
||||
public DataBaseManager() {
|
||||
tables = new HashMap<String,Table>(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the only managed database table namely the hotelRoom table.
|
||||
*/
|
||||
public DB getHotelRoomDB() {
|
||||
Table table = getTable("db-1x3.db");
|
||||
DB db = new Data(table);
|
||||
return db;
|
||||
}
|
||||
|
||||
// hackje voor server->DB-api converters
|
||||
public Table getHotelRoomTable() {
|
||||
return getTable("db-1x3.db");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the database
|
||||
*/
|
||||
public void start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the database manager
|
||||
*/
|
||||
public void stop() {
|
||||
for (Table t:tables.values()) {
|
||||
try {
|
||||
closeTable(t);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING,"Error while closing table: "+t.getName()+" error: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Table openTable(File file) throws IOException {
|
||||
Table t = new Table();
|
||||
t.openTable(file);
|
||||
tables.put(t.getName(),t);
|
||||
logger.fine("Opened table: "+t.getName());
|
||||
return t;
|
||||
}
|
||||
|
||||
public void closeTable(Table table) throws IOException {
|
||||
logger.fine("Closing table: "+table.getName());
|
||||
table.closeTable();
|
||||
}
|
||||
|
||||
public Table getTable(String name) {
|
||||
return tables.get(name);
|
||||
}
|
||||
|
||||
}
|
32
src/suncertify/db/DuplicateKeyException.java
Normal file
32
src/suncertify/db/DuplicateKeyException.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
/**
|
||||
* An DuplicateKeyException is thrown the the database when a record already execits in the database.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DuplicateKeyException extends Exception {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DuplicateKeyException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Message constructor
|
||||
* @param message The error message
|
||||
*/
|
||||
public DuplicateKeyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
31
src/suncertify/db/RecordNotFoundException.java
Normal file
31
src/suncertify/db/RecordNotFoundException.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
/**
|
||||
* An RecordNotFoundException is thrown the the database when a record is not found.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class RecordNotFoundException extends Exception {
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public RecordNotFoundException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Message constructor
|
||||
* @param message The error message
|
||||
*/
|
||||
public RecordNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
83
src/suncertify/db/data/RowCache.java
Normal file
83
src/suncertify/db/data/RowCache.java
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* RowCache stores one record and meta data of data for caching.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class RowCache {
|
||||
|
||||
private Integer recordRow = null;
|
||||
private String[] record = null;
|
||||
private Date dateCreated = null;
|
||||
private Date dateAccess = null;
|
||||
private AtomicInteger countAccess = null;
|
||||
|
||||
/**
|
||||
* Creates new cache row and validates it contains data.
|
||||
* @param record
|
||||
*/
|
||||
public RowCache(Integer recordRow,String[] record) {
|
||||
if (recordRow==null) {
|
||||
throw new NullPointerException("Can't cache null record row number.");
|
||||
}
|
||||
if (record==null) {
|
||||
throw new NullPointerException("Can't cache null record.");
|
||||
}
|
||||
if (record.length==0) {
|
||||
throw new NullPointerException("Can't cache empty record.");
|
||||
}
|
||||
this.record=record;
|
||||
dateCreated = new Date();
|
||||
dateAccess = new Date();
|
||||
countAccess = new AtomicInteger(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the record
|
||||
*/
|
||||
public String[] getRecord() {
|
||||
dateAccess = new Date();
|
||||
countAccess.incrementAndGet();
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateCreated
|
||||
*/
|
||||
public Date getDateCreated() {
|
||||
return dateCreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateAccess
|
||||
*/
|
||||
public Date getDateAccess() {
|
||||
return dateAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* note: use int here so we not cast to much.
|
||||
* @return the countAccess
|
||||
*/
|
||||
public int getCountAccess() {
|
||||
return countAccess.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the recordRow
|
||||
*/
|
||||
public Integer getRecordRow() {
|
||||
return recordRow;
|
||||
}
|
||||
}
|
86
src/suncertify/db/data/RowLock.java
Normal file
86
src/suncertify/db/data/RowLock.java
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* RowLock lock a certain row and has timeout of the lock.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class RowLock {
|
||||
|
||||
private Integer recordRow = null;
|
||||
private Long lockId = null;
|
||||
private Date dateCreated = null;
|
||||
private Date dateAccess = null;
|
||||
private Date dateRelease = null;
|
||||
private AtomicInteger countAccess = null;
|
||||
|
||||
/**
|
||||
* Creates an RowLock
|
||||
* @param recordRow The row index to lock.
|
||||
* @param lockTimeout The lock timeout
|
||||
* @param lockId The id of the lock
|
||||
*/
|
||||
public RowLock(Integer recordRow,long lockTimeout,long lockId) {
|
||||
if (recordRow==null) {
|
||||
throw new NullPointerException("Can't lock null record row number.");
|
||||
}
|
||||
dateCreated = new Date();
|
||||
dateAccess = new Date();
|
||||
dateRelease = new Date(dateAccess.getTime()+lockTimeout);
|
||||
countAccess = new AtomicInteger(0);
|
||||
this.lockId = lockId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the recordRow
|
||||
*/
|
||||
public Integer getRecordRow() {
|
||||
return recordRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateCreated
|
||||
*/
|
||||
public Date getDateCreated() {
|
||||
return dateCreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateAccess
|
||||
*/
|
||||
public Date getDateAccess() {
|
||||
return dateAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateRelease
|
||||
*/
|
||||
public Date getDateRelease() {
|
||||
return dateRelease;
|
||||
}
|
||||
|
||||
/**
|
||||
* note: use int here so we not cast to much.
|
||||
* @return the countAccess
|
||||
*/
|
||||
public int getCountAccess() {
|
||||
return countAccess.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lockId
|
||||
*/
|
||||
public Long getLockId() {
|
||||
return lockId;
|
||||
}
|
||||
}
|
767
src/suncertify/db/data/Table.java
Normal file
767
src/suncertify/db/data/Table.java
Normal file
|
@ -0,0 +1,767 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import suncertify.db.DuplicateKeyException;
|
||||
import suncertify.db.RecordNotFoundException;
|
||||
import suncertify.db.data.column.Column;
|
||||
import suncertify.db.data.column.DeleteFlagConverter;
|
||||
|
||||
/**
|
||||
* The Table class manages one open database file on disk.
|
||||
*
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class Table {
|
||||
|
||||
/** The NMAP'ed bytebuffer to the file database on disk. */
|
||||
private MappedByteBuffer byteBuffer = null;
|
||||
/** Object to locking the bytebuffer. */
|
||||
private Object byteBufferLock = new Object();
|
||||
/** All the columns of this table */
|
||||
private List<Column> columns = null;
|
||||
/** The logger to log to. */
|
||||
private Logger logger = null;
|
||||
/** The total records which are in this file.(incl deleted) */
|
||||
private int records = 0;
|
||||
/** Offset where the data starts in the byteBuffer */
|
||||
private int recordsOffset = 0;
|
||||
/** The charset encoding used for the data. */
|
||||
private Charset charset = null;
|
||||
/** The name of the file */
|
||||
private String name = null;
|
||||
/** locks for rows */
|
||||
private Map<Integer,RowLock> locks = Collections.synchronizedMap(new HashMap<Integer,RowLock>());
|
||||
/** cach for rows */
|
||||
private Map<Integer,RowCache> cache = new HashMap<Integer,RowCache>();
|
||||
/** The maximum of rows in the cache. */
|
||||
private int cacheMax = 100;
|
||||
/** File which is opened */
|
||||
private RandomAccessFile tableFile = null;
|
||||
/** The number of records added when table is enlarged. */
|
||||
private int extraRecords = 4;
|
||||
|
||||
// declair final so can't be altered by reflection
|
||||
/** The readLock for the cache */
|
||||
final private Lock readLock;
|
||||
/** The writeLock for the cache */
|
||||
final private Lock writeLock;
|
||||
/** The row lock counter */
|
||||
final private AtomicInteger rowLocks;
|
||||
|
||||
// REST ARE cache values
|
||||
|
||||
private int totalColumnsByteSize = 0;
|
||||
|
||||
private boolean isFinerLog = false;
|
||||
|
||||
/**
|
||||
* Creates the table object.
|
||||
*/
|
||||
public Table() {
|
||||
logger = Logger.getLogger(Table.class.getName());
|
||||
isFinerLog = logger.isLoggable(Level.FINER);
|
||||
columns = new ArrayList<Column>(10);
|
||||
charset = Charset.forName("US-ASCII");
|
||||
|
||||
ReentrantReadWriteLock locking = new ReentrantReadWriteLock();
|
||||
readLock = locking.readLock();
|
||||
writeLock = locking.writeLock();
|
||||
|
||||
Random random = new Random();
|
||||
rowLocks= new AtomicInteger(random.nextInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a table.
|
||||
*
|
||||
* note: no locking here because connurent access is pas possible
|
||||
* when the table is put in DBManager table storage, which is after this method call.
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
public void openTable(File file) throws IOException {
|
||||
// http://www.codefund.com/52/nio-mappedbytebuffer-filechannel-resizing-524047.shtm
|
||||
//
|
||||
long startTime = System.currentTimeMillis();
|
||||
name = file.getName();
|
||||
|
||||
tableFile = new RandomAccessFile(file,"rw");
|
||||
FileChannel channel = tableFile.getChannel();
|
||||
int length = (int)channel.size();
|
||||
logger.fine("Mapping table size: "+length);
|
||||
byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length);
|
||||
logger.finer("Buf info direct: "+byteBuffer.isDirect()+" loaded: "+byteBuffer.isLoaded()+" readonly: "+byteBuffer.isReadOnly());
|
||||
// read 4 magic bytes
|
||||
int cookie = byteBuffer.getInt();
|
||||
logger.fine("DB File cookie: "+cookie);
|
||||
if (259!=cookie) {
|
||||
throw new IllegalStateException("DB file magic cookie is not correct 259!="+cookie);
|
||||
}
|
||||
|
||||
// # fields
|
||||
char fields = byteBuffer.getChar();
|
||||
|
||||
// dele flag
|
||||
Column c = new Column();
|
||||
c.setCharset(charset);
|
||||
c.setFieldLength(1);
|
||||
c.setFieldName("___DB___DELETED_ROW_FLAG");
|
||||
c.setFieldNameLength(c.getFieldName().length()); // should column 0 should not be saved.
|
||||
c.setObjectConverter(new DeleteFlagConverter());
|
||||
c.setColumnIndex(0);
|
||||
addColumn(c);
|
||||
|
||||
// header
|
||||
for (int i=0;i<fields;i++) {
|
||||
byte size = byteBuffer.get();
|
||||
byte[] fieldName = new byte[size];
|
||||
byteBuffer.get(fieldName);
|
||||
String fieldNameStr = new String(fieldName,charset);
|
||||
byte fieldSize = byteBuffer.get();
|
||||
// note +1 is for del flag column
|
||||
logger.fine("Got field: "+(i+1)+" name: "+fieldNameStr+" size: "+fieldSize);
|
||||
|
||||
c = new Column();
|
||||
c.setCharset(charset);
|
||||
c.setFieldLength(fieldSize);
|
||||
c.setFieldName(fieldNameStr);
|
||||
c.setFieldNameLength(size);
|
||||
c.setColumnIndex(i+1);
|
||||
|
||||
addColumn(c);
|
||||
}
|
||||
|
||||
recordsOffset = byteBuffer.position();
|
||||
records = (length-recordsOffset)/getTotalColumnsByteSize();
|
||||
|
||||
logger.info("Total records: "+records);
|
||||
logger.fine("Records offset: "+recordsOffset);
|
||||
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.info("DB Loaded: "+file.getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table with a given format
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
public void createTable(File file,List<Column> columns) throws IOException {
|
||||
|
||||
if (file.exists()) {
|
||||
throw new IllegalArgumentException("File: "+file.getName()+" already excists.");
|
||||
}
|
||||
if (columns.size()>255) {
|
||||
throw new IllegalArgumentException("More then 255 columns is not supported.");
|
||||
}
|
||||
char colSize = (char)columns.size();
|
||||
|
||||
// create file
|
||||
FileOutputStream outputFile = new FileOutputStream(file, true);
|
||||
logger.info("File stream created successfully: "+file.getName());
|
||||
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
FileChannel channel = outputFile.getChannel();
|
||||
MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
|
||||
logger.finer("Buf info direct: "+byteBuffer.isDirect()+" loaded: "+byteBuffer.isLoaded()+" readonly: "+byteBuffer.isReadOnly());
|
||||
|
||||
// write 4 magic bytes
|
||||
byteBuffer.putInt(259);
|
||||
|
||||
// # fields
|
||||
byteBuffer.putChar(colSize);
|
||||
|
||||
// write field headers
|
||||
for (int i=0;i<colSize;i++) {
|
||||
Column c = columns.get(i);
|
||||
byteBuffer.put((byte)c.getFieldNameLength());
|
||||
byte[] fieldName = c.getFieldName().getBytes(c.getCharset());
|
||||
byteBuffer.put(fieldName);
|
||||
byteBuffer.put((byte)c.getFieldLength());
|
||||
}
|
||||
long stopTime = System.currentTimeMillis();
|
||||
logger.info("Created DB: "+file.getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
} finally {
|
||||
outputFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the table and resources.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void closeTable() throws IOException {
|
||||
synchronized (byteBufferLock) {
|
||||
byteBuffer.force();
|
||||
}
|
||||
tableFile.close();
|
||||
}
|
||||
|
||||
private void resizeTable() {
|
||||
synchronized (byteBufferLock) {
|
||||
try {
|
||||
byteBuffer.force();
|
||||
closeByteBuffer(byteBuffer);
|
||||
byteBuffer=null;
|
||||
|
||||
FileChannel channel = tableFile.getChannel();
|
||||
int lengthOrg = (int)channel.size();
|
||||
int length=lengthOrg+(extraRecords*getTotalColumnsByteSize());
|
||||
|
||||
logger.info("ReMapping size: "+length+" was: "+lengthOrg+" for extra records: "+extraRecords);
|
||||
byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length);
|
||||
|
||||
|
||||
// filling space with free(deleted) records
|
||||
|
||||
byteBuffer.position(lengthOrg);
|
||||
|
||||
for (int i=lengthOrg;i<length;i++) {
|
||||
byteBuffer.put(i, (byte)00);
|
||||
}
|
||||
|
||||
Column c = columns.get(0);
|
||||
for (int i=0;i<extraRecords;i++) {
|
||||
byte[] data = c.getObjectConverter().encodeStorage(c,"true");
|
||||
setColumnDataByte(records+i,0,data);
|
||||
}
|
||||
|
||||
// new total
|
||||
records = records + extraRecords;
|
||||
|
||||
} catch (Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
|
||||
*
|
||||
* @param buffer
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings(value="unchecked")
|
||||
private void closeByteBuffer(final Object buffer) {
|
||||
// AccessController.doPrivileged(
|
||||
// new PrivilegedAction() {
|
||||
// public Object run() {
|
||||
// try {
|
||||
// Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);
|
||||
// getCleanerMethod.setAccessible(true);
|
||||
// sun.misc.Cleaner cleaner = (sun.misc.Cleaner)getCleanerMethod.invoke(buffer,new Object[0]);
|
||||
// cleaner.clean();
|
||||
// } catch(Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Total amount of records which can or are stored in the table.
|
||||
* @return
|
||||
*/
|
||||
public int getTotalRecords() {
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of columns in this table.
|
||||
* @return
|
||||
*/
|
||||
public int getTotalColumns() {
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total byte size of all the columns together.
|
||||
* @return
|
||||
*/
|
||||
public int getTotalColumnsByteSize() {
|
||||
|
||||
if (totalColumnsByteSize>0) {
|
||||
return totalColumnsByteSize;
|
||||
}
|
||||
int result = 0;
|
||||
for (Column c:columns) {
|
||||
result+=c.getFieldLength();
|
||||
}
|
||||
totalColumnsByteSize = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the row Id is in bound of this table.
|
||||
* @param row The row to check
|
||||
* @throws RecordNotFoundException Throws an RecordNotFoundException if row is negative or is out of bounds.
|
||||
*/
|
||||
private void checkBounds(int row) throws RecordNotFoundException {
|
||||
if (row<0) {
|
||||
throw new RecordNotFoundException("Can't handle negative rows.");
|
||||
}
|
||||
if (row>records) {
|
||||
throw new RecordNotFoundException("row number is out of bounds.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this row is an deleted row.
|
||||
* @param row The row to check.
|
||||
* @return true if row is an deleted row.
|
||||
*/
|
||||
private boolean checkDeletedRow(int row) {
|
||||
Column c = columns.get(0);
|
||||
byte[] data = getColumnDataByte(row,0);
|
||||
// extra converting to fit in db interface
|
||||
String result = c.getObjectConverter().decodeStorage(c, data);
|
||||
if ("true".equals(result)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an row is deleted.
|
||||
* @param row The row to check.
|
||||
* @throws RecordNotFoundException is throw when the row is deleted.
|
||||
*/
|
||||
private void checkDeleted(int row) throws RecordNotFoundException {
|
||||
if (checkDeletedRow(row)) {
|
||||
throw new RecordNotFoundException("row is deleted: "+row);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Integer,Integer> colBytes = new HashMap<Integer,Integer>(20);
|
||||
public int getTotalColumnsByteSize(int col) {
|
||||
|
||||
// cached value.
|
||||
if (colBytes.containsKey(col)) {
|
||||
return colBytes.get(col);
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
int cols = 0;
|
||||
for (Column c:columns) {
|
||||
// we store the number of bytes BEFORE column !!
|
||||
colBytes.put(cols, result);
|
||||
result+=c.getFieldLength();
|
||||
cols++;
|
||||
}
|
||||
|
||||
if (colBytes.containsKey(col)) {
|
||||
return colBytes.get(col);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Column not found: "+col);
|
||||
}
|
||||
|
||||
private byte[] getColumnDataByte(int row,int column) {
|
||||
Column c = columns.get(column);
|
||||
int bb = getTotalColumnsByteSize();
|
||||
int offset = recordsOffset+(row*bb)+getTotalColumnsByteSize(column);
|
||||
if (isFinerLog) {
|
||||
logger.finer("Get raw data byte[] ACCESS: row: "+row+" col: "+column+" off: "+offset+" recs: "+records+" start: "+recordsOffset+" recLen: "+bb);
|
||||
}
|
||||
byte[] result = new byte[c.getFieldLength()];
|
||||
|
||||
// only lock byteBuffer access
|
||||
synchronized (byteBufferLock) {
|
||||
byteBuffer.position(offset);
|
||||
byteBuffer.get(result, 0, c.getFieldLength());
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private void setColumnDataByte(int row,int column,byte[] data) {
|
||||
int bb = getTotalColumnsByteSize();
|
||||
int offset = recordsOffset+(row*bb)+getTotalColumnsByteSize(column);
|
||||
if (isFinerLog) {
|
||||
logger.finer("Set raw data byte[] ACCESS: row: "+row+" col: "+column+" off: "+offset+" recs: "+records+" start: "+recordsOffset+" recLen: "+bb+" dataSize: "+data.length);
|
||||
}
|
||||
if (data.length>bb) {
|
||||
throw new SecurityException("May not writes longer data then ");
|
||||
}
|
||||
if (offset>=byteBuffer.limit()) {
|
||||
resizeTable();
|
||||
}
|
||||
|
||||
// only lock byteBuffer access
|
||||
synchronized (byteBufferLock) {
|
||||
byteBuffer.position(offset);
|
||||
byteBuffer.put(data, 0, data.length);
|
||||
}
|
||||
}
|
||||
|
||||
private String getColumnDataString(int row,int column) {
|
||||
Column c = columns.get(column);
|
||||
byte[] data = getColumnDataByte(row,column);
|
||||
|
||||
// extra converting to fit in db interface
|
||||
String result = c.getObjectConverter().decodeStorage(c, data);
|
||||
try {
|
||||
Object o = c.getObjectConverter().decodeInterface(c, result);
|
||||
String result2 = c.getObjectConverter().encodeInterface(c, o);
|
||||
return result2;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Could not convert data: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
private void putColumnDataString(int row,int column,String data) {
|
||||
Column c = columns.get(column);
|
||||
// extra converting to fit in db interface
|
||||
Object result = c.getObjectConverter().decodeInterface(c, data);
|
||||
try {
|
||||
String o = c.getObjectConverter().encodeInterface(c, result);
|
||||
byte[] result2 = c.getObjectConverter().encodeStorage(c, o);
|
||||
setColumnDataByte(row,column,result2);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Could not convert data: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getInterfaceRow(int row) throws RecordNotFoundException {
|
||||
String[] result = cacheGet(row);
|
||||
if (result!=null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
checkBounds(row);
|
||||
checkDeleted(row);
|
||||
|
||||
int cols = getTotalColumns()-1;
|
||||
result = new String[cols];
|
||||
for (int i=0;i<cols;i++) {
|
||||
result[i] = getColumnDataString(row,i+1);
|
||||
}
|
||||
cachePut(row,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void putInterfaceRow(int row,String[] data) throws RecordNotFoundException {
|
||||
checkBounds(row);
|
||||
|
||||
int cols = getTotalColumns()-1;
|
||||
for (int i=0;i<cols;i++) {
|
||||
String value = data[i];
|
||||
putColumnDataString(row,i+1,value);
|
||||
}
|
||||
|
||||
// update cache
|
||||
String[] result = cacheGet(row);
|
||||
if (result!=null) {
|
||||
cachePut(row,result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Column
|
||||
* @param column The column to add.
|
||||
*/
|
||||
public void addColumn(Column column) {
|
||||
columns.add(column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the List of the Columns.
|
||||
* @return all columns
|
||||
*/
|
||||
public List<Column> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this table
|
||||
* @return The name of this table
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
// search
|
||||
|
||||
public int[] searchByInterfaceCriteria(String[] criteria) {
|
||||
|
||||
if (criteria==null) {
|
||||
throw new NullPointerException("Can't search null criteria");
|
||||
}
|
||||
// -1 = deleted flag column
|
||||
if (criteria.length!=getTotalColumns()-1) {
|
||||
throw new IllegalArgumentException("criteria array is not same size as table columns.");
|
||||
}
|
||||
|
||||
Set<Integer> result = new HashSet<Integer>(50);
|
||||
|
||||
|
||||
for (int i=0;i<records;i++) {
|
||||
|
||||
boolean found = false;
|
||||
boolean st = false;
|
||||
int col = 1; // skip del column
|
||||
for (String c:criteria) {
|
||||
if (c.isEmpty()) {
|
||||
col++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (st) {
|
||||
break;
|
||||
}
|
||||
|
||||
//System.out.println("Searching for: "+c);
|
||||
Column column = getColumns().get(col);
|
||||
try {
|
||||
if (column.getColumnSearcher()!=null & c!=null) {
|
||||
|
||||
byte[] data = getColumnDataByte(i,column.getColumnIndex());
|
||||
String dataResult = column.getObjectConverter().decodeStorage(column, data);
|
||||
|
||||
boolean foundData = column.getColumnSearcher().searchColumn(this, column, c, dataResult);
|
||||
if (foundData) {
|
||||
found = true;
|
||||
} else {
|
||||
st = true;
|
||||
if (found) {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
col++;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
result.add(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// put in int array
|
||||
int[] res = new int[result.size()];
|
||||
int index=0;
|
||||
for(Integer i:result) {
|
||||
res[index]=i;
|
||||
index++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// CRUD Actions
|
||||
|
||||
public void update(int row, String[] data, long lockId) throws RecordNotFoundException, SecurityException {
|
||||
checkBounds(row);
|
||||
checkDeleted(row);
|
||||
checkLock(row,lockId);
|
||||
putInterfaceRow(row,data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an Row.
|
||||
*
|
||||
* Only sets row on deleted mark.
|
||||
* And removes row from cached if it was cached.
|
||||
*
|
||||
* @param row
|
||||
* @param lockId
|
||||
* @throws RecordNotFoundException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void delete(int row, long lockId) throws RecordNotFoundException, SecurityException {
|
||||
checkBounds(row);
|
||||
checkDeleted(row);
|
||||
checkLock(row,lockId);
|
||||
putColumnDataString(row,0,"true");
|
||||
|
||||
// update cache
|
||||
String[] result = cacheGet(row);
|
||||
if (result!=null) {
|
||||
cacheRemove(row);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Row
|
||||
* @param interfaceData
|
||||
* @return
|
||||
* @throws DuplicateKeyException
|
||||
*/
|
||||
public int create(String[] interfaceData) throws DuplicateKeyException {
|
||||
|
||||
Column c = columns.get(0);
|
||||
int emptyRow = -1;
|
||||
// seq scanning for deleted records:
|
||||
for (int i=0;i<records;i++) {
|
||||
byte[] data = getColumnDataByte(i,0);
|
||||
|
||||
// extra converting to fit in db interface
|
||||
String result = c.getObjectConverter().decodeStorage(c, data);
|
||||
|
||||
if ("true".equals(result)) {
|
||||
emptyRow = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (emptyRow==-1) {
|
||||
// new recods
|
||||
logger.fine("Creating new records in full file ..");
|
||||
emptyRow = records+1;
|
||||
putColumnDataString(emptyRow,0,"false");
|
||||
}
|
||||
putColumnDataString(emptyRow,0,"false");
|
||||
try {
|
||||
putInterfaceRow(emptyRow,interfaceData);
|
||||
} catch (RecordNotFoundException re) {
|
||||
throw new DuplicateKeyException("NotFoundException wrapper: "+re.getMessage());
|
||||
}
|
||||
return emptyRow;
|
||||
}
|
||||
|
||||
|
||||
// LOCK METHODS
|
||||
|
||||
/**
|
||||
* Onlocks an locks wichs as obtained bt lock method.
|
||||
*/
|
||||
public void unlock(int row,long lockId) throws RecordNotFoundException,SecurityException {
|
||||
checkBounds(row);
|
||||
checkLock(row,lockId);
|
||||
if (isFinerLog) {
|
||||
logger.finer("Locking row: "+row+" with lockId: "+lockId);
|
||||
}
|
||||
locks.remove(row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an lock on an row record.
|
||||
* @param row
|
||||
* @return
|
||||
* @throws RecordNotFoundException
|
||||
*/
|
||||
public RowLock lock(int row) throws RecordNotFoundException {
|
||||
checkBounds(row);
|
||||
checkDeleted(row);
|
||||
RowLock lock = locks.get(row);
|
||||
if (lock!=null) {
|
||||
throw new RecordNotFoundException("row already blocked");
|
||||
}
|
||||
long lockId = rowLocks.getAndIncrement()+new Double(Math.random()).longValue();
|
||||
lock = new RowLock(row,20000,lockId);
|
||||
if (isFinerLog) {
|
||||
logger.finer("Locking row: "+row+" with lockId: "+lockId);
|
||||
}
|
||||
locks.put(row, lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the row has an lock with the lockID.
|
||||
* @param row The row to check the lock on.
|
||||
* @param lockId The lock id.
|
||||
* @throws RecordNotFoundException Is thrown when the row id is invalid.
|
||||
* @throws SecurityException Is thrown when the lock id is invalid.
|
||||
*/
|
||||
public void checkLock(int row,long lockId) throws RecordNotFoundException,SecurityException {
|
||||
checkBounds(row);
|
||||
RowLock lock = locks.get(row);
|
||||
if (isFinerLog) {
|
||||
logger.finer("Checklock: row: "+row+" lockId: "+lockId+" lockOBj: "+lock);
|
||||
}
|
||||
if (lock==null) {
|
||||
throw new SecurityException("No lock for row found.");
|
||||
}
|
||||
if (lock.getLockId()!=lockId) {
|
||||
throw new SecurityException("LockId is not valid for row lock.");
|
||||
}
|
||||
}
|
||||
|
||||
// CACHE METHODS
|
||||
|
||||
private String[] cacheGet(int row) {
|
||||
try {
|
||||
readLock.lock();
|
||||
RowCache c = cache.get(row);
|
||||
if (c==null) {
|
||||
return null; // just return null on miss, don't use exceptions in high performace program flow
|
||||
}
|
||||
return c.getRecord();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* puts an item in the cache
|
||||
* @param row
|
||||
* @param data
|
||||
*/
|
||||
private void cachePut(int row,String[] data) {
|
||||
try {
|
||||
readLock.lock(); // read lock to check on the size
|
||||
if (cache.size()>cacheMax) {
|
||||
return; // don't put anything in cache until there is space
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
try {
|
||||
writeLock.lock(); // write lock and add the new cache item
|
||||
RowCache c = new RowCache(row,data);
|
||||
cache.put(row, c);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an cache item
|
||||
* @param row
|
||||
*/
|
||||
private void cacheRemove(int row) {
|
||||
try {
|
||||
writeLock.lock(); // write lock and removed the cache item.
|
||||
cache.remove(row);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
abstract public class AbstractColumnObjectConverter implements ColumnObjectConverter {
|
||||
|
||||
protected Class<?> convertClass = null;
|
||||
abstract public Object decodeInterface(Column c,String object);
|
||||
abstract public String encodeInterface(Column c,Object object);
|
||||
|
||||
public AbstractColumnObjectConverter(Class<?> convertClass) {
|
||||
this.convertClass=convertClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnObjectConverter#getConvertClass()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getConvertClass() {
|
||||
return convertClass;
|
||||
}
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnObjectConverter#decodeStorage(suncertify.db.data.column.Column, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public byte[] encodeStorage(Column c, String str) {
|
||||
if (str.length()>c.getFieldLength()) {
|
||||
throw new IllegalArgumentException("String is to large to DB");
|
||||
}
|
||||
byte[] data = str.getBytes(c.getCharset());
|
||||
|
||||
// fill out space
|
||||
if (data.length<c.getFieldLength()) {
|
||||
//int space = c.getFieldLength()-data.length;
|
||||
byte[] data2 = new byte[c.getFieldLength()];
|
||||
for (int i=0;i<data2.length;i++) {
|
||||
if (i<data.length) {
|
||||
data2[i]=data[i];
|
||||
} else {
|
||||
data2[i]=' ';
|
||||
}
|
||||
}
|
||||
return data2;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnObjectConverter#encodeStorage(suncertify.db.data.column.Column, byte[])
|
||||
*/
|
||||
@Override
|
||||
public String decodeStorage(Column c, byte[] data) {
|
||||
String result = new String(data,c.getCharset()).trim();
|
||||
return result;
|
||||
}
|
||||
}
|
51
src/suncertify/db/data/column/BooleanObjectConverter.java
Normal file
51
src/suncertify/db/data/column/BooleanObjectConverter.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
public class BooleanObjectConverter extends AbstractColumnObjectConverter {
|
||||
|
||||
public BooleanObjectConverter() {
|
||||
super(Boolean.class);
|
||||
}
|
||||
|
||||
public Object decodeInterface(Column c,String object) {
|
||||
return new Boolean(object);
|
||||
}
|
||||
|
||||
public String encodeInterface(Column c,Object object) {
|
||||
if ((object instanceof Boolean)==false) {
|
||||
throw new IllegalStateException("Data error, object is not Boolean.");
|
||||
}
|
||||
Boolean value = (Boolean)object;
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decodeStorage(Column c,byte[] data) {
|
||||
byte smoking = data[0];
|
||||
if (89==smoking) {
|
||||
return "true";
|
||||
}
|
||||
if (78==smoking) {
|
||||
return "false";
|
||||
}
|
||||
throw new IllegalStateException("Data error, unknow value: "+smoking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeStorage(Column c,String object) {
|
||||
Boolean value = new Boolean(object);
|
||||
byte[] data = new byte[1];
|
||||
if (value) {
|
||||
data[0] = 89;
|
||||
} else {
|
||||
data[0] = 78;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
118
src/suncertify/db/data/column/Column.java
Normal file
118
src/suncertify/db/data/column/Column.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class Column {
|
||||
|
||||
private int columnIndex = 0;
|
||||
private int fieldNameLength = 0;
|
||||
private String fieldName = null;
|
||||
private int fieldLength = 0;
|
||||
private ColumnObjectConverter objectConverter = null;
|
||||
private Charset charset = null;
|
||||
private ColumnSearcher columnSearcher = null;
|
||||
|
||||
/**
|
||||
* @return the columnIndex
|
||||
*/
|
||||
public int getColumnIndex() {
|
||||
return columnIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param columnIndex the columnIndex to set
|
||||
*/
|
||||
public void setColumnIndex(int columnIndex) {
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fieldNameLength
|
||||
*/
|
||||
public int getFieldNameLength() {
|
||||
return fieldNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldNameLength the fieldNameLength to set
|
||||
*/
|
||||
public void setFieldNameLength(int fieldNameLength) {
|
||||
this.fieldNameLength = fieldNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fieldName
|
||||
*/
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldName the fieldName to set
|
||||
*/
|
||||
public void setFieldName(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fieldLength
|
||||
*/
|
||||
public int getFieldLength() {
|
||||
return fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fieldLength the fieldLength to set
|
||||
*/
|
||||
public void setFieldLength(int fieldLength) {
|
||||
this.fieldLength = fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the objectConverter
|
||||
*/
|
||||
public ColumnObjectConverter getObjectConverter() {
|
||||
return objectConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objectConverter the objectConverter to set
|
||||
*/
|
||||
public void setObjectConverter(ColumnObjectConverter objectConverter) {
|
||||
this.objectConverter = objectConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the charset
|
||||
*/
|
||||
public Charset getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param charset the charset to set
|
||||
*/
|
||||
public void setCharset(Charset charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the columnSearcher
|
||||
*/
|
||||
public ColumnSearcher getColumnSearcher() {
|
||||
return columnSearcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param columnSearcher the columnSearcher to set
|
||||
*/
|
||||
public void setColumnSearcher(ColumnSearcher columnSearcher) {
|
||||
this.columnSearcher = columnSearcher;
|
||||
}
|
||||
}
|
19
src/suncertify/db/data/column/ColumnObjectConverter.java
Normal file
19
src/suncertify/db/data/column/ColumnObjectConverter.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
public interface ColumnObjectConverter {
|
||||
|
||||
public Class<?> getConvertClass();
|
||||
|
||||
public Object decodeInterface(Column c,String object);
|
||||
public String encodeInterface(Column c,Object object);
|
||||
|
||||
public String decodeStorage(Column c,byte[] data);
|
||||
public byte[] encodeStorage(Column c,String object);
|
||||
}
|
17
src/suncertify/db/data/column/ColumnSearcher.java
Normal file
17
src/suncertify/db/data/column/ColumnSearcher.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
import suncertify.db.RecordNotFoundException;
|
||||
import suncertify.db.data.Table;
|
||||
|
||||
|
||||
public interface ColumnSearcher {
|
||||
|
||||
public boolean searchColumn(Table table, Column column,String searchString,String columnData) throws RecordNotFoundException;
|
||||
}
|
41
src/suncertify/db/data/column/DateObjectConverter.java
Normal file
41
src/suncertify/db/data/column/DateObjectConverter.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class DateObjectConverter extends AbstractColumnObjectConverter {
|
||||
|
||||
public DateObjectConverter() {
|
||||
super(Date.class);
|
||||
}
|
||||
|
||||
public Object decodeInterface(Column c,String object) {
|
||||
Date realDate = null;
|
||||
try {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
|
||||
realDate = dateFormat.parse(object);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalStateException("Date format error on: '"+object+"'");
|
||||
}
|
||||
return realDate;
|
||||
}
|
||||
|
||||
public String encodeInterface(Column c,Object object) {
|
||||
if ((object instanceof Date)==false) {
|
||||
throw new IllegalStateException("Object is no date");
|
||||
}
|
||||
String value = null;
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
|
||||
value = dateFormat.format((Date)object);
|
||||
return value;
|
||||
}
|
||||
}
|
33
src/suncertify/db/data/column/DeleteFlagConverter.java
Normal file
33
src/suncertify/db/data/column/DeleteFlagConverter.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
public class DeleteFlagConverter extends BooleanObjectConverter {
|
||||
|
||||
@Override
|
||||
public byte[] encodeStorage(Column c, String str) {
|
||||
Boolean value = new Boolean(str);
|
||||
byte[] data = new byte[1];
|
||||
if (value) {
|
||||
data[0] = (byte)255; // java bytes are signed so; -128 == 255 == 0xFF
|
||||
} else {
|
||||
data[0] = 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decodeStorage(Column c, byte[] data) {
|
||||
if (data[0]==0) {
|
||||
return new Boolean(false).toString();
|
||||
} else if (data[0]==(byte)255) {
|
||||
return new Boolean(true).toString();
|
||||
}
|
||||
throw new IllegalArgumentException("Unknow delete flag value: '"+data[0]+"'");
|
||||
}
|
||||
}
|
31
src/suncertify/db/data/column/IntegerObjectConverter.java
Normal file
31
src/suncertify/db/data/column/IntegerObjectConverter.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
public class IntegerObjectConverter extends AbstractColumnObjectConverter {
|
||||
|
||||
public IntegerObjectConverter() {
|
||||
super(Integer.class);
|
||||
}
|
||||
|
||||
public Object decodeInterface(Column c,String object) {
|
||||
if ("".equals(object)) {
|
||||
return 0;
|
||||
}
|
||||
Integer result = new Integer(object);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String encodeInterface(Column c,Object object) {
|
||||
if ((object instanceof Integer)==false) {
|
||||
throw new IllegalStateException("wrong data type");
|
||||
}
|
||||
Integer value = (Integer)object;
|
||||
return value.toString();
|
||||
}
|
||||
}
|
50
src/suncertify/db/data/column/LongObjectConverter.java
Normal file
50
src/suncertify/db/data/column/LongObjectConverter.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class LongObjectConverter extends AbstractColumnObjectConverter {
|
||||
|
||||
public LongObjectConverter() {
|
||||
super(Long.class);
|
||||
}
|
||||
|
||||
public Object decodeInterface(Column c,String object) {
|
||||
Long realRate = null;
|
||||
try {
|
||||
Number number = NumberFormat.getCurrencyInstance(Locale.getDefault()).parse(object);
|
||||
// 123.45
|
||||
if (number instanceof Long) {
|
||||
// Long value
|
||||
realRate = (Long)number;
|
||||
} else if (number instanceof Double) {
|
||||
realRate = ((Double)number).longValue();
|
||||
} else {
|
||||
System.out.println("unknow number: "+number.getClass());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return realRate;
|
||||
}
|
||||
|
||||
public String encodeInterface(Column c,Object object) {
|
||||
if ((object instanceof Long)==false) {
|
||||
throw new IllegalStateException("Data err");
|
||||
}
|
||||
Long value = (Long)object;
|
||||
String str = "$"+value;
|
||||
if (str.length()>c.getFieldLength()) {
|
||||
return null;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
25
src/suncertify/db/data/column/StringColumnSearcher.java
Normal file
25
src/suncertify/db/data/column/StringColumnSearcher.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
import suncertify.db.RecordNotFoundException;
|
||||
import suncertify.db.data.Table;
|
||||
|
||||
public class StringColumnSearcher implements ColumnSearcher {
|
||||
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnSearcher#searchColumn(suncertify.db.data.Table, suncertify.db.data.column.Column, java.lang.String, java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public boolean searchColumn(Table table, Column column,String searchString,String columnData) throws RecordNotFoundException {
|
||||
return columnData.contains(searchString);
|
||||
}
|
||||
|
||||
public void indexColumn(Table table, Column column,String columnData) throws RecordNotFoundException {
|
||||
|
||||
}
|
||||
}
|
34
src/suncertify/db/data/column/StringObjectConverter.java
Normal file
34
src/suncertify/db/data/column/StringObjectConverter.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
|
||||
public class StringObjectConverter extends AbstractColumnObjectConverter {
|
||||
|
||||
public StringObjectConverter() {
|
||||
super(String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnObjectConverter#decodeInterface(suncertify.db.data.column.Column, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object decodeInterface(Column c, String object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.db.data.column.ColumnObjectConverter#encodeInterface(suncertify.db.data.column.Column, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String encodeInterface(Column c, Object object) {
|
||||
if ((object instanceof String)==false) {
|
||||
throw new IllegalStateException("Can only do string");
|
||||
}
|
||||
return (String)object;
|
||||
}
|
||||
}
|
30
src/suncertify/db/data/column/TextIndex.java
Normal file
30
src/suncertify/db/data/column/TextIndex.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.db.data.column;
|
||||
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class TextIndex {
|
||||
|
||||
/** The NMAP'ed bytebuffer to the file database on disk. */
|
||||
private MappedByteBuffer byteBuffer = null;
|
||||
/** Object to locking the bytebuffer. */
|
||||
private Object byteBufferLock = new Object();
|
||||
|
||||
|
||||
|
||||
/// use own table imple for Hit object, word obj == ~~
|
||||
}
|
||||
|
||||
class HitIndex {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
32
src/suncertify/db/data/column/package.html
Normal file
32
src/suncertify/db/data/column/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
Database columns objects.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
32
src/suncertify/db/data/package.html
Normal file
32
src/suncertify/db/data/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
Related data database classes.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
32
src/suncertify/db/package.html
Normal file
32
src/suncertify/db/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The database for doing work on the binary data files.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
231
src/suncertify/models/HotelRoom.java
Normal file
231
src/suncertify/models/HotelRoom.java
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.models;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* The HotelRoom model class.
|
||||
*
|
||||
* This stores all the data which belongs to one hotelroom.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class HotelRoom implements Externalizable {
|
||||
|
||||
private Integer id = null;
|
||||
private String name = null;
|
||||
private String location = null;
|
||||
private Integer size = null;
|
||||
private Boolean smoking = null;
|
||||
private Long priceRate = null;
|
||||
private Date dateAvailable = null;
|
||||
private Integer customerId = null;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the location
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location the location to set
|
||||
*/
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size
|
||||
*/
|
||||
public Integer getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param size the size to set
|
||||
*/
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the smoking
|
||||
*/
|
||||
public Boolean getSmoking() {
|
||||
return smoking;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param smoking the smoking to set
|
||||
*/
|
||||
public void setSmoking(Boolean smoking) {
|
||||
this.smoking = smoking;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the priceRate
|
||||
*/
|
||||
public Long getPriceRate() {
|
||||
return priceRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param priceRate the priceRate to set
|
||||
*/
|
||||
public void setPriceRate(Long priceRate) {
|
||||
this.priceRate = priceRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dateAvailable
|
||||
*/
|
||||
public Date getDateAvailable() {
|
||||
return dateAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dateAvailable the dateAvailable to set
|
||||
*/
|
||||
public void setDateAvailable(Date dateAvailable) {
|
||||
this.dateAvailable = dateAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the customerId
|
||||
*/
|
||||
public Integer getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param customerId the customerId to set
|
||||
*/
|
||||
public void setCustomerId(Integer customerId) {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* We support reading null fields because BU checks should not take place here.
|
||||
* This is here for speed.
|
||||
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
|
||||
*/
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
boolean nullRes = in.readBoolean();
|
||||
id = nullRes?in.readInt():null;
|
||||
nullRes = in.readBoolean();
|
||||
name = nullRes?in.readUTF():null;
|
||||
nullRes = in.readBoolean();
|
||||
location = nullRes?in.readUTF():null;
|
||||
nullRes = in.readBoolean();
|
||||
size = nullRes?in.readInt():null;
|
||||
nullRes = in.readBoolean();
|
||||
smoking = nullRes?in.readBoolean():null;
|
||||
nullRes = in.readBoolean();
|
||||
priceRate = nullRes?in.readLong():null;
|
||||
nullRes = in.readBoolean();
|
||||
dateAvailable = nullRes?new Date(in.readLong()):null;
|
||||
nullRes = in.readBoolean();
|
||||
customerId = nullRes?in.readInt():null;
|
||||
}
|
||||
|
||||
/**
|
||||
* We support writeing null fields because BU checks should not take place here.
|
||||
* This is here for speed.
|
||||
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
|
||||
*/
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
|
||||
if (id==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeInt (id);
|
||||
}
|
||||
if (name==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeUTF (name);
|
||||
}
|
||||
if (location==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeUTF (location);
|
||||
}
|
||||
if (size==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeInt (size);
|
||||
}
|
||||
if (smoking==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeBoolean (smoking);
|
||||
}
|
||||
if (priceRate==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeLong (priceRate);
|
||||
}
|
||||
if (dateAvailable==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeLong (dateAvailable.getTime());
|
||||
}
|
||||
if (customerId==null) {
|
||||
out.writeBoolean (false);
|
||||
} else {
|
||||
out.writeBoolean (true);
|
||||
out.writeInt (customerId);
|
||||
}
|
||||
}
|
||||
}
|
123
src/suncertify/models/HotelRoomDBConverter.java
Normal file
123
src/suncertify/models/HotelRoomDBConverter.java
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import suncertify.db.data.Table;
|
||||
import suncertify.db.data.column.Column;
|
||||
|
||||
/**
|
||||
* The HotelRoomDBConverter
|
||||
*
|
||||
* Converts betreen the HotelRoom model and the binany DB data.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class HotelRoomDBConverter {
|
||||
|
||||
private Table table = null;
|
||||
|
||||
/**
|
||||
* Creates an HotelRoomDBConverter for the given table.
|
||||
* @param table The DB table to do converts for.
|
||||
*/
|
||||
public HotelRoomDBConverter(Table table) {
|
||||
if (table==null) {
|
||||
throw new NullPointerException("Table may not be null.");
|
||||
}
|
||||
this.table=table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts String[] data to en HotelRoom data model.
|
||||
*
|
||||
* @param data The string data.
|
||||
* @return The HotelRoom model.
|
||||
*/
|
||||
public HotelRoom decode(String[] data) {
|
||||
HotelRoom hr = new HotelRoom();
|
||||
for (int i=0;i<=6;i++) {
|
||||
Column c = table.getColumns().get(i+1); // todo bounds
|
||||
Object object = c.getObjectConverter().decodeInterface(c,data[i]);
|
||||
switch(i) {
|
||||
case 0:
|
||||
hr.setName((String)object);
|
||||
break;
|
||||
case 1:
|
||||
hr.setLocation((String)object);
|
||||
break;
|
||||
case 2:
|
||||
hr.setSize((Integer)object);
|
||||
break;
|
||||
case 3:
|
||||
hr.setSmoking((Boolean)object);
|
||||
break;
|
||||
case 4:
|
||||
hr.setPriceRate((Long)object);
|
||||
break;
|
||||
case 5:
|
||||
hr.setDateAvailable((Date)object);
|
||||
break;
|
||||
case 6:
|
||||
hr.setCustomerId((Integer)object);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("out of bounds");
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an HotelRoom model to the String data.
|
||||
*
|
||||
* @param hr The hotelRoom model
|
||||
* @return The data as an String array.
|
||||
*/
|
||||
public String[] encode(HotelRoom hr) {
|
||||
String[] result = new String[7];
|
||||
for (int i=0;i<=6;i++) {
|
||||
Column c = table.getColumns().get(i+1); // todo bounds
|
||||
Object object = null;
|
||||
switch(i) {
|
||||
case 0:
|
||||
object = hr.getName();
|
||||
break;
|
||||
case 1:
|
||||
object = hr.getLocation();
|
||||
break;
|
||||
case 2:
|
||||
object = hr.getSize();
|
||||
break;
|
||||
case 3:
|
||||
object = hr.getSmoking();
|
||||
break;
|
||||
case 4:
|
||||
object = hr.getPriceRate();
|
||||
break;
|
||||
case 5:
|
||||
object = hr.getDateAvailable();
|
||||
break;
|
||||
case 6:
|
||||
object = hr.getCustomerId();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("out of bounds");
|
||||
}
|
||||
String r = null;
|
||||
if (object!=null) {
|
||||
r = c.getObjectConverter().encodeInterface(c, object);
|
||||
} else {
|
||||
r = "";
|
||||
}
|
||||
result[i]=r;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
32
src/suncertify/models/package.html
Normal file
32
src/suncertify/models/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The models used in the application.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
34
src/suncertify/net/NIOChangeRequest.java
Normal file
34
src/suncertify/net/NIOChangeRequest.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
/**
|
||||
* The NIOChangeRequest is used by the NIOConnector to register of change the operation key.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NIOChangeRequest {
|
||||
|
||||
public enum ChangeType {
|
||||
REGISTER,
|
||||
CHANGEOPS
|
||||
}
|
||||
|
||||
public SocketChannel socket;
|
||||
public ChangeType type;
|
||||
public int ops;
|
||||
|
||||
public NIOChangeRequest(SocketChannel socket, ChangeType type, int ops) {
|
||||
this.socket = socket;
|
||||
this.type = type;
|
||||
this.ops = ops;
|
||||
}
|
||||
}
|
308
src/suncertify/net/NIOConnector.java
Normal file
308
src/suncertify/net/NIOConnector.java
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import suncertify.net.NIOChangeRequest.ChangeType;
|
||||
|
||||
/**
|
||||
* The NIOConnector is an abstract base class for creating NIO client/servers.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
abstract public class NIOConnector implements Runnable {
|
||||
|
||||
/** The hostAddress to bind or connect to. */
|
||||
private InetAddress hostAddress;
|
||||
/** The port of the hostAddress */
|
||||
private int port;
|
||||
|
||||
/** The selector we'll be monitoring */
|
||||
protected Selector selector;
|
||||
|
||||
/** The buffer into which we'll read data when it's available */
|
||||
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
|
||||
|
||||
/** A list of PendingChange instances */
|
||||
private List<NIOChangeRequest> pendingChanges = null;
|
||||
|
||||
/** Maps a SocketChannel to a list of ByteBuffer instances */
|
||||
private Map<SocketChannel,List<ByteBuffer>> pendingData = null;
|
||||
|
||||
/** The connection counter */
|
||||
final protected AtomicInteger connectsCounter = new AtomicInteger();
|
||||
|
||||
/** Counter for total connection */
|
||||
volatile protected int totalConnections = 0;
|
||||
|
||||
/** The logger to log to */
|
||||
private Logger logger = Logger.getLogger(NIOConnector.class.getName());
|
||||
|
||||
/** Flag to stop thread */
|
||||
volatile protected boolean stop = false;
|
||||
|
||||
/**
|
||||
* Creates an abstract NIOConnector
|
||||
* @param hostAddress
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public NIOConnector(InetAddress hostAddress, int port) {
|
||||
this.hostAddress = hostAddress;
|
||||
this.port = port;
|
||||
pendingChanges = new LinkedList<NIOChangeRequest>();
|
||||
pendingData = new HashMap<SocketChannel,List<ByteBuffer>>();
|
||||
}
|
||||
|
||||
abstract public void start() throws IOException;
|
||||
abstract public void stop() throws IOException;
|
||||
|
||||
/**
|
||||
* Sends data to the socket, appends it to the pendingData queu
|
||||
* @param socket
|
||||
* @param data
|
||||
*/
|
||||
protected void send(SocketChannel socket,ByteBuffer data) {
|
||||
// Indicate we want the interest ops set changed
|
||||
addChangeRequest(socket, NIOChangeRequest.ChangeType.CHANGEOPS, SelectionKey.OP_WRITE);
|
||||
|
||||
// And queue the data we want written
|
||||
synchronized (pendingData) {
|
||||
List<ByteBuffer> queue = pendingData.get(socket);
|
||||
if (queue == null) {
|
||||
queue = new ArrayList<ByteBuffer>();
|
||||
pendingData.put(socket, queue);
|
||||
}
|
||||
queue.add(data);
|
||||
}
|
||||
|
||||
// Finally, wake up our selecting thread so it can make the required changes
|
||||
selector.wakeup();
|
||||
}
|
||||
|
||||
/**
|
||||
* The NIO IO selector runnable
|
||||
*/
|
||||
public void run() {
|
||||
logger.info("NIO network thread started.");
|
||||
while (stop==false) {
|
||||
try {
|
||||
synchronized (pendingChanges) {
|
||||
int totalChanges = pendingChanges.size();
|
||||
if (totalChanges>0) {
|
||||
for (int i=0;i<totalChanges;i++) {
|
||||
NIOChangeRequest change = pendingChanges.get(i);
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("Changeing "+change.ops+" from: "+change.socket+" type: "+change.type);
|
||||
}
|
||||
switch (change.type) {
|
||||
case CHANGEOPS:
|
||||
SelectionKey key = change.socket.keyFor(selector);
|
||||
if (logger.isLoggable(Level.FINER)) {
|
||||
logger.finer("Changeing "+change.ops+" key: "+key);
|
||||
}
|
||||
if (key!=null && key.isValid()) {
|
||||
key.interestOps(change.ops);
|
||||
}
|
||||
break;
|
||||
case REGISTER:
|
||||
change.socket.register(selector, change.ops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pendingChanges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for an event one of the registered channels
|
||||
selector.select();
|
||||
|
||||
// Iterate over the set of keys for which events are available
|
||||
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
|
||||
while (selectedKeys.hasNext()) {
|
||||
SelectionKey key = selectedKeys.next();
|
||||
selectedKeys.remove();
|
||||
|
||||
if (key.isValid()==false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// check on session object
|
||||
Object o = key.attachment();
|
||||
//mm we can only set attech ment after key is accepted
|
||||
if (o==null & key.isAcceptable()==false) {
|
||||
o = new Integer(connectsCounter.getAndIncrement());
|
||||
key.attach(o);
|
||||
totalConnections++;
|
||||
logger.info("Init Connection: "+key.attachment()+" total: "+totalConnections);
|
||||
}
|
||||
|
||||
// Check what event is available and deal with it
|
||||
try {
|
||||
if (key.isConnectable()) {
|
||||
connect(key);
|
||||
} else if (key.isAcceptable()) {
|
||||
accept(key);
|
||||
} else if (key.isReadable()) {
|
||||
read(key);
|
||||
} else if (key.isWritable()) {
|
||||
write(key);
|
||||
} else {
|
||||
throw new IOException("NIO error, key could not be processed.");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Integer conNr = (Integer)key.attachment();
|
||||
if (ioe.getMessage()!=null && ioe.getMessage().contains("reset by peer")) {
|
||||
logger.log(Level.WARNING,"Connection: "+conNr+" has disconnected on error: "+ioe.getMessage());
|
||||
} else {
|
||||
logger.log(Level.WARNING,"Connection: "+conNr+" has disconnected on error: "+ioe.getMessage(),ioe);
|
||||
}
|
||||
key.cancel();
|
||||
}
|
||||
|
||||
if (key.isValid()==false) {
|
||||
totalConnections--;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING,"Error in NIO Thread: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
// cleaning resources
|
||||
pendingChanges.clear();
|
||||
pendingData.clear();
|
||||
totalConnections = 0;
|
||||
logger.info("NIO network thread stoped.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when the key is connected, emty method.
|
||||
* @param key
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void connect(SelectionKey key) throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when the key is accepted, emty method.
|
||||
* @param key
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void accept(SelectionKey key) throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data from the key and hands it over to processData
|
||||
* @param key
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void read(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
// Clear out our read buffer so it's ready for new data
|
||||
readBuffer.clear();
|
||||
|
||||
int numRead = socketChannel.read(readBuffer);
|
||||
if (numRead == -1) {
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
readBuffer.rewind();
|
||||
readBuffer.limit(numRead);
|
||||
processData(socketChannel, readBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the readed data.
|
||||
*
|
||||
* @param socket
|
||||
* @param readBuffer
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract void processData(SocketChannel socket, ByteBuffer readBuffer) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the data from the key to the pendingData queue
|
||||
* @param key
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void write(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
synchronized (pendingData) {
|
||||
List<ByteBuffer> queue = pendingData.get(socketChannel);
|
||||
// Write until there's not more data ...
|
||||
while (queue.isEmpty()==false) {
|
||||
ByteBuffer buf = queue.get(0);
|
||||
socketChannel.write(buf);
|
||||
if (buf.remaining() > 0) {
|
||||
break; // ... or the socket's buffer fills up
|
||||
}
|
||||
queue.remove(0);
|
||||
}
|
||||
if (queue.isEmpty()) {
|
||||
// We wrote away all data, so we're no longer interested
|
||||
// in writing on this socket. Switch back to waiting for data.
|
||||
addChangeRequest(socketChannel, NIOChangeRequest.ChangeType.CHANGEOPS, SelectionKey.OP_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the default Selector.
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
protected Selector initSelector() throws IOException {
|
||||
return SelectorProvider.provider().openSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an ChangeRequest for the socket
|
||||
* @param socket
|
||||
* @param type
|
||||
* @param ops
|
||||
*/
|
||||
public void addChangeRequest(SocketChannel socket, ChangeType type, int ops) {
|
||||
synchronized (pendingChanges) {
|
||||
pendingChanges.add(new NIOChangeRequest(socket, type, ops));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the hostAddress
|
||||
*/
|
||||
public InetAddress getHostAddress() {
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
205
src/suncertify/net/NetworkClient.java
Normal file
205
src/suncertify/net/NetworkClient.java
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The NetworkClient
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NetworkClient extends NetworkNIOConnector {
|
||||
|
||||
/** Maps a SocketChannel to a RspHandler */
|
||||
private Map<Integer,NetworkResponseHandler> responseHandlers = null;
|
||||
/** Keeps track of the request IDs. */
|
||||
private AtomicInteger requestIds = new AtomicInteger(0);
|
||||
/** The sockets wo connect to */
|
||||
private SocketChannel socket = null;
|
||||
/** The logger to log to. */
|
||||
private Logger logger = Logger.getLogger(NetworkClient.class.getName());
|
||||
/** The left over buffer, used to fix multi threaded requests. */
|
||||
private byte[] leftBuf = null;
|
||||
|
||||
/**
|
||||
* Creates an NetworkClient.
|
||||
*
|
||||
* @param hostAddress
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public NetworkClient(InetAddress hostAddress, int port) throws IOException {
|
||||
super(hostAddress,port);
|
||||
responseHandlers = Collections.synchronizedMap(new HashMap<Integer,NetworkResponseHandler>(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* We override stop to clean our private resources here
|
||||
* @see suncertify.net.NetworkNIOConnector#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws IOException {
|
||||
try {
|
||||
super.stop();
|
||||
} finally {
|
||||
leftBuf = null;
|
||||
try {
|
||||
if (socket!=null) { // start,stop when nothing happend, then socket is still null.
|
||||
socket.close();
|
||||
}
|
||||
} finally {
|
||||
responseHandlers.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an NetworkRequest to the server.
|
||||
* @param request
|
||||
* @param handler
|
||||
* @throws IOException
|
||||
*/
|
||||
public void send(NetworkRequest request, NetworkResponseHandler handler) throws IOException {
|
||||
// We connect on first send
|
||||
if (socket==null) {
|
||||
socket = initiateConnection();
|
||||
}
|
||||
// Register the response handler
|
||||
responseHandlers.put(handler.getNetworkRequest().getRequestId(), handler);
|
||||
|
||||
// send object to socket
|
||||
sendObject(socket,request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process data from the server.
|
||||
*/
|
||||
@Override
|
||||
protected void processData(SocketChannel socket,ByteBuffer readBuffer) throws IOException {
|
||||
|
||||
// we should make sure the happens less often or not at all, because the allocate is an heavy function.
|
||||
if (leftBuf!=null) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("Fixing data: appendSize: "+leftBuf.length+" buf: "+readBuffer.remaining());
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(8192+leftBuf.length+readBuffer.remaining());
|
||||
buffer.limit(leftBuf.length+readBuffer.remaining());
|
||||
|
||||
buffer.put(leftBuf);
|
||||
buffer.put(readBuffer);
|
||||
|
||||
buffer.rewind();
|
||||
readBuffer.clear();
|
||||
readBuffer = buffer;
|
||||
leftBuf = null;
|
||||
}
|
||||
|
||||
ByteBuffer leftOver = receiveObject(socket,readBuffer, new ObjectHandler() {
|
||||
public void processObject(Object object) {
|
||||
NetworkResponse response = (NetworkResponse)object;
|
||||
NetworkResponseHandler handler = responseHandlers.remove(response.getRequestId());
|
||||
if (handler==null) {
|
||||
logger.warning("Error no handler for read data of request "+response.getRequestId());
|
||||
return;
|
||||
}
|
||||
// And pass the response to it
|
||||
handler.handleResponse(response);
|
||||
}
|
||||
},0);
|
||||
if (leftOver==null) {
|
||||
return; // all oke
|
||||
}
|
||||
|
||||
// save left over for when next bytes come in.
|
||||
byte[] data2 = new byte[leftOver.remaining()];
|
||||
leftOver.get(data2);
|
||||
leftBuf = data2;
|
||||
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(leftBuf);
|
||||
ObjectInputStream objstream = new ObjectInputStream(in);
|
||||
int objectSize = objstream.readInt();
|
||||
objstream.close();
|
||||
|
||||
logger.fine("Pasting LeftOver size: "+data2.length+" Next object size: "+objectSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates our connection to the server.
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private SocketChannel initiateConnection() throws IOException {
|
||||
// Create nonblocking socket channel
|
||||
SocketChannel socketChannel = SocketChannel.open();
|
||||
socketChannel.configureBlocking(false);
|
||||
|
||||
// Connect to server
|
||||
socketChannel.connect(new InetSocketAddress(getHostAddress(),getPort()));
|
||||
socketChannel.finishConnect();
|
||||
|
||||
// select register on selector in nio thread
|
||||
addChangeRequest(socketChannel, NIOChangeRequest.ChangeType.REGISTER, SelectionKey.OP_CONNECT);
|
||||
return socketChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InvocationHandler for creating proxed objects.
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public InvocationHandler getInvocationHandler(Class<?> obj) {
|
||||
return new NetworkInvocationHandler(obj,this);
|
||||
}
|
||||
|
||||
/**
|
||||
* InvocationHandler for handeling the method calls of the proxy bean.
|
||||
*
|
||||
*/
|
||||
private class NetworkInvocationHandler implements InvocationHandler {
|
||||
private String beanName = null;
|
||||
private NetworkClient client = null;
|
||||
|
||||
public NetworkInvocationHandler(Class<?> obj,NetworkClient client) {
|
||||
beanName = obj.getName();
|
||||
this.client=client;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
|
||||
// create request and fill it.
|
||||
NetworkRequest request = new NetworkRequest(requestIds.getAndIncrement());
|
||||
request.setRequestBean(beanName, method.getName(), args);
|
||||
// Create handler for when we get response.
|
||||
NetworkResponseHandler handler = new NetworkResponseHandler(request,client);
|
||||
// send and wait..
|
||||
client.send(request, handler);
|
||||
handler.waitForResponse();
|
||||
// we have it.
|
||||
Object result = handler.getResult();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
188
src/suncertify/net/NetworkNIOConnector.java
Normal file
188
src/suncertify/net/NetworkNIOConnector.java
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The NetworkNIOConnector for creating object based serialezed nio client/servers
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
abstract public class NetworkNIOConnector extends NIOConnector {
|
||||
|
||||
/** The logger to log to. */
|
||||
private Logger logger = Logger.getLogger(NetworkNIOConnector.class.getName());
|
||||
|
||||
/** Counter for send Objects */
|
||||
volatile private int sendObjectCounter = 0;
|
||||
|
||||
/** indicating the milisecond value for 1min.. */
|
||||
static final private long ONCE_PER_MINUTE = 1000*60;
|
||||
|
||||
/** Timer object to print stats. */
|
||||
private Timer statsTimer = null;
|
||||
|
||||
/**
|
||||
* Creates an NetworkNIOConnector.
|
||||
*
|
||||
* @param hostAddress
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public NetworkNIOConnector(InetAddress hostAddress, int port) throws IOException {
|
||||
super(hostAddress,port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this Connector by creating the selector
|
||||
* and starts the backend nio thread.
|
||||
* Creates an Timer for printing the stats of this connector.
|
||||
*/
|
||||
@Override
|
||||
public void start() throws IOException {
|
||||
// create selectort
|
||||
selector = initSelector();
|
||||
|
||||
// Start the backend thread
|
||||
Thread t = new Thread(this,"net-nio");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
|
||||
// start the stats timers
|
||||
statsTimer = new Timer("net-stats");
|
||||
statsTimer.scheduleAtFixedRate(new TimerTask() {
|
||||
public void run() {
|
||||
try {
|
||||
logger.info("sendObject() Statistics"+
|
||||
" TPM: "+sendObjectCounter+
|
||||
" TPS: "+(sendObjectCounter/60)+
|
||||
" totalEstablisedConnections: "+totalConnections+
|
||||
" totalHandledConnections: "+connectsCounter.get());
|
||||
} finally {
|
||||
sendObjectCounter=0;
|
||||
}
|
||||
}
|
||||
}, 0, ONCE_PER_MINUTE);
|
||||
|
||||
// reset stats counters
|
||||
sendObjectCounter=0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the connector and backend threads.
|
||||
* cleaning all resources and closing the connections/selector.
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws IOException {
|
||||
if (stop) {
|
||||
throw new IllegalStateException("Can't stop already stopped connector.");
|
||||
}
|
||||
stop = true; // note: thread stops his resources (and selector)
|
||||
try {
|
||||
selector.wakeup();
|
||||
} finally {
|
||||
try {
|
||||
statsTimer.cancel();
|
||||
} finally {
|
||||
|
||||
// simple stop check
|
||||
int max=10;
|
||||
while (totalConnections!=0 & max!=0) {
|
||||
try {
|
||||
max--;
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
selector.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendObject(SocketChannel socket,Object object) throws IOException {
|
||||
|
||||
// write request
|
||||
ByteArrayOutputStream dataArray = new ByteArrayOutputStream(256); // it grows when needed
|
||||
ObjectOutputStream objOutstream = new ObjectOutputStream(dataArray);
|
||||
objOutstream.writeObject(object);
|
||||
objOutstream.close();
|
||||
|
||||
int objectSize = dataArray.size();
|
||||
|
||||
// write request size
|
||||
ByteArrayOutputStream dataArray2 = new ByteArrayOutputStream(objectSize+8);
|
||||
ObjectOutputStream objOutstream2 = new ObjectOutputStream(dataArray2); // todo: remove this new statement
|
||||
objOutstream2.writeInt(objectSize);
|
||||
objOutstream2.close();
|
||||
|
||||
// add request object
|
||||
dataArray2.write(dataArray.toByteArray());
|
||||
super.send(socket, ByteBuffer.wrap(dataArray2.toByteArray()));
|
||||
sendObjectCounter++;
|
||||
}
|
||||
|
||||
public ByteBuffer receiveObject(SocketChannel socket,ByteBuffer readBuffer,ObjectHandler objectHandler,int offset) throws IOException {
|
||||
|
||||
if (readBuffer.limit()<8) {
|
||||
logger.fine("Missing bytes, could not read object Size bufLimit: "+readBuffer.limit());
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(readBuffer.array(),0,readBuffer.limit());
|
||||
|
||||
//System.out.println("in: "+in.available()+" off: "+offset);
|
||||
if ((in.available()-offset)<8) {
|
||||
logger.info("--------------------------------- TODO: error, fix");
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
in.skip(offset);
|
||||
|
||||
ObjectInputStream objstream = new ObjectInputStream(in);
|
||||
int objectSize = objstream.readInt();
|
||||
objstream.close();
|
||||
|
||||
if (objectSize>in.available()) {
|
||||
logger.fine("Not all bytes gotten: objSize: "+objectSize+" inA: "+in.available());
|
||||
readBuffer.position(offset);
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
|
||||
objstream = new ObjectInputStream(in);
|
||||
Object result = null;
|
||||
try {
|
||||
result = objstream.readObject();
|
||||
objectHandler.processObject(result);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IOException("Could not load object class: "+e.getMessage(),e);
|
||||
} finally {
|
||||
if (in.available()>0 ) {
|
||||
logger.fine("==== dubbel request added left over: "+in.available()+" offset: "+(readBuffer.limit()-in.available()));
|
||||
return receiveObject(socket,readBuffer,objectHandler,(readBuffer.limit()-in.available()));
|
||||
//return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface ObjectHandler {
|
||||
public void processObject(Object object);
|
||||
}
|
||||
}
|
139
src/suncertify/net/NetworkRequest.java
Normal file
139
src/suncertify/net/NetworkRequest.java
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
/**
|
||||
* The NetworkRequest is the object sent to the server for invoking a method on a bean.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NetworkRequest implements Externalizable {
|
||||
|
||||
/** The request ID, should be an uniq number */
|
||||
private Integer requestId = null;
|
||||
|
||||
/** The beanName we do the request on. */
|
||||
private String beanName = null;
|
||||
|
||||
/** The methodName of the bean to call. */
|
||||
private String methodName = null;
|
||||
|
||||
/** The argruments of the method name. */
|
||||
private Object[] methodArgs = null;
|
||||
|
||||
public NetworkRequest() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NetworkRequest with an given requestId.
|
||||
* @param requestId The requestId of the response.
|
||||
*/
|
||||
public NetworkRequest(Integer requestId) {
|
||||
if (requestId==null) {
|
||||
throw new NullPointerException("can't handle null requestID.");
|
||||
}
|
||||
this.requestId=requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and check all info for request.
|
||||
* @param beanName
|
||||
* @param methodName
|
||||
* @param methodArgs
|
||||
*/
|
||||
public void setRequestBean(String beanName,String methodName,Object[] methodArgs) {
|
||||
if (beanName==null) {
|
||||
throw new NullPointerException("Can't request null beanName.");
|
||||
}
|
||||
if (beanName.isEmpty()) {
|
||||
throw new IllegalArgumentException("Can't request empty beanName.");
|
||||
}
|
||||
if (methodName==null) {
|
||||
throw new NullPointerException("Can't request null methodName");
|
||||
}
|
||||
if (methodName.isEmpty()) {
|
||||
throw new NullPointerException("Can't request empty methodName");
|
||||
}
|
||||
this.beanName=beanName;
|
||||
this.methodName=methodName;
|
||||
this.methodArgs=methodArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request id.
|
||||
* @return The requestId
|
||||
*/
|
||||
public Integer getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the beanName
|
||||
* @return The beanName to request
|
||||
*/
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the methodName
|
||||
* @return The methodName to request
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the methodArgs
|
||||
* @return The methodArgs to invoke on bean.
|
||||
*/
|
||||
public Object[] getMethodArgs() {
|
||||
return methodArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
|
||||
*/
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
requestId = in.readInt();
|
||||
beanName = in.readUTF();
|
||||
methodName = in.readUTF();
|
||||
int argsCount = in.readInt();
|
||||
if (argsCount==0) {
|
||||
return;
|
||||
}
|
||||
methodArgs = new Object[argsCount];
|
||||
for (int i=0;i<argsCount;i++) {
|
||||
methodArgs[i]= in.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
|
||||
*/
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeInt (requestId);
|
||||
out.writeUTF (beanName);
|
||||
out.writeUTF (methodName);
|
||||
if (methodArgs==null) {
|
||||
out.writeInt(0);
|
||||
return;
|
||||
}
|
||||
out.writeInt(methodArgs.length);
|
||||
for (int i=0;i<methodArgs.length;i++) {
|
||||
out.writeObject(methodArgs[i]);
|
||||
}
|
||||
}
|
||||
}
|
82
src/suncertify/net/NetworkResponse.java
Normal file
82
src/suncertify/net/NetworkResponse.java
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
/**
|
||||
* The NetworkResponse is the object response sent by the server to the client after the request has been processed.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NetworkResponse implements Externalizable {
|
||||
|
||||
/** The request ID for which this response is created. */
|
||||
private Integer requestId = null;
|
||||
/** The object of the resonse to return */
|
||||
private Object result = null;
|
||||
|
||||
public NetworkResponse() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NetworkResponse with an given requestId.
|
||||
* @param requestId The requestId of the response.
|
||||
*/
|
||||
public NetworkResponse(Integer requestId) {
|
||||
if (requestId==null) {
|
||||
throw new NullPointerException("can't handle null requestID.");
|
||||
}
|
||||
this.requestId=requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request id.
|
||||
* @return The requestId
|
||||
*/
|
||||
public Integer getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Result
|
||||
* @return Returns the result.
|
||||
*/
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the result.
|
||||
* @param result The result to response.
|
||||
*/
|
||||
public void setResult(Object result) {
|
||||
this.result=result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
|
||||
*/
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
requestId = in.readInt();
|
||||
result = in.readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
|
||||
*/
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeInt (requestId);
|
||||
out.writeObject (result);
|
||||
}
|
||||
}
|
102
src/suncertify/net/NetworkResponseHandler.java
Normal file
102
src/suncertify/net/NetworkResponseHandler.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* The NetworkResponseHandler
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NetworkResponseHandler {
|
||||
|
||||
/** Stores the request */
|
||||
private NetworkRequest request = null;
|
||||
/** Stores the response */
|
||||
private NetworkResponse response = null;
|
||||
/** The network client */
|
||||
private NetworkClient client = null;
|
||||
|
||||
/**
|
||||
* Creates an NetworkResponseHandler
|
||||
* @param request The request for which this response handler is.
|
||||
* @param client The client
|
||||
*/
|
||||
public NetworkResponseHandler(NetworkRequest request,NetworkClient client) {
|
||||
if (request==null) {
|
||||
throw new NullPointerException("Can't handle response with null request.");
|
||||
}
|
||||
if (client==null) {
|
||||
throw new NullPointerException("Can't handle response with null client.");
|
||||
}
|
||||
this.request=request;
|
||||
this.client=client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when is the response is ready.
|
||||
*
|
||||
* @param response The NetworkResponse
|
||||
*/
|
||||
public void handleResponse(NetworkResponse response) {
|
||||
this.response=response;
|
||||
synchronized (this) {
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks for thread while waiting on respones.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitForResponse() throws InterruptedException {
|
||||
while(this.response == null) {
|
||||
synchronized (this) {
|
||||
this.wait(3000); // 3secs
|
||||
}
|
||||
if (response==null) {
|
||||
// we miss sometimes a result when working with 40+ threads client side.
|
||||
// lets resend and hopes its get returned this time.
|
||||
try {
|
||||
client.send(request,this);
|
||||
} catch (IOException e) {
|
||||
throw new InterruptedException("Error while resending missed request: "+e.getMessage());
|
||||
}
|
||||
synchronized (this) {
|
||||
this.wait(3000);
|
||||
}
|
||||
}
|
||||
if (response==null) {
|
||||
throw new InterruptedException("no result of Id: "+request.getRequestId()+" in time, in thead: "+Thread.currentThread().getName());
|
||||
}
|
||||
if (response.getResult() instanceof Exception) {
|
||||
Exception e = (Exception)response.getResult();
|
||||
throw new RuntimeException("Server got error in request handling: "+e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the NetworkRequest for which the response is active.
|
||||
*/
|
||||
public NetworkRequest getNetworkRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the real result from the response.
|
||||
*/
|
||||
public Object getResult() {
|
||||
if (response==null) {
|
||||
throw new IllegalStateException("No response object, do not call getResult() before waitForResponse().");
|
||||
}
|
||||
return response.getResult();
|
||||
}
|
||||
}
|
107
src/suncertify/net/NetworkServer.java
Normal file
107
src/suncertify/net/NetworkServer.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The NetworkServer provides support to executing beans by remote requests on the serverBackendProvider
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class NetworkServer extends NetworkNIOConnector {
|
||||
|
||||
private ServerBackendProvider serverBackendProvider = null;
|
||||
|
||||
private Logger logger = Logger.getLogger(NetworkServer.class.getName());;
|
||||
|
||||
public NetworkServer(InetAddress hostAddress, int port, ServerBackendProvider serverBackendProvider) throws IOException {
|
||||
super(hostAddress,port);
|
||||
this.serverBackendProvider = serverBackendProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the response back to the client.
|
||||
* @param socket
|
||||
* @param response
|
||||
* @throws IOException
|
||||
*/
|
||||
public void send(SocketChannel socket,NetworkResponse response) throws IOException {
|
||||
sendObject(socket,response);
|
||||
logger.fine("SEND requestId: "+response.getRequestId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the key and makes the socket non-blocking
|
||||
*/
|
||||
@Override
|
||||
protected void accept(SelectionKey key) throws IOException {
|
||||
|
||||
// For an accept to be pending the channel must be a server socket channel.
|
||||
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
|
||||
|
||||
// Accept the connection and make it non-blocking
|
||||
SocketChannel socketChannel = serverSocketChannel.accept();
|
||||
socketChannel.configureBlocking(false);
|
||||
|
||||
// Register the new SocketChannel with our Selector, indicating
|
||||
// we'd like to be notified when there's data waiting to be read
|
||||
socketChannel.register(key.selector(), SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Server socket non-blocking
|
||||
*/
|
||||
@Override
|
||||
protected Selector initSelector() throws IOException {
|
||||
Selector socketSelector = super.initSelector();
|
||||
|
||||
// Create a new non-blocking server socket channel
|
||||
ServerSocketChannel serverChannel = ServerSocketChannel.open();
|
||||
serverChannel.configureBlocking(false);
|
||||
|
||||
// Bind the server socket to the specified address and port
|
||||
InetSocketAddress isa = new InetSocketAddress(getHostAddress(), getPort());
|
||||
serverChannel.socket().bind(isa);
|
||||
|
||||
// Register the server socket channel, indicating an interest in
|
||||
// accepting new connections
|
||||
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
|
||||
return socketSelector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the data in the ServerBackendProvider
|
||||
*/
|
||||
@Override
|
||||
protected void processData(SocketChannel socket,ByteBuffer readBuffer) throws IOException {
|
||||
|
||||
// copy data
|
||||
byte[] data = new byte[readBuffer.remaining()];
|
||||
readBuffer.get(data);
|
||||
|
||||
// give to handerl
|
||||
Runnable worker = serverBackendProvider.dataWorker(this,socket,data);
|
||||
serverBackendProvider.executeWorker(worker);
|
||||
}
|
||||
|
||||
|
||||
public interface ServerBackendProvider {
|
||||
public Runnable dataWorker(NetworkServer server,SocketChannel socket,byte[] data);
|
||||
public void executeWorker(Runnable runable);
|
||||
}
|
||||
}
|
33
src/suncertify/net/package.html
Normal file
33
src/suncertify/net/package.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The network layer.<br/>
|
||||
Bases on a NIO sockets with object stream serilatition.
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
34
src/suncertify/server/ServerException.java
Normal file
34
src/suncertify/server/ServerException.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server;
|
||||
|
||||
/**
|
||||
* The ServerException is thrown when the server has an exception.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ServerException extends Exception {
|
||||
|
||||
/**
|
||||
* Message constructor
|
||||
* @param message The error message
|
||||
*/
|
||||
public ServerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor
|
||||
* @param message The error message
|
||||
* @param exception The error exception
|
||||
*/
|
||||
public ServerException(String message,Exception exception) {
|
||||
super(message,exception);
|
||||
}
|
||||
}
|
215
src/suncertify/server/ServerManager.java
Normal file
215
src/suncertify/server/ServerManager.java
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* The ServerManager manages server beans and create and inject depencicies on the beans.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class ServerManager {
|
||||
|
||||
private ThreadPoolExecutor threadPoolExecutor = null;
|
||||
private Map<String,Class<?>> beans = new HashMap<String,Class<?>>(5);
|
||||
private Map<String,Object> initBeans = new HashMap<String,Object>(5);
|
||||
|
||||
/**
|
||||
* Creates an ServerManager with an worker pool of threads.
|
||||
*/
|
||||
public ServerManager() {
|
||||
// core, max, keepalive
|
||||
threadPoolExecutor = new ThreadPoolExecutor (
|
||||
3,10,2,
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(),
|
||||
new NameingThreadFactory("server-")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the serverManager backend thread pool.
|
||||
*/
|
||||
public void start() {
|
||||
threadPoolExecutor.prestartAllCoreThreads();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the ServerManager backend thread pool.
|
||||
*/
|
||||
public void stop() {
|
||||
threadPoolExecutor.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an Runnable object in the ServerManager thread pool.
|
||||
* @param run The Object to run.
|
||||
*/
|
||||
public void execute(Runnable run) {
|
||||
threadPoolExecutor.execute(run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an bean by its class.
|
||||
* @param serverBeanRemote
|
||||
* @param serverBean
|
||||
*/
|
||||
public void putServerBean(Class<?> serverBeanRemote,Class<?> serverBean) {
|
||||
beans.put(serverBeanRemote.getName(),serverBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an bean which is already created.
|
||||
* @param name
|
||||
* @param serverBean
|
||||
*/
|
||||
public void putServerInitBean(String name,Object serverBean) {
|
||||
initBeans.put(name,serverBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request an server bean.
|
||||
* This methode also makes sure all depencies are injectes into the bean.
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @throws ServerException
|
||||
*/
|
||||
public Object getServerBean(String name) throws ServerException {
|
||||
|
||||
// let init bean be first
|
||||
if (initBeans.containsKey(name)) {
|
||||
return initBeans.get(name);
|
||||
}
|
||||
|
||||
Class<?> c = beans.get(name);
|
||||
if (c==null) {
|
||||
throw new ServerException("Could not find bean for: "+name);
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
try {
|
||||
result = c.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ServerException("Could error while init bean: '"+name+"' "+e.getMessage(),e);
|
||||
}
|
||||
|
||||
for (Field field:result.getClass().getFields()) {
|
||||
ServerResource resource = field.getAnnotation(ServerResource.class);
|
||||
if (resource==null) {
|
||||
continue;
|
||||
}
|
||||
String beanName = resource.beanName();
|
||||
if ("null".equals(beanName)) {
|
||||
beanName = field.getType().getName();
|
||||
}
|
||||
Object bean = getServerBean(beanName);
|
||||
if (bean==null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
field.set(result,bean);
|
||||
} catch (Exception e) {
|
||||
throw new ServerException("Could not load resource for bean: "+name+" resource: "+beanName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the Beans know in the server.
|
||||
* @return
|
||||
*/
|
||||
public List<String> getServerBeanNames() {
|
||||
List<String> result = new ArrayList<String>(beans.keySet());
|
||||
result.addAll(initBeans.keySet());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local InvocationHandler which is used for none network mode for this server.
|
||||
* @return
|
||||
*/
|
||||
public InvocationHandler getLocalInvocationHandler() {
|
||||
return new LocalRequestProxy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custum ThreadFactory for getting thread nameing correctly.
|
||||
*/
|
||||
private class NameingThreadFactory implements ThreadFactory {
|
||||
final ThreadGroup group;
|
||||
final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
final String namePrefix;
|
||||
|
||||
public NameingThreadFactory(String namePrefix) {
|
||||
if (namePrefix==null) {
|
||||
namePrefix = "thread-";
|
||||
}
|
||||
this.namePrefix=namePrefix;
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
if (s != null) {
|
||||
group = s.getThreadGroup();
|
||||
} else {
|
||||
group = Thread.currentThread().getThreadGroup();
|
||||
}
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(group, r,namePrefix+threadNumber.getAndIncrement(),0);
|
||||
if (t.isDaemon()) {
|
||||
t.setDaemon(false);
|
||||
}
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* InvocationHandler for handeling the method calls of the proxy bean.
|
||||
*
|
||||
*/
|
||||
private class LocalRequestProxy implements InvocationHandler {
|
||||
|
||||
private ServerManager serverManager = null;
|
||||
|
||||
public LocalRequestProxy(ServerManager serverManager) {
|
||||
this.serverManager=serverManager;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
|
||||
Object bean = serverManager.getServerBean(proxy.getClass().getName());
|
||||
int pS = 0;
|
||||
if (args!=null) {
|
||||
pS = args.length;
|
||||
}
|
||||
Class<?>[] para = new Class[pS];
|
||||
for (int i=0;i<pS;i++) {
|
||||
para[i] = args[i].getClass();
|
||||
}
|
||||
Method mm = bean.getClass().getMethod(method.getName(), para);
|
||||
Object resultObject = mm.invoke(bean,args);
|
||||
return resultObject;
|
||||
}
|
||||
}
|
||||
}
|
29
src/suncertify/server/ServerResource.java
Normal file
29
src/suncertify/server/ServerResource.java
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The ServerResource is a annotation that can be used to inject beans into your server manages bean.
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ServerResource {
|
||||
|
||||
/**
|
||||
* The beanName to resolve, defaults to the className of the field.
|
||||
* @return
|
||||
*/
|
||||
String beanName() default "null";
|
||||
}
|
24
src/suncertify/server/beans/BookingLogManager.java
Normal file
24
src/suncertify/server/beans/BookingLogManager.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The BookingLogManager
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class BookingLogManager implements BookingLogManagerRemote {
|
||||
|
||||
public List<String> getLastBookings(int logID) {
|
||||
List<String> result = new ArrayList<String>(1);
|
||||
return result;
|
||||
}
|
||||
}
|
20
src/suncertify/server/beans/BookingLogManagerRemote.java
Normal file
20
src/suncertify/server/beans/BookingLogManagerRemote.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server.beans;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The BookingLogManagerRemote
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public interface BookingLogManagerRemote {
|
||||
|
||||
public List<String> getLastBookings(int logID);
|
||||
}
|
102
src/suncertify/server/beans/HotelRoomManager.java
Normal file
102
src/suncertify/server/beans/HotelRoomManager.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import suncertify.db.DB;
|
||||
import suncertify.db.DuplicateKeyException;
|
||||
import suncertify.db.RecordNotFoundException;
|
||||
import suncertify.models.HotelRoom;
|
||||
import suncertify.models.HotelRoomDBConverter;
|
||||
import suncertify.server.ServerResource;
|
||||
|
||||
/**
|
||||
* The HotelRoomManager
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public class HotelRoomManager implements HotelRoomManagerRemote {
|
||||
|
||||
@ServerResource(beanName="hotelRoom.tableBackend")
|
||||
public DB backend = null;
|
||||
|
||||
@ServerResource(beanName="hotelRoom.beanConverter")
|
||||
public HotelRoomDBConverter hotelRoomDBConverter = null;
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#findByCriteria(suncertify.models.HotelRoom)
|
||||
*/
|
||||
@Override
|
||||
public List<HotelRoom> findByCriteria(HotelRoom hotelRoom) throws RecordNotFoundException {
|
||||
String[] data = hotelRoomDBConverter.encode(hotelRoom);
|
||||
int[] result = backend.find(data);
|
||||
List<HotelRoom> rooms = new ArrayList<HotelRoom>(result.length);
|
||||
for (int i:result) {
|
||||
String[] rec = backend.read(i);
|
||||
HotelRoom hr = hotelRoomDBConverter.decode(rec);
|
||||
hr.setId(i);
|
||||
rooms.add(hr);
|
||||
}
|
||||
return rooms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#getAllHotelRooms()
|
||||
*/
|
||||
@Override
|
||||
public List<HotelRoom> getAllHotelRooms() throws RecordNotFoundException {
|
||||
HotelRoom room = new HotelRoom();
|
||||
room.setName("a");
|
||||
return findByCriteria(room); // leaven all values null does an select all
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#delete(suncertify.models.HotelRoom, java.lang.Long)
|
||||
*/
|
||||
@Override
|
||||
public void delete(HotelRoom hotelRoom, Long lockId) throws RecordNotFoundException {
|
||||
backend.delete(hotelRoom.getId(), lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#merge(suncertify.models.HotelRoom, java.lang.Long)
|
||||
*/
|
||||
@Override
|
||||
public void merge(HotelRoom hotelRoom, Long lockId) throws RecordNotFoundException, SecurityException {
|
||||
String[] data = hotelRoomDBConverter.encode(hotelRoom);
|
||||
backend.update(hotelRoom.getId(), data, lockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#persist(suncertify.models.HotelRoom)
|
||||
*/
|
||||
@Override
|
||||
public Integer persist(HotelRoom hotelRoom) throws DuplicateKeyException {
|
||||
String[] data = hotelRoomDBConverter.encode(hotelRoom);
|
||||
return backend.create(data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#lockHotelRoom(java.lang.Integer)
|
||||
*/
|
||||
@Override
|
||||
public Long lockHotelRoom(Integer id) throws RecordNotFoundException {
|
||||
return backend.lock(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see suncertify.server.beans.HotelRoomManagerRemote#unlockHotelRoom(java.lang.Integer, java.lang.Long)
|
||||
*/
|
||||
@Override
|
||||
public void unlockHotelRoom(Integer id, Long lockId) throws RecordNotFoundException {
|
||||
backend.unlock(id, lockId);
|
||||
}
|
||||
}
|
77
src/suncertify/server/beans/HotelRoomManagerRemote.java
Normal file
77
src/suncertify/server/beans/HotelRoomManagerRemote.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
*/
|
||||
|
||||
package suncertify.server.beans;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import suncertify.db.DuplicateKeyException;
|
||||
import suncertify.db.RecordNotFoundException;
|
||||
import suncertify.models.HotelRoom;
|
||||
|
||||
/**
|
||||
* The HotelRoomManagerRemote manages the HotelRooms.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author Willem Cazander
|
||||
* @version 1.0 Dec 14, 2008
|
||||
*/
|
||||
public interface HotelRoomManagerRemote {
|
||||
|
||||
// TEMP !!!
|
||||
public List<HotelRoom> getAllHotelRooms() throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param hotelRoom
|
||||
* @return
|
||||
* @throws RecordNotFoundException
|
||||
*/
|
||||
public List<HotelRoom> findByCriteria(HotelRoom hotelRoom) throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* @throws RecordNotFoundException
|
||||
*/
|
||||
public Long lockHotelRoom(Integer id) throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @param lockId
|
||||
* @throws RecordNotFoundException
|
||||
*/
|
||||
public void unlockHotelRoom(Integer id,Long lockId) throws RecordNotFoundException;
|
||||
|
||||
/**
|
||||
* Persists an HotelRoom
|
||||
* @param hotelRoom
|
||||
* @return
|
||||
* @throws DuplicateKeyException
|
||||
*/
|
||||
public Integer persist(HotelRoom hotelRoom) throws DuplicateKeyException;
|
||||
|
||||
/**
|
||||
* Merges an HotelRoom
|
||||
* @param hotelRoom
|
||||
* @param lockId
|
||||
* @throws RecordNotFoundException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void merge(HotelRoom hotelRoom,Long lockId) throws RecordNotFoundException, SecurityException;
|
||||
|
||||
/**
|
||||
* Deletes an HotelRoom
|
||||
* @param hotelRoom
|
||||
* @param lockId
|
||||
* @throws RecordNotFoundException
|
||||
* @throws SecurityException
|
||||
*/
|
||||
public void delete(HotelRoom hotelRoom,Long lockId) throws RecordNotFoundException, SecurityException;
|
||||
}
|
32
src/suncertify/server/beans/package.html
Normal file
32
src/suncertify/server/beans/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The server service beans.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
32
src/suncertify/server/package.html
Normal file
32
src/suncertify/server/package.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
* Copyright 2008 Willem Cazander.
|
||||
* Created for Sun Certified Developer for the Java 2 Platform
|
||||
* Application Submission (Version 1.1.3)
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
The server for executing services.<br/>
|
||||
|
||||
|
||||
<!--
|
||||
<ul>
|
||||
<li><a href="">hgj</a>
|
||||
</ul>
|
||||
-->
|
||||
|
||||
<h2>Related Documentation</h2>
|
||||
|
||||
None.
|
||||
<!--
|
||||
For overviews, tutorials, examples, guides, and tool documentation, please see:
|
||||
<ul>
|
||||
<li><a href="http://foei.idca.nl/docs/jmx/example1">Example 1</a>
|
||||
</ul>
|
||||
-->
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
</body>
|
||||
</html>
|
102
test/suncertify/db/DataTest.java
Normal file
102
test/suncertify/db/DataTest.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
import suncertify.core.LoadHotelRoomDB;
|
||||
import suncertify.db.Data;
|
||||
import suncertify.db.data.RowLock;
|
||||
import suncertify.db.data.Table;
|
||||
import suncertify.models.HotelRoom;
|
||||
import suncertify.models.HotelRoomDBConverter;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
public class DataTest extends TestCase {
|
||||
|
||||
|
||||
public void printRecord(String[] record) {
|
||||
for (String value:record) {
|
||||
System.out.print("'");
|
||||
System.out.print(value);
|
||||
System.out.print("'\t");
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
|
||||
|
||||
public void testData() throws Exception {
|
||||
|
||||
DataBaseManager dataBaseManager = new DataBaseManager();
|
||||
new LoadHotelRoomDB().loadTable(dataBaseManager);
|
||||
Table table = dataBaseManager.getHotelRoomTable();
|
||||
|
||||
HotelRoomDBConverter c = new HotelRoomDBConverter(table);
|
||||
|
||||
Data d = new Data(dataBaseManager.getHotelRoomTable());
|
||||
printRecord(d.read(0));
|
||||
printRecord(d.read(1));
|
||||
printRecord(d.read(9));
|
||||
|
||||
String[] first = d.read(8);
|
||||
printRecord(first);
|
||||
HotelRoom hr = c.decode(first);
|
||||
String[] back = c.encode(hr);
|
||||
printRecord(back);
|
||||
//assertEquals(first,back);
|
||||
|
||||
table.closeTable();
|
||||
}
|
||||
|
||||
public void testLock() throws Exception {
|
||||
|
||||
DataBaseManager dataBaseManager = new DataBaseManager();
|
||||
new LoadHotelRoomDB().loadTable(dataBaseManager);
|
||||
Table table = dataBaseManager.getHotelRoomTable();
|
||||
|
||||
String[] interfaceData = {"name-FIELD-Data"+System.nanoTime(),"location-FIELD-DATa","45","true","$349.34","2008/02/13","888"};
|
||||
int row = table.create(interfaceData);
|
||||
System.out.println("NEW Rcords row:"+row);
|
||||
|
||||
RowLock lock = table.lock(2);
|
||||
table.unlock(2, lock.getLockId());
|
||||
lock = table.lock(2);
|
||||
table.unlock(2, lock.getLockId());
|
||||
lock = table.lock(2);
|
||||
table.unlock(2, lock.getLockId());
|
||||
|
||||
// get lock
|
||||
lock = table.lock(2);
|
||||
|
||||
boolean error = false;
|
||||
try {
|
||||
table.delete(20, lock.getLockId());
|
||||
} catch (SecurityException se) {
|
||||
error = true;
|
||||
}
|
||||
assertEquals(true,error);
|
||||
|
||||
|
||||
error = false;
|
||||
try {
|
||||
table.delete(200000, lock.getLockId());
|
||||
} catch (RecordNotFoundException se) {
|
||||
error = true;
|
||||
}
|
||||
assertEquals(true,error);
|
||||
|
||||
//table.delete(2, lock.getLockId());
|
||||
table.unlock(2, lock.getLockId());
|
||||
|
||||
error = false;
|
||||
try {
|
||||
Data d = new Data(table);
|
||||
printRecord(d.read(2));
|
||||
} catch (RecordNotFoundException re) {
|
||||
error = true;
|
||||
}
|
||||
//assertEquals(true,error);
|
||||
|
||||
table.closeTable();
|
||||
}
|
||||
|
||||
}
|
111
test/suncertify/db/InsertTest.java
Normal file
111
test/suncertify/db/InsertTest.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
|
||||
|
||||
package suncertify.db;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import suncertify.core.LoadHotelRoomDB;
|
||||
import suncertify.db.Data;
|
||||
import suncertify.db.data.RowLock;
|
||||
import suncertify.db.data.Table;
|
||||
import suncertify.models.HotelRoom;
|
||||
import suncertify.models.HotelRoomDBConverter;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
public class InsertTest extends TestCase {
|
||||
|
||||
|
||||
public void printRecord(String[] record) {
|
||||
StringBuilder buf = new StringBuilder(200);
|
||||
for (String value:record) {
|
||||
buf.append("'");
|
||||
buf.append(value);
|
||||
buf.append("'\t");
|
||||
}
|
||||
buf.append("");
|
||||
|
||||
Logger.getAnonymousLogger().info("data: "+buf);
|
||||
}
|
||||
|
||||
public List<HotelRoom> getKamers() throws Exception {
|
||||
|
||||
URL u = new URL("url-not-there......");
|
||||
InputStream in = u.openStream();
|
||||
|
||||
InputStreamReader fileReader = new InputStreamReader(in,"UTF-8");
|
||||
LineNumberReader lineReader = new LineNumberReader(fileReader);
|
||||
|
||||
List<HotelRoom> result = new ArrayList<HotelRoom>(200);
|
||||
|
||||
String line = null;
|
||||
int i = 0;
|
||||
while ((line = lineReader.readLine()) !=null) {
|
||||
if (line.contains("offerid")) {
|
||||
continue; // skip header
|
||||
}
|
||||
i++;
|
||||
|
||||
String[] d = line.split("\t");
|
||||
|
||||
HotelRoom r = new HotelRoom();
|
||||
r.setDateAvailable(new Date()); // d[11]
|
||||
|
||||
String s = d[1];
|
||||
if (s.length()>63) {
|
||||
s = s.substring(0,63);
|
||||
}
|
||||
r.setLocation(s);
|
||||
|
||||
if ("".equals(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
s = d[2];
|
||||
if (s.length()>63) {
|
||||
s = s.substring(0,63);
|
||||
}
|
||||
r.setName(s);
|
||||
|
||||
if ("".equals(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r.setCustomerId(i);
|
||||
r.setPriceRate(new Long(d[5]));
|
||||
r.setSize(1);
|
||||
r.setSmoking(false);
|
||||
|
||||
result.add(r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void testData() throws Exception {
|
||||
DataBaseManager dataBaseManager = new DataBaseManager();
|
||||
new LoadHotelRoomDB().loadTable(dataBaseManager);
|
||||
Table table = dataBaseManager.getHotelRoomTable();
|
||||
|
||||
Data d = new Data(dataBaseManager.getHotelRoomTable());
|
||||
HotelRoomDBConverter c = new HotelRoomDBConverter(table);
|
||||
|
||||
for (HotelRoom r:getKamers()) {
|
||||
String[] data = c.encode(r);
|
||||
printRecord(data);
|
||||
d.create(data);
|
||||
}
|
||||
|
||||
table.closeTable();
|
||||
}
|
||||
}
|
59
test/suncertify/net/StartServer.java
Normal file
59
test/suncertify/net/StartServer.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import suncertify.core.LoadHotelRoomDB;
|
||||
import suncertify.core.LoadServerBeans;
|
||||
import suncertify.core.NetworkServerWorker;
|
||||
import suncertify.db.DataBaseManager;
|
||||
import suncertify.net.NetworkServer.ServerBackendProvider;
|
||||
import suncertify.server.ServerManager;
|
||||
|
||||
/**
|
||||
* Starts the server.
|
||||
*
|
||||
* Currently max: (note: fully cached results)
|
||||
* Dec 15, 2008 1:19:01 AM suncertify.net.NetworkNIOConnector$1 run
|
||||
* INFO: sendObject() Statistics TPM: 86326 TPS: 1438
|
||||
*
|
||||
* @author Willem Cazander
|
||||
*/
|
||||
public class StartServer {
|
||||
|
||||
private NetworkServer server = null;
|
||||
|
||||
public void start() throws Exception {
|
||||
DataBaseManager dataBaseManager = new DataBaseManager();
|
||||
dataBaseManager.start();
|
||||
final ServerManager serverManager = new ServerManager();
|
||||
serverManager.start();
|
||||
|
||||
new LoadHotelRoomDB().loadTable(dataBaseManager);
|
||||
new LoadServerBeans().loadBeans(serverManager,dataBaseManager);
|
||||
|
||||
ServerBackendProvider serverBackendProvider = new ServerBackendProvider() {
|
||||
public void executeWorker(Runnable runable) {
|
||||
serverManager.execute(runable);
|
||||
}
|
||||
public Runnable dataWorker(NetworkServer server,SocketChannel socket,byte[] data) {
|
||||
return new NetworkServerWorker(serverManager,server,socket,data);
|
||||
}
|
||||
};
|
||||
server = new NetworkServer(null, 9090, serverBackendProvider);
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void stop() throws IOException {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
new StartServer().start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
147
test/suncertify/net/ThreadedClientTest.java
Normal file
147
test/suncertify/net/ThreadedClientTest.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
|
||||
|
||||
package suncertify.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
import suncertify.models.HotelRoom;
|
||||
import suncertify.server.beans.HotelRoomManagerRemote;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests the network layer with multi threads and connections
|
||||
*
|
||||
* @author Willem Cazander
|
||||
*/
|
||||
public class ThreadedClientTest extends TestCase {
|
||||
|
||||
NetworkClient client = null;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
client = new NetworkClient(InetAddress.getByName("localhost"), 9090);
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
client.stop();
|
||||
}
|
||||
|
||||
public void testSingleRequest() throws Exception {
|
||||
final HotelRoomManagerRemote remote = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
client.getInvocationHandler(HotelRoomManagerRemote.class));
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<HotelRoom> rooms = remote.getAllHotelRooms();
|
||||
long stopTime = System.currentTimeMillis();
|
||||
System.out.println("got rooms1: "+rooms.size()+" from threads: "+Thread.currentThread().getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
|
||||
if (rooms.isEmpty()) {
|
||||
assertEquals(true,false);
|
||||
}
|
||||
}
|
||||
|
||||
public void testThreadedRequestSingleRemote() throws Exception {
|
||||
final HotelRoomManagerRemote remote = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
client.getInvocationHandler(HotelRoomManagerRemote.class));
|
||||
|
||||
for (int i=0;i<1;i++) {
|
||||
Thread tt = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
for (int i=0;i<20000;i++) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<HotelRoom> rooms = remote.getAllHotelRooms();
|
||||
long stopTime = System.currentTimeMillis();
|
||||
if (i%1000==0) {
|
||||
System.out.println(i+" got rooms: "+rooms.size()+" from threads: "+Thread.currentThread().getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
tt.setPriority(10);
|
||||
tt.setDaemon(false);
|
||||
tt.setName("client-bench-"+i);
|
||||
tt.start();
|
||||
}
|
||||
|
||||
Thread.sleep(22000);
|
||||
}
|
||||
|
||||
public void testThreadedRequestThreadRemote() throws Exception {
|
||||
for (int i=0;i<10;i++) {
|
||||
Thread tt = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
HotelRoomManagerRemote remote = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
client.getInvocationHandler(HotelRoomManagerRemote.class));
|
||||
for (int i=0;i<1000;i++) {
|
||||
//Thread.sleep(new Random().nextInt(400) );
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<HotelRoom> rooms = remote.getAllHotelRooms();
|
||||
long stopTime = System.currentTimeMillis();
|
||||
if (i%100==0) {
|
||||
System.out.println(i+" got rooms: "+rooms.size()+" from threads: "+Thread.currentThread().getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
tt.setPriority(10);
|
||||
tt.setDaemon(false);
|
||||
tt.setName("client-bench-"+i);
|
||||
tt.start();
|
||||
}
|
||||
Thread.sleep(22000);
|
||||
}
|
||||
|
||||
public void testThreadedRequestPerThreadClient() throws Exception {
|
||||
for (int i=0;i<10;i++) {
|
||||
Thread tt = new Thread(new Runnable() {
|
||||
NetworkClient clientThread = null;
|
||||
public void run() {
|
||||
try {
|
||||
clientThread = new NetworkClient(InetAddress.getByName("localhost"), 9090);
|
||||
clientThread.start();
|
||||
HotelRoomManagerRemote remote = (HotelRoomManagerRemote)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
|
||||
new Class[] { HotelRoomManagerRemote.class },
|
||||
clientThread.getInvocationHandler(HotelRoomManagerRemote.class));
|
||||
for (int i=0;i<1000;i++) {
|
||||
//Thread.sleep(new Random().nextInt(400) );
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<HotelRoom> rooms = remote.getAllHotelRooms();
|
||||
long stopTime = System.currentTimeMillis();
|
||||
if (i%100==0) {
|
||||
System.out.println(i+" got rooms: "+rooms.size()+" from threads: "+Thread.currentThread().getName()+" in "+(stopTime-startTime)+" ms.");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
clientThread.stop();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
tt.setPriority(10);
|
||||
tt.setDaemon(false);
|
||||
tt.setName("client-bench-"+i);
|
||||
tt.start();
|
||||
}
|
||||
Thread.sleep(22000);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue