3
0
Fork 0

Added code

This commit is contained in:
Willem Cazander 2022-11-12 13:48:19 +01:00
parent 8d2771ef74
commit a4e7295bcb
67 changed files with 6291 additions and 0 deletions

94
build/build.xml Normal file
View 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 &#169; 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

Binary file not shown.

29
doc/choices.txt Normal file
View 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.

View 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.&nbsp;
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> -&nbsp; 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.&nbsp; 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.&nbsp;</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.&nbsp;
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.&nbsp; Features that deviate
from specification will not receive full credit.&nbsp; 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:&nbsp; 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.&nbsp;
Both options are equally acceptable.&nbsp; 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.&nbsp; Specifically:
<br>&nbsp;
<li>
&nbsp;You must not require the use of an HTTP server.</li>
<li>
&nbsp;You must not require the installation of a security manager.</li>
<li>
&nbsp;You must provide all classes pre-installed so that no dynamic class
downloading occurs.</li>
<li>
&nbsp;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.&nbsp; 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.&nbsp; 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 &lt;path_and_filename> [&lt;mode>]</tt></blockquote>
Your programs must not require use of command line arguments other than
the single mode flag, which must be supported.&nbsp; 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.&nbsp; First, software checks that
overall structure and nomenclature conform to specification.&nbsp; 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>&nbsp;
<br>&nbsp;
<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
View File

@ -0,0 +1,3 @@
- on high load client network lib locks.

26
doc/version.txt Normal file
View 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

View File

@ -0,0 +1,5 @@
#
# A properties file for i18n keys
#
test = i18n_test

View 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

View 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;
}
}

View 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>";
}
}
}

View 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);
}
}

View 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);
}
}

View 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>

View 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;
}
}

View 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);
}
}

View 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.");
}
}
}

View 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);
}
}

View 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);
}
}
}

View 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
View 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;
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View 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();
}
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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;
}
}

View 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);
}

View 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;
}

View 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;
}
}

View 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]+"'");
}
}

View 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();
}
}

View 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;
}
}

View 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 {
}
}

View 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;
}
}

View 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 {
}

View 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>

View 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>

View 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>

View 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);
}
}
}

View 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;
}
}

View 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>

View 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;
}
}

View 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;
}
}

View 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;
}
}
}

View 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);
}
}

View 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]);
}
}
}

View 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);
}
}

View 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();
}
}

View 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);
}
}

View 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>

View 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);
}
}

View 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;
}
}
}

View 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";
}

View 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;
}
}

View 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);
}

View 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);
}
}

View 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;
}

View 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>

View 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>

View 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();
}
}

View 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();
}
}

View 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();
}
}
}

View 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);
}
}