sommario
Il nostro progetto consiste in una piattaforma web social-style in cui ogni utente si registra rendendo pubblici (all'interno della piattaforma) i propri account (email, twitter, facebook, etc). Ogni utente potrà accedere alle informazioni di una qualsiasi persona tramite il riconoscimento facciale, a patto che essa sia registrata oppure che sia stata "schedata" tramite le api di facebook. Il riconoscimento potrà avvenire:
- lato desktop con il caricamento di una foto attraverso l'applicazione web
- lato mobile tramite il caricamento e anche attraverso un sistema di realtà aumentata.
Il progetto prevede la realizzazione di:
- un'applicazione web, in cui gli utenti potranno registrarsi, modificare i propri dati, cancellare ed aggiungere le proprie foto, caricare foto per riconoscere le persone presenti.
- applicazione android (in seguito anche iphone), in cui gli utenti potranno registrarsi, (modificare i propri dati), richiedere il riconoscimento tramite caricamento foto o tramite realtà aumentata.
Integrazione di un servizio che tracci la posizione e indichi all'utente quali utenti sono vicini a lui, o che dia comunque la possibilità di limitare la ricerca tra gli utenti che sono effettivamente nei paraggi.Il server si deve occupare di gestire tutte le richieste che gli giungono dai client desktop e mobile e di interfacciarsi con le API di face.com (servizio al quale ci appoggiamo attualmente per gli algoritmi di riconoscimento facciale).
Deve perciò gestire login/logout, registrazione, profile editing, riconoscimento delle immagini date le url e interazione con i database.
Per le specifiche più dettagliate si rimanda ai casi d'uso.I vari client, che siano mobile o desktop devono invece preoccuparsi di inviare al server informazioni riguardo la registrazione e la modifica dei dati dell'utente, il login al nostro servizio e la scelta dell'immagine della persona di cui richiedere il riconoscimento facciale.Al momento dell'iscrizione chiediamo (tutti gli elementi sono obbligatori):
- Nome e Cognome,Sesso, Mail e Password, Data di nascita
- Almeno 3 foto in cui è presente solo l'utente (una sorta di immagine del profilo)
- Collegamento con account Facebook (e/o Twitter) tramite login per confermare l'identità.
piattaforma web social-style: piattaforma web che fornisca servizi "sociali", ovvero che permetta l'interazione fra utenti.
utente registrato: qualsiasi persona che si sia registrata fornendo nome, cognome, email, password e altri dati al fine di poter essere riconosciuto e poter riconoscere altri utenti registrati, (requisito fondamentale per la registrazione è il caricamento delle proprie foto).
riconoscimento facciale: è una tecnica di intelligenza artificiale utilizzata in biometria per identificare o verificare l'identità di una persona a partire da una o più immagini che la ritraggono.
applicazione web: un'applicazione accessibile via web per mezzo di Internet dalla quale è possibile gestire i dati del proprio account registrato.
applicazione mobile: un'applicazione appositamente realizzata per dispositivi mobili, e che incorporano almeno una fotocamera, un sistema di localizzazione GPS e una connessione a rete dati a pacchetto.
realtà aumentata: è una tecnica che consiste nel sovrapporre livelli contenenti informazioni all'immagine reale che viene ripresa tramite un dispositivo.
database: è un insieme di archivi collegati secondo un particolare modello logico (relazionale, gerarchico o reticolare) e in modo tale da consentire la gestione dei dati stessi (inserimento, ricerca, cancellazione ed aggiornamento) da parte di particolari applicazioni software dedicate.
social-account: con questo termine indichiamo un profilo di un social network che l'utente ha collegato durante o dopo la registrazione confermando tramite un processo di autenticazione la reale corrispondenza dell'utente col profilo stesso; ogni profilo collegato viene contraddistinto con l'id del corrispondente servizio/social network.
feedback: è una sorta di commento o consiglio che l'utente invia al nostro team per segnalare anomalie o proposte per il miglioramente della nostra piattaforma.
posizione: è la collocazione spaziale dell'utente determinata dalle coordinate geografiche al momento della richiesta di riconoscimento al nostro servizio.
tag: consiste nell'associare l'account di un utente ad una foto in cui è stato riconosciuto il suo volto.
Activity: una specie di "schermata" o finestra di cui sono composte le applicazioni Android, visualizzabile sullo schermo del dispositivo. Per una definizione più rigorosa consultare la documentazione di Android:
http://developer.android.com/guide/topics/fundamentals/activities.htmlI casi d'uso del nostro sistema sono riassunti chiaramente e semplicemente dal seguente schema, che suggerisce anche come abbiamo pensato di strutturare la loro risoluzione.
![usecase.png](/xwiki/bin/download/Courseproject/Visage/usecase.png?height=750&rev=1.1)
Lo schema è abbastanza autoesplicativo, ma sono comunque necessarie alcune considerazioni.
Con User si intendono tutti i "tipi" di utenti, sia che essi accedano al servizio tramite web application che tramite piattaforme mobile.
Con Operator si intendono coloro che avranno il compito di "sorvegliare" che i contenuti caricati dagli utenti non siano "scorretti", previa consultazione dei feedback dagli utenti, ed inoltrare report all'admin, il quale è l'unico a poter prendere provvedimenti.Oltre ai requisiti funzionali necessari per l'effettivo funzionamento del sistema, è necessario fare attenzione a quelle caratteristiche che rendono il sistema ben progettato e che garantiscono la bontà del progetto.
Usabilità Considerando il tipo di sistema che stiamo sviluppando ci si aspetta un minimo di preparazione informatica o dimestichezza con i dispositivi mobili o desktop. Nonostante queste è indispensabile che ogni tipo di utente riesca a fruire del sistema senza la necessità di nessun tipo di istruzioni preliminari.
Affidabilità Essendo il sistema completamente dipendente dall'interazione con un database ci si aspetta che anche in casi di guasti o di problemi elettrici nella server-farm che ospita i nostri server, si possa comunque ripristinare entro breve la situazione precedente e il servizio rimanga comunque funzionante per quanto possibile. In questo senso sarà importante prevedere dei backup e delle copie consistenti del database e fare in modo che ci sia almeno una copia di ogni componente in grado di sopperire al sovraccarico o al malfunzionamente di uno di essi.
Sicurezza La nostra politica prevede che solo chi è regolarmente registrato possa accedere ai nostri servizi, sarà quindi necessaria la presenza di un sistema di autenticazione tramite username/password. Inoltre è fondamentale garantire una struttura che prevenga la possibilità di attacchi informatici vista comunque la presenza nel database di dati personali come foto e password anche se non gestiamo dati sensibili.
Prestazioni e scalabilità Considerando la natura dell'ambiente web e la comprensibile poca pazienza dell'utente che necessita di un servizio rapido, il numero dei server e della banda utilizzabile deve essere scalabile rispetto al numero degli utenti. Per questo si ritiene necessaria una struttura che preveda la possibilità di ampliare il servizio sia in termini di qualità sia quanto riguarda la quantità, il sistema deve essere infatti in grado di interagire potenzialmente con un numero anche elevato di utenti. Inoltre, anche se inizialmente non verranno sviluppate tutte le funzionalità a cui abbiamo pensato, è fondamentale che il sistema possa essere ampliato senza riscontrare problemi riguardo la modifica di componenti già creati.Dal seguente schema si evince come abbiamo deciso di utilizzare un'approccio modulare per suddividere le funzioni del sistema. In questo modo ci risulterà più semplice apportare modifiche a singole parti del sistema o aggiungere ulteriori funzionalità.
Si è cercato di individuare le funzionalità che il sistema deve offrire e suddividerle in moduli logici. L'obiettivo è quello di avere moduli che siano il più possibile indipendenti tra loro.
registration: il processo attraverso cui una persona diventa utente del servizio
authentication: il processo attraverso cui una persona dimostra di essere un utente già registrato fornendo nome utente e pasword, consente di identificare l'utente per l'utilizzo del servizio
userPanel: l'insieme delle procedure attraverso cui un utente ha la facoltà di modificare i dati e le foto che ha inserito al momente della registrazione, collegamento di account compreso.
photo: l'insieme dei processi che riguardano il caricamento e il tagging delle foto
local: l'insieme dei processi che si occupano della posizione spaziale dell'utente
cms: l'insieme delle procedure che consentono all'amministratore e/o agli operatori di disabilitare utenti ed ottenere il log.
dbManager: l'insieme delle procedure che si occupano dell'interazione col database.
managment: il processo che permette di gestire i feedback rilasciati dagli utenti
![Modules.jpg](/xwiki/bin/download/Courseproject/Visage/Modules.jpg?rev=1.1)
Nello schema si evidenza inoltre come abbiamo deciso di tenere la gestione del DB separata dal resto del sistema, di modo da renderla trasparente al sistema.
Gli unici vincoli, facilmente rilassabili, che abbiamo deciso di introdurre sono quelli legati all'interazione tra i client e il sistema, che deve avvenire tramite HTTP request, e tra il sistema e il gestore del DB, che deve avvenire tramite un meccanismo di RPC. Un primo schema generale di soluzione può essere il seguente.
![package.png](/xwiki/bin/download/Courseproject/Visage/package.png?height=650&rev=1.1)
Per motivi di sicurezza, la comunicazione dei vari moduli con il server del database può avvenire solamente tramite il modulo DBOperator che gira su un server separato, con un protocollo RPC da noi ideato basato su richieste HTTP. In pratica i vari moduli non possono collegarsi direttamente al server database con il protocollo MySQL, ma possono chiamare le varie funzioni di DBOperator, le quali a loro volta si occuperanno di comunicare con il server database vero e proprio. In DBOperator c’è una funzione per ogni operazione che può essere effettuata sul database, per esempio insertUser(
Failed to execute the [velocity] macro. Cause: [Nested scripts are not allowed. Current Script Macro [velocity] (source [xwiki:Courseprojects.Sheet]) is executed inside Script Macro [velocity] (source [xwiki:Courseprojects.Sheet])]. Click on this message for details.org.xwiki.rendering.macro.MacroExecutionException: Nested scripts are not allowed. Current Script Macro [velocity] (source [xwiki:Courseprojects.Sheet]) is executed inside Script Macro [velocity] (source [xwiki:Courseprojects.Sheet])
at org.xwiki.rendering.macro.script.AbstractScriptMacro.execute(AbstractScriptMacro.java:178)
at org.xwiki.rendering.macro.script.AbstractScriptMacro.execute(AbstractScriptMacro.java:58)
at org.xwiki.rendering.internal.transformation.macro.MacroTransformation.transform(MacroTransformation.java:311)
at org.xwiki.rendering.internal.transformation.DefaultRenderingContext.transformInContext(DefaultRenderingContext.java:183)
at org.xwiki.rendering.internal.macro.html.HTMLMacro.renderWikiSyntax(HTMLMacro.java:215)
at org.xwiki.rendering.internal.macro.html.HTMLMacro.execute(HTMLMacro.java:150)
at org.xwiki.rendering.internal.macro.html.HTMLMacro.execute(HTMLMacro.java:70)
at org.xwiki.rendering.internal.transformation.macro.MacroTransformation.transform(MacroTransformation.java:311)
at org.xwiki.rendering.internal.transformation.DefaultRenderingContext.transformInContext(DefaultRenderingContext.java:183)
at org.xwiki.rendering.internal.transformation.DefaultTransformationManager.performTransformations(DefaultTransformationManager.java:88)
at org.xwiki.display.internal.DocumentContentAsyncExecutor.executeInCurrentExecutionContext(DocumentContentAsyncExecutor.java:395)
at org.xwiki.display.internal.DocumentContentAsyncExecutor.execute(DocumentContentAsyncExecutor.java:268)
at org.xwiki.display.internal.DocumentContentAsyncRenderer.execute(DocumentContentAsyncRenderer.java:112)
at org.xwiki.rendering.async.internal.block.AbstractBlockAsyncRenderer.render(AbstractBlockAsyncRenderer.java:157)
at org.xwiki.rendering.async.internal.block.AbstractBlockAsyncRenderer.render(AbstractBlockAsyncRenderer.java:54)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.syncRender(DefaultAsyncRendererExecutor.java:290)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.render(DefaultAsyncRendererExecutor.java:267)
at org.xwiki.rendering.async.internal.block.DefaultBlockAsyncRendererExecutor.execute(DefaultBlockAsyncRendererExecutor.java:125)
at org.xwiki.display.internal.DocumentContentDisplayer.display(DocumentContentDisplayer.java:67)
at org.xwiki.display.internal.DocumentContentDisplayer.display(DocumentContentDisplayer.java:43)
at org.xwiki.display.internal.DefaultDocumentDisplayer.display(DefaultDocumentDisplayer.java:96)
at org.xwiki.display.internal.DefaultDocumentDisplayer.display(DefaultDocumentDisplayer.java:39)
at org.xwiki.sheet.internal.SheetDocumentDisplayer.display(SheetDocumentDisplayer.java:245)
at org.xwiki.sheet.internal.SheetDocumentDisplayer.applySheet(SheetDocumentDisplayer.java:225)
at org.xwiki.sheet.internal.SheetDocumentDisplayer.maybeDisplayWithSheet(SheetDocumentDisplayer.java:180)
at org.xwiki.sheet.internal.SheetDocumentDisplayer.display(SheetDocumentDisplayer.java:111)
at org.xwiki.sheet.internal.SheetDocumentDisplayer.display(SheetDocumentDisplayer.java:52)
at org.xwiki.display.internal.ConfiguredDocumentDisplayer.display(ConfiguredDocumentDisplayer.java:68)
at org.xwiki.display.internal.ConfiguredDocumentDisplayer.display(ConfiguredDocumentDisplayer.java:42)
at com.xpn.xwiki.doc.XWikiDocument.display(XWikiDocument.java:1366)
at com.xpn.xwiki.doc.XWikiDocument.getRenderedContent(XWikiDocument.java:1503)
at com.xpn.xwiki.doc.XWikiDocument.displayDocument(XWikiDocument.java:1452)
at com.xpn.xwiki.doc.XWikiDocument.displayDocument(XWikiDocument.java:1421)
at com.xpn.xwiki.api.Document.displayDocument(Document.java:787)
at jdk.internal.reflect.GeneratedMethodAccessor438.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:571)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:554)
at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:221)
at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:368)
at org.apache.velocity.runtime.parser.node.ASTReference.value(ASTReference.java:704)
at org.apache.velocity.runtime.parser.node.ASTExpression.value(ASTExpression.java:75)
at org.apache.velocity.runtime.parser.node.ASTSetDirective.render(ASTSetDirective.java:242)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:439)
at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:190)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.xwiki.velocity.internal.directive.TryCatchDirective.render(TryCatchDirective.java:86)
at org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:304)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:439)
at org.apache.velocity.Template.merge(Template.java:358)
at org.apache.velocity.Template.merge(Template.java:262)
at org.xwiki.velocity.internal.InternalVelocityEngine.evaluate(InternalVelocityEngine.java:225)
at com.xpn.xwiki.internal.template.VelocityTemplateEvaluator.evaluateContent(VelocityTemplateEvaluator.java:105)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.evaluateContent(TemplateAsyncRenderer.java:219)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.renderVelocity(TemplateAsyncRenderer.java:174)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:135)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:54)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.lambda$syncRender$0(DefaultAsyncRendererExecutor.java:284)
at com.xpn.xwiki.internal.security.authorization.DefaultAuthorExecutor.call(DefaultAuthorExecutor.java:98)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.syncRender(DefaultAsyncRendererExecutor.java:284)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.render(DefaultAsyncRendererExecutor.java:267)
at org.xwiki.rendering.async.internal.block.DefaultBlockAsyncRendererExecutor.render(DefaultBlockAsyncRendererExecutor.java:154)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:904)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:866)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:853)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderNoException(InternalTemplateManager.java:808)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderNoException(InternalTemplateManager.java:800)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.renderNoException(DefaultTemplateManager.java:79)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.renderNoException(DefaultTemplateManager.java:73)
at org.xwiki.template.script.TemplateScriptService.render(TemplateScriptService.java:54)
at jdk.internal.reflect.GeneratedMethodAccessor186.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:571)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:554)
at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:221)
at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:368)
at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:492)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.apache.velocity.runtime.directive.VelocimacroProxy.render(VelocimacroProxy.java:218)
at org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:331)
at org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:261)
at org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:304)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:439)
at org.apache.velocity.Template.merge(Template.java:358)
at org.apache.velocity.Template.merge(Template.java:262)
at org.xwiki.velocity.internal.InternalVelocityEngine.evaluate(InternalVelocityEngine.java:225)
at com.xpn.xwiki.internal.template.VelocityTemplateEvaluator.evaluateContent(VelocityTemplateEvaluator.java:105)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.evaluateContent(TemplateAsyncRenderer.java:219)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.renderVelocity(TemplateAsyncRenderer.java:174)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:135)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:54)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.lambda$syncRender$0(DefaultAsyncRendererExecutor.java:284)
at com.xpn.xwiki.internal.security.authorization.DefaultAuthorExecutor.call(DefaultAuthorExecutor.java:98)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.syncRender(DefaultAsyncRendererExecutor.java:284)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.render(DefaultAsyncRendererExecutor.java:267)
at org.xwiki.rendering.async.internal.block.DefaultBlockAsyncRendererExecutor.render(DefaultBlockAsyncRendererExecutor.java:154)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:904)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:866)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:853)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderNoException(InternalTemplateManager.java:808)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderNoException(InternalTemplateManager.java:800)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.renderNoException(DefaultTemplateManager.java:79)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.renderNoException(DefaultTemplateManager.java:73)
at org.xwiki.template.script.TemplateScriptService.render(TemplateScriptService.java:54)
at jdk.internal.reflect.GeneratedMethodAccessor186.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:571)
at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:554)
at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:221)
at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:368)
at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:492)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.apache.velocity.runtime.directive.VelocimacroProxy.render(VelocimacroProxy.java:218)
at org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:331)
at org.apache.velocity.runtime.directive.RuntimeMacro.render(RuntimeMacro.java:261)
at org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:304)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:171)
at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:147)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:439)
at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:190)
at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:439)
at org.apache.velocity.Template.merge(Template.java:358)
at org.apache.velocity.Template.merge(Template.java:262)
at org.xwiki.velocity.internal.InternalVelocityEngine.evaluate(InternalVelocityEngine.java:225)
at com.xpn.xwiki.internal.template.VelocityTemplateEvaluator.evaluateContent(VelocityTemplateEvaluator.java:105)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.evaluateContent(TemplateAsyncRenderer.java:219)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.renderVelocity(TemplateAsyncRenderer.java:174)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:135)
at com.xpn.xwiki.internal.template.TemplateAsyncRenderer.render(TemplateAsyncRenderer.java:54)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.lambda$syncRender$0(DefaultAsyncRendererExecutor.java:284)
at com.xpn.xwiki.internal.security.authorization.DefaultAuthorExecutor.call(DefaultAuthorExecutor.java:98)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.syncRender(DefaultAsyncRendererExecutor.java:284)
at org.xwiki.rendering.async.internal.DefaultAsyncRendererExecutor.render(DefaultAsyncRendererExecutor.java:267)
at org.xwiki.rendering.async.internal.block.DefaultBlockAsyncRendererExecutor.render(DefaultBlockAsyncRendererExecutor.java:154)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:904)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:866)
at com.xpn.xwiki.internal.template.InternalTemplateManager.renderFromSkin(InternalTemplateManager.java:846)
at com.xpn.xwiki.internal.template.InternalTemplateManager.render(InternalTemplateManager.java:832)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.render(DefaultTemplateManager.java:91)
at com.xpn.xwiki.internal.template.DefaultTemplateManager.render(DefaultTemplateManager.java:85)
at com.xpn.xwiki.XWiki.evaluateTemplate(XWiki.java:2565)
at com.xpn.xwiki.web.Utils.parseTemplate(Utils.java:180)
at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:651)
at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:339)
at com.xpn.xwiki.web.LegacyActionServlet.service(LegacyActionServlet.java:108)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.xpn.xwiki.web.ActionFilter.doFilter(ActionFilter.java:122)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.xwiki.wysiwyg.filter.ConversionFilter.doFilter(ConversionFilter.java:61)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter.doFilter(SetHTTPHeaderFilter.java:63)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.xwiki.resource.servlet.RoutingFilter.doFilter(RoutingFilter.java:132)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.xwiki.container.servlet.filters.internal.SavedRequestRestorerFilter.doFilter(SavedRequestRestorerFilter.java:208)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.xwiki.container.servlet.filters.internal.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:111)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:394)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:829)) , getUser() , nelle quali viene creato il codice SQL corrispondente, sanitizzando tutti i parametri, in modo da essere invulnerabili ad attacchi SQL Injection. In questo modo se vengono compromessi i server Apache dove girano i vari moduli, essi non possono eseguire codice SQL arbitrario sul DBMS, ma solo le operazioni consentite tramite DBOperator.
Nel disegno ogni cerchio azzurro è un server ed ogni freccia è una richiesta HTTP, le faccine sono i client degli utenti. Sopra ogni cerchio azzurro c'è scritto l'indirizzo pubblico di quel server. Il sistema è composto da:
- molti server Apache, hanno indirizzo api1,2,..,n.visageme.com, sopra sono presenti tutte le classi php di tutti i componenti del nostro sistema, quindi sono in grado di eseguire qualunque tipo di funzione gli venga chiesta (migliore sfruttamento delle risorse che abbiamo a disposizione)
- molti server database Mysql Cluster (NON CI SONO NEL DISEGNO!)
- molti server di immagini che devono avere solo degli hard disk di grandi dimensioni,per permettere di scaricare ed uploadare le immagini.
Per quanto riguarda il load balancer, se utilizziamo il Virtual Server via IP Tunneling attraverso il "proxy" si fanno passare gli header http di richiesta, le risposte, quindi il traffico grosso vero e proprio, vanno direttamente dai server apache ai client senza passare per il proxy.
Per quanto riguarda l'upload di immagini da memorizzare nell'hard disk sui server img.visageme.com pensavamo di fare in modo che il client viene autorizzato ad uploadare una foto facendo una richiesta al modulo Photo, il quale gli restituirà un token, con il quale il client può connettersi direttamente ai server img.visageme.com.
Per la questione del database: seguendo la stessa filosofia dei server che fanno un po' di tutto, sarebbe coerente mettere un server Mysql Cluster su ogni server Apache, in modo da risparmiare banda, altrimenti i server apache dovrebbero continuamente comunicare con i server del database, ed in questo modo avremmo un cluster molto più grosso che da più ridondanza al database.
L'unico problema che sorgerebbe sarebbe quello della sicurezza in quanto se compromettessero il server apache non dovrebbero poter far danni direttamente al database; questo problema potremmo risolverlo mettendo su ogni server fisico due macchine virtuali separate, una sulla quale ci gira il server apache, una sulla quale ci gira il server mysql cluster. La rete virtuale tra le due macchine virtuali ovviamente è velocissima quindi è come se fosse un unico server, però abbiamo la stessa sicurezza di avere due server separati, uno per apache ed uno per il database.
Intendiamo i componenti completamente distribuiti e distribuibili su server diversi. L'idea consiste nell'utlizzo di minimo 3 server:
- il primo che si occupa solamente di prendere le richieste iniziali (homepage molto minimale)
- il secondo che si occupa del solo modulo foto
- il terzo che si occupa di tutti gli altri moduli
(inizialmente ipotizziamo di adottare questa soluzione in quanto il modulo foto è quello + pesante e quello che richiede in assoluto + banda mentre gli altri sono relativamente abbastanza leggeri; in futuro se ce ne sarà bisogno potremmo usare anche un server per ogni modulo)
La questione del load balancing viene gestita interamente inserendo nelle chiamate una funzione getBestServer(modulo) al posto dell'indirizzo vero e proprio. In questo caso in base a dove sappiamo essere disponibile il modulo e in base al traffico disponibile nei server che lo contengono verrà effettuata la chiamata.
Vantaggi: in questo modo i componenti sono estendibili, modulabili e completamente distribuibili, miglior distribuzione nella rete e non c'è una duplicazione completa.
Svantaggi: ovviamente in questo modo le chiamate a procedura sono completamente in remoto, e l'utilizzo dell'rpc potrebbe creare ulteriori difficoltà oltre a spreco di banda e di tempo. In questa soluzione l'rpc è necessario per la comunicazione tra qualunque modulo.
Caso limite: questa idea potrebbe rimanere valida nel caso in cui mettessimo tutti i componenti sullo stesso server ma l'rpc diverrebbe ovviamente inutile.
Fault tolerance: nel caso in cui un componente risulti non disponibile per qualche motivo (l'rpc ritorna errori o non ritorna perchè il server è morto) la successiva chiamata alla getBestServer(modulo) ci porterà su un'altro server.dove un componente analogo sarà pronto a soddisfare la nostra richiesta.
E' quindi necessario comunque un minimo di duplicazione per garantire il servizio, sarebbe meglio almeno 2 componenti uguali su server diversi.
La soluzione consiste nell'avere un certo numero di server (per adesso cominciamo con 2), che gestiscono le richieste provenienti da zone diverse.
Lo smistamento viene gestito da un load balancer principale che in base alla banda disponibile in quel momento la indirizza a uno dei due server, ogni server ha al suo interno tutti i moduli del sistema ed è quindi autonomo.
Nel caso in cui il server scelto non sia funzionante o riscontri dei problemi dobbiamo essere in grado di rigirare la richiesta al load balancer che si occuperà di inviarla ad un'altro server che nel frattempo dovrebbe rimanere funzionante.
In questo modo la maggior parte delle chiamate avviene in locale all'interno del server senza sprechi di tempo e di banda, mentre per quanto riguarda l'interazione col database va comunque utilizzato un sistema in remoto che garantisca un certo distacco dal resto dei moduli; in questo modo aumentiamo la sicurezza dagli attacchi perchè nascondiamo nei parametri (che sono encodificati) i dettagli del database. (Vedi immagine in "architettura generale del sistema").
Essendo il modulo "photo" il più pesante soprattutto in termini di spazio possiamo ipotizzare di dover utitlizzare altri 2 server con un hard-disk di dimensioni maggiori esclusivamente per lo storage di immagini. Per la questione del database invece riteniamo troppo pesante doverlo replicare ogni volta che si aggiunge un nuovo server, per questo motivo adottiamo la soluzione di utilizzare dei server al solo scopo di contenere dei Mysql Cluster.
In questo modo garantiamo anche maggior sicurezza in quanto se venissero compromessi i server apache non è comunque possibile prendere possesso dei database in quanto essi sono esterni.
Per quanto riguarda le frecce gialle vanno direttamente sui server img.visageme.com ma non immediatamente: infatti il browser fa la richiesta ai server apache passando per il load-balancer, esso gli ritorna l'indirizzo del server effettivo sul quale deve fare l'upload (e forse anche un token per autorizzare ad uploadare) e solo a quel punto il browser uploada sul server che gli è stato indicato.
Vantaggi: ovviamente in questo modo le chiamate a procedura sono quasi completamente in locale, quindi evitiamo spreco di banda e di tempo.
Svantaggi: vi è una duplicazione completa dei moduli sui server che in certi momenti risulta inutile. (Sarebbe bello poter creare e distruggere moduli e componenti a tempo di esecuzione ma per il momento ci limitiamo alla creazione statica)
Fault tolerance: nel caso in cui un componente risulti non disponibile per qualche motivo la chiamata deve poter essere inoltrata al componente analogo sull'altro server quindi si deve ritornare la chiamata al load balancer che la gira dall'altra parte. Sarebbe una buona idea tenere ogni immagine su almeno 2 server distinti in modo che in caso di grave guasto di un server le immagini rimangano comunque accessibili e ripristinabili. Il database inoltre potrebbe, per comodità e risparmio di server, essere collocato nei server delle immagini.
![Mobile.png](/xwiki/bin/download/Courseproject/Visage/Mobile.png?rev=1.1)
In allegato lo zip delle Test Unit
Download PhpTestUnit
![VisageMobileClientBackEnd.png](/xwiki/bin/download/Courseproject/Visage/VisageMobileClientBackEnd.png?height=1200&rev=1.1)
L'idea iniziale da cui siamo partiti per il nostro progetto è lo sviluppo di una applicazione per dispositivi mobili che consenta il riconoscimento facciale tramite Realtà Aumentata. Per questo l'esperienza dell'utente sarà incentrata principalmente nell'utilizzo di questa applicazione per la fruizione del servizio e del sito web per la gestione dell'account e delle varie preferenze sulla privacy. Lo sviluppo è stato inizialmente pensato per dispositivi basati su piattaforme Andoid ed iOS e poi realizzato solamente per Android per la facilità di sviluppo in suddetto ambiente e per la diretta disponibilità di soli smartphone dotati di tale sistema.Il tutto è stato diviso in UserInterface e Controller development garantendo uno sviluppo separato ed indipendente delle 2 parti.La parte UserInterface comprende la gestione grafica dell'interfaccia.La parte Controller invece comprende:
- l'interazione con il server;
- la gestione dello storage;
- il riconoscimento facciale;
Descritto dal grafico seguente, abbiamo esposto la relazione tra le
Activities del nostro client.
La gestione dello storage:Crediamo non sia rilevante soffermarsi su questo in dettaglio; comprende l’utilizzo delle API Android per il salvataggio delle preferenze e dei dati dell’utente loggato.
Il riconoscimento facciale:Questa sezione comprende le classi specializzate nel riconoscere le facce inquadrate dalla fotocamera, o da una immagine selezionata dal filesystem, nel ritagliarle e tramite le nostre API inviarle al Server per il riconoscimento.
Interazione con il Server:Gestisce la comunicazione con il server tramite richieste HTTP (HTTPS in futuro). Abbiamo fatto in modo che fornisse a tutte le altre parti dell’applicazione un’interfaccia di alto livello che permettesse di nascondere i veri dettagli dell’interazione con il Server stesso. Ogni metodo di questa interfaccia corrisponde ad un certo tipo di richiesta che può essere effettuata al server.
A seguire elenchiamo le principali caratteristiche del sistema di comunicazione con il server:
- è basato sulla libreria Apache HttpClient integrata di default in tutte le versioni di Android
- Non è dipendente della piattaforma Android, il codice può essere riutilizzato su qualsiasi altra piattaforma Java
- Supporta l'esecuzione di richieste concorrenti, si possono utilizzare thread diversi per ogni richiesta.
- Cerca il più possibile di riutilizzare le connessioni TCP già instaurate per le richieste successive.
- la comunicazione con il server avviene a basso livello tramite JSON trasferiti con delle richieste HTTP POST, in grado quindi di attraversare senza problemi NAT, firewall e proxy di vario tipo, frequentemente utilizzati nelle connessioni mobile. Essendo l’HTTP un protocollo stateless, vengono tollerate le disconnessioni tra una richiesta e l’altra, ed anche un cambio di indirizzo ip, che avviene per esempio passando da una connessione Wifi ad una UMTS. L’upload dei file avviene invece inviando un’entità HTTP di tipo MIME multipart, in modo da non sprecare banda con l'encoding base64.
- Ad ogni richiesta viene inviato al server il proprio token di autenticazione, tuttavia questo viene mascherato agli utilizzatori, tramite una classe che rappresenta una sessione di comunicazione con il server, nella quale viene memorizzato il token.
- le classi sono state scritte in modo da essere altamente riutilizzabili per un'applicazione che richiede una interazione con un server simile a questa.
- può utilizzare connessioni criptate HTTPS anche con un certificato del server autofirmato copiato sul cellulare tramite un canale di comunicazione sicuro, come il market di Android. In questo modo si può avere una connessione sicura senza dover acquistare un certificato SSL da una Certification Authority
- Linguaggio di riferimento: PHP
- MySql Cluster
- Zend Framework
- Facebook e face.com API
- Meccanismo di comunicazione JSON
- Android SDK
- Meccanismo di comunicazione JSON
- Facebook API
Abbiamo scelto un dominio collegato ad un web server Apache2 che risiede su un Linux Ubuntu Server 11.04 già in nostro possesso; per quanto riguarda il database è stato utilizzato un DBMS MySQL in quanto era una tecnologia da noi conosciuta in corsi precedenti. Per quanto riguarda l'applicazione web, essa è stata sviluppata seguendo i paradigmi della programmazione ad oggetti tramite il linguaggio PHP. Sono state costruite classi per ogni modulo e per ogni oggetto che era stato individuato in precedenza; le varie pagine web del sito che ospita il nostro servizio si preoccupano di chiamare determinati metodi statici di quelle classi e solo nel caso in cui ci si debba interfacciare con il database i moduli stessi richiamano un modulo esterno tramite metodo POST. Il tutto è gestito tramite eccezioni e in caso di errori il database viene ripristinato tramite un rollback manuale. Abbiamo munito il servizio di un sistema di log che ci permette di controllare l'attività degli utenti per comprendere quali sono i passi compiuti con più frequenza e per poter individuare gli errori che avvengono durante l'utilizzo. Inoltre consentiamo agli utenti di informarci tramite feedback riguardo i loro interessi e i possibili sviluppi che gradirebbero vedere nel nostro servizio e soprattutto a proposito dei problemi che hanno riscontrato. Abbiamo perfezionato l'iscrizione al servizio con un sistema di conferma del possesso della mail con cui ci si registra come fa la maggior parte dei siti di un certo livello, che consiste nell'inserimento di un codice che viene inviato via mail. Per il momento il nostro servizio è totalmente dipendente da Face.com che ci permette il riconoscimento facciale tramite delle API relativamente semplici; nel caso in cui esso dovesse fallire o per qualche motivo diventare a pagamento dovremmo verificare se sia più conveniente implementare un riconoscimento interno o preferire un altro tipo di servizio. Al momento il sistema è stato predisposto per gestire anche la posizione degli utenti in modo che la ricerca nel database dei volti venga ristretta a determinate aree geografiche per limitare lo spreco di risorse, ma questa funzionalità non è ancora stata implementata. Sarebbe possibile recuperare le immagini del profilo e i nomi degli amici di facebook delle persone che si registrano al nostro servizio ma per il momento abbiamo lasciato da parte questo metodo di recuperare volti che aiutino la ricerca per evitare problemi legati alla privacy. In questo caso la ricerca verrà effettuata seguendo delle priorità (foto caricate priorità 1, foto catturate tramite api di facebook priorità 2). Un ulteriore sviluppo potrebbe essere quello di chiedere all'utente che ottiene il risultato della ricerca se effettivamente ha trovato la persona che stava cercando e in caso di risposta positiva aggiungere quella foto alle foto di quella persona in modo da affinare una ricerca successiva. Volendo incrementare il legame con facebook potremmo inviare delle notifiche alla persona che viene riconosciuta nella foto in modo da poter avere anche delle conferme dirette sul fatto che sia lei o meno e quindi dei feedback diretti. Per il momento ci siamo occupati di gestire un solo tipo di account (Facebook) ma è ovviamente consequenziale che estendere alla gestione di altri account andrebbe solo ad intaccare la registrazione e la visualizzazione degli account al momento del riconoscimento senza creare alcun tipo di problema. Tramite questo progetto siamo riusciti ad ideare un sistema che sia in grado di funzionare anche in presenza di guasti ad uno qualsiasi dei server, e che riesca a servire un numero grande a piacere di utenti semplicemente aggiungendo nuovi server quando è necessario. Nella nostra realizzazione sperimentale del progetto, per il momento abbiamo utilizzato un solo server per testare il corretto funzionamento del software da noi realizzato. Tuttavia abbiamo implementato il tutto in modo che sia in grado di funzionare con un numero molto elevato di server, soddisfacendo quindi i requisiti di scalabilità e fault tolerance.