[SemanticWeb] Liferay RoadShow a Roma: Liferay nel contesto web semantico

Vi segnalo l’incontro a Roma per il prossimo 11 Giugno 2012LIFERAY ROADSHOW ROMA, in cui si parlerà dell’ Integrazione di Liferay con la piattaforma Apache Stanbol per la gestione semantica dei contenuti.

L’evento di Roma sarà caratterizzato dall’utilizzo della piattaforma Liferay in un contesto web semantico.

DOVE? Università di Tor Vergata
Sala Congressi Facoltà di Ingegneria
Via del Politecnico, 1
00133 Roma

QUANDO? 11 GIUGNO 2012 – ore 14,00 – 17,30

 

 

 

Programma

14:00-14:30 Registrazione partecipanti
14:30-15:00 Presentazione Liferay e nuova piattaforma 6.1
15:00-15:30 Introduzione al Web Semantico [Etcware Srl]
15:30-16:00 Liferay e SKOSware, integrazione con prodotto per la gestione di tesauri SKOS, ricerca e navigazione
16:30-17:00 Case Study [Etcware S.r.l.]
17:00-17:30 Integrazione di Liferay con la piattaforma Apache Stanbol per la gestione semantica dei contenuti. [Etcware S.r.l.]

INFORMAZIONI: Per partecipare all’evento, totalmente gratuito, é richiesta la registrazione tramite il portale Liferay. Per maggiori informazioni contattate ufficio.marketing@smc.it

SITO DELL’EVENTOhttp://www.smc.it/liferay-roadshow-roma

[SemanticWeb] Apache Stanbol: la semantica nei content management systems

Apache Stanbol è un progetto open-source che fornisce uno stack software modulare e un set di componenti riusabili per la gestione semantica dei contenuti.
L’iniziativa è dell’European R&D project IKS (Interactive Knowledge Stack for small to medium CMS providers). La “mission” di IKS è quella di portare le tecnologie semantiche come componenti open-source integrate nei piccoli e medi CMS provider. Infatti, abbiamo applicazioni di tale tecnologia in Alfresco e Liferay.

Apache Stanbol automatizza l’identificazione (detection) delle “named entities” (persone, luoghi e organizzazioni, nonchè link verso risorse esterne, come DBpedia). Il processo di estrazione di queste informazioni (detto di “enhancement“) è ad uno stato abbastanza maturo, infatti le sue caratteristiche di base sono già impiegate dai CMS più utilizzati allo stato attuale (Liferay e Alfresco, come già detto in precedenza).

I componenti di Apache Stanbol sono accessibili tramite interfacce RESTFul e mettono a disposizione servizi semantici per gestire i contenuti. E’ possibile estendere i sistemi tradizionali di content management (CMS) con questi servizi semantici (interni ed esterni). Il core di Stanbol è scritto in Java e si basa sul component framework OSGi.

Le principali caratteristiche di Stanbol sono:

  • Arricchimento semantico dei contenuti: i servizi di Stanbol aggiungono informazioni semantiche a parti di contenuto “non semantico”
  • Reasoning: i servizi sono capaci di ritrovare informazioni semantiche nel contenuto
  • Knowledge Models: i servizi vengono utilizzati per definire e manipolare i data model (ad esempio, le ontologie) che sono usati per memorizzare le informazioni semantiche

Le caratteristiche messe a disposizione da Apache Stanbol sono accessibili, direttamente dai CMS, con interfacce utente avanzate.
La demo online (di base) è disponibile a questo link: http://stanbol.demo.nuxeo.com/

Documentazione di Apache Stanbol: http://incubator.apache.org/stanbol/docs/trunk/index.html

Integrazione di Apache Stanbol con un CMS. Basta connettere il proprio CMS via HTTP ad una istanza di Apache Stanbol, oppure usando un CMS adapter component che faccia da bridge tra un CMIS/JCR compliant content repositories e il repository di metadati semantici presente in Apache Stanbol.

Ecco i vari servizi offerti da Stanbol ai CMS che lo integrano:

  • Basic Content Enhancement: analisi testuale dei contenuti, con estrazione delle named entities (person, place, organization), link suggeriti verso sorgenti open-data
  • Definizione di “local” entities: uso di entità “locali” (come Thesaurus) per rappresentare il contesto di una organizzazione (grazie al suo componente Entityhub). Questo aspetto è particolarmente importante poichè i servizi potrebbero non essere necessariamente esternalizzati su Internet, ma l’organizzazione potrebbe impiegarli nella propria rete aziendale
  • Supporto multilingue: la ricerca testuale del contenuto avviene in più lingue (EN, DE, SV, DA, PT e NL)
  • Ricerca semantica nel Portale: memorizza e indicizza gli item dei contenuti, migliorando la ricerca semantica nell’applicazione
  • Refactoring Enhancements for SEO: “refactor” dei risultati estratti, collegandoli alla propria ontologia
  • Trasformazione della struttura del repository del CMS in vere e proprie ontologie
  • Inserimento di altre repository come thesaurus o ontologie di dominio

Apache Stanbol usa una interfaccia stateless per permettere agli utenti di inviare contenuto agli Enhancement Engines (i motori di cui è composto Stanbol e ottenere risultati (enhancements) in formato RDF (Resource Definition Framework), senza memorizzare nulla sul server.

Inoltre, mette a disposizione un meccanismo per lavorare con vocabolari in linguaggi standard come dataset codificati in SKOS (Simple Knowledge Organization Systems) o RDF. Il componente Entityhub di Stanbol crea e gestisce gli indici estratti da questi dataset e i vari Enhancement Engines li usano durante il processo di “enhancement“.

Gli Enhancement Engines sono diversi e suddivisi in categorie (Preprocessing, Natural Language Processing, Linking Suggestions, PostProcessing/Other):

  • Preprocessing: Language Identification Engine, Tika Engine e Metaxa Engine (effettuano l’identificazione linguistica del contenuto testuale, l’estrazione di testo e metadati da vari formati documentali con Apache Tika)
  • Natural Language Processing: Named Entity Extraction Enhancement Engine (NLP processing con OpenNLP Engine e identificazione di persone, luoghi e organizzazioni), KeywordLinking Engine (NLP processing con OpenNLP, supporto multilingue, identificazione delle occorrenze di entità non tipate, come concetti, tassonomie locali, …)
  • Linking Suggestions: Named Entity Tagging Engine (suggerimenti di link da fonti dette Linked DataSources, come DBpedia), Geonames Enhancement Engine (suggerimento di link usando geonames.org e organizzazione gerarchica dei link per le locations), OpenCalais Enhancement Engine (integra servizi da Open Calais), Zemanta Enhancement Engine (integra i servizi di Zemanta)
  • Postprocessing/Other: CachingDereferencerEngine (deprecato, ma ritrova contenuti addizionali per la presentazione degli enhancement results), Refactor Engine (trasforma i risultati –enhancements– in accordo con l’ontologia target)

Le named entities estratte (persone, luoghi e organizzazioni) sono strutturate secondo un grafo RDF, particolarmente comodo per utilizzare le informazioni all’esterno del motore, per descrivere l’intera repository e ricercare i risultati.

 ————————————————————————

Appuntamento al LIFERAY ROADSHOW a ROMA:

Vi segnalo l’incontro a Roma per il prossimo 11 Giugno 2012: LIFERAY ROADSHOW ROMA, in cui si parlerà dell’ Integrazione di Liferay con la piattaforma Apache Stanbol per la gestione semantica dei contenuti.

DOVE? Università di Tor Vergata
Sala Congressi Facoltà di Ingegneria
Via del Politecnico, 1
00133 Roma

QUANDO? 11 GIUGNO 2012 – ore 14,00 – 17,30

INFORMAZIONI: Per partecipare all’evento, totalmente gratuito, é richiesta la registrazione tramite il portale Liferay. Per maggiori informazioni contattate ufficio.marketing@smc.it

————————————————————————

Articoli utili:

In Italia si è poveri e si rimane poveri

Il titolo trasmetterà angoscia alla maggior parte di voi, perché sicuramente chi legge questo blog sta sulla mia stessa barca, ossia non è sicuramente ricco. Ho letto e meditato su una frase detta da Giulio Sapelli, docente di economia politica e storia economica all’Università Statale di Milano, e su un articolo letto su Linkiesta.it : “I figli dei poveri restano poveri: quanto è ingiusta l’Italia“.

La frase di Sapelli dice questo: «È difficile a un figlio di operai – come ero io e lo ero molto felicemente – fare alcunché di diverso (oggi, in questo tempo terribile), da ciò che fa il padre; così come è difficile, se non si nasce ricchi, diventarlo, ricco».

Vorrei sottolineare una frase dell’articolo in cui si analizza come è mutata la nostra società negli ultimi anni e dove (probabilmente?) è da ricercarne la causa: “La banca diviene un super mercato di vendita di strumenti di distruzione di massa senza porto d’armi. Da allora tutti i ministri economici del mondo sono collegati con il capitale finanziario in più o meno rilevante misura o evidenza o mancanza di pudore“.

Negli ultimi mesi, se non anni, abbiamo sentito parlare di crisi fino alla nausea. Addirittura portata all’esasperazione, con decine di suicidi di imprenditori che si sentono negli ultimi tempi ai telegiornali (come se prima non ci fossero mai stati ?! ). Ancora più nausea fanno i politici che si meriterebbero di non essere votati alle prossime elezioni…nessuno! Tanto alcuni di loro, anche se stanno a casa, continueranno a percepire vitalizi e benefit vari, o a svolgere il loro lavoro da libero professionista.

Comunque, in questa riflessione si parla della disuguaglianza di reddito presente in Italia, che arriva ai livelli degli Stati Uniti e supera, addirittura, quella dei Paesi OCSE. I grafici che riporto di seguito sono quelli presenti sul sito di Linkiesta.it e tratti dall’articolo citato in precedenza. In particolare, viene utilizzato il coefficiente di Gini, indice di concentrazione (tra 0 e 1) per misurare la diseguaglianza nella distribuzione del reddito o anche della ricchezza. Valori bassi del coefficiente indicano una distribuzione abbastanza omogenea, con il valore 0 che corrisponde alla pura equidistribuzione (ad esempio, la situazione in cui tutti percepiscano esattamente lo stesso reddito); valori alti del coefficiente indicano una distribuzione più diseguale, con il valore 1 che corrisponde alla massima concentrazione (ovvero la situazione dove una persona percepisca tutto il reddito del paese mentre tutti gli altri hanno un reddito nullo).

Quoto l’articolo del mio amico Mimmo sul suo blog DiarioAntiPolitico: “Più poveri e più incazzati“.

Quindi, come si fa a diventare ricchi (se già non lo si è) in Italia? O vincendo al Superenalotto o, peggio, rubando!

Creative Commons License
This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2012/05/28/in-italia-si-e-poveri-e-si-rimane-poveri/.

[DWR] Direct Web Remoting: Easy AJAX for Java

DWR (Direct Web Remoting) è una libreria Java open-source (Apache Software License v2) che permette a Java (lato back-end) e JavaScript (lato front-end) di interagire e chiamarsi a vicenda nel modo più semplice possibile.
DWR si integra con Spring, Struts, Hibernate e altri framework.

 

Ecco lo slogan di DWR: “DWR is Easy Ajax for Java“.

Ecco il sito ufficiale di DWR: http://directwebremoting.org

Cosa fa DWR? DWR permette di generare codice JavaScript che permetta ai web browser di chiamare in sicurezza codice Java come se venisse eseguito localmente. Effettua una operazione di marshalling virtuale che include collections, POJOs, XML e binary data (come immagini e file PDF).
Mette a disposizione anche una funzionalità di Reverse Ajax, che permette a codice Java in esecuzione sul server di utilizzare/richiamare API lato client per pubblicare aggiornamenti su determinati gruppi di browser.

Questo tipo di interazione è, dunque, bidirezionale – browser che chiama il server e server che chiama il browser.
DWR supporta Comet, Polling e PiggyBack (spedendo i dati in una normale request) come modalità per la notifica da server a browser.

Come funziona? Il meccanismo di interazione bidirezionale avviene tramite chiamate RPC (Remote Procedure Call).
Nella seguente figura, viene mostrato un primo diagramma che rappresenta come DWR altera il contenuto di una select HTML con il risultato di un evento JavaScript (il client chiama il server per farsi restituire i risultati):


Il Reverse Ajax di DWR (disponibile dalla versione 2.0) permette a codice Java in esecuzione sul server di intercettare quali client stanno visualizzando determinate pagine, in modo da inviare loro (tramite JavaScript) dei risultati (meccanismo di comunicazione inverso – da server a client):


DWR è composto da due parti principali:

  • una servlet Java in esecuzione sul server che processa le richieste e manda le risposte indietro al browser
  • JavaScript in esecuzione sul browser che manda le richieste e può dinamicamente aggiornare il contenuto della pagina

DWR genera dinamicamente codice JavaScript da classi Java ed effettua il marshalling dei dati scambiati in modo bidirezionale, eseguendo il tutto lato server.
Il metodo di remoting functions (Reverse Ajax) da Java a JavaScript fornisce un meccanismo RPC molto simile a RMI o SOAP, con il vantaggio che l’esecuzione avviene su un browser senza necessità di plugin addizionali.

Download di DWR: http://directwebremoting.org/dwr/downloads/index.html

Installazione di DWR: http://directwebremoting.org/dwr/introduction/getting-started.html#fiveSteps

Continua la lettura

Google Knowledge Graph: verso la nuova generazione dei motori di ricerca

Google ha un graph che la sa lunga (tratto da PuntoInformatico.it)

Knowlegde Graph è la nuova proposta di Mountain View per il suo search. Non è semantica, ma allarga il numero di informazioni fornite cercando di indovinare il vero significato di una ricerca

Si chiama Knowledge Graph il nuovo progetto di Google: si tratta di un ulteriore strumento a supporto del suo motore di ricerca e che dovrebbe servire a “scoprire nuove informazioni velocemente e facilmente”. Per “graph” Google intende un “modello intelligente in grado di capire le entità del mondo reale e le loro relazioni le une con le altre: fatti, dunque, non stringhe casuali di caratteri”.

Con Knowledge Graph, per il momento disponibile solo negli Stati Uniti ma già con opzioni specifiche per l’utilizzo mobile, Google intende dunque affinare le ricerche finora effettuate solo sulla base delle citazioni delle parole chiave e con i risultati che sono organizzati in base all’importanza stabilità dall’algoritmo PageRank.

Mountain View non arriva ad utilizzare l’aggettivo “semantico”, ma descrive semplicemente il tentativo di mettere in relazione la chiave di ricerca inserita dagli utenti (chiamata “oggetto”) con una selezione di concetti effettuata a monte: parla di circa 3,5 miliardi di diversi attributi impiegati finora per questa organizzazione, per il momento concentrata su 500 milioni di “oggetti”.

Così Knowledge Graph, che Google definisce “il primo passo verso la nuova generazione dei motori di ricerca”, promette di portare informazioni che sono rilevanti rispetto alla parola chiave, pur non citandola direttamente. Se si cercano informazioni su un pittore rinascimentale, dice BigG, il sistema restituirà risorse utili a documentarsi a tutto tondo sul movimento artistico, altri nomi famosi del periodo, tecniche di pittura ecc.

Graficamente Knowledge Graph segue una strada non dissimile da quella imboccata dal nuovo redesign di Bing: offre una colonna di risultati che occupa la fascia destra della pagina affiancandosi ai risultati tradizionali ed opzioni che permettono di affinare la ricerca originale definendo meglio l’oggetto: l’esempio che fa Mountain View è quello del “Taj Mahal”, parola che può riferirsi al monumento, ad un casinò, ad un musicista o ad un ristorante indiano nelle vicinanze.

Sempre sulla destra troveranno poi spazio le informazioni ritenute fondamentali sull’oggetto, organizzate in una sorta di specchietto in stile Wikipedia, selezionate in base alle precedenti ricerche aggregate compiute sull’argomento da altri utenti. Inoltre, accanto a queste trovano spazio curiosità e fatti che potrebbero in ogni caso risultare interessanti per l’utente perché, appunto, meno noti.

Dietro le quinte, in pratica, Knowledge Graph si appoggia a dati raccolti negli anni e su quanto finora cercato dagli utenti: una questione che ha naturalmente spinto gli osservatori a continuarsi a chiedere fin dove può arrivare l’occhio indiscreto di Google e cosa impedisce di fare invece il vincolo alla privacy degli utenti, anche se i loro dati vengono trattati in maniera aggregata.

Google, d’altronde, nel frattempo ha aumentato i dati raccolti e indicizzati dalle sue applicazioni web-crawling, i suoi bot: secondo lo sviluppatore canadese Alex Pankratov questi hanno ora imparato a comportarsi “più da umani” facendo girare anche i contenuti JavaScript e arrivando così ad esplorare anche i contenuti dinamici delle pagine.

Claudio Tamburrino

Informazioni dettagliate le trovate sul sito di Google:

http://www.google.com/insidesearch/features/search/knowledge.html

[JSON] Introduzione al diffuso formato di scambio dei dati

JSON (JavaScript Object Notation) è un semplice formato per lo scambio di dati. Per le persone è facile da leggere e scrivere, mentre per le macchine risulta facile da generare e analizzarne la sintassi. Si basa su un sottoinsieme del Linguaggio di Programmazione JavaScript, Standard ECMA-262 Terza Edizione – Dicembre 1999.

JSON è un formato di testo completamente indipendente dal linguaggio di programmazione, ma utilizza convenzioni conosciute dai programmatori di linguaggi della famiglia del C, come C, C++, C#, Java, JavaScript, Perl, Python, e molti altri. Questa caratteristica fa di JSON un linguaggio ideale per lo scambio di dati.

JSON è basato su due strutture:

  • Un insieme di coppie nome/valore. In diversi linguaggi, questo è realizzato come un oggetto, un record, uno struct, un dizionario, una tabella hash, un elenco di chiavi o un array associativo.
  • Un elenco ordinato di valori. Nella maggior parte dei linguaggi questo si realizza con un array, un vettore, un elenco o una sequenza.

Queste sono strutture di dati universali. Virtualmente tutti i linguaggi di programmazione moderni li supportano in entrambe le forme. E’ sensato che un formato di dati che è interscambiabile con linguaggi di programmazione debba essere basato su queste strutture.

In JSON:

  • Un oggetto è una serie non ordinata di nomi/valori. Un oggetto inizia con { (parentesi graffa sinistra) e finisce con } (parentesi graffa destra). Ogni nome è seguito da : (due punti) e la coppia di nome/valore sono separata da , (virgola).

  • Un array è una raccolta ordinata di valori. Un array comincia con [ (parentesi quadra sinistra) e finisce con ] (parentesi quadra destra). I valori sono separati da , (virgola).

  • Un valore può essere una stringa tra virgolette, o un numero, o vero o falso o nullo, o un oggetto o un array. Queste strutture possono essere annidate.

  • Una stringa è una raccolta di zero o più caratteri Unicode, tra virgolette; per le sequenze di escape utilizza la barra rovesciata. Un singolo carattere è rappresentato come una stringa di caratteri di lunghezza uno. Una stringa è molto simile ad una stringa C o Java.

  • Un numero è molto simile ad un numero C o Java, a parte il fatto che i formati ottali e esadecimali non sono utilizzati.

I caratteri di spaziatura possono essere inseriti in mezzo a qualsiasi coppia di token.

A parte alcuni dettagli di codifica, questo descrive totalmente il linguaggio.

Fonte: http://www.json.org/json-it.html

 

[Spring] Spring3: dai Controller ai Repository [Parte2]

In questa Parte 2 del tutorial di Spring3, vengono mostrate alcune classi di esempio con relative annotazioni per ciascuno strato della nostra web application:

  • strato controller (Spring MVC): annotazione @Controller
  • strato di business logic: annotazione @Service
  • strato di persistenza e modellazione dei dati (Spring ORM): annotazioni @Entity e @Repository

Model @Entity

Riporto qui di seguito un esempio di model o entity, che mappa una tabella sul database con relative associazioni ad altre entità. Il model viene annotato con @Entity e deve essere enumerato nelle annotatedClass del file spring-orm.xml, visto nella Parte1 di questo tutorial. Per maggiori informazioni, leggere anche Hibernate Annotations.

Nell’esempio sono riportate anche delle annotazioni per la validazione dei campi del model (javax.validation e org.hibernate.validator.constraints), che spostano la validazione lato server verso il lato persistenza e che Spring intercetta e gestisce con opportuni messaggi di stato.

package com.yourDomain.model;

import com.yourDomain.interceptors.IAuditLog;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;

@Entity
@Table(name="utenti")
@NamedQueries({
	@NamedQuery(name = "Utente.findAll", query = "from Utente where id!=-1 order by cognome"),
	@NamedQuery(name = "Utente.findById", query = "from Utente r where r.id = :idUtente"),
	@NamedQuery(name = "Utente.findByCodiceFiscaleAndEmail", query = "from Utente r where lower(r.codiceFiscale) = lower(:codiceFiscale) and lower(r.email) = lower(:email) and dataCancellazione is null and abilitato = true"),
	@NamedQuery(name = "Utente.findByCodiceFiscaleOrEmail", query = "from Utente r where (lower(r.codiceFiscale) = lower(:codiceFiscale) or lower(r.email) = lower(:email) ) and dataCancellazione is null")
})
public class Utente implements Serializable,IAuditLog {

	private static final long serialVersionUID = 8797826874630455491L;

	public static final Integer ID_ADMINISTRATOR = -1;

	@Id
	@GeneratedValue
	@Column(name="id")
	private Integer id;

	@Column(name="matricola",nullable=true,length=50)
	private String matricola;

	@Column(name="cognome",nullable=false,length=255)
	@NotEmpty
	@NotNull
	private String cognome;

	@Column(name="nome",nullable=false,length=255)
	@NotEmpty
	@NotNull
	private String nome;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=StatoCivile.class)
	@JoinColumn(name = "fk_stato_civile", nullable = true, referencedColumnName = "id")
	private StatoCivile statoCivile;

	@Column(name="codice_fiscale",nullable=true,length=16)
	@NotEmpty
	@NotNull
	@Pattern(regexp="^[a-zA-Z]{6}[0-9]{2}[abcdehlmprstABCDEHLMPRST]{1}[0-9]{2}([a-zA-Z]{1}[0-9]{3})[a-zA-Z]{1}$")
	private String codiceFiscale;

	@Column(name="data_nascita",nullable=true)
	@Temporal(TemporalType.DATE)
	@DateTimeFormat(pattern="dd/MM/yyyy")
	private Date dataNascita;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=Comune.class)
	@JoinColumn(name = "fk_comune_nascita", nullable = true, referencedColumnName = "id")
	private Comune comuneNascita;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=Stato.class)
	@JoinColumn(name = "fk_stato_nascita", nullable = true, referencedColumnName = "id")
	private Stato statoNascita;

	@Column(name="indirizzo_residenza",length=255,nullable=true)
	private String indirizzoResidenza;

	@Column(name="cap_residenza",length=5,nullable=true)
	@Length(min=0,max=5)
	@Pattern(regexp="^[0-9]{0,5}")
	private String capResidenza;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=Comune.class)
	@JoinColumn(name = "fk_comune_residenza", nullable = true, referencedColumnName = "id")
	private Comune comuneResidenza;

	@Column(name="email",length=255,nullable=false)
	@NotEmpty
	@NotNull
	@Email
	private String email;

	@Column(name="partita_stipendio",length=50,nullable=true)
	private String partitaStipendio;

	@Column(name="sesso",length=1,nullable=true)
	@NotEmpty
	@NotNull
	private String sesso;

	@Column(name="telefono",length=100,nullable=true)
	//@Pattern(regexp="^(1\\s*[-\\/\\.]?)?(\\((\\d{3})\\)|(\\d{3}))\\s*[-\\/\\.]?\\s*(\\d{3})\\s*[-\\/\\.]?\\s*(\\\\d{4})\\s*(([xX]|[eE][xX][tT])\\.?\\s*(\\d+))*$")
	private String telefono;

	@Column(name="fax",length=100,nullable=true)
	//@Pattern(regexp="^(1\\s*[-\\/\\.]?)?(\\((\\d{3})\\)|(\\d{3}))\\s*[-\\/\\.]?\\s*(\\d{3})\\s*[-\\/\\.]?\\s*(\\\\d{4})\\s*(([xX]|[eE][xX][tT])\\.?\\s*(\\d+))*$")
	private String fax;

	@Column(name="cellulare",length=100,nullable=true)
	//@Pattern(regexp="^(1\\s*[-\\/\\.]?)?(\\((\\d{3})\\)|(\\d{3}))\\s*[-\\/\\.]?\\s*(\\d{3})\\s*[-\\/\\.]?\\s*(\\\\d{4})\\s*(([xX]|[eE][xX][tT])\\.?\\s*(\\d+))*$")
	private String cellulare;

	@Column(name="codice_abi",length=100,nullable=true)
	private String codiceABI;

	@Column(name="codice_cab",length=100,nullable=true)
	private String codiceCAB;

	@Column(name="numero_figli",nullable=true)
	private Integer numeroFigli;

	@Column(name="perc_invalidita",length=100,nullable=true)
	//@Pattern(regexp="^\\d+((\\.|,)\\d+)?$")
	private String percentualeInvalidita;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=AlboProfessionale.class)
	@JoinColumn(name = "fk_albo_professionale", nullable = true, referencedColumnName = "id")
	private AlboProfessionale alboProfessionale;

	@ManyToOne(fetch=FetchType.EAGER, targetEntity=SpecializzazioneProfessionale.class)
	@JoinColumn(name = "fk_spec_professionale", nullable = true, referencedColumnName = "id")
	private SpecializzazioneProfessionale specializzazioneProfessionale;

	@Column(name="data_modifica",nullable=true)
	@Temporal(TemporalType.DATE)
	@DateTimeFormat(pattern="dd/MM/yyyy")
	private Date dataModifica;

	@Column(name="data_creazione",nullable=true)
	@Temporal(TemporalType.DATE)
	@DateTimeFormat(pattern="dd/MM/yyyy")
	private Date dataCreazione;

	@Column(name="data_cancellazione",nullable=true)
	@Temporal(TemporalType.DATE)
	@DateTimeFormat(pattern="dd/MM/yyyy")
	private Date dataCancellazione;

	@Column(name="data_ultimo_accesso",nullable=true)
	@Temporal(TemporalType.DATE)
	@DateTimeFormat(pattern="dd/MM/yyyy")
	private Date dataUltimoAccesso;

	@ManyToOne(fetch=FetchType.LAZY, targetEntity=Utente.class)
	@JoinColumn(name = "fk_utente_modifica", nullable = true, referencedColumnName = "id")
	private Utente utenteModifica;

	@Column(name="abilitato",nullable=false)
	private boolean abilitato = true;

	@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL,targetEntity=GruppoOperativo.class)
	@JoinTable(name = "associativa_utenti_gruppi",
			joinColumns = @JoinColumn(name = "fk_Utente", referencedColumnName = "id"),
			inverseJoinColumns = @JoinColumn(name = "fk_gruppo", referencedColumnName = "id")
	)
	private List<GruppoOperativo> gruppiOperativi;

	@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL,targetEntity=TitoloStudio.class)
	@JoinTable(name = "associativa_utenti_titolistudio",
			joinColumns = @JoinColumn(name = "fk_Utente", referencedColumnName = "id"),
			inverseJoinColumns = @JoinColumn(name = "fk_titolo_studio", referencedColumnName = "id")
	)
	private Set<TitoloStudio> titoliStudio;

	@OneToMany(mappedBy = "Utente", cascade = CascadeType.ALL, fetch = FetchType.LAZY, targetEntity=Rapporto.class)
	private List<Rapporto> rapporti;

	//@Column(name="nato_estero",nullable=true)
	@Transient
	private boolean natoInStatoEstero;

	@Transient
	private boolean isLogged;

	@Transient
	private String maxVisibility;

	public Utente(){

	}

/**
    QUI TUTTI I METODI DI GET E SET
**/

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Utente other = (Utente) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

}

 

@Controller

Il controller è una interfaccia che riceve una richiesta HTTP – HttpServletRequest e HttpServletResponse – simile alla Action di Struts. Dunque, definisce lo strato di interfaccia tra presentation e business layer. L’annotazione da utilizzare è @Controller e per permettere a Spring MVC di effettuare l’autowiring in fase di startup della web app occorre inserire nel file di configurazione (spring-application.xml) il tag mvc:annotation-driven (come visto nella Parte1). Nel seguente esempio, vengono annotati anche gli editors, che sono utili per popolare dinamicamente select o checkbox lato template. L’annotazione @InitBinder serve per configurare il controller allo startup della web application (in questo caso, a registrare la lista degli Editors). Con @Autowired viene iniettato il servizio che verrà utilizzato dal controller.

Non è necessaria una interfaccia da implementare, ma occorre solo annotare la classe con @Controller, in quanto il controller stesso non viene “iniettato”.

Per maggiori dettagli sui controller e su Spring MVC, leggere questo link: Web MVC Framework.

package com.yourDomain.controller;

import com.yourDomain.model.Profilo;
import com.yourDomain.model.Rapporto;
import com.yourDomain.model.Utente;

import java.beans.PropertyEditorSupport;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/anagraficautente")
@SessionAttributes({"utenteLoggato","utenteSelezionato"})
public class UtenteController {

	protected static Logger log = Logger.getLogger(UtenteController.class);

	@Autowired
	UtenteService UtenteService;

	@InitBinder
	public void initBinder(WebDataBinder b) {
		DateFormat dateFormat = new SimpleDateFormat(SiapConfigProperties.getValue("dateFormat.small"));
		b.registerCustomEditor(Profilo.class, new ProfiloEditor());
	}

	//EDITOR
	private class DateEditor extends CustomDateEditor {

		public DateEditor(DateFormat dateFormat, boolean allowEmpty) {

			super(dateFormat, allowEmpty);
			// TODO Auto-generated constructor stub
			}
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				try {
					if(!Utils.isEmpty(text)){
						DateFormat df = new SimpleDateFormat(SiapConfigProperties.getValue("dateFormat.small"));
						setValue(df.parse(text));
					}
				} catch (Exception e) {
					setValue(null);
				}
		    }
		    @Override
		    public String getAsText() {
		    	if(((Date) getValue()) == null)
		    		return "";

		    	DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
		        return ((String) formatter.format(getValue()));
		    }
	}

	//EDITOR
	private class ProfiloEditor extends PropertyEditorSupport {
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				try {
					if(!Utils.isEmpty(text)){
						Profilo profilo = profiloService.getProfilo(Integer.valueOf(text));
						if(profilo.getId()==null)setValue(null);
						else setValue(profilo);
					}
				} catch (Exception e) {
					setValue(null);
				}
		    }
		    @Override
		    public String getAsText() {
		    	if((Profilo) getValue() == null ||((Profilo) getValue()).getId()==null)
		    		return "";
		    	String id = ((Profilo) getValue()).getId().toString();
		        return id;
		    }
	}

	@RequestMapping(value = "/utente", method = {RequestMethod.GET,RequestMethod.POST})
	public ModelAndView redirectToAnagraficaUtente(@RequestParam(value = "id", required = false) String id,
			HttpSession session,
			ModelAndView mav) {

		try{
			Utente Utente = null;

			if(id == null && session.getAttribute("UtenteSelezionata") != null){
				Utente = (Utente)session.getAttribute("UtenteSelezionata");
			}else if(id != null){
				if(id != ""){
					Utente = UtenteService.getUtente(Integer.parseInt(id));
				}else if(id == ""){
					Utente = (Utente) session.getAttribute("utenteLoggato");
				}
				mav.addObject("UtenteSelezionata", Utente);
			}

			if(Utente == null){
				mav.addObject("result", ResultBean.writeMessageByKey(ResultBean.ERROR, "Utente.storico.error"));
				mav.setViewName(MappingMavController.STORICO_CARRIERA_JSP);

			}

			mav.setViewName("/anagraficaUtente");

		} catch (Exception e) {
			mav.addObject("result", ResultBean.writeMessageByKey(ResultBean.ERROR, "error.generic"));
			log.error("UtenteController - metodo redirectToAnagraficaUtente: ",e);
		}	

		return mav;
	}

}

 

@Service

Con l’annotazione @Service viene definita la classe di servizio con la logica di business, iniettata nel controller o in altri strati della nostra web application. Tale classe implementa una interfaccia. In tale strato è possibile definire la gestione delle transazioni, sia mappando le regole sul file spring-orm.xml, come visto nella Parte1, che inserendo sulla classe di servizio (gestione globale della transazione) e sui singoli metodi (gestione locale della transazione) l’annotazione @Transactional (definendo il tipo di propagazione, come avviene negli EJB). In tale classe vengono “iniettati” anche i DAO per la comunicazione con il database o altre classi di servizio (annotazione @Autowired).

package com.yourDomain.service;

import com.yourDomain.model.Utente;
import java.util.Map;

public interface UtenteService {
	Utente getUtenteByCodiceFiscaleAndEmail (String codiceFiscale, String email) throws Exception;
	boolean updateUtente (Utente Utente) throws Exception;
	public Map<String,String> getContestiAndOperazioniUtente (Utente Utente) throws Exception;
}


package it.beniculturali.siapweb.service.impl;

import it.beniculturali.siapweb.dao.ContestoDao;
import it.beniculturali.siapweb.dao.UtenteDao;
import it.beniculturali.siapweb.model.Contesto;
import it.beniculturali.siapweb.model.Utente;
import it.beniculturali.siapweb.service.UtenteService;
import it.beniculturali.siapweb.utilities.Utils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("utenteService")
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
public class UtenteServiceImpl implements UtenteService {

	protected static Logger log = Logger.getLogger(UtenteServiceImpl.class);

	public UtenteServiceImpl(){

	}

	@Autowired
	private ContestoDao contestoDao;

	@Autowired
	private UtenteDao utenteDao;

	@Override
	/**
	 * metodo che ritorna la utente con un dato codice fiscale e una email
	 *
	 * @param codiceFiscale, email
	 * @return Utente
	 *
	 */
	public Utente getUtenteByCodiceFiscaleAndEmail (String codiceFiscale, String email) throws Exception{
		log.debug("UtenteServiceImpl - getUtenteByCodiceFiscaleAndEmail: inizio metodo");
		Utente utente = utenteDao.getUtenteByCodiceFiscaleAndEmail(codiceFiscale, email);
		log.debug("UtenteServiceImpl - getUtenteByCodiceFiscaleAndEmail: fine metodo");
		return utente;
	}

	/**
	 * metodo che aggiorna i dati di una determinata utente
	 *
	 * @param codiceFiscale, email
	 * @return Utente
	 *
	 */
	@Override
	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public boolean updateUtente(Utente utente) throws Exception {
		log.debug("UtenteServiceImpl - updateUtente: inizio metodo");

			boolean result = false;
			log.debug("Aggiornamento dei dati della utente con id."+utente.getId());
			result = utenteDao.updateUtente(utente);

		log.debug("UtenteServiceImpl - updateUtente: fine metodo");
		return result;
	}

	/**
	 * metodo che ritorna la mappa dei contesti di un utente con relative operazioni permesse
	 *
	 * @param utente
	 * @return
	 * @throws Exception
	 */
	@Override
	public Map<String,String> getContestiAndOperazioniUtente(Utente utente) throws Exception {
		Map<String,String> contestiUtenteMap = new HashMap<String, String>();
		log.debug("UtenteServiceImpl - getContestiAndOperazioniUtente: inizio metodo");
		try{

			List<Contesto> contestiUtente = contestoDao.getContestiAndOperazioniUtente(utente);

			//costruisco la lista delle operazioni per ogni contesto

			if(contestiUtente!=null){

				for(Contesto contestoUtente : contestiUtente){

					//costruisco la mappa con le operazioni permesse dell'utente loggato
					contestiUtenteMap.put(contestoUtente.getId().toString(), Utils.convertListStringInSingleString(contestoUtente.getTipiOperazioniUtente(),","));
				}
			}

		}
		catch(Exception e){
			log.error("ContestoDaoImpl - getContestiAndOperazioniUtente: ",e);
		}
		log.debug("UtenteServiceImpl - getContestiAndOperazioniUtente: fine metodo");
		return contestiUtenteMap;
	}

}

 

@Repository

L’annotazione @Repository definisce le classi dello strato di persistenza, ossia i cosiddetti DAO (Data Access Object). Anche qui le classi implementano una interfaccia, visto che verranno “iniettate” nello strato di servizio (con annotazione @Autowired). Qui viene iniettato anche il SessionFactory (o l’HibernateTemplate), il manager che ci permetterà di eseguire le operazioni CRUD sulla basedati definita e configurata nella Parte1 di questo tutorial.

package com.yourDomain.dao;

import com.yourDomain.model.GruppoOperativo;
import com.yourDomain.model.Utente;

import java.util.List;

public interface UtenteDao {

	List<Utente> getUtenti() throws Exception;
	Utente getUtenteByCodiceFiscaleAndEmail (String codiceFiscale, String email) throws Exception;
	boolean isUtenteRegistrato (String codiceFiscale, String email, Integer idUtente) throws Exception;
	Utente getUtente (Integer idUtente) throws Exception;
	public int countUtentiForGruppoOperativo (GruppoOperativo gruppoOperativo) throws Exception;
	boolean saveUtente(Utente nuovoUtente) throws Exception;
	boolean updateUtente(Utente risorsa) throws Exception;

}

 

package com.yourDomain.dao.impl;

import com.yourDomain.dao.UtenteDao;
import com.yourDomain.model.GruppoOperativo;
import com.yourDomain.model.Utente;

import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository("utenteDao")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UtenteDaoImpl implements UtenteDao {

	@Autowired
	SessionFactory sessionFactory;

	protected static Logger log = Logger.getLogger(UtenteDaoImpl.class);

	public UtenteDaoImpl() {

	}

	/**
	 * metodo che ritorna la lista degli utenti
	 *
	 * @return List<Utente>
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Utente> getUtenti() {
		Session session = sessionFactory.getCurrentSession();
		Query query = session.getNamedQuery("Utente.findAll");
		return query.list();
	}

	/**
	 * metodo che ritorna l'utente con un dato codice fiscale e una email
	 *
	 * @param codiceFiscale
	 *            , email
	 * @return Utente
	 *
	 */
	@Override
	public Utente getUtenteByCodiceFiscaleAndEmail (String codiceFiscale, String email) throws Exception{
		Session session = sessionFactory.getCurrentSession();
		Query query = session.getNamedQuery("Utente.findByCodiceFiscaleAndEmail")
			.setString("codiceFiscale", codiceFiscale)
			.setString("email", email);
		return (Utente)query.uniqueResult();
	}

	/**
	 * metodo che ci dice se c'è un utente registrato con un dato codice fiscale o email
	 *
	 * @param codiceFiscale
	 *            , email
	 * @return Utente
	 *
	 */
	@SuppressWarnings("unchecked")
	@Override
	public boolean isUtenteRegistrato (String codiceFiscale, String email, Integer idUtente) throws Exception{
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(Utente.class);
		criteria.add(Restrictions.isNull("dataCancellazione"));

		Criterion criterion1 = Restrictions.eq("codiceFiscale", codiceFiscale).ignoreCase();
		Criterion criterion2 = Restrictions.eq("email", email).ignoreCase();

		Criterion ORcriterion	= Restrictions.or(criterion1, criterion2);
		criteria.add(ORcriterion);

		if(idUtente!=null){

			criteria.add(Restrictions.ne("id",idUtente));
		}

		List<Utente> utentiRegistrati = criteria.list();

		return utentiRegistrati!=null&&utentiRegistrati.size()!=0?true:false;
	}

	/**
	 * metodo che ritorna un utente corrispondente ad un determinato id
	 *
	 * @param idUtente
	 *
	 */
	@Override
	public Utente getUtente(Integer idUtente) throws Exception {
		Session session = sessionFactory.getCurrentSession();
		Query query = session.getNamedQuery("Utente.findById")
			.setInteger("idUtente", idUtente);
		return (Utente)query.uniqueResult();
	}

	/**
	 *  metodo che conta quanti utenti sono associati a quel gruppo operativo
	 *
	 * @param gruppoOperativo
	 * @return
	 * @throws Exception
	 */
	@Override
	public int countUtentiForGruppoOperativo (GruppoOperativo gruppoOperativo) throws Exception{
		Session session = sessionFactory.getCurrentSession();
		Criteria criteria = session.createCriteria(Utente.class)
		.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
	    .setFetchMode("gruppiOperativi", FetchMode.JOIN);  

		criteria.createAlias("gruppiOperativi", "g",CriteriaSpecification.INNER_JOIN);
		criteria.add(Restrictions.eq("g.id", gruppoOperativo.getId()));
		criteria.add(Restrictions.isNull("dataCancellazione"));

		Number count = (Number) criteria.setProjection(Projections.rowCount()).uniqueResult();

		return count!=null?count.intValue():0;

	}

	/**
	 * metodo che aggiorna i dati di una determinata utente
	 *
	 * @param idUtente
	 *
	 */
	@Override
	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public boolean updateUtente(Utente utente) throws Exception {

		try{

			Session session = sessionFactory.getCurrentSession();

			utente.setDataModifica(new Date());
		    session.clear();
			session.update(utente);
			session.flush();
			//session.evict(utente);
		}
		catch(Exception e){
			log.error("UtenteDaoImpl - updateUtente: ",e);
			return false;
		}
		return true;
	}

	/**
	 * metodo per il salvataggio di una nuova utente
	 *
	 * @param utente
	 * @return
	 * @throws Exception
	 */
	@Override
	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public boolean saveUtente(Utente nuovoUtente) throws Exception {

		try{
			Session session = sessionFactory.getCurrentSession();
			session.clear();
			session.save(nuovoUtente);
			session.flush();
			//session.evict(nuovoUtente);
		}
		catch(Exception e){
			log.error("UtenteDaoImpl - saveUtente: ",e);
			return false;
		}
		return true;
	}
}
Spring3_SampleAnnotations
Titolo: Spring3_SampleAnnotations (0 click)
Etichetta:
Filename: spring3_sampleannotation.zip
Dimensione: 8 kB

Come sta cambiando Volunia: importanti novità dal 18 maggio 2012

In questi mesi, vi sarà sicuramente capitato di domandarvi che fine avesse fatto Volunia e, probabilmente, cosa stava nascondendo il silenzio e l’assenza di comunicazioni da parte nostra.

Questa scelta vi sarà sembrata incomprensibile, magari a tratti anche irrispettosa e poco ragguardevole nei confronti di chi ha dimostrato curiosità, interesse e partecipazione intorno al progetto. Se il nostro atteggiamento è risultato tale, o vi ha in qualche modo infastidito, vi preghiamo di accettare le nostre scuse. Chiediamo scusa soprattutto ai nostri Power User, che nonostante tutto, sono rimasti con noi, hanno continuato a scoprire, scandagliare, studiare la piattaforma di Volunia.

Ci teniamo, però, a farvi sapere che non è mai stata nostra intenzione ignorare le voci rivolte a noi o chiudere le porte ai nostri sostenitori. Abbiamo preferito, in questi mesi, rimanere momentaneamente in disparte, per osservare doviziosamente quello che stava succedendo, in seguito al lancio della prima Beta, e ascoltare con attenzione tutto ciò che ci veniva criticato, suggerito, consigliato.

Abbiamo accettato, seppur con dispiacere, anche polemiche e duri attacchi, comprendendo che erano dettati dal disappunto e dalla delusione che probabilmente questa nostra linea di azione ha contribuito ad alimentare.

Questo nostro ritiro si è tradotto, dunque, in un’approfondita attività di analisi delle criticità, che ci ha portato a comprendere, mediante un duro e scrupoloso lavoro di ricerca e implementazione, cosa migliorare, cosa modificare, cosa sostituire o integrare in Volunia.

Dal 18 maggio, infatti, i nostri Power User potranno testare con mano alcuni sostanziali cambiamenti, che consentiranno di comprendere ancora meglio l’identità, l’unicità di Volunia e le sue grandi potenzialità.

Ecco in anteprima qualche anticipazione:

  • Rafforzeremo le funzioni di ricerca attraverso l’integrazione nel sistema Volunia con uno dei principali motori di ricerca presenti sul mercato mondiale. Abbiamo deciso, pur continuando a portare avanti lo sviluppo del nostro motore, di mettere a vostra disposizione un motore di ricerca primario, per consentirvi di fruire di tutte le funzionalità di Volunia e di tutte le sue potenzialità.
  • Volunia avrà una nuova veste grafica, più funzionale e accattivante, pensata e realizzata anche grazie al Vostro contributo.
  • Metteremo a vostra disposizione documenti più chiari ed esaustivi riguardanti le politiche di privacy e i termini e condizioni di utilizzo del servizio Volunia.

E’ iniziata, dunque, la nuova fase di Volunia, agli aggiornamenti apportati il 18 maggio ne seguiranno altri, a partire dal 21 maggio.

Stiamo lavorando con solerzia per riuscire ad aprire Volunia a tutti. La nostra intenzione e la nostra speranza è di riuscire a renderlo disponibile al pubblico entro il 14 giugno. Questo tempo ci sarà utile a verificare, grazie anche al prezioso contributo dei nostri Power User, che durante questa seconda fase di Beta testing non emergano grosse criticità.

La svolta di Volunia inizia, però, in realtà, già oggi.

Questo che state leggendo, infatti, è il post inaugurale di blog.volunia, il nostro canale di comunicazione ufficiale attraverso il quale, a partire da questo momento, vi terremo al corrente di tutti i nostri passi nella crescita del progetto Volunia: le novità, il lancio ufficiale con apertura pubblica e tutte le innovazioni che apporteremo da ora in poi.

Con blog.volunia aumenteranno, oltretutto, le possibilità di interazione con voi utenti e se lo vorrete, potrete diventare parte integrante delle scelte di Volunia partecipando, per esempio, a sondaggi riguardanti la scelta di alcuni aspetti grafici, legati alle mappe visuali.

Oltre al blog, la nostra comunicazione passerà anche attraverso un servizio di newsletter e una rinnovata sezione Q&A.
Saremo sempre presenti. Sarete costantemente aggiornati e informati sugli sviluppi di Volunia e sulle tempistiche necessarie a rendere la nostra piattaforma sempre funzionale e in linea con le vostre esigenze e aspettative.

Grazie a tutti per averci aspettato.

Il Team Volunia

Mie considerazioni dopo aver letto l’articolo su Il Giornale (09 febbraio 2012):

Volunia, ma che delusione il Google made in Italy Lo abbiamo provato per voi

Debutta il motore di ricerca italiano, salutato da tutti come rivoluzionario. Il “papà”: siamo solo all’inizio, ma dovevamo mostrarci agli investitori
E’ vero, Volunia è all’inizio di una strada tutta in salita, ma con una idea eccellente. Il web è “social”? Ebbene, anche lo strumento che utilizziamo per navigarlo lo diventa. Purtroppo, il progetto nasce in un periodo non proprio roseo per la finanza mondiale. Ribadirei una cosa scontata, ossia che il grosso problema non è tanto il limite tecnologico, che si supera con il lavoro e la ricerca (cosa in cui noi Italiani siamo imbattibili), ma sono i soldi che non girano per finanziare progetti del genere.
Forse occorreva soltanto aspettare un pò prima di far uscire la versione “alfa”, tanto criticata forse immeritamente, ma con problemi evidenti (nella presentazione e nelle funzionalità).
L’articolo de Il Giornale che considera una delusione il “Google made in Italy” è per me sdegnoso per rappresentare un lavoro che nasce dalla collaborazione di una piccola equipe di studenti ed ex studenti dell’Università, dove insegna lo stesso Marchiori. Ma che ci si aspettava? Davvero di riprogettare Google da un giorno all’altro? Io premierei soprattutto l’idea brillante che, se trova a metà di quest’anno una realizzazione concreta e ben apprezzata, potrà essere un risultato straordinario per l’innovazione italiana.
Ancora una volta una idea innovativa che nasce nelle nostre Università ma che, stavolta, potrebbe essere sviluppata anche in casa nostra, invece di vedere le nostre menti geniali trovare gloria altrove.

[Spring] Spring3: dai Controller ai Repository [Parte1]

In questo articolo, riporto la configurazione di Spring per il supporto alle annotations (sia sui model, che sui servizi e DAO) e all’utilizzo di Spring MVC (controller). Ricordiamo che Spring è il framework open source per lo sviluppo di applicazioni su piattaforma Java attualmente più utilizzato e riconosciuto come valida alternativa agli Enterprise JavaBeans (EJB).

In un secondo tutorial (Parte 2), verranno riportati degli esempi di controller (interfaccia che riceve una richiesta HTTP – HttpServletRequest e HttpServletResponse – simile alla Action di Struts), di model o entity (modello dei dati o entità, ossia bean che rappresenta la tabella sulla basedati, con relative associazioni ad altre entità), di service (interfaccia con la logica di business della web application) e di repository (interfaccia DAO che esegue le operazioni CRUD sulla basedati), con relative annotations (@Controller, @Entity, @Service, @Repository).

Grazie all’utilizzo delle annotations, si riduce l’overhead per la scrittura di codice nei file XML, risparmiando tempo anche nel debug e manutenzione del codice (clean code). Il mapping dei bean di Spring, infatti, avviene tutto sul sorgente JAVA, mantenendo anche una netta separazione tra la configurazione del framework e le interfacce/classi della nostra applicazione.

Gli step da seguire per la configurazione di Spring+Hibernate nella nostra web application sono i seguenti:

  1. Installazione delle librerie di Spring e Hibernate con l’ausilio di MAVEN
  2. Integrazione di Spring nella web application (dispatcher, filters, listeners, servlets nel file web.xml)
  3. Logging di Spring e Hibernate
  4. Configurazione del context-application di Spring (configurazione core)
  5. Configurazione dell’ORM Hibernate in Spring
  6. Sicurezza in Spring
  7. Configurazione di Spring MVC

I file di configurazione di Spring sono stati divisi a seconda del modulo/componente che si intende utilizzare nella nostra web application (Spring ORM, Spring Security, Spring MVC, Spring Core), per avere una maggiore leggibilità e flessibilità nella scelta delle componenti da installare. I nomi dei file riportati di seguito (spring-application.xml, spring-servlet.xml, spring-orm.xml, spring-security.xml) non sono imposti dalla specifica di Spring, come neanche la suddivisione adottata.

Continua la lettura

Vita da programmatore (da “Il MessaGGiero”)

(Tratto da “Il MessaGGiero”: http://www.messaggiero.it/weblog/pivot/entry.php?id=7 )

La definizione per il termine “Programmatore” su Wikipedia http://it.wikipedia.org/wiki/Programmatore riporta testualmente:
Il programmatore (o coder) è il professionista che scrive dei programmi software in un determinato linguaggio di programmazione“.

Non so voi ma io leggendo questa definizione mi sento più un chip elettronico che una persona in carne ed ossa.

La mia definizione di programmatore è molto diversa da quella ufficiale, ossia:

Il programmatore è chi, pensando di far soldi come professionista dei computer, si ritrova a fare la fame per il profitto di qualcun altro“.

Molta gente del settore, si sente offesa se chiamata semplicemente “programmatore“, appellandosi al fatto che esistono varie qualifiche.

La lista delle qualifiche è la seguente:

1 – Programmatore junior:
Il povero disgraziato che inizia quest’ infame carriera ignaro del proprio destino.

2 – Programmatore senior:
Il povero diavolo che ormai si è resoconto della fesseria che ha fatto ma non può tornare indietro.

3 – Analista Programmatore:
Il povero diavolo al punto 2 che dopo aver chiesto un aumento all’azienda, invece dei soldi, gli rifila la qualifica.

4 – Analista:
Il povero diavolo al punto 3 che dopo aver chiesto nuovamente all’azienda un aumento gli avanza la qualifica congratulandosi con lui, con sorrisi a 44 denti, per il salto di carriera e per le tante possibilità che il nuovo titolo gli offrirà per il suo futuro.
Il povero deluso, si renderà conto solo il giorno dopo, che continua a fare il programmatore con lo stesso stipendio di prima.

Nell’immaginario comune, si pensa al programmatore come una persona introversa, occhialuta che programma tutto nella sua vita dal software che scrive fino alla cadenza oraria per andare a fare la pipì!

Tutto questo è assolutamente errato!. La vita del programmatore è una vera avventura, volendo usare un termine informatico è una vita assolutamente “RANDOM” (casuale).

Il programmatore di per se (indipendentemente dalla qualifica) non è una vera e propria categoria unica ma bensì una macro categoria che si scinde in vari filoni.

I filoni principali sono:

1 – Programmatore impiegato in enti statali.

2 – Programmatore impiegato in enti para-statali.

3 – Programmatore per aziende software nel settore privato.

4 – Programmatore “consulente” impiegato presso un’azienda di consulenze settore privato.

5 – Programmatore “consulente” freelance settore privato a partita Iva.

Sicuramente queste 5 categorie non coprono tutti i possibili casi ma credo a mio avviso che siano almeno le più rappresentative.

Analizziamole una per una. Continua la lettura

Creative Commons License
This work by Francesco Ficetola is licensed under a Creative Commons Attribution 4.0 International License.
Based on a work at www.francescoficetola.it.
Permissions beyond the scope of this license may be available at http://www.francescoficetola.it/2012/05/15/vita-da-programmatore-da-il-messaggiero/.