[JSON] La specifica JSON-RPC 2.0: alcuni client iOs


masthead-jsonrpc2base
Esiste una specifica alquanto diffusa per la distribuzione di servizi RESTful, con l’ovvio formato di interscambio JSON, nota come JSON-RPC 2.0.

Pe le caratteristiche di dettaglio di questa specifica vi rimando al sito ufficiale: http://www.jsonrpc.org/specification 

In breve, JSON-RPC non è altro che un protocollo per la chiamata di procedure remote, dove è possibile passare al servizio anche oggetto complessi ed avere in output dati multipli. La descrizione del servizio (una sorta di WSDL) è ben definita, come anche i codici di errore e di successo restituiti dalla chiamata. In sintesi, non è altro che un “modo” per la scrittura di servizi RESTful secondo un certo standard.

La cosa interessante è che il servizio remoto viene interrogato tramite i comuni protocolli HTTP o TCP/IP e la serializzazione degli oggetti di output avviene in formato JSON. Una richiesta di servizio è una chiamata a un metodo specifico e che contiene le seguenti proprietà:

  • method – una stringa con il nome del metodo da invocare.
  • params – un array di oggetti da passare come parametri al metodo definito.
  • id un valore di qualsiasi tipo, che viene utilizzato per abbinare la risposta alla richiesta

Esempio:  {“jsonrpc”: “2.0”, “method”: “subtract”, “params”: [42, 23], “id”: 1}

json-rpc2.0 Per poter richiamare questi servizi da un’app mobile iOs, ho provato i seguenti client:

Esiste anche la possibilità di richiamare i servizi JSON-RPC in “modalità nativa”, come descritto da questo tutorial:

[PrimeFaces] Due approcci per customizzare i tag di PrimeFaces

Logo Prime FacesIn un recente post, ho “lodato” PrimeFaces come uno dei migliori framework Java Server Faces (JSF) attualmente in circolazione. In effetti, le componenti grafiche, rispetto ad altre librerie del genere (vedi Rich Faces), sono sicuramente più stabili, complete e graficamente più carine. Tuttavia, può capitare di dover fare delle customizzazioni, specie per renderne alcune davvero accessibili (nonostante da documentazione si dichiari l’aderenza di PrimeFaces alle specifiche Accessibile Rich Internet Applications – WAI-ARIA).

Illustro qui due metodi per customizzare i tag di Prime. Nell’esempio, verrà modificato la componente “PanelGrid” (p:panelGrid), ma la procedura può essere applicata a tutti i tag della libreria “core”.

Entrambi metodi che vi illustrerò, prendono come riferimento la documentazione dei tag di PrimeFaces. Ecco il link alla documentazione dell’attuale versione (4.0): Documentazione PrimeFaces 4.0

Ad esempio, per il tag PanelGrid ecco le informazioni che ci servono:

tagPanelGrid PrimeFaces

 

1° Metodo: Customizzazione della Renderer Class (RenderKit)

Se vi occorre customizzare soltanto il rendering della componente grafica, basta estendere la classe “Renderer” ad essa associata. Come già anticipato sopra, per capire qual è tale classe, occorre leggere la documentazione relativa al tag da customizzare. Nel caso del panelGrid, la classe da estendere è org.primefaces.component.panelgrid.PanelGridRenderer

NOTA. Gli attributi rendererType e rendererClass, che si leggono da documentazione, non coincidono. Quindi, state attenti ad annotarvi queste informazioni, perché occorre configurarle allo stesso modo per la classe “custom” che scriverete, come illustrato di seguito.

Ecco la classe CustomPanelGridRenderer che estende quella “core” PanelGridRenderer:

package it.francescoficetola.prime.web.component;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.primefaces.component.column.Column;
import org.primefaces.component.panelgrid.PanelGrid;
import org.primefaces.component.panelgrid.PanelGridRenderer;
import org.primefaces.component.row.Row;

public class CustomPanelGridRenderer extends PanelGridRenderer{

	 public CustomPanelGridRenderer() {
                super();
	        System.out.println("costruttore classe custom renderer");
	 }

         @Override
	 public void encodeRow(FacesContext context, Row row, String columnRole, String rowClass, String columnClass) throws IOException {
	        ResponseWriter writer = context.getResponseWriter();

	        writer.startElement("tr", null);
	        if(shouldWriteId(row)) {
	            writer.writeAttribute("id", row.getClientId(context), null);
	        }

	        writer.writeAttribute("class", rowClass, null);
	        writer.writeAttribute("role", "row", null);

	        for(UIComponent child : row.getChildren()) {
	            if(child instanceof Column && child.isRendered()) {
	                Column column = (Column) child;
	                String styleClass = null;
	                String userStyleClass = column.getStyleClass();

	                if(userStyleClass != null && columnClass != null) styleClass = columnClass + " " + userStyleClass;
	                else if(userStyleClass != null && columnClass == null) styleClass = userStyleClass;
	                else if(userStyleClass == null && columnClass != null) styleClass = columnClass;

	                writer.startElement("td", null);
	                if(shouldWriteId(column)) { 
	                    writer.writeAttribute("id", column.getClientId(context), null);
	                }
	                writer.writeAttribute("role", columnRole, null);

	                if(column.getStyle() != null) writer.writeAttribute("style", column.getStyle(), null);
	                if(styleClass != null) writer.writeAttribute("class", styleClass, null);
	                if(column.getColspan() > 1) writer.writeAttribute("colspan", column.getColspan(), null);
	                if(column.getRowspan() > 1) writer.writeAttribute("rowspan", column.getRowspan(), null);

	                column.encodeAll(context);

	                writer.endElement("td");
	            }
	        }

	        writer.endElement("tr");
	    }
}

Nell’esempio precedente, è stato effettuato l’override del metodo encodeRow. In base al comportamento che vorrete customizzare, occorre individuare nella classe “Renderer” della vostra componente, il metodo associato a tale comportamento ed effettuarne l’override, modificandone la logica.

Per poter registrare la vostra classe “custom” di rendering, occorre configurare il faces.config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
        version="2.0">

	<render-kit>
            <renderer>
                <component-family>org.primefaces.component</component-family>
                <renderer-type>org.primefaces.component.PanelGridRenderer</renderer-type>
                <renderer-class>it.francescoficetola.prime.web.component.CustomPanelGridRenderer</renderer-class>
            </renderer>
        </render-kit>

</faces-config>

I valori da associare agli attributi component-familyrenderer-type li prendete da documentazione del tag, come suddetto. In questo modo, ogni volta che utilizzate il “core tag” sulle pagine JSF della vostra applicazione (nell’esempio, p:panelGrid), in automatico verrà richiamata la vostra classe “renderer”.

NOTA. Se notate che nulla accade, provate ad inserire nel file web.xml della vostra applicazione le seguenti righe di codice (inserendo anche il file faces-config.xml nella cartella WEB-INF):

    <context-param>
        <param-name>javax.faces.CONFIG_FILES</param-name>
        <param-value>
            /WEB-INF/faces-config.xml, /faces-config.xml
        </param-value>
    </context-param>

 

2° Metodo: Customizzazione del tag (CustomTag)

Il secondo metodo che vi illustro è sicuramente il più completo, perché vi permette di modificare tutto il comportamento del tag associato alla componente grafica, e non solo il suo rendering.

In questo caso, vanno estesi sia il Component Class che il Renderer Class. Nel caso del p:panelGrid di questo esempio:

Renderer class: org.primefaces.component.panelgrid.PanelGridRenderer

Component class: org.primefaces.component.panelgrid.PanelGrid

package it.francescoficetola.prime.web.component;

import javax.faces.component.FacesComponent;
import org.primefaces.component.panelgrid.PanelGrid;

@FacesComponent("it.francescoficetola.prime.component.CustomPanelGrid")
public class CustomPanelGrid extends PanelGrid{

	public CustomPanelGrid() {
		super();
		System.out.println("Costruttore del component class");
	}

	@Override
	public void setColumns(int _columns) {
	    getStateHelper().put(PropertyKeys.columns, _columns);
	}
}

Nell’esempio del PanelGrid, è stato effettuato l’override del metodo setColumns, ma anche qui vale quanto detto nel 1° metodo di customizzazione, ossia che in base al comportamento che vorrete customizzare, occorre individuare nel Component Class il metodo associato per modificandone la logica, attraverso l’override.

Di seguito, vi ripeto la classe di “renderer” custom, che anche per questo metodo va prevista, ma che in più presenta anche delle annotazioni di classe:

package it.francescoficetola.prime.web.component;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;

import org.primefaces.component.column.Column;
import org.primefaces.component.panelgrid.PanelGrid;
import org.primefaces.component.panelgrid.PanelGridRenderer;
import org.primefaces.component.row.Row;

@FacesRenderer(
	    componentFamily=PanelGrid.COMPONENT_FAMILY,
	    rendererType="it.francescoficetola.prime.web.component.CustomPanelGridRenderer"
	)
public class CustomPanelGridRenderer extends PanelGridRenderer{

	public CustomPanelGridRenderer() {
	    System.out.println("costruttore della classe renderer");
	    }

         @Override
	 public void encodeRow(FacesContext context, Row row, String columnRole, String rowClass, String columnClass) throws IOException {
	        ResponseWriter writer = context.getResponseWriter();

	        writer.startElement("tr", null);
	        if(shouldWriteId(row)) {
	            writer.writeAttribute("id", row.getClientId(context), null);
	        }

	        writer.writeAttribute("class", rowClass, null);
	        writer.writeAttribute("role", "row", null);

	        for(UIComponent child : row.getChildren()) {
	            if(child instanceof Column && child.isRendered()) {
	                Column column = (Column) child;
	                String styleClass = null;
	                String userStyleClass = column.getStyleClass();

	                if(userStyleClass != null && columnClass != null) styleClass = columnClass + " " + userStyleClass;
	                else if(userStyleClass != null && columnClass == null) styleClass = userStyleClass;
	                else if(userStyleClass == null && columnClass != null) styleClass = columnClass;

	                writer.startElement("td", null);
	                if(shouldWriteId(column)) { 

	                    writer.writeAttribute("id", column.getClientId(context), null);
	                }
	                writer.writeAttribute("role", columnRole, null);

	                if(column.getStyle() != null) writer.writeAttribute("style", column.getStyle(), null);
	                if(styleClass != null) writer.writeAttribute("class", styleClass, null);
	                if(column.getColspan() > 1) writer.writeAttribute("colspan", column.getColspan(), null);
	                if(column.getRowspan() > 1) writer.writeAttribute("rowspan", column.getRowspan(), null);

	                column.encodeAll(context);

	                writer.endElement("td");
	            }
	        }

	        writer.endElement("tr");
	    }

}

A questo punto, occorre creare la taglib con i propri “custom tag”. Nel mio caso, ho creato un file customtag.taglib.xml, con il seguente contenuto:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0"
>
    <namespace>http://francescoficetola.it/ui</namespace>

    <tag>
        <tag-name>custompanelgrid</tag-name>
        <component>
            <component-type>it.francescoficetola.prime.web.component.CustomPanelGrid</component-type>
            <renderer-type>it.francescoficetola.prime.CustomPanelGridRenderer</renderer-type>
        </component>
    </tag>
</facelet-taglib>

Nel file della taglib, occorre registrare tutti i “custom tag” che prevedete (nel mio caso, ho per ora solo il custompanelgrid, che vi ricordo estende il tag “core” p:panelgrid di PrimeFaces). Salvate questo file nella directory WEB-INF del vostro progetto.

Infine, occorre registrare la taglib nel file web.xml, come segue:

	<!-- CONTEXT PARAM  -->
	<context-param>
	    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
	    <param-value>/WEB-INF/customtag.taglib.xml</param-value>
	</context-param>

Ora siamo pronti ad utilizzare il nostro custom tag. Ricordatevi di definire il namespace nella pagina JSF in cui utilizzare la vostra componente custom:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<ui:composition 
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:c="http://java.sun.com/jsp/jstl/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui"
	xmlns:customtag="http://francescoficetola.it/ui"
>

<h:html>

   <h:head>
   </h:head>

   <h:body>

	<h:form id="myForm">

            <p:messages id="messages" /> 

	     <h:panelGroup id="myPanelGroup">

		 <customtag:custompanelgrid>

		        <p:row>
				<p:column>Colonna 1</p:column>
                                <p:column>Colonna 1</p:column>
			</p:row>

	         </customtag:custompanelgrid>

	     </h:panelGroup>

	</h:form>

   </h:body>

</h:html>

</ui:composition>

 

Riferimenti utili:

[iOs] Idee e codici per menù ed altri componenti grafiche con effetti e transizioni su Code4App

Condivido qui un sito interessante, Code4App, dove vengono proposti menù ad effetto con transizioni:

In realtà, sul sito di Code4App troverete anche tante altre idee per la vostra app, come tab bar, animazioni, calendar, tabelle, ecc. ecc. Ovviamente troverete anche i codici sorgenti da scaricare e provare in xCode.

Ecco le categorie attualmente disponibili:

CodeApp - Category

Devo dire che è davvero una bella idea quella di raccogliere su un sito tutti i progettini utili ed interessanti condivisi da utenti di GitHub, BitBucket ed altri. Spesso, infatti, è difficile cercare quello che serve sui social network per programmatori, perché non mettono a disposizione una “vetrina” immediata che consente di individuare il componente desiderato.

Ecco i menù che ho trovato interessanti su Code4App e che ho usato per una mia app:

ios_menu popupscroll_menu ios