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