Tag Archive: Spring

Automatische Proxywahl für Mule ESB Webservices

Wenn man Services in Mule konfiguriert wird man einige benutzen, welche externe Services aufrufen. Allerdings hängt es von der Umgebung ab, ob und für welche Hosts ein Proxy Server verwendet werden muss. Um die Rekonfiguration von Mule je Umgebung zu vermeiden benutzen wir einen automatischen Proxy Connector. Da ich den ganz nett finde möchte ich Ihn Euch gerne näher bringen. Vielleicht ist er auch für Euch nutzbar
(weiterlesen …)

Fabian Lange

 

Timeout ist nicht gleich Timeout

Letzte Woche mussten ich einen Webservice-Client erweitern, sodass er die Verarbeitung abbricht, wenn die Gegenseite nicht schnell genug ein Ergebnis liefert. Das Ganze ist mit spring-webservices implementiert und verwendet die WebServiceTemplate Klasse. (weiterlesen …)

Eugen Melnichuk

 

Agile Testing Days – Automated Integration Testing in Agile Environments

… by Slobodanka Sersik and Dr. Gerald Schröder

Der Rahmen für diese Session ist ein ziemlich großes (Fracht-)Container-Managementsystem, in etwa 200 Mannjahre. Zum Entwurf und Erstellung der Testcases diente ein Model, das aus Scenarien, Schritten, Adaptern, Komponenten und Simulatoren besteht.
(weiterlesen …)

Andreas Ebbert-Karroum

 

codecentric coding night – facts & figures

Hier einige interessante Statistiken zur coding night. Da die coding night ein “Projekt im Zeitraffer” war, sind die von Hudson bei den automatischen Builds erstellten Statistiken ganz interessant.

JUnit Test Ausführung

coding-night09-junit-trend
Das erste was auffällt ist, daß es erst ab Build #68 Testergebnisse gab. Der Build fand um 22:28:56 statt, was etwas mehr als 6 Stunden nach dem ersten commit (16:01:27) entspricht. Der Grund ist zum einen, daß erst Verzeichnisstrukturen in den ersten commits aufgesetzt wurden. Zum anderen ist TDD bei nicht vorhandener codebasis auch recht schwer, zumal die ersten Stunde wirklich eher unkoordiniert waren (das erste Scrum of Scrums zur Synchronisation fand um 20 Uhr statt). Allgemein positiv ist der konstante Aufwärtstrend. Die fehlgeschlagenen Tests sind hauptsächlich einem größeren Refactoring geschuldet. Zudem verhinderte zeitgleiches Grillen, daß diese Fehler schnell bemerkt und korrigiert wurden.

Testabdeckung

Test coverage
Der Graph ist auch sehr aufschlussreich, so erkennt man daß die Testabdeckung sehr breit ist, da etwa 90% aller Klassen und Packages abgedeckt wurden. Daß die “Conditionals” rapide fielen hatte den Grund, daß die Software in der Tat bis Build 83 keine If Verzweigung enthielt. Dies spricht für eine sehr geringe Komplexität, welches der Verwendung von Spring anzurechnen ist, da man selber keine Verzweigungen programmieren muss wenn man immer die richtigen Objekte vom Container übergeben bekommt. Zwar versuchte man dann auch später implementierte Verzweigungen abzudecken, war aber nicht wirklich erfolgreich. Dies liegt meiner Meinung nach daran daß die Verzweigungen durch Fehler/Exception Handling entstehen und nicht so schön testbar sind. Die steigende Methoden und Zeilenabdeckung ist gut, aber insgesamt viel zu niedrig. Die Ursachen dafür sind allerdings nachvollziehbar. So schlagen sich vorbereitete aber nicht genutzte Services (toter code) durch.  Auch die Modellklassen und unzählige Getter und Setter sind teilweise nicht extra getestet.
Zusammen zeigen die ersten beiden Statistiken ein positives Bild. Kontinuierliches Testen erfolgt auch in stressigen Projekten und bringt eine gewisse Sicherheit über die Qualität.

Code Wachstum

coding-night09-code-trend
Abgebildet sind die Zeilen selbstgeschriebenen Codes über Zeit. Man sieht den schnellen Wachstum der Zeilenzahl. Es sieht also nach einem sehr produktivem Projekt auch. Die Verteilung des Codes auf die Entwickler ist interessant, man ist fast geneigt zu sagen: 20% der Entwickler haben 80% des Codes geschrieben. Allerdings relativiert sich dies etwas dadurch, daß die Anwesenheit an dem Wochenende stark schwankte. Die 4-6 stärksten Balken verteilen sich somit auch auf die Entwickler welche fast permanent anwesend waren. Eine Anmerkung am Rande: Letzendlich ist es doch erschreckend, wie viel Code für relativ wenig Funktionalität benötigt wurde. Diesen Kritikpunkt muss Java leider einstecken.

Code Typ

coding-night09-code-type
Das Tortendiagramm zeigt es deutlich. Wir haben hauptsächlich Java code geschrieben. JSPs wurden als Views genutzt. XML ist kaum vorhanden, da wir größtenteils Annotations verwendet haben anstelle von langen Spring Konfigurationen. Ausgeblendet aus dieser Ansicht sind Javascriptbibliotheken welche eingebunden wurden aber im src Verzeichnis liegen und damit von FishEye als unser Code gezählt wird. Auch zeigt die Verteilung, daß relativ wenig untestbarers entstanden ist. Ausser den Views, welche in egal welcher Form immer problematisch sind, ist fast der komplette Code mit Java Mitteln testbar.

Fabian Lange

 

Multiple Selects mit Spring MVC

Während unserer coding night, zu der mit Sicherheit noch ein separater Blogeintrag folgt, setzen wir voll auf Spring Technologien. Dabei hat sich eine vermutlich simple Anforderung als ziemlich halsbrecherisch herausgestellt.

Wie kann man mit Spring MVC eine Select box darstellen, bei der man multiple Elemente auswählen kann, welche dann in eine Collection der Bean hinzugefügt werden?

Wir implementiere eine einfache Zeiterfassung. In dem Domänenmodell gibt es Projekte, denen Mitarbeiter zugeordnet sind. Zudem können Projekte Aufgaben haben, denen auch Mitarbeiter zugeordnet sein können. In der View zum erstellen der Aufgaben benötigen wir also eine Selectbox aus allen verfügbaren Mitarbeitern.

Modell

Hier das wichtigste der Aufgaben und Mitarbeiter:

Task

@Entity
public class Task implements Serializable {
	@Id
	@GeneratedValue
	private long id;
 
	@ManyToMany
	private Set<Staff> staffs = new HashSet<Staff>(0);
 
	//...
}

Staff

@NamedQuery(name = "staff.activeStaff", query = "select s from Staff s where s.disabled = false")
@Entity
@DiscriminatorValue("STAFF")
public class Staff extends Person {
 
	//...
}

Person

@NamedQuery(name = "person.findByUsername", query = "from Person p where p.login.username = :username")
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person implements Serializable {
 
	@Id
	@GeneratedValue
	private long id;
 
	//...
}

View

In der view, in der die Tasks erstellt werden sollen, brauchen wir also eine select box, welche alle verfügbaren Mitarbeiter anzeigt. Die ausgewählten Mitarbeiter sollen dann der Aufgabe hinzugefügt werden. Die View ist mit der Task hinterlegt, und fügt alle aktiven Mitarbeiter zu einem Attribut hinzu:

@Controller
@SessionAttributes("project")
public class ProjectController {
	@RequestMapping(method = RequestMethod.GET, value = "/project/createTask.action")
	public void createTaskView(@ModelAttribute Task task, Model model) {
		List<Staff> activeStaff = timetrackingService.getActiveStaff();
		model.addAttribute("activeStaff", activeStaff);
	}
 
	//...

Die entsprechende JSP sieht folgendermaßen aus:

<td><label for="staffs">Chose Staff: </label></td>
<td><form:select path="staffs" multiple="true" items="${activeStaff}" itemLabel="fullName" itemValue="id"/></td>
<td><form:errors path="staffs" /></td>

Das Problem, sobald man die Form submitted, bekommt man eine ServletRequestBindingException, denn Spring weiß nicht wie man aus einem String (bzw. String[] wenn mehrere Personen markiert waren) ein Set erstellt.

org.springframework.web.bind.ServletRequestBindingException: Errors binding onto object 'task'; nested exception is org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'task' on field 'staffs': rejected value [3]; codes [typeMismatch.task.staffs,typeMismatch.staffs,typeMismatch.java.util.Set,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [task.staffs,staffs]; arguments []; default message [staffs]]; default message [Failed to convert property value of type [java.lang.String] to required type [java.util.Set] for property 'staffs'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [de.codecentric.timetracking.model.Staff] for property 'staffs[0]': no matching editors or conversion strategy found]

Zudem ist der generierte HTML-code lückenhaft, er enthält keine id für die einzelnen Mitarbeiter!

<select id="staffs" multiple="multiple" name="staffs">
<option value="">firstname lastname</option>
<option value="">aaaa aaaa</option>
<option value="">firstname lastName</option>
<option value="">firstname aaaa</option>
<option value="">firstname lastname</option>
</select>
<input type="hidden" value="1" name="_staffs"/>

Id als String

Um die ID des Mitarbeiters in das value-Attribut der option zu bekommen, kann man einen eigenen Getter auf der Person implementieren, und diesen dann in der JSP statt der ID verwenden:

public abstract class Person implements Serializable {
	//...
	public String getIdAsString() {
		return new Long(id).toString();
	}
}
<form:select path="staffs" itemValue="idAsString" multiple="true" items="${activeStaff}" itemLabel="fullName"/>

InitBinder

Die Lösung für das Binding-Problem ist, dass wir für das Attribut ‘staffs’ einen eigenen PropertyEditor registrieren müssen. Spring bringt eine Reihe eigener PropertyEditoren mit, in diesem Falle können wir den CustomCollectionEditor wiederverwenden. Um von der String-ID wieder auf den Mitarbeiter mappen zu können, müssen wir uns auch noch eine Map initialisieren, die dieses Mapping vorhält.

public class ProjectController {
 
private Map<String, Staff> staffCache;
 
@RequestMapping(method = RequestMethod.GET, value = "/project/createTask.action")
public void createTaskView(@ModelAttribute Task task, Model model) {
	List<Staff> activeStaff = timetrackingService.getActiveStaff();
	staffCache = new HashMap<String, Staff>();
	for (Staff staff : activeStaff) {
		staffCache.put(staff.getIdAsString(), staff);
	}
	model.addAttribute("activeStaff", activeStaff);
}
 
@InitBinder
protected void initBinder(WebDataBinder binder) throws Exception {
	binder.registerCustomEditor(Set.class, "staffs", new CustomCollectionEditor(Set.class) {
		protected Object convertElement(Object element) {
			if (element instanceof Staff) {
				System.out.println("Converting from Staff to Staff: " + element);
				return element;
			}
			if (element instanceof String) {
				Staff staff = staffCache.get(element);
				System.out.println("Looking up staff for id " + element + ": " + staff);
				return staff;
			}
			System.out.println("Don't know what to do with: " + element);
			return null;
		}
	});
}

Der Code enthält noch etwas Debug-output nach System.out, der natürlich noch entfernt werden muss. Er zeigt aber sehr schön, dass der Code sehr (zu?) häufig aufgerufen wird. Außerdem wird erwartetn, dass die Property in beide Richtungen konvertiert werden kann!

Allein wenn die select box angezeit werden soll, steht folgendes im Log:

Looking up staff for id 1: Staff(firstname lastname)
Looking up staff for id 1: Staff(firstname lastname)
Converting from Staff to Staff: Staff(firstname lastname)
Looking up staff for id 2: Staff(aaaa aaaa)
Looking up staff for id 2: Staff(aaaa aaaa)
Converting from Staff to Staff: Staff(aaaa aaaa)
Looking up staff for id 3: Staff(firstname lastName)
Looking up staff for id 3: Staff(firstname lastName)
Converting from Staff to Staff: Staff(firstname lastName)
Looking up staff for id 4: Staff(firstname aaaa)
Looking up staff for id 4: Staff(firstname aaaa)
Converting from Staff to Staff: Staff(firstname aaaa)
Looking up staff for id 5: Staff(firstname lastname)
Looking up staff for id 5: Staff(firstname lastname)
Converting from Staff to Staff: Staff(firstname lastname)

Wenn man einen Mitarbeiter aus der Select-Box auswählt und die Form submitted, findet sich dann aber wie erwartet nur ein Eintrag im Log:

Looking up staff for id 3: Staff(firstname lastName)

Fazit

Angesichts der Masse an Webframeworks, die es gibt, finde ich es erschreckend Kompliziert so etwas einfaches wie eine multiple select Box mit Spring MVC zu implementieren. Da ich mir Spring MVC aber auch erst seit gestern genauer angesehen habe, verstehe ich es vielleicht noch nicht richtig, von daher bin ich sehr für Vorschläge zu haben, wie man das beschriebene Szenario mit Spring MVC-Mitteln eleganter und einfacher implementieren kann.

Andreas Ebbert-Karroum

 

JavaOne 2009: RIA development with JavaFX

“Hallo” von der JavaOne 2009! Zusammen mit drei meiner Kollegen sowie Hunderten von Entwicklern, Architekten und den größten Java Unternehmen bin ich gerade auf der Nummer eins Java Konferenz im schönen San Francisco (ich habe hier zum ersten Mal James Gosling live beim T-Shirt schleudern gesehen – leider habe ich keins gefangen).

Eins der Themen welches mich am meisten interessiert ist der aktuelle Stand von JavaFX (gerade wurde die Version 1.2 freigegeben). Seit Jahren entwickle ich nur JSPs, und ich schaue mich schon seit längerem nach einer neuen, innovativen und schicken Art den View Layer darzustellen um, ohne auf die gewohnten Features von Java zu verzichten zu wollen. JavaFX gibt es nun set knapp 2 Jahren (zum ersten Mal angekündigt im Mai 2007, das 1.0 Release kam im Dezember 2008) und ist mittlerweile ein stabiles und in Produktion einsetzbares Framework.

Ich habe mir Sessions über die Integration von Spring und JBoss Seam mit JavaFX (@see Flamingo) angesehen, welche es ermöglicht echte Enterprise Applikationen zu entwickeln. Auch wurde gezeigt, wie Adobe Photoshop/Illustrator Dateien direkt in ein JavaFX Archiv (eine .jfz Datei) exportiert werden können. Ein Entwickler kann über Namenskonventionen (jfx:layerid) direkt auf die enthaltenden Layer zugreifen und diese manipulieren. Auf diese Art und Weise wird es möglich, einem Designteam eine Spec zu geben, um ein Artefakt entwickeln, welches dann einfach in die Applikation integriert werden kann.

Was mir besonders gut gefallen hat ist die Möglichkeit Anwendungen auf verschiedene Plattformen wie das Web, den Desktop oder auch mobile Endgeräte zu deployen. Es wird auch möglich sein seine Anwendungen direkt in den brandneuen Java Store (der Java Store wurde während der Konferenz als geschlossene Beta gestartet, eine offene Beta Phase soll später im Sommer folgen) zu deployen.

Auch hat sich die Unterstützung für JavaFX in der Entwicklungsumgebung eclipse
verbessert. Netbeans ist immer noch die bevorzugte IDE, aber ich arbeite täglich mit eclipse und es gibt ein offizielles Plugin auf javafx.com sowie Firmen, welches Tools wie exadel‘s JavaFX Studio entwickeln. Dank dieser Tools konnte ich in wenigen Minuten mein erstes JavaFX “Anwendung” (nur ein schöner Text auf einem 3D Kreis) entwickeln und starten.

Als nächstes möchte ich echte Anwendungen schreiben, nicht nur ein “Hey, ein animiertes Ding – hab ich mit JavaFX gemacht” Demo. Wer sich selber die Finger schmutzig machen will kann die excellenten Tutorials auf javafx.com ausprobieren.

So, ich muss los, ich bin schon spät dran, die nächste Session geht gleich los.

Nick Prosch