Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen

Montag, 24. Juni 2024

Search for a packaged jar in JFrog

 It always takes me some time in JFrog to find out where specific jars are used, so here a short instruction:


1. Go to Artifacts:




2. Open the filter and choose Type "Archive"

3. Put the name or part of the name of the jar, that usage you want to find out, into the name field:


That's it.



Mittwoch, 25. Oktober 2023

Primefaces dialog stopped working after migration from 11 to 12

JSF 2.1.19 
Primefaces 12.0 

 After migrating Primefaces from 11 to 12 the dialog buttons (yes and no) stopped working, the action in the underlying commandButton was not called anymore. The problem was solved with adding the attribute type="button" to the confirmDialog


Donnerstag, 13. April 2023

Migrate to Spring Boot 3, but stay with jaxws-api 2.3.1

There are good guides (Spring Boot 3.0 Migration Guide) to migrate a Spring Boot 2.7.x project to 3.0.x, but in my case I got some technical debt from jaxws.

The project consumes a lot of different services (soap, rest) where the generated code is capsuled in a little jar. This jars are used by some other projects, so I could not touch them. This means the project has to use jaxws-api 2.3.1.

I got a lot of errors when following the normal migration guides with the jaxb stuff which all could be solved with the proper dependencies.

Dependencies before migration:


     	<dependency>
            <groupid>javax.xml.ws</groupid>
            <artifactid>jaxws-api</artifactid>
        </dependency>
        <dependency>
            <groupid>com.sun.xml.ws</groupid>
            <artifactid>rt</artifactid>
            <version>2.3.2</version>
            <exclusions>
                <!--this is excluded to have fewer log entries on startup-->
                <exclusion>
                    <artifactid>ha-api</artifactid>
                    <groupid>org.glassfish.ha</groupid>
                </exclusion>
            </exclusions>
        </dependency>

After a lot of trail and error I came up with the following solution:

        <dependency>
            <groupId>javax.xml.ws</groupId>
            <artifactId>jaxws-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <!-- needed for java.lang.ClassNotFoundException: com.sun.xml.bind.api.JAXBRIContext -->
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.messaging.saaj</groupId>
            <artifactId>saaj-impl</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.jvnet.staxex</groupId>
            <artifactId>stax-ex</artifactId>
            <version>1.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>rt</artifactId>
            <version>2.3.1</version>
            <exclusions>
                <!-- this is excluded to have fewer log entries on startup -->
                <exclusion>
                    <artifactId>ha-api</artifactId>
                    <groupId>org.glassfish.ha</groupId>
                </exclusion>
            </exclusions>
        </dependency>


Mittwoch, 13. November 2013

WSDL Location im generierten WebServiceClient passt nicht

Maven 3.0.4
jaxws-maven-plugin 2.1

Generiert man sich aus einem wsdl mit Maven über jaxws-maven-plugin den Client bastelt er einen einen schönen Konstruktor für den Aufruf des Services, der auch funktioniert, wenn man ihn an Ort und Stelle ausprobiert.

Deployed man das dann jedoch auf einen Server geht nichts mehr:
ERROR MyServiceImpl - Service method 'public abstract MyClass myMethod()' threw an unexpected exception: javax.xml.ws.WebServiceException: The following WSDL exception occurred: WSDLException: faultCode=WSDL4JWrapper : : javax.wsdl.WSDLException: WSDLException: faultCode=WSDL4JWrapper : : java.io.FileNotFoundException: unsinnigerPfadzurWSDL (A file or directory in the path name does not exist.)
Der Pfad wird irgendwie unsinnig zusammengesetzt, weil man den default Konsturktor des Services verwendet hat, es gibt aber noch einen zweiten:
MyWebService(URL wsdlLocation, QName serviceName)
Hier kann man sich den Pfad nun selber zusammenbasteln:
MyWebService svc = new MyWebService (WebServiceUtil.class.getClassLoader().getResource("wsdl/MyWSDL.wsdl"), new QName(diesen Teil aus dem default Konstruktor einfach kopieren));
Auf diese Weise wird das wsdl File immer gefunden, egal wo man das Projekt deployed.



Donnerstag, 28. Februar 2013

GWT: TabLayoutPanel wird im IE nicht angezeigt

GWT 2.5

Immer wieder der IE, diesmal in allen von mir getesteten Versionen (7, 8, 9, 10).
Die Tableiste wurde nicht angezeigt, Lösung war bei der Erzeugung des TabLayoutPanel die Unit nicht in EM sondern in PX anzugeben. Gefunden habe ich die Lösung hier: Google Code - Issue 6506: TabLayoutPanel UiBinder Tabs aren't displayed in IE9

Montag, 25. Februar 2013

GWT: SuggestBox und Tabulator KeyStroke in der CellTable

GWT 2.5

In letzter Zeit handelten meine Beiträge größtenteils von CellTable und SuggestBox und auch diesmal geht es so weiter. Folgende Problemstellung: Ich habe in der Table die Möglichkeit geschaffen daß man mit Tab-Sprüngen die Zellen wechselt, hier der Link dazu wie man das macht: stackoverflow Frage + Antwort.

Nun ist es aber mal so, das wenn man mit Tab die Zelle wechselt der KeyUp Event schon in der neuen Zelle stattfindet und hier beginnen die Probleme: Die SuggestBox glaubt durch das KeyUp das der User etwas in der TextBox verändert hat und läuft gleich mal los um Vorschläge einzuholen... für meine Erfordernisse ganz und gar unnötig bzw. will ich nicht daß der im Feld stehende Wert gleich mal dazu verwendet wird Services aufzurufen.

Die SuggestBox behandelt das in der privaten Methode addEventsToTextBox(), und da privat kann man das Teil nicht einfach überschreiben. Eine Möglichkeit ist es nun die gesamte Klasse zu kopieren und bei der Behandlung des KeyUp Events den Tab KeyStroke daran zu hindern die Methode refreshSuggestions() aufzurufen. Das funktioniert, nur ist das Kopieren ganzer Klassen für eine Zeile Änderung und die Übernahme der Package Struktur (notwendig weil die SuggestBox auf protected Teile im Package com.google.gwt.user.client.ui zugreift) einfach nur gruselig.

Ich habe mich deshalb entschlossen der TextBox einen KeyUpHandler hinzuzufügen der der Textbox die Möglichkeit gibt sich zu merken welcher Key losgelassen wurde. Das verwende ich nun in meinem SuggestOracle in der Methode requestSuggestions. Den gesamten Code der Implementierung kann man sich  aus meinen vorherigen Beiträgen zusammenreimen, hier die aktuell nötigen Änderungen damit das ganze klappt:

Hier die erweiterte TextBox die ich dann zum Erzeugen meiner SuggestBox verwende:

 private class MyTextBox extends TextBox {
  public int currentKeyUpStroke;
  private MyTextBox(Element element) {
   super(element);
   this.addKeyUpHandler(new KeyUpHandler() {
    @Override
    public void onKeyUp(KeyUpEvent event) {
     MyTextBox.this.currentKeyUpStroke = event.getNativeKeyCode();
    }
   });
  }
  public int getCurrentKeyUpStroke() {
   return currentKeyUpStroke;
  }
 }


Und hier die Stelle wo ich, bevor ich meine Services aufrufe, überprüfe ob nicht etwa ein Tab der Auslöser des ganzen war:

 private SuggestOracle getSuggestOracle() {
  final SuggestOracle so = new SuggestOracle() {

   @Override
   public void requestSuggestions(final Request request, final Callback callback) {

    if (request.getQuery().length() > 3
      && ((MyTextBox) RegeldatenTextInputCell.this.suggestBox.getTextBox()).getCurrentKeyUpStroke() != KeyCodes.KEY_TAB) {




Freitag, 15. Februar 2013

GWT: SuggestBox in CellTable -> Auswahl per Maus klappt nicht.

GWT 2.5

In diesem Post habe ich eine SuggestBox mit einer Cell in einer CellTable verbunden, das klappte auch überraschend gut. Man konnte einen Vorschlag auswählen und der würde auch übernommen. Nur klappte das leider nur mit den Pfeiltasten und einer Enter Bestättigung, wollte man per Maus auswählen wurde der Wert einfach nicht übernommen.

Analog zu diesem Problem gibt es ein bisschen etwas im Netz zu finden, aber wirklich den Durchbruch brachte keiner der Tips:

codinginthetrenches.com: catching value change events from the gwt suggestbox
Google Code: google-web-toolkit: SuggestBox OnChange fired before suggestion text is set

Ich brachte das Teil endlich dazu die Maus Auswahl zu schlucken, aber nun nahm er die Pfeil/Enter Auswahl nicht mehr an, dazu die Codezeilen die in der onBrowserEvent Methode in meiner schon sehr erweiterten TextInputCell:


if (BrowserEvents.FOCUS.equals(eventType) && (isUserid || isUseridStrict || connectedUserid != null)) {
   TextBox textBox = new MyTextBox(getInputElement(parent));
   suggestBox = new MySuggestBox(getSuggestOracle(), textBox);
   suggestBox.onAttach();

   suggestBox.addSelectionHandler(new SelectionHandler<Suggestion>() {
    @Override
    public void onSelection(SelectionEvent<Suggestion> event) {
     final String selected = event.getSelectedItem().getReplacementString();
     ValueChangeEvent.fire(suggestBox, selected);
    }
   });
   suggestBox.addValueChangeHandler(new ValueChangeHandler<String>() {

    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
     valueUpdater.update(event.getValue());
     suggestBox.setValue(event.getValue());
    }
   });
  }

Ich hatte soweit herausgefunden daß ich den valueUpdater benutzen musste damit die Table überhaupt mitbekommt daß ich etwas verändert habe, bei der Pfeil/Enter Auswahl kam das aber gar nicht gut an, aus welchem Grund auch immer nahm nun diese keine Auswahl mehr, wenn wer eine Erklärung dafür hat, ich würde mich freuen.

Mein größtes Problem war, wie unterscheide ich im Valuechangehandler ob ich durch einen Mausklick oder durch Pfeil/Enter updaten will? Schlussendlich hab ich dann irgendwann geschnallt dass wenn ich mit Pfeil/Enter in die onValueChange Methode rutsche den Value der suggestBox schon irgendwo gesetzt hatte, wenn also der Wert des Events und der in der suggestBox gleich sind brauche ich den valueUpdater nicht mehr zu bemühen, bzw. darf ihn gar nicht anwerfen, da sonst ja meine Pfeil/Enter Auswahl nicht mehr funktioniert:


suggestBox.addValueChangeHandler(new ValueChangeHandler<String>() {

    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
     if (!suggestBox.getValue().equals(event.getValue())) {
      valueUpdater.update(event.getValue());
     }
     suggestBox.setValue(event.getValue());
    }
   });


Nachtrag 21.2.2013:

Leider funktioniert meine Lösung nicht für den IE8, darum hier Änderungen die mit dem aktuellen Chrome, FF und IE8 funktionieren, aber imho noch viel lausiger sind als die ursprünglich schon sehr dreckige Lösung:


suggestBox.addSelectionHandler(new SelectionHandler<Suggestion>() {
    @Override
    public void onSelection(SelectionEvent<Suggestion> event) {
     final String selected = event.getSelectedItem().getReplacementString();
     if (nativeEvent.getType().equals(BrowserEvents.CLICK)
       || !Window.Navigator.getUserAgent().contains("MSIE 8.0")) {
      ValueChangeEvent.fire(suggestBox, selected);
     }
    }
   });

   suggestBox.addValueChangeHandler(new ValueChangeHandler<String>() {

    @Override
    public void onValueChange(ValueChangeEvent<String> event) {
     if (!event.getValue().equals(suggestBox.getValue()) || Window.Navigator.getUserAgent().contains("MSIE 8.0")) {
      valueUpdater.update(event.getValue());
     }
    }
   });


nativeEvent ist einfach der Parameter der onBrowserEvent Methode.

Freitag, 1. Februar 2013

GWT Celltable: Bestimmte Input Felder in einer Zeile verstecken

GWT 2.5

Die Zellen einer Celltable werden ja normalerweise in über die Column definiert, allerdings kann es ja sein dass bestimmte Zellen in einer Zeile "anders" sein sollen. In meinem Fall wollte ich zeilenabhängig bestimmte Felder verstecken, der Rest sollten ganz normale TextInputCells sein. Dazu habe ich mir einfach den Code der TextInputCell kopiert und ein bisschen erweitert.

Zum einen eine Instanzvariable hidden hinzugefügt, die ich beim Instanzieren mal false setze, da wenn nicht anders entschieden das Feld nicht versteckt sein soll.

 public ExtendendedBrowserEventsTextInputCell() {
  super(BrowserEvents.CHANGE, BrowserEvents.KEYUP, BrowserEvents.KEYPRESS);
  this.hidden = false;
  if (template == null) {
   template = GWT.create(Template.class);
  }
 }


Und zum anderen in der getValue der Spalte mal abgefragt ob ich in der richtigen Zeile bin und dort das hidden gesetzt.

 private final class TestColumn extends Column<String[], String> {
  int index;
  ListDataProvider<String []> provider;

  public TestColumn(int index, ListDataProvider<String[]> provider, Cell cell) {
   super(cell);
   this.index = index;
   this.provider = provider;
  }

  @Override
  public String getValue(String[] object) {

   if (provider != null && provider.getList().indexOf(object) > 0
     && this.getCell() instanceof ExtendendedBrowserEventsTextInputCell) {
    ExtendendedBrowserEventsTextInputCell cell = (ExtendendedBrowserEventsTextInputCell) this.getCell();
    cell.hidden = true;
   }

   return object[index];
  }
 }

Die render Methode der Cell erweitern, da ich weiß das die Felder die ich treffen will, keinen Inhalt haben funktioniert das so:

@Override
 public void render(Context context, String value, SafeHtmlBuilder sb) {
  // Get the view data.
  Object key = context.getKey();
  ViewData viewData = getViewData(key);
  if (viewData != null && viewData.getCurrentValue().equals(value)) {
   clearViewData(key);
   viewData = null;
  }

  String s = (viewData != null) ? viewData.getCurrentValue() : value;
  if (s != null) {
   sb.append(template.input(s));
  } else if (hidden) {
   sb.appendHtmlConstant("<input type=\"hidden\" tabindex=\"-1\"></input>");
  } else {
   sb.appendHtmlConstant("<input type=\"text\" tabindex=\"-1\"></input>");
  }
 }

Schon verschwinden Felder aus der CellTable.




Dienstag, 25. Dezember 2012

GWT: Cell in Celltable dynamisch verändern

GWT 2.5

Wenn die Anforderung laute je nach Cell Value Veränderungen z.B. in der Farbe der Schrift vorzunehmen habe ich eine Lösung gefunden, die wahrscheinlich nicht ideal ist, die ich nichtsdestotrotz hier vorstellen möchte.

Als erstes möchte ich die TextInputCell etwas erweitern, in diesem Fall zum zweiten Mal, da ich vorher schon Ausbauten brauchte, der wichtige Punkt ist in jedem Fall dass ein eigenes Template gestaltet werden kann:


public class MyTextInputCell extends ExtendendedBrowserEventsTextInputCell {

 interface Template extends SafeHtmlTemplates {
  @Template(<input type=\"text\" value=\"{0}\" tabindex=\"-1\" size=\"{1}\" maxlength=\"{1}\" style=\"color:{2}\"></input>")
  SafeHtml input(String value, String size, String textColor);
 }

Zu beachten ist, das die Farbe über style geändert wurde, einfach die color reinzuschreiben reichte aus irgend einem Grund nicht.
Das Ganze kommt dann in der überschriebenen Methode render zum Tragen:


@Override
 public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
  // Get the view data.
  Object key = context.getKey();
  ViewData viewData = getViewData(key);
  if (viewData != null && viewData.getCurrentValue().equals(value)) {
   clearViewData(key);
   viewData = null;
  }

  String s = (viewData != null) ? viewData.getCurrentValue() : value;
  if (s != null) {
   sb.append(myTemplate.input(s, size, textColor));
  } else {
   sb.appendHtmlConstant("<input type=\"text\" tabindex=\"-1\"></input>");
  }
 }
textColor ist dabei eine Instanzvariable, doch wann verändere ich diese entsprechend?
Ich greife da in der Column Implementierung in der Methode getValue, hier kann man schön Wertabhängig die InstanzVariable textColor verändern. Gewählt habe ich diesen Weg, weil ich ein großes Array an Namen brauche um die Farbe des Textes zu bestimmen und mir es am geschicktesten schien dieses Array der Column mitzugeben.

private static final class MyColumn extends Column<String[], String> {

  int index;
  Name[] names;

  public MyColumn(Cell<String> cell, int index, Name[] names) {
   super(cell);
   this.index = index;
   this.names = names;
  }

  @Override
  public String getValue(String[] data) {
   if (this.getCell() instanceof MyTextInputCell) {
    MyTextInputCell cell = (MyTextInputCell) this.getCell();
    if ((cell.isUserid || cell.isUseridStrict) && !Utils.isUseridInNames(data[index], this.names)) {
     cell.textColor = "red";
    } else {
     cell.textColor = "black";
    }
   }
   return data[index];
  }
 }

Es gibt sicher elegantere Methoden, ich würde mich freuen wenn jemand mir eine zeigt.

Links:
Frage dazu auf stackoverflow

Samstag, 15. Dezember 2012

GWT: SuggestBox in einer CellTable

GWT 2.5

Hat man sich einmal entschlossen eine CellTable zu verwenden und stößt dann auf Anforderungen die die CellTable nicht von vornherein vorgesehen hat kann das sehr ärgerlich werden. Mir ging es so bei der Anforderung eine SuggestBox in der Table zu verwenden.
Schlußendlich stellte sich heraus daß das Ganze gar nicht so eine Zauberei ist, muß aber auch dazusagen, daß die Lösung noch nicht wirklich den Praxistest erlebt hat.

Meine Lösung besteht darin, einfach die TextInputCell zu extenden und so eine SuggestBox reinzuschummeln:


public class SuggestBoxTextInputCell extends TextInputCell {

 MySuggestBox suggestBox;

 private class MyTextBox extends TextBox {
  public MyTextBox(Element element) {
   super(element);
  }
 }

 private class MySuggestBox extends SuggestBox {
  public MySuggestBox(SuggestOracle suggestOracle, TextBox textBox) {
   super(suggestOracle, textBox);
  }

  @Override
  public void onAttach() {
   super.onAttach();
  }
 }

 public SuggestBoxTextInputCell() {
  super();
 }


 @Override
 public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
   ValueUpdater<String> valueUpdater) {
  super.onBrowserEvent(context, parent, value, event, valueUpdater);
  String eventType = event.getType();
  if (BrowserEvents.FOCUS.equals(eventType)) {
   TextBox textBox = new MyTextBox(getInputElement(parent));
   suggestBox = new MySuggestBox(getSuggestOracle(), textBox);
   suggestBox.onAttach();
  }
 }

 private SuggestOracle getSuggestOracle() {
        //this does not work without implementation
        return null;
 }
}

Die Methode gestSuggestOracle muss natürlich noch implementiert werden um den Beispielcode lauffähig zu bekommen.
Links:
Google Groups Beitrag
Stackoverflow Beitrag zum Thema

Freitag, 23. November 2012

Einbindung von Source eines Submoduls für GWT/Maven

GWT 2.5.0
gwt-maven-plugin 2.5.0
Maven 3.0.3

Bei einem mehrmoduligen GWT/Maven Projekts ist das Model oft in einem anderen Modul als im eigentlichen GWT Modul (web Modul). Für das gwt-maven-plugin werden auf der Homepage 2 Möglichkeiten vorgeschlagen das zu lösen:

http://mojo.codehaus.org/gwt-maven-plugin/user-guide/project.html

Erster Vorschlag das Goal gwt:resources hinzuzufügen funktioniert ausgezeichnet, allerdings möchte man das Problem manchmal nicht über zusätzliche Commandline Befehle lösen sondern über die pom Konfiguration. Hier wird vorgeschlagen das ganze über das Attribut compileSourcesArtifacts zu lösen, das funktioniert aus mir nicht ganz erklärlichen Gründen nicht.

Meine Lösung war dann genau wie vorgeschlagen das zusätzliche gwt.xml im Submodul anzulegen:


  
  


 und dieses im gwt.xml des GWT Moduls zu mit "inherits" einzubinden.


Damit funktioniert das Ganze leider noch nicht, im pom.xml des Moduls, wovon das Model eingebunden werden soll muß man noch folgendes eintragen:

 
  
   
    src/main/java
    
     **/*.java
    
   
   
    src/main/resources
    
     **/*.xml
    
   
  
 



Mittwoch, 7. November 2012

Java: Deep Copy von Listen

Eine "tiefe" Kopie einer beliebigen Liste in Java ist gar nicht so selbstverständlich wie man meinen möchte, die meisten Ansätze kopieren nämlich zwar die Liste, aber der Inhalt bleibt Referenz und somit wird die Kopie nicht "tief".

Eine kleine Methode löst mir das Problem:

public static List<ResultLine> deepCopyListResultLine(List<ResultLine> list) {
  List<ResultLine> resList = new ArrayList<ResultLine>();
  for (ResultLine line : list) {
   resList.add(new ResultLine(line));
  }
  return resList;
 }


Voraussetzung ist natürlich dass das Objekt über einen Konstruktor verfügt der diese Art der Duplizierung möglich macht:

public class ResultLine implements Serializable {

 public ResultLine() {

 }

 public ResultLine(ResultLine line) {
  this.plz = line.getPlz();
  this.app = line.getApp();
  this.eighty = line.getEighty();
  this.eightyAnz = line.getEightyAnz();
  this.firstTen = line.getFirstTen();
  this.firstTenAnz = line.getLastTenAnz();
  this.lastTen = line.getLastTen();
  this.lastTenAnz = line.getLastTenAnz();
  this.ldkz = line.getLdkz();
  this.makler = line.isMakler();
  this.mobile = line.isMobile();
  this.sessionAnz = line.getSessionAnz();
 }

Auf diese Weise ist ein "tiefes" Kopieren kein Problem mehr.

Freitag, 3. August 2012

Jar auf die javac -target Version überprüfen

Baut man sich ein Fat Jar zusammen und bindet dabei Third Party Jars ein gibt es derzeit in Maven keinen Warnhinweis, das einige der fremden Jars unter Umständen eine höhere Version der Runtime brauchen als als Zielplattform vorgesehen/möglich ist.

Hier hilft einen das Programm JarCheck, damit kann man einfach alle Klassen eines beliebigen Jars auf die benötigte Runtime überprüfen.
Hier überprüfe ich Beispielsweise ob alle Klassen auch schön im Bereich von Java 1.1 bis 1.4 liegen:


java -jar jarcheck.jar myFatJar.jar 1.1 1.4

Links:
Download JarCheck


Freitag, 9. März 2012

Problem beim Auslesen eines Blobs aus SQLite: invalid stream header

org.xerial.sqlite-jdbc 3.7.2
mysql-connector-java 5.1.18

Ursprünglich habe ich das Speichern und Auslesen eines Objekts für eine MySql Datenbank geschrieben, aber um das ganze ohne laufenden MySql Server testbar zu machen wollte ich einfach auch eine sqLite Datenbank als Alternative zur Verfügung haben. Ich habe nicht schlecht gestaunt, als derselbe Code, der für MySql einwandfrei funktionierte, bei SQLite beim Auslesen des Blobs eine Fehlermeldung warf:

java.io.StreamCorruptedException: invalid stream header: 61742E75 at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:797) at java.io.ObjectInputStream.(ObjectInputStream.java:294)

Nachlesen in Foren ergab, dass ObjectInputStream nicht funktioniert wenn die Daten nicht zuvor mit ObjectOutputStream der Datenbank übergeben wurden.

Hier mein ursprünglicher Code zum Einspielen des Objects:

public static void insertIntoTable(BigInteger id, SessionData sd, byte[] rtsd, IvissWorker ivissWorker) {
    PreparedStatement pstmt = null;
    Connection con = null;
    try {
        con = getConnection();
        pstmt = con
                .prepareStatement("REPLACE INTO iviss_session_table (id, ivissblob, rtblob, lastaccess) VALUES(?,?,?,?)");
        pstmt.setLong(1, Long.parseLong(id.toString()));
        pstmt.setObject(2, sd);
        pstmt.setObject(3, rtsd);
        pstmt.setDate(4, new Date(System.currentTimeMillis()));
        pstmt.executeUpdate();
    } catch (SQLException e) {
        ivissWorker.getIvissWorkerOutputHandler().addError(Constants.ERROR_205, "", DbConfiguration.getDbUri());
    } finally {
        try {
            if (pstmt != null) {
                pstmt.close();
            }
            if (con != null) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Beim Auslesen aus einer SQLite Datenbank schlug dann das Erzeugen des ObjectInputstream fehl:

public static SessionData getIvissSession(BigInteger id) throws IvissDatabaseException {
    SessionData sd = null;
    PreparedStatement pstmt = null;
    Connection con = null;
    try {
        con = getConnection();
        pstmt = con.prepareStatement("SELECT ivissblob FROM iviss_session_table WHERE id =?");
        pstmt.setLong(1, Long.parseLong(id.toString()));
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            byte[] ivissblob = rs.getBytes("ivissblob");
            ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(ivissblob));
            sd = (SessionData) objectIn.readObject();
            objectIn.close();
        }

    } catch (SQLException e) {
        throw new IvissDatabaseException(Constants.ERROR_202);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {

        try {
            if (pstmt != null) {
                pstmt.close();
            }
            if (con != null) {
                con.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    return sd;
}

Gelöst wurde das Problem, indem ich der Datenbank das Object nicht mit .setObject übergeben habe, sondern als byte Array, das byte Array wird wiederrum mit ObjectOutputStream erzeugt, damit kam ObjectInputStream dann zurecht. Warum der MySql Treiber hier weniger Probleme macht und etwas aus dem ResultSet übergibt, mit dem der ObjectInputStream gut zurechtkommt bleibt mir ein Rätsel.

Hier die geänderte Zeile bei der Übergabe:

     pstmt.setBytes(2, IvissUtil.getBytes(sd));

Und hier die Methode die mir das byte Array erzeugt:

public static byte[] getBytes(Object obj) throws java.io.IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(obj);
    oos.flush();
    oos.close();
    bos.close();
    byte[] data = bos.toByteArray();
    return data;
}

Links:
Frage diesbezüglich in stackoverflow

Donnerstag, 2. Februar 2012

Statische HashMap deklarieren und mit statischen Konstruktor initialisieren

Eine statische finale HashMap ist eine tolle Sache, aber wie befüllen?

Hier ein Codeschnipsel, das dies vorführt:

public final class Constants {
 public static final Map ERRORMAP = new HashMap();
 public static final String ERROR_500 = "f500";
 public static final String ERROR_502 = "f502";
 public static final String ERROR_503 = "f503";
 public static final String ERROR_504 = "f504";
 public static final String ERROR_505 = "f505";
 public static final String ERROR_506 = "f506";
 static {
  errorMap.put(ERROR_500, "ConvertListDef: Invalid characters before newline. Only spaces and tabs allowed.");
  errorMap.put(ERROR_502, "ConvertListDef: Missing '='");
  errorMap.put(ERROR_503, "ConvertListDef: Value does not comply with naming convention");
  errorMap.put(ERROR_504, "ConvertListDef: Syntactically invalid Attributename");
  errorMap.put(ERROR_505, "ContextDef: Name of context invalid");
  errorMap.put(ERROR_506, "ContextDef: Name of contextproperty invalid");
 }
}

Der Zauberbereich ist der "statische" Konstruktor, der nur einmal bei Programmstart aufgerufen wird und mir meine HashMap befüllt.

Links:
Guido Krüger - JAVA 1.1 lernen - Kapitel 7
Siafoo Snippet



Mittwoch, 4. Januar 2012

Java Installation Error 1723 (missing DLL)

Windows 7 (Servicepack 1) 32 Bit

Aus irgendeinem Grund ließ sich auf meinem System kein Java mehr installieren und eine alte Version nicht deinstallieren, jeder Versuch endete mit dieser Meldung:



Zahlreiche Foreneinträge sahen das Problem bei einem korrupten Windows Installer und rieten in diesem Fall zu Registry Manipulationen mit Tools oder per Hand zu Fuß, mir war das alles ein bisschen zu vage, neu aufsetzten kommt nicht in Frage, darum ganz Old Style: Java Folder von einem System wo alles klappt rüberkopiert und den bin-Ordner in den Systempfad gelegt.

Der schnellste Weg auf der graphischen Oberfläche die Path Variable zu verändern:

Windows + Pause
-> Erweiterte Systemeinstellungen
-> Umgebungsvariablen
-> in Systemvariablen die Varialbe Path bearbeiten

Nachtrag:
Nachdem diese Lösung aber nicht dazu taugt die Java-Plugins in die verschiedenen Browser reinzubekommen mußte ich wohl oder übel das 1723er Problem an der Wurzel erledigen.

Nach einigen Stunden verschiedenster Versuche funktionierte das Löschen der Java-Installations-Reste (die Ursache des Problems) mit dem Tool Revo Uninstaller Pro (eine 30 Tage Trail Version). Dort einfach nach Java suchen und alle relevanten Einträge ausmerzen, bei mir waren erst beim zweiten Durchgang wirklich alle weg, dann funktionierte die Neuinstallation von Java wieder einwandfrei.

Link:
Wikipediaeintrag zu Umgebungsvarialbe

Dienstag, 1. November 2011

Selenium IDE - Select

Selenium IDE 1.3.0
selenium-java 2.11.0


Eine praktische Option der Selenium IDE ist daß man JUnit Tests aus einem aufgenommen Testfall generieren kann. Leider funktioniert das mit Drop Down Listen nicht so einfach, generiert man bekommt man für diese Fälle im JUnit Test folgendes:

// ERROR: Caught exception [ERROR: Unsupported command [select]]

Liest man nach gibt es die Klasse Select, mit der man das händisch nachtragen kann, allerdings befand sich diese bei mir nicht im Klassenpfad, Problem war das ich nur den HtmlUnit Driver inkludiert hatte, das support Package ist dort nicht inkludiert.

Gibt man Maven die Anweisung das selenium-java Projekt zu inkludieren findet er auch die Select Klasse.

        
            org.seleniumhq.selenium
            selenium-java
            2.11.0
            test
        

Nun kann man die Select Klasse supereinfach zum Auswählen der entsprechenden Option verwenden:

Select select = new Select(driver.findElement(By.id("aktEntry.risiko.value")));
select.selectByVisibleText("American Football");


Sonntag, 10. April 2011

Heapsort in Java

Hier eine Implementierung von Heapsort in Java:

package at.ande.sorting.heapsort;

import java.util.ArrayList;

public class HeapSort {
 
 ArrayList list;
 int length;
 
 public ArrayList start(ArrayList arraylist){
  list = arraylist;
  length = list.size();
  createHeap();
  while(length > 1){
   length--;
   change(0, length);
   downheap(0);
  }
  return list;
 }
 
 public void createHeap(){
  for (int i = length / 2 - 1; i >= 0; i--){
   downheap(i);
  }
 }
 
 public void downheap(int i){
  int j = 2 * i + 1;
  while (j < length){
   if(j + 1 < length && list.get(j + 1) > list.get(j)){
    j++;
   }
   if(list.get(i) > list.get(j)){
    break;
   }
   change(i, j);
   i = j;
   j = 2 * i + 1;
  }
 }
 
 public void change(int i, int j){
  int temp = list.get(i);
  list.set(i, list.get(j));
  list.set(j, temp);
 }
}



Im Vergleich zu den auch in diesem Blog implementieren Sortieralgorithmen schneidet Heapsort ganz gut ab:

List Area: 0 - 999
List Numbers: 100000
Unsorted List:
- Iterative Quicksort: 123 ms
- Bubblesort: 45787 ms
- Gnomesort: 75418 ms
- Heapsort: 103 ms
Sorted List:
- Iterative Quicksort: 1518 ms
- Bubblesort: 5 ms
- Gnomesort: 8 ms
- Heapsort: 49 ms

Links:
Wikipediaeintrag über Heapsort
Ausführlicher Artikel der Uni Flensburg über Heapsort

Gnomesort in Java

Hier eine Implementierung von Gnomesort:

package at.ande.sorting.gnomesort;

import java.util.ArrayList;

public class GnomeSort {
 
 ArrayList list;

 public ArrayList start(ArrayList arraylist) {
  list = arraylist;
  sort();
  return list;
 }
 
 public void sort(){
  int right = 1;
  int left = 0;
  while (right != list.size()){
   if (list.get(left) <= list.get(right)){
    right = right + 1;
    left = left + 1;
   } else {
    int temp = list.get(left);
    list.set(left, list.get(right));
    list.set(right, temp);
    if(left != 0){
     left = left -1;
     right = right - 1;
    }
   }
  }
 }
}


Das Laufzeitverhalten ist nicht gerade überzeugend:

List Area: 0 - 999
List Numbers: 100000
Unsorted List:
-Iterative Quicksort: 135 ms
-Bubblesort: 43729 ms
-GnomeSort: 70638 ms
Sorted List:
-Iterative Quicksort: 1767 ms
-Bubblesort: 3 ms
-GnomeSort: 12 ms

Links:
Wikiartikel zu Gnomesort

Iteratives Quicksort in Java

Nachdem man bei der rekursiven Quicksort sehr schnell an Speichergrenzen stößt habe ich es mal iterativ implementiert.
Der Vergleich zu meiner Implementierung von Bobblesort zeigt bei einer Liste von 100000 Einträgen mit 1000 verschiedenen Werten einen beträchlichen Geschwindigkeitsvorsprung:
- Bubblesort ca. 40000 ms.
- Quicksort ca. 120 ms.
Übergibt man jedoch beiden eine schon sortierte Liste derselben Größe kehrt sich das um:
- Bubblesort ca. 12 ms.
- Quicksort ca. 2000 ms.

package at.ande.sorting.quicksort;

import java.util.ArrayList;
import java.util.Stack;

import at.ande.sorting.utils.SortingUtils;

public class QuickSort2 {

 ArrayList list;

 public ArrayList quickSort2(ArrayList arraylist) {
  list = arraylist;
  sort(0, arraylist.size() - 1);
  return list;
 }

 public void sort(int left, int right) {
  Stack stack = new Stack();
  while (true) {
   if (left < right) {
    int pivot = list.get(SortingUtils.randomOfTwo(left, right));
    int i = left - 1;
    int j = right + 1;

    while (true) {
     do {
      i = i + 1;
     } while (list.get(i) < pivot);

     do {
      j = j - 1;
     } while (list.get(j) > pivot);

     if (i >= j) {
      break;
     }
     int temp = list.get(i);
     list.set(i, list.get(j));
     list.set(j, temp);
    }
    stack.push(right);
    right = left > (i - 1) ? left : (i - 1);
   } else {
    if (stack.size() == 0) {
     break;
    }
    left = right + 1;
    right = stack.pop();
   }
  }
 }
}



Links:
Wikipediaeintrag Quicksort
Ausführliche Seite über Quicksort