inital commit

This commit is contained in:
Tilman Walther
2012-02-10 22:42:30 +01:00
commit 115bd4d29f
27 changed files with 3331 additions and 0 deletions
@@ -0,0 +1,129 @@
package de.tilman.transactions;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.log4j.Logger;
public class DatabaseController {
private final static Logger log = Logger.getLogger(DatabaseController.class);
final String DB_TREIBER = "org.hsqldb.jdbcDriver";
// final String DB_URL = "jdbc:hsqldb:file:database/db;ifexists=true;shutdown=true"; // embedded mode, für Testzwecke
final String DB_URL = "jdbc:hsqldb:hsql://localhost/transaktionen"; // Datenbank läuft separat im server mode
final String DB_LOGIN = "sa";
final String DB_PASSWORT = "";
String tblTransactions = "Transaktionen";
String tblCategories = "Kategorien";
Connection connection;
Statement statement;
PreparedStatement selectCategoriesSql;
PreparedStatement insertTransactionSql;
PreparedStatement getLastIdSql;
ResultSet resultSet;
String path;
boolean hasAuslagen;
public DatabaseController(String tblTransactions, String tblCategories, String path, boolean hasAuslagen) throws Exception {
this.tblTransactions = tblTransactions;
this.tblCategories = tblCategories;
this.path = path;
this.hasAuslagen = hasAuslagen;
Class.forName("org.hsqldb.jdbcDriver");
connection = DriverManager.getConnection(DB_URL, DB_LOGIN, DB_PASSWORT);
statement = connection.createStatement();
// prepare SQL statements
selectCategoriesSql = connection.prepareCall("SELECT * FROM \""+tblCategories+"\" ORDER BY \"ID\" asc");
insertTransactionSql = connection.prepareCall("INSERT INTO \""+tblTransactions+"\" (\"ID\", \"Datum\", \"Kategorie\", \"Betrag\", \"Beschreibung\", \"Auslage\") VALUES (null,?,?,?,?,?)");
}
public SortedMap<Integer, String> getCategories() throws SQLException {
resultSet = selectCategoriesSql.executeQuery();
TreeMap<Integer, String> categoryMap = new TreeMap<Integer, String>();
while (resultSet.next()) {
categoryMap.put(resultSet.getInt(1), resultSet.getString(2));
}
return categoryMap;
}
public int writeTransaction(Transaktion transaction) throws SQLException {
insertTransactionSql.setBigDecimal(3, transaction.betrag);
insertTransactionSql.setInt(2, transaction.kategorie);
insertTransactionSql.setDate(1, new java.sql.Date(transaction.datum.getTime()));
insertTransactionSql.setString(4, transaction.beschreibung);
insertTransactionSql.setInt(5, transaction.auslage);
insertTransactionSql.execute();
// return the ID of the new row
resultSet = statement.executeQuery("CALL IDENTITY();");
resultSet.next();
int lastId = resultSet.getInt(1);
log.info("written transaction with ID " + lastId);
return lastId;
}
public void deleteTransaction(int id) throws SQLException {
log.info("delete transaction #" + id);
statement.execute("DELETE FROM \""+tblTransactions+"\" WHERE id=" + id);
}
public Transaktion getLastTransaction() throws SQLException {
resultSet = statement.executeQuery("SELECT \"ID\", \"Datum\", \"Kategorie\", \"Betrag\", \"Beschreibung\", \"Auslage\" FROM \""+tblTransactions+"\" WHERE id = (SELECT Max(id) FROM \""+tblTransactions+"\");");
resultSet.next();
return new Transaktion(resultSet.getInt(1), resultSet.getBigDecimal(4), resultSet.getInt(3), resultSet.getDate(2), resultSet.getString(5), resultSet.getInt(6));
}
public LinkedList<Transaktion> getLastTransactions(int num) throws SQLException {
LinkedList<Transaktion> list = new LinkedList<Transaktion>();
Map<Integer, String> categories = getCategories();
resultSet = statement.executeQuery("SELECT \"ID\", \"Datum\", \"Kategorie\", \"Betrag\", \"Beschreibung\", \"Auslage\" FROM \""+tblTransactions+"\" ORDER BY \"Datum\" desc, \"ID\" desc LIMIT " + num);
while (resultSet.next()) {
Transaktion trns = new Transaktion(resultSet.getInt(1), resultSet.getBigDecimal(4), resultSet.getInt(3), categories.get(resultSet.getInt(3)), resultSet.getDate(2), resultSet.getString(5), resultSet.getInt(6));
list.push(trns);
}
return list;
}
public BigDecimal getSumExpenses(int id) throws SQLException {
resultSet = statement.executeQuery("SELECT SUM(\"Betrag\") FROM \"" + tblTransactions + "\" WHERE \"Auslage\"=" + id);
resultSet.next();
BigDecimal result = resultSet.getBigDecimal(1);
if (result == null)
return new BigDecimal(0);
return result;
}
public void resetExpenses(int id) throws SQLException {
log.info("resetting expenses for ID " + id);
statement.execute("UPDATE \"Transaktionen\" SET \"Auslage\"=0 WHERE \"Auslage\"=" + id);
}
public void close() throws SQLException {
selectCategoriesSql.close();
insertTransactionSql.close();
log.info("shutting down database");
statement.execute("SHUTDOWN COMPACT");
statement.close();
connection.close();
log.info("database closed");
}
}
+398
View File
@@ -0,0 +1,398 @@
package de.tilman.transactions;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerList;
import org.mortbay.jetty.handler.ResourceHandler;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.thread.QueuedThreadPool;
public class Service {
private final static Logger log = Logger.getLogger(Service.class);
private static int hostPort = 8080;
protected Server jetty;
private static SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
private Random rnd = new Random();
public void start() {
BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d{ISO8601} - %m%n")));
try {
log.info("open database");
DatabaseController database = new DatabaseController("Transaktionen", "Kategorien", "/input", true);
log.info("add shutdown hook for database");
Runtime.getRuntime().addShutdownHook(new ShutdownThread(database));
DatabaseController databaseTilman = new DatabaseController("Transaktionen_Tilman", "Kategorien_Tilman", "/tilman", false);
jetty = new Server(hostPort);
jetty.setThreadPool(new QueuedThreadPool(10));
Context inputContext = new Context(jetty, "/", Context.SESSIONS);
inputContext.addServlet(new ServletHolder(new ReadServlet(database)), "/input");
inputContext.addServlet(new ServletHolder(new StatsServlet(database)), "/input/last");
inputContext.addServlet(new ServletHolder(new CsvServlet(database)), "/input/csv");
inputContext.addServlet(new ServletHolder(new ReadServlet(databaseTilman)), "/tilman");
inputContext.addServlet(new ServletHolder(new StatsServlet(databaseTilman)), "/tilman/last");
inputContext.addServlet(new ServletHolder(new CsvServlet(databaseTilman)), "/tilman/csv");
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setResourceBase("resources");
log.info("serving " + resourceHandler.getBaseResource());
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resourceHandler, inputContext, new DefaultHandler() });
jetty.setHandler(handlers);
jetty.start();
jetty.join();
log.info("Listening at " + hostPort);
} catch (Exception e) {
e.printStackTrace();
log.fatal("Failed to start on port " + hostPort + ", reason: " + e.getMessage());
}
}
protected static void writeHeader(PrintWriter out) {
out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
"<html xmlns='http://www.w3.org/1999/xhtml'>" +
"<head><title>Ausgaben</title>" +
"<meta http-equiv=\"content-type\" " +
"content=\"text/html; charset=utf-8\" />");
out.println("<meta name='viewport' content='width=360'/>");
out.println("<meta name='apple-mobile-web-app-capable' content='yes' />");
out.println("<link rel='apple-touch-icon' href='/icon.png'/>");
out.println("<style type='text/css'>\na:link { color:darkred; }\na:visited { color:darkred; }\n</style>");
out.println("</head><body style='font-family:Arial;sans-serif;'>"); // onload='document.forms[0].betrag.focus()'
}
protected static void writeFooter(PrintWriter out) {
out.println("</body></html>");
out.close();
}
protected static void showTable(DatabaseController database, int num, PrintWriter out) throws ServletException {
out.println("<table border='1' cellpadding='3' style='margin:auto; margin-top: 2em; font-size: 80%; border-collapse:collapse;'>");
out.println("<tr><th>Datum</th><th>Kategorie</th><th>Betrag</th><th>Beschreibung</th></tr>");
LinkedList<Transaktion> transactions = null;
try {
transactions = database.getLastTransactions(num);
} catch (SQLException se) {
throw new ServletException(se);
}
while (!transactions.isEmpty()) {
Transaktion t = transactions.removeLast();
out.println("<tr><td>" + formatter.format(t.datum) + "</td><td>" + StringEscapeUtils.escapeHtml4(t.kategorieName) + "</td><td align=\"right\" " + ((t.auslage > 0) ? "style=\"background-color: #ccddff;\">" : ">") + t.betrag.toPlainString() + "&nbsp;€</td><td>" + ((t.beschreibung == null) ? "" : StringEscapeUtils.escapeHtml4(t.beschreibung)) + "</td></tr>");
}
out.println("</table>");
}
public class ReadServlet extends HttpServlet {
private static final long serialVersionUID = 1572581546682459768L;
private int undoChallenge = -1;
private int auslagenChallenge = -1;
private int lastId = -1;
private DatabaseController database;
public ReadServlet(DatabaseController database) {
super();
this.database = database;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
writeHeader(out);
if (request.getParameter("chl") != null) {
if ((undoChallenge == Integer.parseInt(request.getParameter("chl"))) && (lastId == Integer.parseInt(request.getParameter("del")))) {
try {
database.deleteTransaction(lastId);
} catch (SQLException se) {
throw new ServletException(se);
}
showMessage(out, "Transaktion gelöscht.");
}
else if (auslagenChallenge == Integer.parseInt(request.getParameter("chl"))) {
try {
database.resetExpenses(Integer.parseInt(request.getParameter("id")));
} catch (SQLException se) {
throw new ServletException(se);
}
showMessage(out, "Auslagen zurückgesetzt.");
}
undoChallenge = -1;
auslagenChallenge = -1;
}
showInputForm(out);
showTable(database, 10, out);
showAuslagen(out);
writeFooter(out);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
boolean error = false;
String errorMessage = null;
// der Betrag kann mit Punkt oder Komma als Dezimalzeichen eingegeben werden
String betragStr = StringUtils.replaceChars(request.getParameter("betrag"), ',', '.');
// wenn kein Vorzeichen angegeben wurde, nehmen wir eine Ausgabe an
// und setzen den Betrag negativ
if (!(betragStr.startsWith("-") || betragStr.startsWith("+"))) {
betragStr = "-" + betragStr;
}
BigDecimal betrag = null;
try {
betrag = new BigDecimal(betragStr);
if (betrag.compareTo(BigDecimal.valueOf(0)) == 0)
error = true;
}
catch (NumberFormatException nfe) {
error = true;
}
if (error)
errorMessage = "<span style='color: red;'>Fehler: </span> &quot;" + request.getParameter("betrag") + "&quot; ist kein zulässiger Betrag.";
Date datum = null;
try {
datum = formatter.parse(request.getParameter("datum"));
} catch (ParseException pe) {
error = true;
errorMessage = "<span style='color: red;'>Fehler:</span> &quot;" + request.getParameter("datum") + "&quot; ist kein zulässiges Datum.";
}
if (!error) {
Transaktion transaction = new Transaktion(betrag, Integer.parseInt(request.getParameter("kategorie")), datum, request.getParameter("beschreibung"), (database.hasAuslagen ? Integer.parseInt(request.getParameter("auslage")) : 0));
try {
lastId = database.writeTransaction(transaction);
} catch (SQLException se) {
throw new ServletException(se);
}
}
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
writeHeader(out);
if (!error)
showLastTransaction(out);
else
showMessage(out, errorMessage);
showInputForm(out);
showTable(database, 10, out);
showAuslagen(out);
writeFooter(out);
}
private void showInputForm(PrintWriter out) throws ServletException {
SortedMap<Integer, String> categories;
try {
categories = database.getCategories();
} catch (SQLException e) {
throw new ServletException(e);
}
out.println("<form action='" + database.path + "' method='post' style='text-align: center;'><table border='0' cellpadding='1' style='margin:auto;'>");
out.println("<tr><td align='right'>Betrag:</td><td align='left'><input name='betrag' type='text' size='10' maxlength='10' style='font-size:100%' /></td></tr>");
out.println("<tr><td align='right'>Kategorie:</td><td align='left'><select name='kategorie' size='1' style='width: 23ex; font-size:100%'>");
for (Map.Entry<Integer, String> category : categories.entrySet()) {
if (category.getKey() == 4) {
out.println("<option selected='selected' value='" + category.getKey() + "'>" + StringEscapeUtils.escapeHtml4(category.getValue()) + "</option>");
}
else {
out.println("<option value='" + category.getKey() + "'>" + StringEscapeUtils.escapeHtml4(category.getValue()) + "</option>");
}
}
out.println("</select></td></tr>");
out.println("<tr><td align='right'>Datum:</td><td align='left'><input name='datum' type='text' size='10' maxlength='10' value='" + formatter.format(new Date()) + "' style='font-size:100%' /></td></tr>");
out.println("<tr><td align='right'>Notiz:</td><td align='left'><input name='beschreibung' type='text' size='25' maxlength='255' style='font-size:100%' /></td></tr>");
if (database.hasAuslagen)
out.println("<tr><td align='right'>Auslage:</td><td align='left'><input name='auslage' type='radio' value='0' checked='checked' />&nbsp;Keine&nbsp;&nbsp;&nbsp;<input name='auslage' type='radio' value='1' />&nbsp;Tilman&nbsp;&nbsp;&nbsp;<input name='auslage' type='radio' value='2' />&nbsp;Anica</td></tr>");
out.println("<tr><td align='center' colspan='2'><input type='submit' value='Absenden' /></td></tr></table>");
out.println("</form>");
}
private void showAuslagen(PrintWriter out) throws ServletException {
if (database.hasAuslagen) {
auslagenChallenge = rnd.nextInt(Integer.MAX_VALUE);
out.println("<table border='0' cellpadding='3' style='margin:auto; margin-top: 2em; font-size: 80%; border-collapse:collapse;'>");
try {
out.println("<tr><td>Auslagen Anica </td><td align=\"right\">" + database.getSumExpenses(2) + "&nbsp;€</td><td><span style='color: red; font-weight: bold;'><a href='" + database.path + "?id=2&chl=" + auslagenChallenge + "'>überwiesen</a></span></td>");
out.println("<tr><td>Auslagen Tilman </td><td align=\"right\">" + database.getSumExpenses(1) + "&nbsp;€</td><td><span style='color: red; font-weight: bold;'><a href='" + database.path + "?id=1&chl=" + auslagenChallenge + "'>überwiesen</a></span></td>");
} catch (SQLException se) {
throw new ServletException(se);
}
out.println("</table>");
}
}
private void showLastTransaction(PrintWriter out) throws ServletException {
Transaktion trns = null;
try {
trns = database.getLastTransaction();
} catch (SQLException e) {
throw new ServletException(e);
}
out.println("<div style='text-align: center; font-size: 80%; font-weight: bold; padding: 0.5ex; background-color: lightgray; width: 25em; margin:auto; margin-bottom: 3em;'>");
out.println("gespeichert: ");
out.print(trns.datum + " ");
if (trns.betrag.compareTo(BigDecimal.valueOf(0)) < 0) {
out.print("<span style='color: red;'>");
}
else {
out.print("<span style='color: green;'>");
}
out.println(trns.betrag.toPlainString() + "&nbsp;€</span>");
undoChallenge = rnd.nextInt(Integer.MAX_VALUE);
out.println("&nbsp;&nbsp;&nbsp;<span style='color: red; font-weight: bold;'><a href='" + database.path + "?del=" + trns.id + "&chl=" + undoChallenge + "'>löschen</a></span>");
out.println("</div>");
}
private void showMessage(PrintWriter out, String message) {
out.println("<div style='text-align: center; font-weight: bold; padding: 0.5ex; border: 2px dotted red; background-color: lightgray; width: 25em; margin:auto; margin-bottom: 3em;'>");
out.println(message);
out.println("</div>");
}
}
public class StatsServlet extends HttpServlet {
private static final long serialVersionUID = 4104919572342151480L;
private DatabaseController database;
public StatsServlet(DatabaseController database) {
super();
this.database = database;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
writeHeader(out);
showTable(database, ((request.getParameter("n") != null) ? Integer.parseInt(request.getParameter("n")) : 20), out);
writeFooter(out);
}
}
public class CsvServlet extends HttpServlet {
private static final long serialVersionUID = 4104919572342151480L;
private DatabaseController database;
public CsvServlet(DatabaseController database) {
super();
this.database = database;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
char separator = ';';
if (request.getParameter("separator") != null) {
separator = request.getParameter("separator").charAt(0);
}
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
writeHeader(out);
out.println("<pre>");
out.println("ID" + separator + "Datum" + separator + "Kategorie" + separator + "Betrag" + separator + "Beschreibung");
List<Transaktion> transactions = null;
try {
transactions = database.getLastTransactions(((request.getParameter("n") != null) ? Integer.parseInt(request.getParameter("n")) : 50));
} catch (SQLException se) {
throw new ServletException(se);
}
for (Transaktion t : transactions) {
String s = "" + t.id + separator + formatter.format(t.datum) + separator + StringEscapeUtils.escapeHtml4(t.kategorieName) + separator + t.betrag.toPlainString() + separator + ((t.beschreibung == null) ? "" : StringEscapeUtils.escapeHtml4(t.beschreibung));
System.out.println(s);
out.println(s);
}
out.println("</pre>");
writeFooter(out);
}
}
class ShutdownThread extends Thread {
DatabaseController database;
public ShutdownThread(DatabaseController database) {
this.database = database;
}
public void run() {
try {
database.close();
} catch (SQLException se) {
log.error(se);
}
}
}
public static void main(String[] args) {
Service service = new Service();
service.start();
}
}
+32
View File
@@ -0,0 +1,32 @@
package de.tilman.transactions;
import java.math.BigDecimal;
import java.util.Date;
public class Transaktion {
public int id;
public BigDecimal betrag;
public int kategorie;
public String kategorieName;
public Date datum;
public String beschreibung;
public int auslage;
public Transaktion(int id, BigDecimal betrag, int kategorie, Date datum, String beschreibung, int auslage) {
this.id = id;
this.betrag = betrag;
this.kategorie = kategorie;
this.datum = datum;
this.beschreibung = beschreibung;
this.auslage = auslage;
}
public Transaktion(int id, BigDecimal betrag, int kategorie, String kategorieName, Date datum, String beschreibung, int auslage) {
this(id, betrag, kategorie, datum, beschreibung, auslage);
this.kategorieName = kategorieName;
}
public Transaktion(BigDecimal betrag, int kategorie, Date datum, String beschreibung, int auslage) {
this(-1, betrag, kategorie, datum, beschreibung, auslage);
}
}
+18
View File
@@ -0,0 +1,18 @@
package org.example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello Servlet</h1>");
response.getWriter().println("session=" + request.getSession(true).getId());
}
}
+32
View File
@@ -0,0 +1,32 @@
package org.example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
public class HelloWorld extends AbstractHandler {
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException,
ServletException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<pre>Aloha,\nfunky time</pre>");
Request base_request = (request instanceof Request) ? (Request)request:HttpConnection.getCurrentConnection().getRequest();
base_request.setHandled(true);
}
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
server.setHandler(new HelloWorld());
server.start();
server.join();
}
}
+2
View File
@@ -0,0 +1,2 @@
<h1>Hello World Webapp</h1>
<a href="/hello">Hello Servlet</a>
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>org.example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
</web-app>