4. November 2011 von Oliver Fischer in Java, Java Code Beispiele
Auf Bitte einiger Teilnehmer unseres gestrigen Vortrags mit Arno Haase zu Scala in der Praxis ist hier der Quelltext.
package a
sealed abstract class Expr
case class IntExpr (i: Int) extends Expr
case class VarExpr (name: String) extends Expr
case class BinExpr (left: Expr, right: Expr, op: String) extends Expr
object Expr {
def eval (e: Expr, vars: Map[String, Int]): Int = e match {
case IntExpr (i) => i
case VarExpr (v) => vars(v)
case BinExpr (left, right, "+") => eval (left, vars) + eval (right, vars)
case BinExpr (left, right, "*") => eval (left, vars) * eval (right, vars)
}
}
class ExprWithSyntax (e: Expr) {
def + (other: Expr) = BinExpr (e, other, "+")
def * (other: Expr) = BinExpr (e, other, "*")
def apply (vars: (String, Int)*) = {
val m = vars.foldLeft (Map[String, Int]()) ((res, cur) => res + cur)
Expr.eval (e, m)
}
}
object ExpressionSyntax {
implicit def intAsExpr (i: Int) = IntExpr (i)
implicit def withSyntax (e: Expr) = new ExprWithSyntax (e)
implicit def intWithSyntax (i: Int) = new ExprWithSyntax (IntExpr (i))
def Var (s: String) = VarExpr (s)
}
object HelloMain {
def main (args: Array[String]) {
import ExpressionSyntax._
val e = 5 * (3 + Var ("x"))
// println (Expr.eval (e, Map ("x" -> 2)))
println (e ("x" -> 2))
}
}
9. Juni 2010 von Jan Lolling in Java, Java Code Beispiele
Ant ist ein überaus mächtiges Werkzeug für die Automatisierung und Sicherstellung des build-Prozesses in immer gleicher Qualität. Zudem ist es sehr leicht anpassbar und erweiterbar.
Hier ein paar Beispiele aus der Java User Group:
Diese Task sind als Binaries und Source code verfügbar und stehen unter der GPL. Da diese Libs nicht in Produkte integriert werden stellt die GPL auch kein Problem für den kommerziellen Einsatz dieser Task dar.
Diese Task sind bereits im produktiven Einsatz in aktuell 3 Projekten (1 Open Source Projekt und 2 Individual Projekte für kommerzielle Zwecke).
Viel Spass beim Ausprobieren.
Wir freuen uns über Anregungen und Kommetare: jan dot lolling at googlemail dot com.
5. April 2010 von Jan Lolling in Java, Java Code Beispiele
Schlagwörter: Oracle JDBC Meta data
Das Konstrukt der Packages wird durch JDBC nicht wirklich gut unterstützt. JDBC geht leider auch von eindeutigen Namen für functions und procedures aus. Somit hat man ein Problem mit überladenen procedures. Diese unterscheiden sich nicht im Namen sondern in der Anzahl und Typen der Parameter.
Der Oracle-JDBC-Treiber gibt alle Informationen raus, es erfordert nur etwas Geschick diese Informationen einzusammeln.
1. Die Name der packages werden als CATALOG ausgegeben.
2. Die Parameter kennen ihren Index. Wenn ein Parameter für scheinbar die selbe procedure erscheint mit dem gleichen Index, dann ist das ein Zeichen für eine überladene procedure.
Der folgende Beispielcode geht davon aus, dass die procedures und functions in speziellen Objekten gehalten werden und die Parameter besitzen auch ihre eigene Transferklasse.
/**
* load procedure and functions
*
* @param schema
* object that represent a schema
* @return true if everything went well
*/
public boolean loadProcedures(SQLSchema schema) {
if (logger.isDebugEnabled()) {
logger.debug("loadProcedures schema=" + schema);
}
// makes this thread save
inRefreshCycle = true;
boolean ok = false;
// don' worry about that, we use our own database pool
final DatabaseSession session = DatabaseSessionPool.getDatabaseSession(cd.getUniqueId());
if (session == null) {
// return if no connection to database avialable
return false;
}
try {
Connection conn = session.getConnection();
DatabaseMetaData dbmd = conn.getMetaData();
schema.clearProcedures(); // remove any previously loaded procedures
ResultSet rs = dbmd.getProcedures(null, schema.getName(), null);
if (rs != null) {
// loading all procedures and functions
while (rs.next()) {
// PROCEDURE_CAT contains the package name
String catalogName = rs.getString("PROCEDURE_CAT");
String name = rs.getString("PROCEDURE_NAME");
if (catalogName != null && catalogName.length() > 0) {
name = catalogName + "." + name;
}
// create an new one
SQLProcedure procedure = new SQLProcedure(this, schema, name);
// decide if it is a function
short pType = rs.getShort("PROCEDURE_TYPE");
procedure.setFunction(pType == DatabaseMetaData.procedureReturnsResult);
schema.addProcedure(procedure);
objectMap.put(name, procedure);
}
rs.close();
}
// loading procedure/function parameters
rs = dbmd.getProcedureColumns(null, schema.getName(), null, null);
if (rs != null) {
// an index for overloaded procedures
int procedureIndex = 0;
String prevProcedureName = "noprocedurehere_xx";
while (rs.next()) {
// PROCEDURE_CAT contains the package name
String catalogName = rs.getString("PROCEDURE_CAT");
String name = rs.getString("PROCEDURE_NAME");
if (catalogName != null && catalogName.length() > 0) {
// add the catalog name as package name
name = catalogName + "." + name;
}
int pos = 0;
try {
// position of this parameter in the procedure parameter
// list
pos = rs.getInt("ORDINAL_POSITION");
} catch (Exception e) {
// perhaps this column is not defined in every database
// type
pos = -1;
}
if (prevProcedureName.equals(name)) {
if (pos == 0) {
// if we get the same procedure name and a parameter
// with position zero increase the procedure index
// that means point to the next procedure with the
// same name
procedureIndex++;
}
} else {
procedureIndex = 0;
}
String columnName = rs.getString("COLUMN_NAME");
List list = schema.getProcedures(name);
SQLProcedure procedure = list.get(procedureIndex);
if (procedure != null) {
procedure.addParameter(columnName, // parameter name
rs.getShort("DATA_TYPE"), // parameter type as
// integer defined
// in class
// java.sql.Type
rs.getString("TYPE_NAME"), // parameter type as
// string
rs.getInt("LENGTH"), // length of the parameter
// if parameter is
// string or number type
rs.getInt("PRECISION"), // precision of the
// parameter if the
// parameter is a number
// type
rs.getShort("COLUMN_TYPE")); // input or output
// parameter as
// integer:
// refer
// DatabaseMetaData.procedureColumnReturn
}
// keep the name of the last procedure to detect overloaded
// procedures
prevProcedureName = name;
}
rs.close();
}
schema.setProcedureLoaded();
ok = true;
} catch (SQLException sqle) {
// creates a error message to show it in GUI
errorMessage = "loadProcedures schema=" + schema + " failed: "
+ sqle.getMessage();
} finally {
// put the session back in the pool
DatabaseSessionPool.release(session);
}
inRefreshCycle = false;
return ok;
}
21. Mai 2009 von Jan Lolling in Java, Java Code Beispiele
Debian packages sind so ziemlich das eleganteste was es an Verteilungsmechanismen für Software gibt. Diese Art der Softwareverteilung steht auch für Java-Anwendungen zur Verfügung. Idealerweise macht man das innerhalb des build-Prozesses z.B. in Ant.
Hier wird nun kurz ein sehr hilfreicher Ant-Task vorgestellt.
Für eine Desktop-Anwendung unter Linux werden zum einen die eigentlichen Programm-Dateien benötigt als auch eine Datei (.desktop) die das Programm in den Menüs von KDE oder Gnome bekannt macht und zudem den Komfort bietet das Programm auch gleich für die Behandlung von Mimetypes zu registrieren. Es ist also kein Fummeln an irgendeiner Registry erforderlich, diese Zuordnung steht in der desktop-Datei und Gnome/KDE erkennen das automatisch.
Hier der Link zu dem Ant-Task bei Google-Code
Es sind genau genommen 2 Ant-Tasks erforderlich:
- desktopentry erstellt die .desktop-Datei
- deb erstellt das Debian-Archiv
Beide sind im Projekt sehr gut dokumentiert.
Hier ein Beispiel-Ant-task:
<target name="deb" depends="jar" description="build the i386 deb file">
<delete failonerror="false" >
<fileset dir="${distrib}">
<include name="sqlrunner*.deb" />
<include name="sqlrunner*.desktop" />
</fileset>
</delete>
<taskdef name="desktopentry" classname="com.googlecode.ant_deb_task.DesktopEntry"/>
<desktopentry
toFile="${distrib}/sqlrunner.desktop"
name="SQLRunner"
comment="Database SQL Client"
icon="/usr/local/sqlrunner/sqlrunner.png"
exec="/usr/local/sqlrunner/sqlrunner.sh %f"
type="Application"
terminal="false"
mimeType="text/x-sql"
path="/usr/local/sqlrunner"
categories="Development;"
/>
<taskdef name="deb" classname="com.googlecode.ant_deb_task.Deb"/>
<deb
todir="${distrib}"
package="sqlrunner"
section="devel"
architecture="all"
depends="sun-java5-jre|sun-java6-jre">
<version upstream="${version}"/>
<maintainer name="Jan Lolling" email="jan.lolling@mac.com"/>
<description synopsis="Java based database client">
SQLRunner is a Java programm to handle database with a easy to use SQL interface.
.
The SQLRunner has advanced import and export capabilities.
.
SQLRunner ships with a large number of JDBC driver (e.g. Oracle, Postgres, DB2, MS-SQL, Informix, Derby, Sybase, MaxDB, MySQL).
.
Download at SourceForge:
.
http://sourceforge.net/projects/jugbbsqlrunner/
.
Homepage for Java Web Start:
.
http://web.me.com/jan.lolling/SQLRunner/SQLRunner.html
</description>
<tarfileset dir="${lib}" prefix="usr/local/sqlrunner">
<include name="hsqldb.jar" />
<include name="ifxjdbc.jar" />
<include name="jconn3.jar" />
<include name="ldapjdbc.jar" />
<include name="ojdbc14.jar" />
<include name="sqljdbc.jar" />
<include name="mssql2000_jdbc.jar" />
<include name="mysql-connector-java-5.1.5-bin.jar" />
<include name="postgresql-8.2-506.jdbc2.jar" />
<include name="sapdbc-7_6_00_30_5567.jar" />
<include name="looks-2.1.4.jar" />
<include name="liquidlnf.jar" />
<include name="log4j-1.2.15.jar" />
<include name="servlet.jar" />
<include name="ui.jar" />
<include name="derby.jar" />
<include name="db2jcc4.jar" />
<include name="db2jcc_license_cu.jar" />
<include name="poi-3.1-FINAL-20080629.jar" />
<include name="jnlp.jar" />
</tarfileset>
<tarfileset file="${distrib}/sqlrunner2.jar" prefix="usr/local/sqlrunner"/>
<tarfileset file="${src}/sqlrunner.png" prefix="usr/local/sqlrunner"/>
<tarfileset file="${src}/sqlrunner.sh" prefix="usr/local/sqlrunner" filemode="755"/>
<tarfileset file="${distrib}/sqlrunner.desktop" prefix="usr/share/applications"/>
</deb>
</target>
Hinweise zum desktopentry-Task:
Da man leider nicht direkt die Extention einer Datei referenzieren kann, muss man wenn man sein Programm für einen Dateityp registrieren lassen will erst den passenden mime-type finden. Gnome war so nett in den Dateiattributen z.B. für SQL-Scripte den mime-type text/x-sql zu nennen.
Das Attribute “categories” beschreibt in welchem Menü später der Eintrag auftauchen soll. Es gibt festgelegte Hauptmenüpunkte – diese werden englisch vorgegeben.
Hinweise zum deb-Task:
Bei der Synopsis ist zu beachten, dass der Punkt in eigener Zeile eine Leerzeile provoziert ohne den Punkt selbst darzustellen.
Besonders hervorzuheben ist das depends-Attribute. Hier kann man z.B. vorgeben welche packages zuvor installiert werden müssen (was dann auch automatisch getan wird. Im Fall von Java-Anwendungen sichern wir hier die Existenz der virtuellen Maschiene ab. Das Pipe ist als Oder-Verknüpfung zu verstehen.
Ein deb-Archiv ist im Grunde sehr einfach. Es enthält die Dateien genauso wie sie auf dem Zielsystem auch vorhanden sein sollen. Die tarfilesets enthalten also hier alle notwendigen Dateien (inklusive der zuvor erstellten desktop-Datei). Die Pfadangaben sind allesamt relativ zu / (deshalb fehlt irritierenderweise das /-Symbol -> Kein Fehler !)
7. Februar 2009 von Jan Lolling in Java, Java Code Beispiele
Schlagwörter: Java, SQL, Sun
Ich habe für meinen Editor eine Möglichkeit gesucht die aktuelle Zeile unter dem Cursor vollständig mit einer anderen Hintergrundfarbe hervorzuheben. Diese Möglichkeit habe ich folgendermassen realisiert:
Zusammenfassung:
Der JEditorPane füge ich einen speziellen CaretListener hinzu der bei Veränderungen des Cursors einen wiederum für die aktuelle Zeile einen Highlighter einrichtet. Das besondere ist der als innere Klasse realisierte HightlighterPainter. Dieser ist so entwickelt, dass er die ganze Zeile unabhängig von der Zeichenanzahl also auf die sichtbare Breite des Editors hervorhebt.
Hier nun der Quelltext des CaretListeners:
package sqlrunner.text;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.Position;
import javax.swing.text.Utilities;
import javax.swing.text.View;
public class HighlightCurrentLineCaretListener implements CaretListener {
static final Color DEFAULT_COLOR = new Color(230, 230, 250);
private Highlighter.HighlightPainter painter;
private Object highlight;
public HighlightCurrentLineCaretListener() {
this(null);
}
public HighlightCurrentLineCaretListener(Color highlightColor) {
Color c = highlightColor != null ? highlightColor : DEFAULT_COLOR;
this.painter = new LineHighlightPainter(c);
}
public void caretUpdate(CaretEvent evt) {
final JTextComponent comp = (JTextComponent) evt.getSource();
if (comp != null && this.highlight != null) {
comp.getHighlighter().removeHighlight(this.highlight);
this.highlight = null;
}
int pos = comp.getCaretPosition();
final Element elem = Utilities.getParagraphElement(comp, pos);
int start = elem.getStartOffset();
int end = elem.getEndOffset();
try {
this.highlight = comp.getHighlighter().addHighlight(start,
end,
this.painter);
comp.repaint();
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
/**
* Simple highlight painter that fills a highlighted area with
* a solid color.
*/
public static class LineHighlightPainter extends
LayeredHighlighter.LayerPainter {
private Color color;
/**
* Constructs a new highlight painter. If <code>c</code> is null,
* the JTextComponent will be queried for its selection color.
*
* @param c
* the color for the highlight
*/
public LineHighlightPainter(Color c) {
this.color = c;
}
/**
* Returns the color of the highlight.
*
* @return the color
*/
public Color getColor() {
return this.color;
}
// --- HighlightPainter methods ---------------------------------------
/**
* Paints a highlight.
*
* @param g
* the graphics context
* @param offs0
* the starting model offset >= 0
* @param offs1
* the ending model offset >= offs1
* @param bounds
* the bounding box for the highlight
* @param c
* the editor
*/
public void paint(Graphics g, int offs0, int offs1, Shape bounds,
JTextComponent c) {
final Rectangle alloc = bounds.getBounds();
try {
// --- determine locations ---
TextUI mapper = c.getUI();
final Rectangle p0 = mapper.modelToView(c, offs0);
final Rectangle p1 = mapper.modelToView(c, offs1);
// --- render ---
if (getColor() == null) {
g.setColor(c.getSelectionColor());
} else {
g.setColor(getColor());
}
final Rectangle r = p0.union(p1);
g.fillRect(r.x, r.y, r.width, r.height);
} catch (BadLocationException e) {
// can't render
}
}
// --- LayerPainter methods ----------------------------
/**
* Paints a portion of a highlight.
*
* @param g
* the graphics context
* @param offs0
* the starting model offset >= 0
* @param offs1
* the ending model offset >= offs1
* @param bounds
* the bounding box of the view, which is not
* necessarily the region to paint.
* @param c
* the editor
* @param view
* View painting for
* @return region drawing occured in
*/
@Override
public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds,
JTextComponent c, View view) {
if (getColor() == null) {
g.setColor(c.getSelectionColor());
} else {
g.setColor(getColor());
}
// Should only render part of View.
try {
// --- determine locations ---
Shape shape = view.modelToView(
offs0,
Position.Bias.Forward,
offs1,
Position.Bias.Backward,
bounds);
Rectangle r = shape instanceof Rectangle ? (Rectangle) shape
: shape.getBounds();
g.fillRect(r.x, r.y, c.getWidth(), r.height);
return r;
} catch (BadLocationException e) {
// can't render
}
return null;
}
}
}
Diesen CaretListener muss man nun mit:
textComp.addCaretListener(new HighlightCurrentLineCaretListener());
der Textkomponente hinzufügen. Hat bei mir ausgezeichnet funktioniert. Ich habe diesen Code unter Mac OS X und Windows getestet und er läuft abwärts bis Java 5.