Canigó - Streaming de fitxers en clients REST.docx

Documentos relacionados
Aplicació Canigó 3.1 sense frontend

Configuració scope view JSF a Spring 3

Examen parcial Convocatoria de junio de 2005 FUNDAMENTOS DE LA PROGRAMACIÓN

Via alternativa per al traspàs d artefactes al SIC

Configuració de Canigó LOPD. Aquest how-to va dirigit a tots aquells usuaris que vulguin utilitzar la última versió de canigo.support.lopd.

Canigó HOW-TO s. Eines d intercepció de peticions http

Unidad Didáctica 2. Elementos básicos del lenguaje Java Tipos, declaraciones, expresiones y asignaciones

Configuració autenticació bàsica a Canigó 3.1

EXERCICI 6 PICASA PICASA.

Colas Implementación con gestión estática de memoria

PROGRAMACIÓN EN JAVA. { una línea para definir, crear o ejecutar ; }

PROGRAMACIÓN ORIENTADA A OBJETOS 10/02/2009. Examen de Java. Nombre: DNI: Titulación:

PROGRAMACION I Archivos directos

CLAVE EXAMEN: a cd. c u r s o r = c u r s o r. g e t S i g u i e n t e ( ) ; p o s i c i o n ++;

Excepciones. Excepciones

Entrada y Salida de datos

Experto Universitario Java Enterprise Spring

Construcciones del Lenguaje Java

Algoritmos y Estructuras de Datos Tema 2: Diseño de Algoritmos

Practica 1.Documentació adicional

Centro Asociado Palma de Mallorca. Antonio Rivero Cuesta

3.9 Streams y Archivos Streams Básicos 18/04/2004. API de InputStream (1/2) Streams de Bytes y Caracteres. API de OutputStream

INDICE Prologo 1 Recorrido rápido de java 2 Clases y objetos 3 Extensión de clases

Programación Orientada a Objetos. Java: Excepciones

/** * Raíz del árbol de contactos presentes en el directorio */ private. /** * Número de contactos en el directorio */ private int numcontactos;

Interfaces. Amparo López Gaona. Septiembre de Amparo López Gaona () Interfaces Septiembre de / 1

PROGRAMACIÓN ORIENTADA A OBJETOS 1/7/2009. Examen de Java. Nombre: DNI: Titulación:

Fundamentos de Computadores y Lenguajes

Execució demo Equipaments al nou entorn de Treball

Sockets en Java. Prof. Wílmer Pereira Universidad Simón Bolívar

Custodia i control de versions de codi de les aplicacions

Aplicacions web bàsiques Introducció a servlets i JSP

Gestió d excepcions amb JSF 2. Arquitectes i desenvolupadors d aplicacions web basades en el framework Canigó 3.

Examen Teórico Convocatoria de Junio de 2012

EXEMPLE D UTILITZACIÓ DE PATRONS GRASP 1

HOJA DE EJERCICIOS 5 PROGRAMACIÓN CON EXCEPCIONES EN JAVA

Arquitecturas cliente/servidor

Programación Orientada a Objetos. Java: Excepciones

PRIMER EXAMEN PARCIAL. 5 de febrero de SOLUCIONES

Java Servlets. Qué es un programa? Luis Fernando Llana Díaz. 22 de abril de input Programa output. En pascal:

Disseny de la persistència Serialització

Soluciones al Examen de Fundamentos de Computadores y Lenguajes

Manual d accés a les aplicacions

Manejo de excepciones en Java. ELO329: Diseño y Programación Orientados a Objetos Agustín J. González

Manejo de errores: Excepciones en Java. ELO329: Diseño y Programación Orientados a Objetos

Fem un correu electrónic!! ( )

Programación II - TP1 1er Cuatrimestre 2018

Tipos DataInputStream/DataOutputStream: L/E de datos de tipo simple y Cadenas (Strings) ObjectInputStream/ObjectOutputStream: para persistencia de obj

Validacions amb Java Bean Validation (JSR-303)

Sebastián García Galán

UNITAT REVISAR EL DOCUMENT

Manual d ús d OWNCLOUD

Soluciones al Examen de Fundamentos de Computadores y Lenguajes

Soporte a Desarrolladores. Resolucionando Problemas Comunes de Conectividad

Programación Avanzada, curso 2011 Juan Manuel Fernández Peña

5.- Quan fem un clic sobre Nou treball accedim a la següent finestra que ens permet definir els diferents aspectes del nou treball: Nom : Nom del

Depto. Ingeniería de Sistemas Telemáticos Universidad Politécnica de Madrid ETSI Telecomunicación Fundamentos de Programación 15 de diciembre de 2011

Maestro Coordinador de la Carrera Gestión de la Calidad Director de la Facultad

Introducción a Java LSUB. 30 de enero de 2013 GSYC

Aplicaciones Cliente-Servidor Con Datagramas

Tema 4. Excepciones en Java

Software de Comunicaciones I.T.T. Especialidad Telemática Escuela Politécnica Superior Universidad Carlos III de Madrid

Java Session. Usando Java Session en aplicaciones web

Com treballar amb un array de bytes.

Guia d ús. Descarregar vistes des de l Arconte Portal

Rutines Independents

Programación Concurrente en Java

Guía de l Ús del Portal de Proveïdors. Requisits tècnics del proveïdor

CLASE SOCKET. 1. Crear un nuevo socket usando un constructor de la clase. 2. El socket trata de conectarse al host remoto.

PROJECTE: FRAMEWORK DE PERSISTÈNCIA J2EE

CERTIFICAT DIGITAL D USUARI

Parte I: Programación en un lenguaje orientado a objetos

Rol Nom de la variable Clau Cuiner APP_CHEF_KEY 0001 Cambrer APP_WAITER_KEY 0002 Encarregat APP_BOSS_KEY 0003

Soluciones Kata TDD. Solución requisito 1

DOSSIER PER DONAR D ALTA CITA PRÈVIA A TRAVÉS D EVIA

Com participar en un fòrum

NIVEL 15: ESTRUCTURAS RECURSIVAS BINARIAS

Por el contrario System.in es un byte Stream sin caracteristicas de character Stream.

INGENIERÍA DE PROTOCOLOS DE COMUNICACIONES (MÓDULO 2)

Unitat 2 EQUACIONS DE PRIMER GRAU. Matemàtiques, Ciència i Tecnologia 5. TRANSFORMACIONS D EXPRESSIONS ALGEBRAIQUES UNITAT 2 EQUACIONS DE PRIMER GRAU

Variables. Una variable no es más que un nombre simbólico que identifica una dirección de memoria: vs.

Solución al Examen de Fundamentos de Computadores y Lenguajes

Solución al Examen de Prácticas de Programación (Ingeniería Informática)

El correu brossa és l enviament massiu i intencionat de correus electrònics a persones que no volen rebre aquests missatges.

TEMA 8. Excepciones en Java. Curso de Java. Manejo de Excepciones

Excepciones y E/S Java y Servicios Web I Master en Ingeniería Matemática

Manual de configuració comptes de en centres educatius

Gestores de seguridad en Java

MANUAL: OBRIR PORTS I DMZ

Problema Master mind. Extracte de solució

Java Optional ifpresent y como utilizarlo

Java RMI. las RPC de Java. Parte I. Luis Fernando Llana Díaz. Departamento de Sistemas Informáticos y ProgramaciónUniversidad Complutense de Madrid

Usos del certificat digital amb dispositius mòbils iphone/ipad

Tema 2.- Objetos y mensajes

Pràctica 7: Programació d un servidor TCP.

Transcripción:

A qui va dirigit Aquest how-to va dirigit als perfils tècnics (desenvolupadors i arquitectes) que desenvolupin aplicacions que realitzin connexions a serveis REST amb pujada o descàrrega de fitxers. Introducció En aquest HowTo s explica com realitzar crides per pujar i descarregar fitxers de un servei REST. Es realitza tant la pujada com la baixada de les dades del fitxer en blocs, sense carregar tot el contingut en memòria. Pàgina 1 de 10

Objecte a pujar Primer de tot s ha de crear l objecte a enviar amb l esquema que espera el servei REST. En el nostre exemple el servei espera rebre una petició JSON com la següent: El servei Rest d exemple espera la següent petició: { "Document":{ "nom":"prova_complerta.txt", "data":<<prova_complerta.txt en base64>> Generem la següent classe de Java: public class Document { private String data; private String nom; /*Getters & Setters*/ public String getdata() { retorn data; @JsonProperty("data") public void setdata(string data) { this.data = data; public String getnom() { return nom; @JsonProperty("nom") public void setnom(string nom) { this.nom = nom; Pàgina 2 de 10

Pujar Fitxer Per a realitzar la crida al servei REST utilitzem RestTemplate que es pot trobar a la llibreria spring-web. (org.springframework.web.client.resttemplate) Primer s ha de crear el bean resttemplate: <bean id="resttemplate" class="org.springframework.web.client.resttemplate"> <property name="requestfactory" ref="clienthttprequestfactory" /> <property name="messageconverters"> <list> <bean id="jsonmessageconverter" class="org.springframework.http.converter.json.mappingjackson2httpmessageconverter"> <property name="supportedmediatypes"> <list> <bean id="jsonmediatypetextplain" class="org.springframework.http.mediatype"> <constructor-arg value="text" /> <constructor-arg value="plain" /> <bean id="jsonmediatypeapplicationjson" class="org.springframework.http.mediatype"> <constructor-arg value="application" /> <constructor-arg value="json" /> </list> </property> </list> </property> <bean id="clienthttprequestfactory" class="org.springframework.http.client.bufferingclienthttprequestfactory" > <constructor-arg> <bean class="org.springframework.http.client.simpleclienthttprequestfactory"> <property name="bufferrequestbody" value="false" /> </constructor-arg> És necessari indicar la propietat bufferrequestbody a false per a poder enviar la petició amb streaming. A la classe on realitzarem la petició REST s ha d injectar el bean creat: @Autowired private RestTemplate resttemplate; Es crea l objecte a enviar i el InputStream del qual es llegirà el contingut del fitxer: Document document = new Document(); Document.setNom("prova_complerta"); InputStream data = new FileInputStream(new File("/data/prova_complerta.txt")); Pàgina 3 de 10

I la crida a la petició REST: resttemplate.execute(url, HttpMethod.POST, requestcallback, responseextractor); A requestcallback s ha de fer els següents passos: Obtenir el canal d escriptura de la request. Escriure els bytes corresponents a la crida de upload a realitzar fins arribar al punt on s ha d enviar el contingut del fitxer Escriure el contingut del fitxer en base64 de tal forma que aquest contingut no arribi a estar en memòria al servidor en cap moment mentre s escriu Escriure els bytes corresponents a la resta de la crida final RequestCallback requestcallback = new RequestCallback() { public void dowithrequest(final ClientHttpRequest request) throws IOException { request.getheaders().add("content-type", "application/octet-stream"); //Obtenir el canal d escriptura de la request de la connexió: OutputStream output = request.getbody(); //objecte que utilitzarem per passer a JSON el nostre objecte ObjectMapper mapper = new ObjectMapper(); String jsoninstring = mapper.writevalueasstring(document); //Tallem el String per on hem d enviar el fitxer int split = jsoninstring.indexof("data"); //Escrivim la primera part de la nostra petició String begin = jsoninstring.substring(0, split + 6); output.write(begin.getbytes("utf-8")); // Codifiquem I escrivim el nostre fitxer BASE64Encoder encoder = new BASE64Encoder(); encoder.encode(data, output); ; // Acabem d escriure la nostra petició String end = jsoninstring.substring(split + 9, jsoninstring.length()); output.write(end.getbytes("utf-8")); Pàgina 4 de 10

Objecte a rebre Primer de tot s ha de crear l objecte a rebre amb l esquema que utilitza el servei REST. En el nostre exemple el servei REST retorna una resposta com la següent: { "Resposta":{ "codi":"ok", "descripcio":"correcte", "id":"aa12", "nom":" prova_complerta.txt", "mimetype":"text/plain", "datasize":43, "dataencoding":"base64", "dataencodedsize":60, "data":<<prova_complerta.txt en base64>> Generem la següent classe Java: public class Resposta { private String codi; private String descripcio; private String id; private String nom; private String mimetype; private Integer datasize; private String dataencoding; private Integer dataencodedsize; private ByteArrayOutputStream data; /*Getters & Setters*/ public String getcodi() { return codi; @JsonProperty("codi") public void setcodi(string codi) { this.codi = codi; public String getdescripcio() { return descripcio; @JsonProperty("descripcio") public void setdescripcio(string descripcio) { this.descripcio = descripcio; public String getid() { return id; @JsonProperty("id") public void setid(string id) { this.id = id; public String getnom() { return nom; Pàgina 5 de 10

@JsonProperty("nom") public void setnom(string nom) { this.nom = nom; public String getmimetype() { return mimetype; @JsonProperty("mimeType") public void setmimetype(string mimetype) { this.mimetype = mimetype; public Integer getdatasize() { return datasize; @JsonProperty("dataSize") public void setdatasize(integer datasize) { this.datasize = datasize; public String getdataencoding() { return dataencoding; @JsonProperty("dataEncoding") public void setdataencoding(string dataencoding) { this.dataencoding = dataencoding; public Integer getdataencodedsize() { return dataencodedsize; @JsonProperty("dataEncodedSize") public void setdataencodedsize(integer dataencodedsize) { this.dataencodedsize = dataencodedsize; public ByteArrayOutputStream getdata() { return data; @JsonProperty("data") public void setdata(bytearrayoutputstream data) { this.data = data; /* Fi Getters & Setters*/ Pàgina 6 de 10

Descarregar Fitxer Al objecte responseextractor de la crida resttemplate.execute és on es tracta la resposta rebuda. ResponseExtractor<ResponseEntity<Resposta>> responseextractor = new ResponseExtractor<ResponseEntity<Resposta>>() { public ResponseEntity<Resposta> extractdata(clienthttpresponse response) throws IOException { Resposta resposta = null; ; if (response.getstatuscode().is2xxsuccessful()){ //Obtenim la resposta InputStream is= response.getbody(); final ByteArrayOutputStream os = new ByteArrayOutputStream(); StreamingJsonParser parser = new StreamingJsonParser(os); try{ parser.parse(is); String jsonresponse=parser.getresponsebuffer().tostring(); jsonresponse=jsonresponse.replace(",\"\"data\":\"", ""); ObjectMapper mapper = new ObjectMapper(); resposta= mapper.readvalue(jsonresponse, Resposta.class); resposta.setdata(os); catch (Exception e){ return new ResponseEntity<Resposta>(resposta,response.getStatusCode()); Per tractar la resposta s han de crear dos classes. StreamingJsonParser que s utilitza per a llegir la resposta obtinguda, obtenir el valor de cada camp i setejar-lo al nostre objecte Resposta. Quan ha de llegir el camp data, que té els bytes del fitxer en Base64 ho fa amb streaming sense deixar el seu contingut en memòria. I per altra banda la classe InnerInputStream per a realitzar aquesta lectura. Per últim mostrem el codi d aquestes dues classes: Pàgina 7 de 10

StreamingJsonParser.java Canigó - Streaming de fitxers en clients REST.docx public class StreamingJsonParser { private long expectedbase64size; private OutputStream os; private StringBuilder responsebuffer; public StreamingJsonParser(OutputStream os) { this.os = os; public long getexpectedbase64size() { return expectedbase64size; public void ondataencodedsize(string previoustextcontent) throws Exception { expectedbase64size = parselong(previoustextcontent); public void ondata(inputstream inputstream) throws Exception { readbase64content(inputstream, expectedbase64size); public void parse(inputstream inputstream) throws Exception { responsebuffer= new StringBuilder(); StringBuilder buffer = new StringBuilder(); int rb = inputstream.read(); while (rb!= -1) { responsebuffer.append((char) rb); if (rb == '"') { if (!readmorerequestcontent(buffer, inputstream)) { rb = '"'; continue; else buffer.append((char) rb); rb = inputstream.read(); private String parsestring(inputstream inputstream) throws Exception { StringBuilder sb = new StringBuilder(); sb.append('"'); int rb = -1; boolean isscaping = false; while ((rb = inputstream.read())!= -1) { responsebuffer.append((char) rb); if (rb == '"' &&!isscaping) break; else if (rb == '\\') isscaping =!isscaping; else { sb.append((char) rb); isscaping = false; sb.append('"'); return sb.tostring(); Pàgina 8 de 10

private long parselong(string text) throws Exception { int indbegin = text.indexof(':'); if (indbegin < 0) throw new Exception("expected long value not found"); int indend = text.indexof(','); if (indend < 0) indend = text.indexof(''); if (indend < 0) indend = text.indexof(']'); if (indend < 0) throw new Exception("expected long value not found"); return new Long(text.substring(indBegin + 1, indend)); private boolean readmorerequestcontent(stringbuilder buffer, InputStream inputstream) throws Exception{ Method onpropertycallback=null; boolean incominginputstreambeingread=true; String previoustextcontent=buffer.tostring(); buffer.delete(0,buffer.length()); // reset buffer if(previoustextcontent.startswith("\"")){ String onpropertycallbackname="on"+previoustextcontent.substring(1, previoustextcontent.indexof('"',1)); try{ onpropertycallback=this.getclass().getmethod( onpropertycallbackname,inputstream.class); catch(nosuchmethodexception nsex){ try{ onpropertycallback=this.getclass().getmethod(onpropertycallbackname,string.class); incominginputstreambeingread=false; catch (NoSuchMethodException nsex2){ if (onpropertycallback!=null){ try{ onpropertycallback.invoke(this, incominginputstreambeingread?inputstream:previoustextcontent); catch (Throwable t){ throw new Exception("Error invoking "+onpropertycallback.getname()+": "+ (t.getcause()!=null?t.getcause().getmessage():t.getmessage())); else buffer.append(parsestring(inputstream)); return incominginputstreambeingread; private void readbase64content(inputstream parentinputstream, long expectedinputsize) throws Exception{ InnerInputStream innerinputstream= new InnerInputStream (parentinputstream,expectedinputsize); BASE64Decoder decoder = new BASE64Decoder(); decoder.decodebuffer(innerinputstream, os); if ('"'!=(char)parentinputstream.read()) throw new Exception("unexpected huge string ending character"); public StringBuilder getresponsebuffer() { return responsebuffer; Pàgina 9 de 10

InnerInputStream.java Canigó - Streaming de fitxers en clients REST.docx public class InnerInputStream extends InputStream { private InputStream parentinputstream; private long numbytesleft; public InnerInputStream(InputStream parentinputstream, long maxbytestoread) throws Exception { this.parentinputstream = parentinputstream; this.numbytesleft = maxbytestoread; public int read() throws IOException { if (numbytesleft > 0) { numbytesleft--; int b = parentinputstream.read(); if (b == -1) numbytesleft = 0; // end of stream reached before expected max size. return b; return -1; public int available() throws IOException { int avail = parentinputstream.available(); if (numbytesleft < avail) return (int) numbytesleft; // avail to expected max size. return avail; public int read(byte[] b) throws IOException { return read(b, 0, b.length); public int read(byte[] b, int off, int len) throws IOException { int rb = -1; if (numbytesleft > 0) { int bmax = ((b.length - off) < len)? b.length - off : len; if (bmax <= numbytesleft) rb = parentinputstream.read(b, off, bmax); else rb = parentinputstream.read(b, off, (int) numbytesleft); if (rb == -1) numbytesleft = 0; // end of stream reached before expected max size. else numbytesleft -= rb; return rb; Pàgina 10 de 10