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.



Freitag, 5. Juli 2013

JMeter und JSF 1.2

JMeter 2.9
JSF 1.2

Bei JSF 1.2 Applikationen gibt es für JMeter ein paar Hürden, ein paar konnte ich lösen:

1. Bei JSF 1.2 Applikationen werden für die *.jsf Requests Redirects ausgeführt die im Script vorhanden sind --> die Redirects werden also 2x ausgeführt

Lösung: Redirects händisch von den Requests entfernen:


2. Schon das Logon klappt nicht im Script, es wirft einen 404.

Lösung: HTTP Authorisierungs Manager hinzufügen




3. Manche jsf Seiten werfen einen 500er obwohl eigentlich alles zu stimmen scheint, typischer Stacktrace:

javax.servlet.ServletException: viewId:/person.jsf - View /person.jsf could not be restored.
at java.lang.Throwable.<init>(Throwable.java:80)
Wenn man mit JMeter Proxy das Script aufgenommen hat ist zwar der javx.faces.ViewState als Param im Request aufgenommen, aber durch verschiedene widrige Umstände wie zB die Redirects aus dem ersten Tip müssen die stateViews nicht mehr übereinstimmen. Abhilfe schafft hier ein Regular Expression Extractor:



So holt man sich den ViewState aus den Responses:



Und so stopft man diese Variable in die eigenen Requests:




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.




Donnerstag, 3. Januar 2013

GWT: Celltable Filter

GWT 2.5

Will man eine Celltable filtern (sprich Zeilen verschwinden lassen bei denen kein Element der Zeile dem Filterkriterium entspricht) geht das mit Tabellen, die fix sind und auch keine veränderbaren Elemente beherbergen, ziemlich einfach:

Einfach ein Eingabefeld wo der Filterwert eingegeben wird:


  filterTextBox.addKeyUpHandler(new KeyUpHandler() {

   @Override
   public void onKeyUp(KeyUpEvent event) {
    TableFilter.filterTable(allContent, tableDataProvider.getList(),
     filterTextBox.getText());
   }
  });


Dazu die Util Methode, wobei allContent den gesamten Content der Table darstellt:

 public static List<T> filterTable(List<T> allContent, List<T> actTableContent, String filterText) {
  if (!allContent.isEmpty()) {
   for (T entry : allContent) {
    if (!entry.getName().toLowerCase().contains(filterText.toLowerCase())
      && !entry.getText().toLowerCase().contains(filterText.toLowerCase())) {
     actTableContent.remove(entry);
    } else if (!actTableContent.contains(entry)) {
     actTableContent.add(entry);
    }
   }
  } else {
   actTableContent.clear();
  }
  return actTableContent;
 }

Probleme bereitete mir allerdings die Aufgabe, wie filtern wenn der Inhalt nicht fest steht und während verschiedener Filtereinstellungen verändert werden kann durch Eingabe in Zellen, durch hinzufügen oder löschen von ganzen Zeilen? Mit dem obigen Mechanismus müßte ich nach jeder möglichen Veränderung den "allContent" entsprechend anpassen, kann dazu aber nicht die Liste aus dem ListDataProvider verwenden, da diese ja gerade gefiltert sein könnte und deshalb nicht vollständig. Ich suchte also nach einer Möglichkeit Zeilen zu verstecken und fand schließlich eine super Lösung im Blog artiom.pro. Sie funktioniert einwandfrei, vielen Dank für diese Codeschnipsel.

Hier der Link direkt zur Lösung.