• Non ci sono risultati.

configurazione e attivazione del servizio, e visualizzazione

5.2 Il servizio: ImageFabric

5.2.3 configurazione e attivazione del servizio, e visualizzazione

L’attivazione del servizio avviene tramite la pressione del pulsante ’’Start’’ presente nel form che viene visualizzato all’avvio dell’applicazione (Figura 5.3). Tale form è gestito tramite la classeFrmPreview. Nel form, oltre al pulsante che permette di far partire il servizio è presente anche un bottone per metterlo in pausa e per eseguire la configurazione. È inoltre presente unaPictureBox la quale mostra un anteprima dell’immagine. All’apertura dell’applicazione il servizio va subito ad esporre i suoi metodi tramite la creazione di unWebServiceHost. Viene poi messo in attesa che un azione venga intrapresa dall’utente tramite la pressione di uno dei tre pulsanti visualizzati.

Alla pressione del tasto di avvio dell’applicazione viene per prima cosa creata un istanza della classe ImageFactory. Viene poi fatto partire il Timer che dà inizio all’acquisizione e al salvataggio delle immagini. Per quanto riguarda invece la configurazione, essa avviene tramite un form secondario (Figura 5.4) gestito dalla classeFrmConf. In tale form viene richiesto di selezionare la webcam da cui acquisire i dati e la risoluzione delle immagini acquisite. Le informazioni tra cui scegliere vengono fornite dal componente per l’interazione con la webcam, di cui si è già precedentemente discusso. È possibile in qualunque momento mettere in pausa l’acquisizione dei dati tramite il pulsante ‘‘stop’’, esso fa in modo che ilTimer fermi temporaneamente l’acquisizione dei dati. Il servizio può essere riattivato premendo nuovamente il pulsante start.

55 55 di 87

Figura 5.3: Screen shoot diImageFabric in funzione.

Figura 5.4: Screen shoot della finestre di configurazione diImageFabric.

Luca Pasa 5.2. IL SERVIZIO: IMAGEFABRIC 5.2.4 Esposizione servizio

Per l’esposizione del servizio si è scelto di utilizzareWPFche ci assicura un ottima interpolabilità e un ottima integrazione conWinows Azure AppFabric ServiceBus. Sì è inoltre deciso di implementare un servizioRESTfulquesto per ottenere un alto grado di interpolabilità e per permette anche a client molto semplici, come ad esempio un browser, di poter accedere al servizio. Inoltre è cosi possibile accedere alla risorse esposte utilizzando semplici URI. Dal punto di vista dei client, consumare un servizio RESTFul, è molto più semplice ed economico, in quanto non richiede l’utilizzo di particolari tecnologie, ma solo delle operazioni base del protocollohttp. La scelta di utilizzare un servizio RESTFulè stata inoltre favorita dalla necessità di esporre un feed RSS.

L’utilizzo di WCFe REST ha portato ad adottare uno specifico modello di program-mazione che richiede la creazione di specifiche classi ed interfacce. Per prima cosa è stata creata l’interfaccia del servizio la quale contiene la segnatura dei metodi che il servizio espone. I metodi esposti sono due: un primo metodo che restituisce il feed in formatoRSS 2.0, mentre il secondo restituisce uno Streamrappresentante singola immagine. Per rendere possibile l’esposizione di taleendpoint conWCFl’interfaccia è stata marcata con l’attributo<ServiceContract()>, in questo modo si va a definire quella classe come il contratto del servizio. Mentre i metodi sono stati marcati con l’attributo <OperationContract()> andando così a segnalare quale operazioni devono essere esposte. L’utilizzo del paradigmaRESTha inoltre portato alla necessità di collegare delle URI ad ogni operazione, per fare ciò si sono usati gli attributi

<WebGet()>. Nel caso del metodo per la restituzione di un immagine è stata inoltre parametrizzata l’URI, in modo che l’ultimo elemento della stessa risulti essere la data e l’ora dell’immagine che si vuole ottenere. L’implementazione dell’interfaccia avviene tramite la classeServiceImplche va quindi ad implementare i due metodi definiti dell’interfaccia: getFeed()e getImg(ts As String). Il primo di questi due metodi va a richiamare la funzione getFeedRSS, messa a disposizione dalla classe singletonImageManagment, grazie alla quale è possibile restituire il feed in formato RSS 2.0. il metodogetImg va invece a codificare il valore passato tramite la URI al fine di avere un formato data e ora valido. Va poi ad utilizzare questo valore come parametro passato al metodogetImageStreammesso sempre a disposizione dalla classe singletonImageManagment.

Come spiegato precedentemente è stato scelto di utilizzareWindows Azure Appfabric Service Bus, e per questo è stato necessario accedere al portale di gestione di Windows Azure e creare un nuovo namespace per il servizio. In Figura 5.5 è visualiz-zato come si presentava il portale di gestione dopo la creazione del namespace.

Per rendere possibile l’esposizione del servizio è necessario impostare alcuni parametri di connessione ed impostazione all’interno del file di configurazione dell’applicazione:

App.config. In questo file è per prima cosa presenta la scelta di utilizzare il binding webHttpRelayBinding. Questo binding permette di creare servizi basati HTTP/REST e rende possibile esporre i servizi senza che i client si interfaccino direttamente con il servizio, grazie alrelay service che espone un endpoint HTTP. In questo modo i client per interfacciarsi al servizio basta che sappiano utilizzare il protocolloHTTP. All’interno della configurazione del webHttpRelayBindingè stato aggiunto un impor-tante opzione riguardante la necessita di autenticarsi da parte dei client. L’opzione in questione èrelayClientAuthenticationTypepresente nella gestione della sicurez-za. A questa opzione è stato assegnato valore ‘‘None’’, in questo modo i client non necessitano di autenticarsi per accedere al servizio.

Sì è poi specificato il servizio da esporre e impostato il comportamento, a questo segue la configurazione del endpoint andando ad assegnare il binding precedentemente

57 57 di 87

Figura 5.5: Portale di gestione Windows Azure Service Bus dopo la creazione del namespace.

configurato. È stato poi configurato il comportamento dell’endpoint, andando a specificare le credenziali shared secretnecessarie all’applicazione per poter esporre l’endpoint. Tali credenziali sono state ottenute al momento della creazione e configu-razione del namespace.

Per completare l’esposizione è stato istanziato in fine un oggettoWebServiceHost, il quale verrà creato ed aperto all’avvio dell’applicazione.

5.2.5 log

Per assicurare una buona gestione delle possibili eccezioni ed errori che possono presentarsi in futuro durante l’utilizzo dell’applicazione, è stato deciso di creare un file di log nel quale registrate lo stackTrace delle eccezioni che vengono sollevate durante l’esecuzione. Per fare ciò ci si è appoggiati alla libreria NSpring la quale offre un meccanismo semplice ed efficace per la gestioni del log, che va ad astrarre la complessità della creazione e gestione manuale di un file.

Per garantire un utilizzo unificato delle funzioni di log è stata creata la classe Log, la quale implementa il design pattern singleton. Essa va inoltre a mettere a disposizione dei metodi che automatizzano l’inserimento dei messaggi di log all’interno del file.

assicurando così che tutti i messaggi abbiano un formato comune.

Per gestire l’inserimento dei log è stato aggiunto all’interno dei blocchi Try-catch, presenti in tutti i metodi, una chiamata al metodo di inserimento di un nuovo messaggio di log nel file. Il messaggio darà lo stackTrace dell’errore. Sì è deciso di inserire lo stackTrace in quanto si ritiene molto importante al fine di poter risalire alla causa dell’eccezione. L’eventuale inserimento del solo messaggio generato dall’eccezione, o addirittura del solo tipo di eccezione, non avrebbe dato informazioni abbastanza complete e significative.

5.2.6 coordinamento e gestione dei componenti

Nella gestione delle varie funzioni esposte è stato necessario individuare un com-ponente che coordinasse le varie operazione e quindi facesse cooperare in maniera ordinata i vari componenti. Il componente individuato ad eseguire tale scopo è la classe FrmPreview. La scelta è stata principalmente fatta sulla base della necessità di rispettare le scelte dell’utente nell’attivazione, configurazione e messa in pausa del servizio. L’interazione viene gestita dalla classe FrmPreview. Inoltre, la volontà di

Luca Pasa 5.2. IL SERVIZIO: IMAGEFABRIC mantenere fortemente separati la gestione dei dati, la gestione dell’interazione con la webcam e l’implementazione del servizio, hanno richiesto l’utilizzo di un ‘‘aggregatore di funzioni’’. È infatti la classeFrmPreview a coordinare le richieste ai vari comparti dell’applicazione tramite l’utilizzo di un Timer, il quale va a sollevare un evento all’interno del quale avvengono le chiamate alle funzioni che permettono di eseguire l’acquisizione e la memorizzazione dei dati.

59 59 di 87

5.3 Il Client Desktop: ImageConsumer

L’applicazione client desktop permette di accedere e consumare il servizio. Per fare ciò l’applicazione deve ottenere il feed nel quale sono collezionati i link alla varie immagini. Ognuno di questi link va a rappresentare la richiesta al servizio di una singola immagine. La scelta riguardante quali immagini andare effettivamente ad ottenere tra quelle esposte è fatta in base ai limiti imposti dalla velocità di connessione e dalla disponibilità di memoria.

Questa applicazione vuole dare all’utente la possibilità di visualizzare le immagini ottenute dal servizio e di navigare fra esse, vengono infatti mantenute in memoria le cento immagini più recenti ottenute dal servizio tra le quali l’utente può scegliere quale visualizzare. Oppure è possibile attivare la modalità che permette di visualizzare sempre l’ultima immagine ottenuta. Uno degli aspetti che si è voluto curare nella realizzazione del servizio assicurare che l’interfaccia grafica non subisca rallentamenti durante il download di un immagine. Per questo ci si è preoccupati di andare ad utilizzare meccanismi per la gestione dell’esecuzione parallela.

Nella creazione di tale applicazione client sono state individuate alcune funzioni fondamentali che hanno portato alla necessità di creare determinati componenti e di effettuare determinate scelte architetturali:

• ricezione dati;

• gestione interazione con il servizio;

• gestione dei dati ricevuti;

• visualizzazione dei dati;

• gestione log di sistema.

L’applicazione client in questione è stata realizzata utilizzando il linguaggioVisual Basic.NET. È inoltre interessante notare che grazie all’utilizzo di un servizio REST non è strettamente necessario utilizzare WCFper comunicare con esso.

La gestione di tali funzionalità è eseguita tramite alcuni componenti che interagiscono tra loro tramite un preciso schema. I componenti in gioco sono i seguenti:

• Receiver: gestisce le richieste al servizio;

• ServiceManager: decide come e quando eseguire le richieste al servizio;

• DataManager: gestisce la memorizzazione dei dati;

• Interfaccia utente: mostra le immagini e gestisce l’iterazione con l’utente;

• Gestore di log: fornisce metodi per l’inserimento di messaggi nel log dell’appli-cazione.

In Figura 5.6 viene riportato il diagramma delle classi dell’applicazioneImageConsumer.

Luca Pasa 5.3. IL CLIENT DESKTOP: IMAGECONSUMER

#Dispose(in disposing : Boolean) -InitializeComponent()

-FrmClient_Disposed(in sender : Object, in e : EventArgs) -FrmClient_Load(in sender : Object, in e : EventArgs) +HandleNewItem(in sender : Object, in e : EventArgs) -sldImgNav_Scroll(in sender : Object, in e : EventArgs) -changeImage(in img : Image, in dt : Date) -components : IContainer

-ImgItemInverseComparison(in x : ImageItem, in y : ImageItem) : Integer +add(in dt : Date, in img : Image)

+ItemInserted(in sender : Object, in e : EventArgs) : EventHandler +OnAdd(in e : EventArgs)

-getImgAsync(in imgDate : Date, in NTime : Integer = 0) +StartUpdateImgs()

-OnTimedEvent(in source : Object, in e : ElapsedEventArgs) -_lastUpdate : Date = DateTime.MinValue +CompareTo(in obj : Object) : Integer -_img : Image

-_dTime : Date ImageItem +receiveNewImageDataList(in imgAfter : Date) : List

-InverseDateOrder(in x : Date, in y : Date) : Integer +GetImagebyDate(in dtime : Date) : Image

-BASE_SERVICE_URL : String = "https://webcamprototype.servicebus.appfabriclabs.com/imageFabric/"

L'evento che segnala l'inserimento di un oggetto sollevato da DataManager, viene catturato da FrmClient al fine di gestire in maniera efficente la visualizzazione dei dati.

Singleton

Singleton

ComponentModel::Component

IComparable

+imageToStream(in img : Image, in iFormat : ImageFormat) : Stream +streamToImage(in stream : Stream) : Image

ImgCoverter

Figura 5.6: Schema delle classi diImageConsumer.

61 61 di 87

L’interazione tra i componenti segue una precisa logica: ilServiceManagerattende una richiesta da parte dell’interfaccia utente per cominciare l’interazione con il servizio, che avviene tramite l’utilizzo dei metodi messi a disposizione dalReceiver. Al momento dell’arrivo dei dati Servicemanagerva ad immagazzinarli in memoria tramite l’utilizzo delDataManager, il quale si preoccuperà di segnalare all’interfaccia utente la presenza di un nuovo dato da visualizzare. In Figura 5.7 viene riportato lo schema che mostra come interagiscono tra loro questi componenti.

ImageFabric Receiver

ServiceManager

Interfaccia utente

DataManager

Evento D’inserimento Nuovo dato ImageConsumer

Figura 5.7: Schema interazione tra componenti diImageConsumer.

5.3.1 ricezione dati

La ricezione dei dati esposti dal servizio richiede due principali operazioni: la ricezione del feed RSS e la ricezione delle singole immagini esposte. Queste funzioni sono implementate all’interno della classe Receiver.

Per quanto riguarda la prima operazione si va a accedere alla URI a cui è esposto il feed e si va leggere il codiceXMLche lo rappresenta. Tale codice viene codificato tramite l’oggetto XmlReader, ed il risultato utilizzato per creare un oggettoSyndicationFeed. L’utilizzo di un oggetto SyndicationFeed ci permette un facile e veloce accesso ai dati evitando così di eseguire un parsing manuale del XML. Per questo metodo si è inoltre ritenuto necessario dare la possibilità all’utilizzatore di filtrare i dati che si vogliono ottenere. Il filtraggio avviene per data, dando la possibilità di ottenere informazioni strettamente successive ad una data e ora passate come parametro del metodo che permette la ricezione stessa.

Un’altra peculiarità di questo metodo è data dal fatto che il valore restituito è un lista di oggettiDateTimeche rappresentano la data e l’ora di acquisizione delle nuove immagini esposte dal servizio. Questo è possibile grazie al fatto che si è deciso di utilizzare la data e l’ora di acquisizione come identificativi per le immagini. Questa scelta si ripercuote inoltre sul secondo metodo che esegue la ricezione, infatti esso richiede come parametro di input la data e l’ora di acquisizione dell’immagine che si

Luca Pasa 5.3. IL CLIENT DESKTOP: IMAGECONSUMER desidera ottenere. Questo parametro viene utilizzato per andare a creare l’URI che permette di effettuare la richiesta al servizio, l’URI ha la seguente forma:

https://webcamprototype.servicebus.appfabriclabs.com/imageFabric/getImage/[Data e ora dell’immagine richiesta]

Creata tale URI possiamo eseguire un HttpWebRequest per ottenere i dati richiesti che ci saranno inviati comeStream, per farlo è però prima necessario impostare il metodo per la richiesta a Get. Appena ci arriverà la HttpWebResponse possiamo andare a convertire loStream nell’immagine, e per farlo si utilizza le funzionalità messe a disposizione dalla classeImageConverter. Questa classe fornisce due metodi statici che provvedono alla conversione daStreama immagine e viceversa.

In questi metodi possiamo notare come non ci sia traccia dell’utilizzo diWCF, questo è stato possibile grazie all’utilizzo di un servizioRESTFul, rendendo quindi possibile la creazione di client anche non utilizzando tecnologia microsoft. Inoltre ricordiamo che il servizio è esposto tramite l’utilizzo diWindows Azure AppFabric Service Bus, ma come si può vedere nei metodi che si interfacciano con il servizio, non è presente alcuna riga di codice che dipenda dall’utilizzo di questa tecnologia. Questo dimostra la trasparenza di questo servizio offerto dalla piattaformaWindows Azure del quale però si possono apprezzare i benefici: non è infatti stato necessario eseguire alcuna modifica ad impostazione di firewall o NAT per eseguire la connessione al nostro servizioImageFabric.

5.3.2 gestione interazione con il servizio

La gestione dell’interazione con il servizio è affidata alla classeServiceManager. In questa classe è definito quando e come eseguire le richieste al servizio e come gestire i dati ricevuti. Per assicurare che la gestione del servizio avvenga attraverso un unica istanza di questa classe è stato deciso di far in modo che implementi il design pattern Singleton. La classe prevede che essa venga avviata da un richiesta di attivazione dell’interazione con il servizio e poi possa gestire autonomamente tale interazione andando a salvare i dati tramite il DataManager. Alla ricezione di tale richiesta, che avviene tramite il metodoStartUpdateImgs, viene creato unTimer il quale ogni cinque secondi solleva l’eventoElapsed che è gestito dal metodoOnTimedEvent. In questo metodo vengono eseguite due operazioni: l’aggiornamento dei dati e viene calcolato fra quanto tempo verrà eseguito il prossimo aggiornamento. Viene infatti tenuto conto del tempo richiesto per la ricezione dei dati, tempo che viene detratto dall’intervallo dei cinque secondi, in modo da avere la massima regolarità nelle richieste ed avere piene indipendenza da eventuali problemi di velocità nella rete.

Nel poco probabile caso che l’invio dell’immagine richieda più di cinque secondi ci si limiterà ad eseguire l’aggiornamento cinque secondi dopo, andando così a saltare uno o più aggiornamenti previsti, al fine di non accodare inutilmente richieste, che nel lungo periodo potrebbero causare un blocco del sistema.

Per quanto riguarda l’aggiornamento dei dati viene utilizzato il metodo UpdateIm-ageList. All’interno di questo metodo si richiede per prima cosa al servizio (tramite il Receiver) la lista degli ultimi elementi esposti più aggiornati rispetto a quelli di cui si è già in possesso. Ricevuti tali dati si estrae la data e ora più recente, e si esegue la richiesta al servizio di tale immagine. La richiesta di un’immagine può avere un peso importante, e quindi anche un costo a livello computazionale rilevante ai fini dell’esecuzione, inoltre esiste la possibilità di voler eseguire la richiesta di due o più immagini, andando così a rendere molto costosa tale operazione. È per questo stato deciso di implementare questa operazione in maniera asincrona andando ad applicare

63 63 di 87

il concetto del parallel computing. Per farlo è stato deciso di utilizzare la libreria Task Parallella quale, oltre a rendere possibile l’esecuzione di un applicazione in multi-threading, permette l’ottimizzazione dell’esecuzione di task anche su processori multicore. L’applicazione di tale scelta all’esecuzione della richiesta di immagini al servizio ha portato a dover affrontare alcune problematiche. Una di queste è stata la gestione di problemi di connessione o di temporanea impossibilità di ottenere i dati.

In questo caso sì è deciso di tentare per tre volte, e in caso di fallimento di tutti e tre i tentativi, di gestire l’errore. Il codice di richiesta è stato incapsulato all’interno della funzione getImgAsyncnella quale oltre ad eseguire il tentativo di ottenere l’immagine dal servizio va anche, in caso di successo, ad inserirla in memoria. Per farlo si va ad utilizzare le funzioni messe a disposizione dalDataManager.

5.3.3 gestione dei dati ricevuti

La gestione dei dati viene eseguita tramite la classe DataManager. Questa classe si occupa del salvataggio in memoria dei dati, dell’inserimento e della lettura degli stessi.

Viene inoltre qui definito il numero massimo di dati mantenuti contemporaneamente.

Si è deciso di mantenere in memoria non più di cento elementi, onde evitare sovrac-carico di memoria. Gli elementi vengono mantenuti in una struttura dati di tipo ListOf(T). per incapsulare i vari elementi si è creata la classeImageItemLa quale mantiene in memoria le sole informazioni utili: l’immagine e la data e l’ora in cui l’immagine è stata catturata. Questa classe va inoltre ad implementare l’interfaccia IComparable che permette di eseguire confronti tra oggetti da essa definiti. Essendo che i confronti in questo caso vengono utilizzati per ordinare temporalmente i vari elementi, si è deciso di basare l’implementazione di tale interfaccia sulla data e l’ora salvate in modo da permettere un facile ordinamento temporale degli elementi ricevuti dal servizio.

La classeDataManager comunica con altre 2 classi: con ilServiceManager che richia-ma i metodi per eseguire l’inserimento degli elementi, e con l’interfaccia utente (FrmClient) tramite un evento che segnala la disponibilità di nuovi dati.

Nel primo caso il metodo che viene esposto allo scopo di inserire nuovi elementi è il metodo add. Questo metodo richiede come parametri d’ingresso l’immagine, la data e l’ora in cui è stata catturata. Con questi dati va a creare un oggetto di tipo ImageItemed inserirlo nella lista. Viene inoltre controllato che non venga superato il numero massimo di elementi che si è deciso di mantenere in memoria, nel caso ci si trovasse in questa situazione il metodo sì occuperebbe di eliminare l’elemento meno recente presente nella lista. Alla fine di queste operazioni viene sollevato l’eventoItemInsertedper segnalare all’interfaccia utente la presenza di nuovi dati da visualizzare. Tale evento viene definito all’interno della classe, insieme al delegate che permette alla classe ricevente di gestirlo.

L’interfaccia grafica necessita anche di conoscere gli oggetti presenti in memoria, per questo è stata creata la funzione getListche ritorna una copia ordinata per data (dalla più recente alla meno recente) della lista di elementi attualmente mantenuti

L’interfaccia grafica necessita anche di conoscere gli oggetti presenti in memoria, per questo è stata creata la funzione getListche ritorna una copia ordinata per data (dalla più recente alla meno recente) della lista di elementi attualmente mantenuti