Vaadin jako klient webservice III: wywołanie metody testowej

Czas na wielkie łał, czyli wywołanie usługi… w końcu.

Adapter interfejsu Ideone

I szerzej dowolnej usługi kompilatora. Po co? Oczywiście po to by w razie czego uniezależnić się od dostawcy. Proste.

Listing 1. CompilerApi

package pl.koziolekweb.vaadin.codecompiler.api;

import java.text.ParseException;

import pl.koziolekweb.vaadin.codecompiler.data.TestResponse;

public interface CompilerApi {

	TestResponse testFunction() throws ParseException;

}

Na chwilę obecną wersja uproszczona zawierająca tylko jedną metodę. Klasa TestResponse:

Listing 2. TestResponse

package pl.koziolekweb.vaadin.codecompiler.data;

import java.sql.Timestamp;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

@Entity
@NamedQueries(value = { @NamedQuery(name = "getAll", query = "Select t from TestResponse t"),
		@NamedQuery(name = "getbyId", query = "Select t from TestResponse t Where t.timestamp=:id") })
public class TestResponse {

	private String moreHelp;
	private String error;
	private Double pi;
	private Boolean oOok;
	private Long answerToLifeAndEverything;
	@Id
	private Timestamp timestamp;

	public Long getAnswerToLifeAndEverything() {
		return answerToLifeAndEverything;
	}

	public String getError() {
		return error;
	}

	public String getMoreHelp() {
		return moreHelp;
	}

	public Boolean getoOok() {
		return oOok;
	}

	public Double getPi() {
		return pi;
	}

	public Timestamp getTimestamp() {
		return timestamp;
	}

	public void setAnswerToLifeAndEverything(Long answerToLifeAndEverything) {
		this.answerToLifeAndEverything = answerToLifeAndEverything;
	}

	public void setError(String error) {
		this.error = error;
	}

	public void setMoreHelp(String moreHelp) {
		this.moreHelp = moreHelp;
	}

	public void setoOok(Boolean oOok) {
		this.oOok = oOok;
	}

	public void setPi(Double pi) {
		this.pi = pi;
	}

	public void setTimestamp(Timestamp timestamp) {
		this.timestamp = timestamp;
	}

}

Reprezentuje odpowiedź serwera wzbogaconą o znacznik czasu, który robi za klucz główny dla encji w bazie danych (nie rób tak w produkcji). Podpięcie do bazy będzie tymczasowe i będzie służyło do momentu kiedy funkcja ta będzie pełniła już tylko rolę testową, a nie wspomagającą deweloperkę.
Metoda testFunction ma tą zaletę, że zawsze zwraca to samo. Zatem idealnie nadaje się do testów. Sama implementacja interfejsu usługi jest prosta jak konstrukcja cepa:

Listing 3. IdeoneCodeCompilerService

package pl.koziolekweb.vaadin.codecompiler.api;

import java.rmi.RemoteException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;

import pl.koziolekweb.vaadin.codecompiler.api.parsers.APIResponseParser;
import pl.koziolekweb.vaadin.codecompiler.com.ideone.api.IdeoneServicePort;
import pl.koziolekweb.vaadin.codecompiler.data.ServiceUser;
import pl.koziolekweb.vaadin.codecompiler.data.TestResponse;
import pl.koziolekweb.vaadin.codecompiler.data.dao.TestResponseDao;

public class IdeoneCodeCompilerService implements CompilerApi {

	private ServiceUser serviceUser;

	private IdeoneServicePort servicePort;

	private APIResponseParser responseParser;

	private TestResponseDao testResponseDao;

	public void setServicePort(IdeoneServicePort servicePort) {
		this.servicePort = servicePort;
	}

	public void setServiceUser(ServiceUser serviceUser) {
		this.serviceUser = serviceUser;
	}


	public void setTestResponseDao(TestResponseDao testResponseDao) {
		this.testResponseDao = testResponseDao;
	}

	@Override
	public TestResponse testFunction() throws ParseException {
		Object[] testFunction;
		TestResponse testResponse;
		try {
			testFunction = servicePort.testFunction(serviceUser.getUser(), serviceUser.getPass());
			testResponse = responseParser.parseTestResponse(testFunction);
		} catch (RemoteException e) {
			testResponse = buildFailedTestResponse(e);
		}
		testResponseDao.create(testResponse);
		return testResponse;
	}

	private TestResponse buildFailedTestResponse(RemoteException e) {
		TestResponse testResponse;
		testResponse = new TestResponse();
		testResponse.setTimestamp(new Timestamp(new Date().getTime()));
		testResponse.setError(e.getLocalizedMessage());
		return testResponse;
	}
}

Składa się ona z kilku rzeczy. Po pierwsze interfejs właściwy usługi. Ten sam, który wygenerowaliśmy za pomocą Axisa (po drobnych zmianach kosmetycznych związanych z mało przyjaznymi nazwami). Mamy też klasę ServiceUser, która trzyma informacje dostępowe. Po drugie APIResponseParser, czyli takie coś, co będzie nam zamieniało odpowiedź serwera na obiekt bliższy javowej estetyce. Niestety Ideone poszedł po najmniejszej linii oporu i zwraca obiekty soap:Array, czyli w praktyce ciąg wartości oddzielonych przecinkami. Naszym zadaniem jest to przerobić na obiekty javy. Jak? O tym później. Po trzecie mamy jeszcze dao, które obsługuje nam zapis do bazy danych.
Teraz pytanie czy takie coś nie łamie zasady SRP?

SRP ole!

O SRP pisałem dawno temu… i muszę jeszcze napisać ostatnią część cyklu… no fajnie…

Pisałem wtedy, że SRP nie oznacza jednej czynności, ale jedną odpowiedzialność na pewnym poziomie abstrakcji. Od naszego serwisu wymagamy by udostępniał nam pewne metody, ale też chcemy by była możliwość uzyskania informacji o tym jak zakończyły się wywołania. Informacje te składujemy w bazie. Problem w tym, że nie można wskazać jednoznacznie kto powinien zapisywać te informacje. Czy API, które wywołujemy czy też nasz kod wywołujący? No właśnie… jedną z zalet wprowadzenia interfejsu pośredniego jest możliwość zamknięcia w nim wszystkich tych problematycznych rzeczy. W razie czego wymienimy implementację.
Z punktu widzenia klienta wywołujemy usługę i wiemy, że wynik będzie zawsze do pobrania z bazy. Z punktu widzenia usługi właściwej też tylko wywołujemy metodę zdalną i tyle. Pośredniczący w tym procesie adapter pozwala na dodanie różnych dodatkowych funkcjonalności.
Na obecnym etapie wygląda to nie za dobrze, ale wraz z dodawaniem kolejnych metod stworzymy sobie grupę helperów, które będą zajmowały się obsługą parsowania i zapisu do bazy. W rezultacie nasz interfejs będzie robił za „palcowego” (ty zrób to, ty to, a ty to).

Odpalamy

Teraz wystarczy, że do aplikacji dodasz jeden przycisk i w nim wywołasz metodę testFunction. Gotowe…

Na koniec konfiguracja spring.xml

Listing 4. spring.xml



	
		
	
	
		
	
	
		
	
	
		
	


                                                                       
 
	                                            
	                                            
                                                                                   
                                                                                          

                                                                                   
                                                                                          
        
                                                                                   

	                                         
		                                        
	                                                                  
                                                                          

Po kolejnych zmianach wrzucę projekt na SVNa. Będzie łatwiej 😀

3 myśli na temat “Vaadin jako klient webservice III: wywołanie metody testowej

  1. Cześć, czy zamierzasz kontynuować tą serię? Chętnie jeszcze bym poczytał o powstawaniu tego serwisu. 😉

  2. Ok, w takim razie czekam z niecierpliwością. 😉 Już myślałem, że w ogóle porzuciłeś projekt, także przywróciłeś mi nadzieję. 😀

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax