viernes 12 de junio de 2009

Recetario SCDJWS

Ya soy Sun Certified Developer for Java Web Services. Y como es costumbre, procedo a contarles que tuve que hacer y dejar de hacer para agregar esta certificación a mi palmarés:

Como ya conté en un post anterior, yo compré dos vouchers de certificación allá por agosto del año pasado, aprovechando que estaban a mitad de precio. Los dos vouchers vencían en Junio, así que optimistamente comencé a estudiar para obtener la SCBCD, certificación que obtuve en marzo de este año.

Por mi dejadez y descuido, estuve sin tocar un libro de Java hasta finales de Junio, cuando recordé el voucher que tenía pendiente y lo próximo de su vencimiento. Sin tener otra alternativa, programé rendir el SCDJWS 5 el 11 de Junio, un día antes de su vencimiento.

Ahora, mi experiencia práctica en Web Services es bastante...básica. A lo mucho he hecho unos cuantos clientes de WS en Axis, y eso es todo; por lo que necesitaba empezar por lo básico, y empezar cuanto antes dado que tenía menos de 15 días.

Pero antes, unas precisiones sobre el examen. El SCDJWS 5.0 es un exámen bastante nuevo, y como tal no existen guías de certificación ni exámenes de ejemplo aún. Pero, para certificarse basta con 42%. A pesar de que la Web de Sun diga lo contrario, el passing score es de 42%. Créanme, así dice en mi report de Prometric y así dicen los foristas de Javaranch.

Volviendo al relato,entonces empecé mi preparación. Como mencioné no existe aún una guía para el exámen; así que buceando por la red, encontré el post de un tipo que había aprobado la versión beta del exámen, y que recomendaba leer SOA Using Java Web Services de Mark D. Hansen (aunque decía que no cubría todos los temas del exámen). Dado que era la única sugerencia que encontré (casi todo lo que encontré fue para la versión anterior del exámen), me dispuse a comenzar su lectura.

Sólamente leí dos capítulos, que produjeron unos cuantos posts. El libro es bastante bueno y completo, pero era demasiado contenido para un novato para mí. Sin embargo, el leer ese par de capítulos me dio una buena idea de lo que me esperaba (un sinnúmero de especificaciones por leer).

Entonces, recurrí a Amazon para buscar un libro de Web Services que cubra JAX-WS (la API en la que te evalúan) y que sea sencillo. Para mi sorpresa, habían poquísimos libros que tocaban JAX-WS (en efecto, el examen es bastante nuevo xD), pero entre los pocos listados uno prometía: Java Web Services: Up and Running de Martin Kalin.

El libro de Kalin estaba más orientado a mi perfil (newbie), y con lo que ya había leído en Hansen me fue iluminando poco a poco en el mundo de los Web Services. El libro didáctico y sencillo, y se apoya en bastante código fuente y ejemplos prácticos. Pero eso no basta para dar un exámen de certificación, así que estando al 80% dejé el libro, y me dispuse a buscar otra fuente.

La encontré en las SCDJWS 5 Study Notes de Ivan Krizsan. Iván había dado el exámen, lo había aprobado y comparte sus notas con el que quiera leerlas. El documento no tiene la didáctica de un libro, pero extrae de las especificaciones los puntos que vienen en el examen (cubre casi todos los objetivos). Este pdf si me lo leí completito; y terminando me dispuse a buscar preguntas de ejemplo para ver que tanto había asimilado.


Lastimosamente, no las encontré. El exámen es demasiado nuevo, por lo que todavía no salen simuladores, así que tuve que conformarme con preguntas de la versión anterior del examen, en los mocks de Actualtests. La versión anterior y la actual coinciden en muchos temas (WSDL, UDDI, XML Schema, JAXP, etc), por lo que traté de responder sólamente las preguntas que sabía podían venirme en el examen. Una buena selección de ellas pueden ubicarlas en el blog. Resolviendo las preguntas me di cuenta que andaba algo flojo en WSDL y XML, por lo que apoyé en J2EE Web Services de Richard Monson-Haefel para aclarar las cosas (este libro cubre los objetivos de la versión anterior, pero en temas de WSDL y XML los temas coinciden); y para entender mejor los patrones en los que te evalúan le di una repasadita a Core J2EE Patterns: Best Practices and Design Strategies de Deepak Alur,John Crupi y Dan Malks.

Todo eso lo hice en más o menos 13 días. Faltando ya tres días para el examen, me puse a repasar los temas en los que estaba flojo de la Guía SCDJWS 5 de Mikalai Zaikin; que tiene mejor cobertura de temas que la de Iván, pero por eso también es más extensa. El 9 de Junio detuve mi preparación, y me resigné a mi suerte.

Llegó el día del examen, el cúal rendí en Cibertec. El examen era de 65 preguntas, y la gran mayoría trataba de casos de aplicación prácticos. Eran preguntas del tipo: "En la empresa A, requieren una aplicación con tales requisitos no funcionales, y tienen tantas limitantes. ¿Que tecnología se debe usar?", aunque también estaban las de dominio del API y los estándares (aunque en minoría). Terminé el examen, y a la salida la misma señorita sonriente de la vez pasada me informaba que estaba certificado.

Todavía no tengo claro cúal será el siguiente paso. Tal vez podría ser el Certified Scrum Master, aprovechando el curso que se viene, o tal vez el Certified Software Development Associate de la IEEE. En cuanto me decida les aviso, hasta ese entonces planeo tomarme un descanso. Hasta otra!!

martes 9 de junio de 2009

JAX-WS: Un cliente y un servidor

(Imagen : Rembrandt - La ascención de Cristo y María Magdalena)

Es hora de hacer un ejemplo, que ya estábamos demasiado "académicos". Se tendrá una clase de implementación Hello, que estará anotada como endpoint de web service mediante @WebService. Hello declara un sólo método denominado sayHello, anotado con @WebMethod. @WebMethod expone al método anotado a los clientes del Web Service. El método sayHello devuelve un saludo a los clientes, usando el nombre pasado como parámetro para armar el saludo. La clase de implementación define un constructor por defecto público, que no recibe argumentos (parámetros).

package helloservice.endpoint;

import javax.jws.WebService;

@WebService
public class Hello{
private String message = new String("Hello, ");

public void Hello(){}

@WebMethod
public String sayHello(String name){
return message + name + ".";
}
}


Ahora veamos al cliente. HelloClient es un programa Java stand-alone que accede al método sayHello de HelloService. Hace esta llamada a través de un port, un objeto local que actúa como proxy del servicio remoto. Este port es creado en tiempo de desarrollo por la herramienta wsimport, que genera artefactos portables de JAX-WS en base a un archivo WSDL.

AL invocar métodos remotos en el port, el cliente realiza lo siguiente:

Se utiliza la anotación javax.xml.ws.WebServiceRef para declarar una referencia a un web service. @WebServiceRef utiliza el elemento wsdlLocaltion para especificar el URI del WSDL del servicio desplegado

@WebServiceRef(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
static HelloService service;


Se obtiene un proxy para el servicio, tambien conocido como port, al invocar getHelloPort en el service.

Hello port = service.getHelloPort();


El port implementa la SEI definida por el servicio.

Se invoca al método sayHello del port, pasándole al servicio un name.

String response = port.sayHello(name);


Aquí tenemos todo el código de HelloClient:

package simpleclient;

import javax.xml.es.WebServiceRef;
import helloservice.endpoint.HelloService;
import helloservice.endpoitn.hello;

public class HelloClient{
@WebServiceRef=(wsdlLocation="http://localhost:8080/helloservice/hello?wsdl")
static HelloService service;

public static void main(String[] args){
try{
HelloClient client = new HelloClient();
client.doTest(args);
}catch(Exception e){
e.printStackTrace();
}

}

public void doTest(String[] args){
try{
Hello port = service.getHelloPort();
String name;
if (args.length > 0){
name = args[0];
}else{
name = "No Name";
}
String response = port.sayHello(name);
System.out.println(response);

}catch(Exception e){
e.printStackTrace();
}
}
}


Basado en la Guía SCDJWS de Mikalai Zaikin

lunes 8 de junio de 2009

Creating a New ServiceBinding Object

El objeto JAXR ServiceBinding se corresponde con la estructura UDDI bindingTemplate, y representa la información técnica necesaria para acceder a un servicio. Puede tener cualquier número de specification links y sólamente un Access URI.

Un objeto ServiceBinding no tiene un nombre, pero casi siempre tendrá un accessURI, que es la dirección electrónica del servicio. Por ejemplo:

ServiceBinding binding = lifeCyclemngr.createServiceBinding();
service.addServiceBinding(binding);
binding.setValidateURI(false);
binding.setAccessURI("http://qwerty.org/iop");

Cuando se guarda un ServiceBinding en un registro UDDI, el registro verifica que el accessURI es un URL válido. La llamada al método setValidateURI(false) sobreescribe este comportamiento. Si se comenta esta línea y el URL especificado no existe, el programa lanzará una excepción indicando que la URL es inválida.

Entonces, la B es la alternativa de nuestra elección.

Pregunta tomada de ActualTests

Mapping JAXR to the UDDI Inquiry API


La Inquiry API de UDDI tiene básicamente dos tipos de operaciones SOAP: find_XXX y get_XXX. Las operaciones find_XXX se mapen directamente a métodos definidos en BusinessQueryManager, y muchas operaciones get_XXX definidas en la Inquiry API de UDDI están definidas implícitamente al navegar los objetos del infomodel.

La interfaz BusinessQueryManager define varios métodos findXXX() que se corresponden con las operaciopnes fin de la Inquiry API de UDDI.

Por lo que la alternativa B sería nuestra mejor opción.

Pregunta tomada de ActualTests

The RegistryObject Interface

La mayoría de interfaces definidas en el modelo de información de JAXR extienden de la interfaz javax.xml.registry.infomodel.RegistryObject. Esta interfaz define alrededor de tres docenas de métodos, de los cúales sólo algunos aplican a los tipos de datos UDDI.

La primera vez que se guardan RegistryObjects de ciertos tipos (como Organization y Concept) en un registro UDDI, se les asigna un UUID Key (Universally Unique Identifier) . Se puede obtener el key que el registro ha generado para un objeto invocando a getKey().

Esto con concuerda con la alternativa A y la alternativa B.

Pregunta tomada de ActualTests

Mapping JAXR to the UDDI Inquiry API

Es posible buscar por Organization, Service, ServiceBinding, ClassificationScheme y objetos Concept mediante el criterio classifications.

Paras buscar mediante Classification, es necesario instanciar la clase Classification, lo que significa que primero hay que encontrar su ClassificationScheme y despues crear una instancia de Classification. Al utilizar múltiples objetos Classification en este criterio, la búsqueda se conducirá como una búsqueda AND.

El parámetro de búsqueda classifications se corresponde con elemento de búsqueda UDDI categoryBag.

El objeto Organization es la raíz de una entrada de negocio UDDI. Representa una instancia de la estructura de datos UDDI businessEntity.

Un objeto Organization contiene un nombre de negocio y descripción, información de contacto, categoría de industria y valores de identificación, junto a una colección de cero o más objetos BusinessService, cada uno de los cúales representa un tipo de servicio electrónico (por lo general un Web Service o un sitio Web).

Lo que nos lleva a seleccionar la alternativa D.

Pregunta tomada de ActualTests

The Concept Information Object

En UDDI la estructura de datos tModel se utiliza para describir las especificaciones técnicas de un Web Service. Un TModel técnico puede hacer referencia a un documento WSDL, un documento de esquema XML, u otra especificación. En el caso de Web Services J2EE, un tModel técnico por lo general se refiere a un documento WSDL que describe un web Service.

En JAXR el objeto Concept representa un tModel técnico. Un objeto Concept se crea independientemente de un Organization y es referido por uno o más Web Services. Esto es útil cuando un tModel técnico hace referencia a un documento WSDL estándar.

Pregunta tomada de ActualTests

DataHandler

La clase DataHandler nos facilita en SAAJ el crear y agregar archivos adjuntos a mensajes SOAP. Cuando se agrega un adjunto a un mensaje SAAJ, el objeto adjuntado siempre es embebido por un objeto DataHandler. Esto puede ser oculto y ocurrir detrás del escenario, o puede hacerse explícitamente. Así:

AttachmentPart pdfAttach = message.createAttachmentPart();
FileDataSource file = new FileDataSource("manuscript.pdf");
DataHandler pdfDH = new DataHandler(file);
pdfAttach.setDataHandler(pdfDH);

La clase DataHandler puede ser instanciada para representar cualquier tipo de data: una imagen, un documento PDF, un Documento DOM, etc. DataHandler provee métodos para leer y escribir streams de data, acceder a tipos MIME de data y crear objetos Java que representen data en el stream.

Por lo que señalaríamos a la alternativa B como correcta.

Pregunta tomada de ActualTests

The SOAPHeader Type

El elemento Header de SOAP puede tener cero o más header blocks. En SAAJ, el tipo SOAPHeader representa al elemento Header, y el tipo SOAPHeaderElement representa un header block individual. SOAPHeader provee métodos para agregar, examinar y remover objetos SOAPHeaderElement, lo que agrega, examina o remueva header blocks de un documento SOAP.

Los receptores de SOAP pueden usar esta funcionalidad para acceder a todos los header blocks, header blocks asociados con un actor en particular, o los header blocks con mustUnderstand igual a true para un actor en particular. La clase SOAPHeader provee 5 métodos para examinar o extraer header blocks. La definición de la clase SOAPHeader es:

package javax.xml.soap;
import java.util.Iterator;

public interface SOAPHeader extends SOAPElement {
public SOAPHeaderElement addHeaderElement( Name name )
throws SOAPException;
public Iterator extractHeaderElements(String actor);
public Iterator examineHeaderElements(String actor);
public Iterator examineMustUnderstandHeaderElements(String actor);
public Iterator examinAllHeaderElements();
public Iterator extractAllHeaderElements();
}


Dicho esto, la alternativa A es la correcta.

Pregunta tomada de ActualTests

The SOAPElement Type

Los elementos específicos a la aplicación que no son parte del namespace XML de SOAP se representan mediante objetos del tipo SOAPElement. Este tipo puede representar cualquier elemento XML. Contiene métodos para acceder a elementos hijo, atributos, información del namespace y demás. Como cualquier elemento XML puede contener a otros elementos XML, un SOAPELement puede contener otros objetos SOAPElement. El tipo SOAPElement modela una estructura jerárquica que se corresponde con la estructura jerárquica de XML. El tipo SOAPElement es supertipo de otros tipos SOAP, incluyendo SOAPEnvelope, SOAPBody, SOAPBodyElement, SOAPHeader, SOAPHeaderElement y los elementos fault. El tipo Node es el supertipo de SOAPElement. El tipo SOAPElement se define así:

package javax.xml.soap;
import java.util.Iterator;

public interface SOAPElement extends Node, org.w3c.dom.Element {
public SOAPElement addAttribute(Name name, String value)
throws SOAPException;
public SOAPElement addChildElement(Name name) throws SOAPException;
public SOAPElement addChildElement(SOAPElement element)
throws SOAPException;
public SOAPElement addChildElement(String localName) throws SOAPException;
public SOAPElement addChildElement(String localName, String prefix)
throws SOAPException;
public SOAPElement addChildElement(String localName, String prefix,
String uri) throws SOAPException;
public SOAPElement addNamespaceDeclaration(String prefix, String uri)
throws SOAPException;
public SOAPElement addTextNode(String text);
public Iterator getAllAttributes();
public String getAttributeValue(Name name);
public Iterator getChildElements();
public Iterator getChildElements(Name name);
public Name getElementName();
public String getEncodingStyle();
public Iterator getNamespacePrefixes();
public String getNamespaceURI(String prefix);
public Iterator getVisableNamespacePrefixes();
public boolean removeAttribute(Name name);
public boolean removeNamespaceDeclaration(String prefix);
public boolean removeContents();
public void setEncodingStyle(String encodingStyle);
}


Entonces, la A se convertiría en nuestra alternativa.

Pregunta tomada de ActualTests

Working with SOAP Documents



SAAJ provee un número de interfaces que se pueden usar para construir un documento SOAP simple. Aquí tenemos el diagrama de herencia:




Un mensaje o documento SOAP es una instancia XML compuesta por elementos y atributos. Por conveniencia, cada parte de un documento SOAP tiene un tipo correspondiente SAAJ. El Envelope es representado por SOAPEnvelope, el Header es representado por SOAPHeader, el Body por SOAPBody y así sucesivamente. El tipo SOAPElement es utilizado para elementos específicos de la aplicación que no pertenecen al namespace de SOAP.

El supertipo de SOAPElement, y por consiguiente de todos sus subtipos, es Node. La interfaz Node nos provee de unos cuantos métodos útiles para navegar a través de un árbol jerárquico de elementos, remover nodos del árbol y marcar nodos para reciclaje.

Con lo que queda demostrado que la B es la opción válida.

Pregunta tomada de ActualTests

Creating a SOAP Message


MessageFactory es la factory principal de SAAJ. Con esta clase se comienza cada vez que se crea un SOAP Message.

La clase MessageFactory es abstracta y no puede ser instanciada. Mediante el método new Instance() se crea un objeto que pertenece a un subtipo de MessageFactory.

MessageFactory posee dos métodos createMessage(). El primero no recibe argumentos , y simplemente genera una instancia de SOAPMessage.

La parte MIME principal de un mensaje SwA es siempre el documento XML SOAP. Cuando el mensaje no tiene adjuntos, se puede usar simplemente los métodos getSOAPBody y getSOAPHeader de SOAPMessage para acceder a estos elementos del mensaje SOAP directamente. Por ejemplo:

MessageFactory msgFactory = MessageFactory.newInstance();
SOAPMessage message = msgFactory.createMessage();
message.getSOAPHeader().detachNode();
SOAPBody body = message.getSOAPBody();

Lo que encaja a la perfección con la alternativa D.

Pregunta tomada de ActualTests

JAXP

JAXP (Java API for XML Processing) permite a las aplicaciones parsear, transformar, validar y consultar documentos XML mediante un API que es independiente de una implementación de procesador XML particular. JAXP provee una capa conectable que permite a los vendedores proveer sus propias implementaciones sin introducir dependencias en el código de la aplicación. Usando este software, los desarrolladores de aplicaciones y herramientas pueden construir aplicaciones Java de soporte XML para e-commerce, integración de aplicaciones y publicación web.

JAXP es un componente estándar de la plataforma Java. Una implementación de JAXP 1.3 está incluida en J2SE 5.0 y una implementación de JAXP 1.4 está en Java SE 6.0.

Deducimos entonces que la A es la correcta.

Pregunta tomada de ActualTests

XSLT


XSLT (XML Stylesheet Language for Transformations) permite el escribir data XML en un archivo, convertir data XML a otros formatos y, junto con SAX, convertir data legacy a formato XML.

Funciones: Convertir data XML a otros formatos, y escribir data XML a archivos.

Capacidades: Dado un conjunto de instrucciones de transformación, convierte data en formato XML a otro formato.

Esto nos lleva a escoger la A.

Pregunta tomada de ActualTests

SAX

SAX (Simple API for XML Parsing) provee un mecanismo orientado a eventos, de acceso serial que procesa la data XML un elemento a la vez. SAX es un API push, lo que implica que el cliente implementa callbacks que son invocados para cuando cierta data ,como elementos, es encontrada al momento de parsear el documento.

SAX usa menos capacidad de procesamiento y de memoria, pero no nos da acceso al modelo de objetos completo de un documento XML. Es aplicable en aplicaciones del lado del servidor y de alta performance que filtran data.

SAX se orienta al procesamiento independiente del estado, donde el manejo de un elemento no depende del elemento anterior.

Por esto, la C es la correcta.

Pregunta tomada de ActualTests

domingo 7 de junio de 2009

SOAP over HTTP

Los códigos de éxito HTTP de nivel 200 son utilizados para indicar que un request SOAP fue recibido y procesado correctamente. Los códigos de éxito HTTP 200 OK y 202 Accepted son utilizados en Web Services.

200 OK: Cuando una operación SOAP genera un mensaje SOAP response, el código de respuesta HTTP para procesamiento exitoso es 200 OK. Este código de respuesta indica que el mensaje de respuesta no es un fault, y que contiene un mensaje SOAP response normal.

202 Accepted: Este codigo de respuesta significa que el request fue procesado exitosamente pero que no hay data SOAP de respuesta. Este tipo de operación SOAP es similar a los métodos Java que retornan void.

Aunque los mensajes SOAP One-Way son conceptualmente unidireccionales, cuando se solicita sobre HTTP siempre se envía una respuesta al emisor. Los mensajes SOAP One-way no devuelven SOAP Faults o resultados de algún tipo, por lo que el código de respuesta HTTP 202 Accepted indica sólamente que el mensaje llegó al receptor (no indica que el mensaje fue procesado con éxito)

Lo que nos lleva a seleccionar la alternativa A.

Pregunta tomada de ActualTests

EJB Endpoints

Es recomendable usar un EJB Endpoint cuando:

  • Ya tenemos un EJB stateless existente que se requiere exponer como Web Service
  • La lógica de negocio que utiliza el servicio se encuentra en la capa EJB, de modo que el endpoint y la lógica de negocio se mantengan en la misma capa.
  • Se requiere de los servicios de transacciones y seguridad que ofrece el contenedor EJB.
  • Se quiere tener un control de seguridad a nivel de método.
  • Se requiere de un contenedor que administre los accesos concurrentes a instancias del endpoint.

Entonces, la B es nuestra respuesta.

Pregunta tomada de ActualTests

The UDDI Inquiry API


UDDI requiere soporte de SOAP sobre HTTP. En efecto, las especificación UDDI requiere que los registros UDDI soporte una serie de operaciones de Web Service basadas en SOAP, llamadas el Programming API de UDDI. Estos mensajes SOAP utilizan el modo de messaging Document/Literal y estan descritas a detalle en el documento WSDL ubicado en la web de UDDI.org. Esto hace de UDDI un Web Service, como cualquier otro Web Service basado en SOAP y WSDL. Los Web Services de UDDI se dividen en dos API's basadas en WSDL y SOAP: la Inquiry API y la Publishing API. La Inquiry API se usa para buscar y leer data de un registro UDDI, mientras que la Publishing API se usa para agregar, modificar o eliminar data de un registro UDDI.

Lo que nos hace quedarnos con la C y la D.

Pregunta tomada de ActualTests

The UDDI Publishing API


Las organizaciones utilizan la Publishing API para agregar, modificar o eliminar información de un registro UDDI. Esta API perimite a las organizaciones el guardar sus propias estructuras businessEntity, businessService, bindingTemplate, tModel y publisherAssertion en un registro UDDI, y removerlas cuando sea necesario.

Como la Inquiry API, la Publishing API es un Web Service basado en el modo de messaging Document/Literal de SOAP, y es descrita mediante un documento WSDL. A diferencia de la Inquiry API, la Publishing API requiere que los operadores UDDI utilicen HTTPS (HTTP con SSL 3.0) para efectos de confidencialidad y como forma de autenticación. Además, cada mensaje (excepto el de login) debe incluir un token de autorización que es procesado por el registro UDDI al inicio de la sesión. Cada sesión tiene un token de autenticación único, que sólamente es válido durante la existencia de la sesión.

Entonces, la D es nuestra respuesta.

Pregunta tomada de ActualTests

sábado 6 de junio de 2009

The businessService and bindingTemplate Structures

El tipo complejo businessEntity declara un elemento businessServices, que puede contener uno o muchas estructuras de datos businessService. Cada businessService contiene uno o más entradas bindingTemplate. La relación entre la estructura businessService y la estructura bindingTemplate es similar a la relación entre los elementos service y port del WSDL: un businessService representa una agrupación de entradas bindingTemplate relacionadas. Un bindingTemplate describe un endpoint de WebService y representa la "huella técnica" de un Web Service. En otras palabras, lista todos los tipos tModel que describen un Web Service, que describen las especificaciones técnicas de un Web Service.

Por esto, la B es la correcta.

Pregunta tomada de ActualTests

viernes 5 de junio de 2009

tModels for WSDL Documents


Al publicar un Web Service en UDDI, el bindingTemplate debe hacer referencia a un tModel de WSDL. Además, el tModel debe estar categorizado como el tipo de UDDI wsdlSpec (puede tener otras categorizaciones también) y debe proveer un XPointer a un elemento binding de un documento WSDL accesible. Por ejemplo:

tModel tModelKey="UUID:4C9D3FE0-2A16-11D6-9B59-000629DC0A53">
<name>Monson-Haefel:BookQuote</name>
<description xml:lang="en">
Provides a wholesale price given for a ISBN number.
</description>
<overviewDoc>
<description xml:lang="en">
This URL points to the BookQuote WSDL document.
</description>
<overviewURL>http://www.Monson-Haefel.com/jwsed1/BookQuote.wsdl
#xmlns(wsdl=http://schemas.xmlsoap.org/wsdl/) xpointer(/wsdl:definitions/wsdl:portType[
@name="BookQuoteBinding"])
</overviewURL>
</overviewDoc>
<categoryBag>
<keyedReference
tModelKey="uuid:C1ACF26D-9672-4404-9D70-39B756E62AB4"
keyName="types"
keyValue="wsdlSpec"/>
</categoryBag>
</tModel>


Es de importancia el elemento overviewURL, que debe apuntar al binding WSDL representado en el tModel.

Entonces, la B es la correcta.

Pregunta tomada de ActualTests

The accessPoint Element



Al definir un bindingTemplate, la especificación UDDI nos da la opción de escoger un elemento accessPoint, o un elemento hostingRedirector (pero no los dos). Sin embargo, el Basic Profile obliga a usar el elemento accesPoint en bindingTemplates que representen Web Services: el uso de hostingRedirector no está permitido.

El elemento accesPoint provee la dirección electrónica exacta del servicio. Esta dirección puede ser una varios estándares definidos, incluyendo "mailto", "https", "ftp", "phone" u "other". El tipo de dirección es indicado por el atributo URLType del elemento accessPoint. Un ejemplo:

<bindingTemplates>
<bindingTemplate bindingKey="391E2620-3301-11D6-9F18-000629DC0A53">
<description xml:lang="en">
This service uses a SOAP RPC/Encoded Endpoint
</description>
<accessPoint URLType="http">
http://www.Monson-Haefel.com/jwsed1/BookQuote
</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo
tModelKey="uddi:4C9D3FE0-2A16-11D6-9B59-000629DC0A53"/>
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>


Un bindingTemplate debe tener sólamente un elemento accessPoint. Si el Web Service es accesible desde más de un URL se debe definir un bindingTemplate diferente para cada URL.

Por lo expuesto, la alternativa A es válida.

Pregunta tomada de ActualTests

The types Element


El elemento types sirve como contenedor para definir cualquier tipo de datos que no está descrito en los tipos contenidos en XML schema: tipos complejos y tipos simples. Los tipos de datos y elementos definidos en el elemento types se usan en las definiciones message al declarar los parts (payloads) de los messages.

El atributo targetNamespace del esquema XML debe ser un valor válido y no nulo, caso contrario los elementos y tipos no pertenecerían a un namespace válido. Además, el esquema XML definido en el elemento types debe pertenecer a un namespace especificado en el documento WSDL (por lo general en el elemento definitions) o a un namespace de documento WSDL importado. En otras palabras, el documento WSDL debe estar conciente de todos los namespaces usados en el documento.

Entonces, la alternativa A nos satisface.

Pregunta tomada de ActualTests

The soapbind:body Element

Los atributos del elemento soapbind:body cambian dependiendo del estilo de messaging usado: RPC o Document. El elemento soapbind:body tiene cuatro tipos de atributo: use, namespace, part y encodingStyle.

El atributo use tiene que ser "literal", y ese el valor asumido si el elemento soapbind:by no declara el atributo use. El atributo encodingStyle nunca es usado, debido a que los Web Services que siguen WS-I se basan el esquema XML W3C, que implica el uso de la declaración use="literal". Otros estilos de encoding, como el Encoding SOAP 1.1, no se utilizan. El atributo part especifica que elementos part de la definición message están siendo usados. El atributo part sólamente es necesario si se está usando un subconjunto de los elementos part declarados en el mensaje.

Para mensajes de estilo RPC, el atributo namespace debe especificarse con una URI válida. El URI puede ser el mismo que targetNamespace del documento WSDL. Por otro lado, los mensajes document-style no deben especificar el atributo namespace en el elemento soapbind:body. El namespace del fragmento de documento XML se deriva del esquema XML.

Dicho esto, nos quedamos con la B.

Pregunta tomada de ActualTests

The binding Element

El elemento binding mapea un portType abstracto a un conjunto de protocolos concretos como SOAP y HTTP, estilos de messaging (RPC o Document) y estilos de encoding (Literal o SOAP Encoding). El elemento binding y sus subelementos se usan en combinación con elementos específicos del protocolo. Los elementos binding identifican que elementos portType y operation están siendo enlazados, mientras que los elementos específicos del protocolo declaran el protocolo y el estilo de encoding asociados con el portType. Cada tipo de protocolo (SOAP, MIME y HTTP) tiene su propio grupo de elementos específicos de protocolo y su propio namespace.

Lo que concuerda a la perfección con la alternativa D.

Pregunta tomada de ActualTests

SOAP Namespaces

Los esquemas XML SOAP definen al atributo mustUnderstand como tipo xsd:boolean, lo que permite cuatro valores posibles: "1", "true", "0" o "false". Esta flexibilidad ha causado problemas de interoperabilidad en el pasado, cuando el receptor espera valores de "1" o "0" pero el emisor envía "true" o "false". De acuerdo al Basic profile, las aplicaciones SOAP deben configurar el atributo mustUnderstand con "1" o "0". "True" y "False" no están permitidos.

También, todos los elementos locales de un mensaje SOAP deben estar cualificados con un namespace (con prefijos del namespace SOAP 1.1), dado que el esquema XML para SOAP especifica el atributo elementFormDefault como "qualified".Además, el Basic Profile requiere que todos lo elementos específicos a la aplicación contenidos en el elemento Body deben estar qualificados. Los elementos no cualificados en el body SOAP crean demasiada ambiguedad.

Por lo que nos quedamos con la A y la C.

Pregunta tomada de ActualTests

The WSDL Abstract Interface

WSDL soporta la sobrecarga (overloading) de operations, que es bastante similar la sobrecarga de métodos de Java. En WSDL, dos operations pueden tener el mismo nombre y diferir en sus mensajes output o input. Desafortunadamente, esta capacidad ha ocasionado problemas de interoperabilidadm así que el Basic Profile prohibe la sobrecarga de operations. Cada operación definida en un portType debe tener un name único. Esto implica también que es perfectamente aceptable que dos o más elementos portType declaren elementos operation con el mismo nombre, porque cada portType se considera una definición separada.

Por otro lado, un part de un message puede declarar o un atributo type o un atributo element, pero nunca los dos. El cual usar depende del tipo de messaging que se está haciendo. Si se utiliza un messaging de estilo RPC, los elementos part deben usar el atributo type; si se usa messaging de estilo Document, los elementos part deben usar el atributo element. El messaginde estilo RPC utiliza tipos para definir las llamadas a procedimientos, donde cada elemento representa un tipo de parámetro. El el messaging de estilo Document, se intercambian fragmentos de documentos XML y hace referencia a los elementos globales.

Entonces, la A y la C son correctas.

Pregunta tomada de ActualTests

The mustUnderstand Attribute


Cuando un header block tiene el atributo mustUnderstand con valor de "1", se le llama header block obligatorio. Los nodos SOAP deben ser capaces de procesar cualquier heder block obligatorio, si es que tiene el rol especificado en el atributo actor del header block.

MustUnderstand significa que el nodo debe reconocer el header block por estructura XML y su namespace, y saber como procesarlo. Si el nodo está en el rol indicado en el atributo actor del header block, pero no está programado para procesar el header block, entonces el header block no ha sido comprendido.

Si un nodo no comprende un header block obligatorio, debe generar una SOAP fault (algo así como una excepción de Java) y descartar el mensaje. No debe enviar el mensaje al siguiente nodo en la ruta del mensaje.

Por lo que la C es la correcta.

Pregunta tomada de ActualTests

jueves 4 de junio de 2009

SOAP Faults


Un mensaje SOAP que contiene un elemento Fault en el Body se denomina Fault Message. Un Fault Message es análogo a una excepción Java, ya que es generado cuando ocurre un error. Los fault messages se utilizan en el messaging request-response. Los nodos en la ruta del mensaje generar fault messages al procesar mensajes request. Cuando ocurre un error, el nodo receptor envía un fault message al emisor. Los faults son ocasionados por formato de mensaje incorrecto, problemas de versión, problemas en el proceso de headers o errors específicos de aplicación.

Cuando se genera un fault message, el Body del mensaje SOAP debe contener sólamente un elemento Fault y nada más. El elemento Fault debe contener un elemento faultcode y un elemento faultstring, y opcionalmente y elemento faultactor y detail.

Por lo tanto, las correctas son la B, la C y la E.

Pregunta tomada de ActualTests

The faultcode Element

El elemento faultcode puede usar cualquiera de cuatro fault codes estándar para indentificar un error:

  • Client
  • Server
  • VersionMismatch
  • MustUnderstand

El elemento faulcode debe contener unos de los códigos estándar listados, junto al prefijo del namespace apropiado. El usar prefijos permite un versionado fácil de los fault codes estándar.

Por lo que la B y la C son correctas.

Pregunta tomada de ActualTests

SOAP Messaging Modes

Aunque SOAP soporte cuatro modos de messaging (RPC/Literal, Document/Literal, RPC/Encoded y Document/Encoded) en Basic Profile permite sólamente el uso de RPC/Literal o Document/Literal. Los modos RPC/Encoded y Document/Encoded son prohibidos explícitamente.

Un modo de messaging esta definido por su estilo de messaging (RPC o Document) y estilo de encoding. Existen dos tipos de encoding usados en messaging SOAP: SOAP encoding y Literal Encoding. SOAP Encoding no es soportado por lo Web Services WS-I debido a que ocasiona problemas de interoperabilidad. "Literal" significa que el fragmento del documento XML puede ser validado contra su esquema XML.

Por eso, nos quedamos con la A y la C

Pregunta tomada de ActualTests

Key Web Services Design Decisions

Una implementación de un servicio puede ser vista como dos capas: una capa de interacción y una capa de procesamiento.

La capa de interacción del servicio consiste en la interfaz endpoiint que el servicio expone a los clientes y a través de la cual recibe las solicitudes de los clientes. La capa de interacción también incluye la lógica sobre como el servicio delega las solicitudes a componentes de lógica de negocio y elabora las respuestas. Cuando recibe solicitudes de los clientes, la capa de interacción realiza el pre-procesamiento requerido antes de delegar las solicitudes a los componentes de lógica de negocio. Cuando termina de ejecutarse la lógica de negocio, la capa de interacción envía la respuesta al cliente. En ciertos casos, esta capa mapea los documentos XML a objetos que enviará a los componentes de lógica de negocios como parámetro.

La capa de procesamiento del servicio contiene toda la lógica de negocio necesaria para procesar las solicitudes del cliente. También es responsable de la integración con otros EIS's y otros Web Services. En el caso de aplicaciones existentes que quiere publicarse como web Services, la aplicación existente constituye la capa de procesamiento.

Por lo expuesto, nos quedamos con la B y la C.

Pregunta tomada de ActualTests

Web Service Broker

Problema: Se desea proveer acceso a uno o más servicios mediante XML y protocolos Web.

Solución: Utilizar un Web Service Broker para exponer y actuar como intermediario de uno o más servicio mediante XML y protocolos Web.

Un Web Service Broker es un servicio complejo expuesto como Web Service. Coordina la interacción entre uno o más servicios, agrega responses y puede demarcar transacciones. Un Web Service Broker se expone mediante una interfaz como WSDL.

Por esto, la respuesta es la E.

Pregunta tomada de ActualTests

Session Façade



Problema: Se desea exponer los componentes de negocio y servicios a clientes remotos.

Solución: usar Session Façade para encapsular los componentes de la capa de negocio y exponer servicios complejos a los clientes remotos. Los clientes acceden al session facade en lugar de acceder a los componentes de negocio directamente.

Un Session Façade se implemente como session bean que interactúa con los componentes de negocio, como Business Objects y Application Services. Un Session Façade provee una capa de servicio remota que expone sólamente las interfaces requeridas por los clientes.

Un Session Façade trabaja mejor si contiene poca o ninguna lógica de negocio. De ser necesaria lógica de negocio, debería colocarse en un Application Service, a ser invocado por el Session Façade.

Entonces, nos quedamos con la B.

Pregunta tomada de ActualTests

Service Locator

Problema: Se requiere localizar transparentemente componentes de negocio y servicios de manera uniforme.

Solución: Utilizar un Service Locator para implementar y encapsular el lookup de componentes. Un Service Locator oculta los detalles de implementación del mecanismo lookup y encapsula las dependencias relacionadas.

Las aplicaciones cliente pueden usar Service Locator para reducir la complejidad del código, brindando un único punto de control y mejorando la performance al proveer capacidades de chaching. Por lo general, se necesita un único Service Locator para toda la aplicación. Service Locator reduce la dependencia del cliente en la infraestructura lookup.

Service Locator se implemente generalmente como un Singleton.

Con todo esto, creo que está claro que nos quedamos con la C.

Pregunta tomada de ActualTests

Qualified and Unqualified Elements



Los elementos pueden estar cualificados o no por un namespace; o sea, los elementos de un documento XML pueden o no requerir prefijos QName. Los elementos globales y los atributos globales siempre deben estar cualificados, lo que significa que en una insatncia XML se les debe anexar un prefijo para formar un QName. La excepción es cuando un elemento global es parte de un namespace por defecto, en donde no es necesario que se le cualifique con un prefijo (todos los elementos no cualificados se asume pertenecen al namespace por defecto) . El namespace por defecto no aplica a los atributos globales; los atributos globales siempre deben contar con prefijo.

Mientras que los elementos y atributos globales siempre deben ser cualificados, los elementos locales pueden no necesitar cualificarse. Los esquemas XML definen dos atributos, elementsFormDefault y attributesFormDefault, que determinan si los elementos locales de una instancia XML deben cualificarse con un prefijo o no.

Por lo que la B es la correcta.

Pregunta tomada de ActualTests

miércoles 3 de junio de 2009

Namespace Defaulting



El valor del atributo en una declaración de namespace puede estar vacía. Esto tiene el mismo efecto, dentro del alcance de la declaración, de no haber namespace por defecto.

Lo que nos lleva a deducir que la respuesta correcta es la D.

Pregunta tomada de ActualTests

Default Namespaces, Prefixes, and Qualified Names


Las declaraciones xmlns definen el namespace por defecto para un elemento y sus descendientes. El alcance del namespace por defecto aplica sólamente para el elemento y sus descendientes. Por ejemplo:

<?xml version="1.0" encoding="UTF-8" ?>
<purchaseOrder orderDate="2003-09-22"
xmlns="http://www.Monson-Haefel.com/jwsbook/PO">
<accountName>Amazon.com</accountName>
<accountNumber>923</accountNumber>

<address xmlns="http://www.Monson-Haefel.com/jwsbook/ADDR">
<name>AMAZON.COM</name>
<street>1850 Mercer Drive</street>
<city>Lexington</city>
<state>KY</state>
<zip>40511</zip>
</address>

<book>
<title>J2EE Web Services</title>
<quantity>300</quantity>
<wholesale-price>29.99</wholesale-price>
</book>
<total>8997.00</total>
</purchaseOrder>


El xmlns utilizado en el elemento address aplica sólamente para los elementos address, name, street city, state y zip. El namespace por defecto de purchaseOrder aplica para todos los elementos excepto los elementos de address, porque el elemento address sobreescribe el namespace por defecto de purchaseOrder para definir su propio namespace por defecto.

Se le puede asignar a un namespace XML un prefijo, y utilizar este prefijo para calificar cada elemento.

Entonces, nos quedamos con la A y la D


Pregunta tomada de ActualTests

The service and port elements

El elemento service contiene uno o más elementos port, cada uno de los cuales representa un Web Service diferente. El elemento port asigna un URL a un binding específico.

Un service puede tener más de un elemento port, cada uno de los cúales le asigna un URL a un binding específico. Es posible para dos o más elementos port asignarle diferentes URL's al mismo binding, lo que sería útil para balance de carga.

El elemento soapbind:address asigna una dirección de Internet a un binding SOAP mediante su atributo location. EL Basic Profile permite sólamente URL's que usen el esquema HTTP o HTTPS.

Dos o más elementos port dentro del mismo documento WSDL no deben especificar el mismo valor de URL para el atributo location de soapbind:address.

Por lo expuesto, nos quedamos con la B.

Pregunta tomada de ActualTests

The all element

La mayoría de veces los complex types se harán en base a elementos sequence, pero ocasionalmente se puede recurrir al elemento all. A diferencia de sequence, que define el orden exacto de los elementos hijos, el elemento all de un esquema XML permite a los elementos aparecer en cualquier orden. Cada elemento en el grupo all puede ocurrir una vez o ninguna; no se aceptan otras multiplicidades. En otras palabras, minOccurs es siempre 0 y maxOccurs es siempre 1. Finalmente, sólamente se puede usar elementos simples en un grupo all, no se permite incluir grupos sequence/all.

Por eso, nos quedamos con la A y la C

Pregunta tomada de ActualTests

Sequences of Elements

La mayoría de declaraciones complexType en esquemas contendrán un elemento sequence que listará una o más definiciones element. Las definiciones element nos indican que elementos se encuentran incluidas en el tipo, el orden en el que aparecerán y el tipo de data que cada elemento contendrá.


El atributo nillable en la declaración de elementos nos indica si un elemento puede contener nil. Sus valores posibles son true o false, y el valor por defecto es false.

Para representar que un elemento tiene el valor de nil en una instacia de documento, se coloca el atributo nil en true. Ahora, el atributo nil está definido como parte del namespace de esquemas XML , por lo que debe aparecer en una instancia de documento con un prefijo asociado al namespace(como xsi:). El mecanismo nil aplica sólamente a valores de elementos, y no a valores de atributos. Un elemento con xsi:nil="true" no debería tener contenido en el elemento, pero puede llevar atributos.

Entonces, nos quedamos con la B y la C.


Pregunta tomada de ActualTests

Occurrence Constraints


La multiplicidad de un elemento -número de veces de ocurrencia en una instancia del documento- es controlada por restricciones de ocurrencia, que son declaradas mediante los atributos maxOccurs y minOcurrs. Por ejemplo:

<complexType name="USAddress">
<sequence>
<element name="name" type="string" />
<element name="street" type="string"
minOccurs="1" maxOccurs="2" />
<element name="city" type="string" />
<element name="state" type="string" />
<element name="zip" type="string" />
</sequence>
</complexType>


Las restricciones de ocurrencia especifican que en una instancia de USAddress el elemento street debe estar presente como mínimo una vez y como máximo dos. El valor por defecto para maxOcurrs y minOcurrs es "1", así que si estos atributos no se especifican el elemento debe estar presente sólamente una vez.

Concluimos entonces, que la respuesta es la D.


Pregunta tomada de ActualTests

martes 2 de junio de 2009

Mapping JAXR to the UDDI Inquiry API

El método findCallerAssociations() devuelve un Collection de objetos Association, relativos al caller, que se corresponden con el criterio de búsqueda especificado. El método sólamente devolverá las asociaciones creadas usando las credenciales del caller. El método está definido así:

public BulkResponse findCallerAssociations(Collection findQualifiers, Boolean confirmedByCaller, Bolean confirmedByOtherParty, Collection associationTypes)

Para que este método funcione, el caller debe estar autentificado en el registro UDDI. Sólamente se devolverán las asociaciones que sonpopiedad del caller y que se correspondan con el criterio de búsqueda. Para el siguiente caso:

BulkResponse response = queryMnrg.findCallerAssociations(null, Boolean.TRUE, Boolean.FALSE, null);


Esta llamada devolverá un Collection de objetos Association que han sido confirmados por el caller (nosotros), pero que todavía no han sido confirmadas por la otra parte.

Dado esto, nos quedamos con la C.

Pregunta tomada de ActualTests

SOAPHeaderElement


SOAPHeaderElement es una abstracción de un header block y nos permite crear y examinar los atributos y elementos hijos de un header block en particular. Cada header block puede tiener un atributo actor, un atributo mustUnderstand además de elementos hijos y otros atributos. La definición de SOAPHeaderElement es:

public interface SOAPHeaderElement extends SOAPElement{

public String getActor();
public boolean getMustUnderstand();
public void setActor(String actorURI);
public void setMustUnderstand(boolean flag);

}


Los métodos de SOAPHeaderElement se emplean para modificar y examinar header blocks.

Entonces, como muestra la imagen, la respuesta es la D

Pregunta tomada de ActualTests

JAXP APIs


JAXP son las iniciales de Java API for XML Processing. JAXP contiene las siguientes API's:

  • SAX: Simple API for XML Parsing
  • DOM: Document Object Model
  • Stax: Streaming API for XML
  • XSLT : XML Stylesheet Language for Transformations

Por lo que la que nos atañe es la A

Pregunta tomada de ActualTests

The UDDI Publishing API

La operación delete_tModel no elimina la estructura de datos tModel del registro UDDI. Lo que hace es hacerla invisible a las operaciones "find" ,aunque todavía podríamos obtenerla mediante un mensaje get_tModelDetail. Para eliminar un tModel de un registro UDDI de manera permanente, se le debe hacer una petición al UDDI operator.

Por ende, nos quedamos con la A y la D

Pregunta tomada de ActualTests

Basic WSDL Operation Types


WSDL tiene 4 tipos de transmisión que un endpoint puede soportar:

  • One-Way: El endpoint recibe un mensaje
  • Request-response: El endpoint recibe un mensaje y envía un mensaje relacionado
  • Solicit-response: El endpoint envía un mensaje, y recibe un mensaje relacionado.
  • Notification: El endpoint envía un mensaje

WSDL se refiere a estos tipos como operaciones. WSDL sólamente define bindings para los tipos One-Way y Request-Response.

Entonces, la respuesta es la A y la D

Pregunta tomada de ActualTests

SOAP Message Elements


Sobre el elemento Header, de un mensaje SOAP se puede decir que:

  • Pertenece al namespace: http://www.w3.org/2003/05/soap-envelope
  • El nombre del elemento es "Header"
  • El elemento Header es opcional en un mensaje SOAP
  • Contiene uno o más elementos XML, llamados header blocks
  • Suelen contener: credenciales de seguridad, identificadores de transacción, instrucciones de routing, información de debugging, etc.
Entonces, la respuesta es la A y la B

Pregunta tomada de ActualTests

SOAP Faults

Un mensaje SOAP que contiene un elemento "Fault" dentro del elemento "Body" se denomina un fault message.

Los fault messages se utilizan para reportar errores a otros nodos en la ruta del mensaje. Los errores pueden ser por formato de mensaje inadecuado, versiones incompatibles, problemas de proceso de cabeceras o errores específicos de la aplicación.

Aquí tenemos un faul message de SOAP:

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:m="http://www.example.org/timeouts"
xmlns:xml="http://www.w3.org/XML/1998/namespace">
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
<env:Subcode>
<env:Value>m:MessageTimeout</env:Value>
</env:Subcode>
</env:Code>
<env:Reason>
<env:Text xml:lang="en">Sender Timeout</env:Text>
<env:Text xml:lang="sv">Avsändar timeout</env:Text>
</env:Reason>
<env:Detail>
<m:MaxTime>P5M</m:MaxTime>
</env:Detail>
</env:Fault>
</env:Body>
</env:Envelope>


Si un error ocurre, el nodo SOAP sigue el siguiente proceso:

  • Se genera una SOAP Fault en el nodo (intermediario o receptor final)
  • Si el patrón de intercambio de mensajes es One-Way, la SOAP fault no debe transmitirse al emisor, y debe ser almacenada en algún sitio.
  • Si el patrón de intercambio de mensajes es request-response, la SOAP fault debe transmitirse al emisor. El nodo que reciba la SOAP fault debe tomar las medidas del caso.

Si el elemento SOAP Body contiene un elemento Fault, sólamente debe contener un sólo elemento Fault y nada más.

Por ende, la respuesta es la B.

Pregunta tomada de ActualTests

elementFormDefault

Disculpen por poner las preguntas como imagen, pero no había otra manera:

El atributo elementFormDefault especifica si los elementos de un esquema XML necesitan estar calificados por el prefijo del namespace al que pertenecen.

Si el atributo elementFormDefault tiene el valor de "qualified" -como en la pregunta- en la declaración del esquema:

<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:ivan="http://www.ivan.com/schemas"
targetNamespace="http://www.ivan.com/schemas"
elementFormDefault="qualified">
...
</schema>



Entonces los elementos locales del namespace deben estar calificados con el prefijo del namespace:

<ivan:person xmlns:ivan="http://www.ivan.com/schemas"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.ivan.com/schemas personSchema.xsd"
hasDog=”true”>
<ivan:firstName>Steven</ivan:firstName>
<ivan:lastName>Segal</ivan:lastName>
<ivan:age>39</ivan:age>
</ivan:person>


Por lo tanto, las que aplican son la C y la D

Pregunta tomada de ActualTests

Son pocos, pero son

Bienvenidos, visitantes


Visitas al Blog, cortesía de BlogPatrol

A su disposición