Enunciate es una herramienta de documentación de servicios que se integra en nuestro proyecto y permite documentar automáticamente nuestra API REST en formato HTML.
Enunciate se invoca desde proyectos FundeWeb mediante la ejecución de una tarea ANT creada para tal efecto (similar a la invocación de Genética). Además de ANT, Enunciate se puede integrar mediante Maven, Gradle o directamente por programación.
La configuración de Enunciate se basa en el fichero enunciate.xml. En este fichero se puede configurar tanto aspectos visuales de la documentación (textos, estilos, plantillas, etc.) como funcionales (módulos, namespaces, rutas, etc.). Desde MNCS proporcionamos un archivo enunciate.xml con la configuración básica, así como la plantilla traducida y la hoja de estilo modificada para generar el HTML con un aspecto similar a las aplicaciones FundeWeb.
Para generar una documentación completa, Enunciate extrae información del Javadoc de las clases del servicio. Además, proporciona una serie de anotaciones que completan el conjunto de conceptos usados en los servicios REST (códigos de respuesta, códigos de alerta, cabeceras, parámetros, ejemplos de peticiones, etc.). Una vez configurado Enunciate, se recomienda revisar la sección de Anotaciones para ampliar los comentarios de los servicios a documentar.
Instalación y configuración de Enunciate mediante tareas Ant para aplicaciones FundeWeb 2 desplegadas en WebLogic 12.1.3 (IDE FundWeb 2.0).
Enunciate vendrá incorporado en la versión de FundeWeb 2.0.42 y posteriores. Por lo que no será necesario realizar algunos de los pasos.
<!-- Tareas para ENUNCIATE --> <target name="enunciate.generate.doc" description="Generador documentacion REST"> <timestamp message="Inicio de generacion de documentacion de Enunciate"/> <delete dir="${basedir}/generacion/enunciate/build" failonerror="no"/> <mkdir dir="${basedir}/generacion/enunciate/build" /> <path id="enunciate.classpath"> <fileset dir="${fundeweb.enunciate.home}/lib"> <include name="*.jar" /> </fileset> </path> <taskdef name="enunciate" classname="com.webcohesion.enunciate.EnunciateTask"> <classpath refid="enunciate.classpath" /> </taskdef> <enunciate basedir="${basedir}${enunciate.package.rest}" configFile="${basedir}/generacion/enunciate/resources/enunciate.xml" compiledebuginfo="true" buildDir="${basedir}/generacion/enunciate/build"> <include name="**/*.java" /> <classpath refid="enunciate.classpath" /> </enunciate> <copy todir="${basedir}/generacion/enunciate/build/docs/img" overwrite="true"> <fileset dir="${basedir}/generacion/enunciate/resources/img" /> </copy> <timestamp message="Fin de generacion de documentacion. Comenzando la copia de ficheros."/> <antelope:if> <bool> <isset property="enunciate.web.doc.path" /> </bool> <echo message="Copiando documentacion a la carpeta: ${basedir}/${enunciate.web.doc.path}" /> <copy todir="${basedir}\${enunciate.web.doc.path}" overwrite="true"> <fileset dir="${basedir}/generacion/enunciate/build/docs" /> </copy> </antelope:if> <timestamp message="Fin generate.doc"/> </target> <!-- -->
Ignorar paso si la aplicación esta creada con el arquetipo de FundeWeb 2.0 versión 0.0.11 o posterior.
Una vez instalado Enunciate y creada la tarea Ant en el build.xml, hay que crear las siguientes propiedades en el fichero build.properties para configurar la información específica de nuestro proyecto:
## Variables para ejecución de ENUNCIATE (GENERACION DE DOCUMENTACIÓN REST) enunciate.package.rest=/web/src/main/java/unica/rest/servicios/ #comentar para no pasar doc al módulo web enunciate.web.doc.path=\\web\\src\\main\\web_resources\\doc\\ ## Variables de configuración de ENUNCIATE enunciate.api.version=v1 enunciate.api.title=UNICA API REST enunciate.api.header=Documentación API REST UNICA enunciate.api.description=Esta es la documentación de la API REST de la aplicación UNICA, para más información escriba a: mcns@um.es enunciate.private.package=unica.rest.servicios.auth enunciate.rest.root=../services/rest/
Los parámetros para configurar Enunciate son:
Instalación y configuración de Enunciate mediante plugin Maven para aplicaciones FundeWeb 2 desplegadas en WebLogic 12.2 (IDE FundWeb 2.1).
1. Añadir las siguientes properties en el pom.xml del módulo web.
<properties> .. <enunciate.resources>${maven.multiModuleProjectDirectory}\..\generacion\enunciate\resources\</enunciate.resources> <enunciate.build.directory>${maven.multiModuleProjectDirectory}\..\generacion\enunciate\build\</enunciate.build.directory> .. </properties>
2. En el mismo fichero pom.xml, añadir el siguiente plugin dentro del primer bloque build:
<build> <finalName>[APLICACION]-web</finalName> <plugins> ... <plugin> <groupId>com.webcohesion.enunciate</groupId> <artifactId>enunciate-maven-plugin</artifactId> <version>2.12.1</version> <configuration> <configFile>${enunciate.resources}\enunciate.xml</configFile> <!-- Ejemplo inclusión/exclusión como sources de artefactos externos --> <!-- <sourcepathIncludes> <sourcepathInclude> <groupId>es.um.atica.fundeweb</groupId> <artifactId>fundeweb-jaxrs</artifactId> </sourcepathInclude> <sourcepathInclude> <groupId>es.um.atica.fundeweb.weblogic</groupId> <artifactId>fundeweb-java-services-config</artifactId> </sourcepathInclude> <sourcepathInclude> <groupId>es.um.atica.fundeweb.weblogic</groupId> <artifactId>fundeweb-jersey</artifactId> </sourcepathInclude> </sourcepathIncludes> <sourcepathExcludes > <sourcepathExclude> <groupId>javax.ws.rs.</groupId> <artifactId>jsr311-api</artifactId> </sourcepathExclude> <sourcepathExclude> <groupId>javax.ws.rs.</groupId> <artifactId>javax.ws.rs-api</artifactId> </sourcepathExclude> </sourcepathExcludes> --> </configuration> <executions> <execution> <goals> <goal>docs</goal> </goals> <configuration> <skipEnunciate>true</skipEnunciate> </configuration> </execution> </executions> </plugin> ... </plugins>
3. Descargar los ficheros de configuración y descomprimirlos en “generacion/enunciate/”.
4. Copiar en el fichero build.xml la tarea ant para lanzar el plugin de Enunciate:
<!-- Tareas para ENUNCIATE --> <target name="enunciate.generate.doc" description="Generador documentacion REST - FundeWeb 2.1" depends="init"> <timestamp message="Inicio de generacion de documentacion de Enunciate"/> <timestamp message="Limpieza de generación anterior." /> <delete dir="${basedir}/generacion/enunciate/build" failonerror="no"/> <mkdir dir="${basedir}/generacion/enunciate/build" /> <timestamp message="Inicio install módulo WEB." /> <echo message="Instalando el módulo WEB (mvn install). Log en el fichero: maven_web_install.log." /> <maven module="web" task="install" description="Instalar el proyecto (mvn install)." log.file="maven_web_install.log" /> <timestamp message="Fin install." /> <timestamp message="Invocación plugin maven ENUNCIATE. Log en el fichero: maven_enunciate_docs.log." /> <maven module="web" task="enunciate:docs" description="Pasando Enunciate (mvn -e enunciate:docs)." log.file="maven_enunciate_docs.log" /> <timestamp message="Fin de generacion de documentacion. Comenzando la copia de ficheros."/> <copy todir="${basedir}/generacion/enunciate/build/docs/img" overwrite="true"> <fileset dir="${basedir}/generacion/enunciate/resources/img" /> </copy> <timestamp message="Borrando targets"/> <delete dir="${web.target.dir}/${web.module.name}" failonerror="true" /> <delete dir="${web.target.dir}/maven-status" failonerror="true" /> <delete dir="${web.target.dir}/enunciate" failonerror="true" /> <delete failonerror="true"> <fileset dir="${web.target.dir}"> <include name="${web.module.name}*.jar" /> <include name="${web.module.name}*.war" /> <exclude name="generated-sources" /> <exclude name="m2e-wtp" /> <exclude name="classes" /> </fileset> </delete> <timestamp message="Targets borrados"/> <antelope:if> <bool> <isset property="enunciate.web.doc.path" /> </bool> <echo message="Copiando documentacion a la carpeta: ${basedir}/${enunciate.web.doc.path}" /> <copy todir="${basedir}\${enunciate.web.doc.path}" overwrite="true"> <fileset dir="${basedir}/generacion/enunciate/build/docs" /> </copy> </antelope:if> <timestamp message="Fin generate.doc"/> </target> <!-- -->
Una vez añadido el plugin y creada la tarea Ant en el build.xml, hay que crear la siguiente propiedad en el fichero build.properties para determinar si la documentación generada se pasa al módulo web de nuestro proyecto y se publica junto al resto de páginas.
## Variables para ejecución de ENUNCIATE (GENERACION DE DOCUMENTACIÓN REST) #comentar para no pasar doc al módulo web enunciate.web.doc.path=\\web\\src\\main\\web_resources\\doc\\
El resto de configuración se realiza en el fichero enunciate.xml.
En este fichero se especifica el título y la descripción que aparecerá en la documentación HTML, así como los paquetes a analizar buscando servicios a documentar y los módulos de Enunciate a generar.
Sustituye todos los textos entre corchetes por la información propia de tu aplicación.
Puede ampliarse más información en la WiKi de Enunciate.
Una vez realizados los pasos anteriores dispondremos de la configuración básica para invocar Enunciate y generar la documentación de nuestra API REST. Para ello necesitamos ejecutar la tarea Ant enunciate.generate.doc (1) creada anteriormente.
En la imagen puede observarse que, con las rutas por defecto, la documentación generada se ubica en la carpeta /generacion/enunciate (2).
Además, si se ha establecido la variable enunciate.web.doc.path en el fichero build.properties, la carpeta /docs se copiará al módulo web de nuestro proyecto quedando así publicada junto al resto de la aplicación (3).
Para aplicaciones desplegadas en el IDE de FundeWeb 2.1, además, se crearán dos ficheros en la carpeta log/ con el resultado del install del módulo web y de la ejecución del plugin de Maven.
Toda la configuración de Enunciate se realiza a través del fichero enunciate.xml. Este fichero se copia a la raíz del proyecto al descomprimir el fichero .7z del apartado de instalación y establece la configuración básica proporcionada por MNCS.
En este fichero se establecen los textos que aparecen en el HTML, algunos metadatos de nuestra API, la posible exclusión de clases, definición de namespaces y los distintos módulos que se van a generar.
El concepto de módulo es básico en Enunciate. Un módulo es una extensión por la que se indica a Enunciate que debe generar los archivos para una determinada tecnología (jaxb, jaxws, php, ruby…).
Por defecto se genera la documentación para todos los módulos.
Para desactivar un módulo hay que indicarlo explícitamente añadiendo el módulo y poniendo disabled=“true”.
A continuación se detallan los aspectos más importantes de la configuración del fichero enunciate.xml.
Puede obtenerse más información en la wiki de Enunciate User Guide.
Se pueden crear facets para agrupar acciones sobre determinados paquetes. Con la configuración básica proporcionada se ha creado un facet “private” para no generar documentación sobre determinados paquetes privados que se deseen omitir.
Puede obtenerse más información en las wikis de Enunciate Facets y Excluding Including Classes.
Por defecto Enunciate genera la documentación en base a una hoja de estilo y a una plantilla de transformación propia contenidas en sus librerías. La ejecución de Enunciate permite parametrizar estos aspectos visuales, así que desde MNCS hemos realizado algunas modificaciones en los ficheros “visuales” para dar un aspecto más corporativo. Estos ficheros se copian al proyecto al descomprimir los archivos .7z del apartado de instalación.
Puede obtenerse más información en la wiki de enunciate Custom Skin.
Como se ha mencionado anteriormente, un módulo es una extensión de Enunciate que especifica la tecnología para la cuál se generará la documentación (y los objetos, según el caso).
Por defecto todos los módulos se generan automáticamente. Para especificar que no se desea generar un módulo, hay que incluirlo específicamente con el atributo disabled=“true”.
A continuación se mencionan los módulos más relevantes de Enunciate:
Puede obtenerse más información sobre el resto de módulos en la wiki de Enunciate Modules.
Para generar una documentación HTML lo más completa posible es necesario completar el Javadoc de nuestros servicios.
Es aconsejable comentar la declaración de las clases de nuestros servicios. De esta forma aparecerá en la descripción del recurso en la documentación HTML.
Además, Enunciate proporciona una serie de etiquetas para ayudar a completar la documentación. Estas son algunas de las más interesantes:
Puede obtenerse más información sobre las anotaciones en la Wiki de Enunciate Enunciate Specific Annotations.
Todos los ejemplos mostrados usan etiquetas Javadoc para generar la documentación.
En aplicaciones desplegadas en WebLogic 12.2, si se desea ampliar el mecanismo y usar las anotaciones propias de Enunciate que figuran en su WiKi habrá que añadir la siguiente dependencia a los pom.xml de la aplicación:
<dependency> <groupId>com.webcohesion.enunciate</groupId> <artifactId>enunciate-core-annotations</artifactId> <version>2.12.1</version> </dependency>
También debemos asegurarnos que nuestro proyecto tiene los “build files” acordes:
build.xml v0.0.12 Este fichero ya contiene la tarea ANT configrada en los pasos anteriores. Incluido en el arquetipo de FundeWeb 2.0 versión 0.0.11 o posterior.
common.build.xml v0.0.13. Incluido en el arquetipo de FundeWeb 2.0 versión 0.0.11 o posterior.
Pon aquí tus propuestas de FAQs, indicando qué problema tienes, y buscaremos la solución lo antes posible. Si además lo has resuelto, puedes indicar cómo lo has hecho.
Formato de petición de FAQ:
**Título** //Descripción del problema// //Tecnología afectada (Fundeweb 1/2)// //Cómo reproducir el error// **Solución** //Descripción de la solución// Tus datos de contacto --- //[[correo@umOticarum.es|Tu Nombre]] dd/mm/yyyy //
Si nuestro servicio hace uso de clases/librerías que no están en la ruta definida en la variable enunciate.package.rest, Enunciate dará un error generando la documentación.
Solución
La solución pasa por modificar la tarea ANT en el build.xml y añadir classpath's con las rutas donde se encuentran las clases/librerías.
Esto también sirve para añadir librerías del repositorio maven local.
También es posible añadir las fuentes de las librerías como sourcepath para que genere la documentación de clases aunque no estén en nuestro proyecto.
Ejemplo:
Para generar la documentación cuando se están usando las clases del manejo de errores de la WiKi Manejo de errores en servicios REST, es necesario definir los path de la tarea ANT enunciate.generate.doc de la siguiente forma:
<!-- librerias enunciate --> <path id="enunciate.classpath"> <fileset dir="${fundeweb.enunciate.home}/lib"> <include name="*.jar" /> </fileset> </path> <!-- librerias incluidas con maven --> <!-- hay un problema con el rango de las versiones, lo ideal seria incluir todas asi--> <artifact:dependencies pathId="dependency.rest.classpath" > <artifact:localRepository path="${fundeweb.maven.repository}" /> <dependency groupId="org.um.atica" artifactId="ejb_interfaces" version="[2.0.0, 2.1.0)" scope="compile" /> <dependency groupId="com.sun.jersey" artifactId="jersey-core" version="1.19.4" scope="compile" /> </artifact:dependencies> <!-- librerias propias incluidas manualmente --> <!-- no se pueden incluir con artifact:dependencies por fallo con rango de versiones --> <path id="fundeweb.rest.classpath"> <fileset dir="${fundeweb.maven.repository}/es/um/atica/fundeweb"> <include name="**/*.jar"/> <exclude name="**/*-sources.jar"/> </fileset> <fileset dir="${fundeweb.maven.repository}/org/hibernate"> <include name="**/*.jar" /> <exclude name="**/*-sources.jar"/> </fileset> <fileset dir="${fundeweb.maven.repository}/org/jboss/seam/jboss-seam"> <include name="**/*.jar" /> <exclude name="**/*-sources.jar"/> </fileset> </path> <!-- fuentes propias --> <path id="fundeweb.rest.sourcepath"> <fileset dir="${fundeweb.enunciate.home}/lib"> <include name="**/*-sources.jar"/> </fileset> <fileset dir="${fundeweb.maven.repository}/es/um/atica/fundeweb"> <include name="**/*-sources.jar"/> </fileset> <fileset dir="${fundeweb.maven.repository}/org/hibernate"> <include name="**/*-sources.jar"/> </fileset> <fileset dir="${fundeweb.maven.repository}/org/jboss/seam/jboss-seam"> <include name="**/*-sources.jar"/> </fileset> </path> <taskdef name="enunciate" classname="com.webcohesion.enunciate.EnunciateTask"> <classpath refid="enunciate.classpath" /> <classpath refid="fundeweb.rest.classpath" /> <classpath refid="dependency.rest.classpath" /> </taskdef> <enunciate basedir="${basedir}${enunciate.package.rest}" configFile="${basedir}/generacion/enunciate/resources/enunciate.xml" compiledebuginfo="true" buildDir="${basedir}/generacion/enunciate/build"> <include name="**/*.java" /> <classpath refid="enunciate.classpath" /> <classpath refid="fundeweb.rest.classpath" /> <classpath refid="dependency.rest.classpath" /> <sourcepath refid="fundeweb.rest.sourcepath" /> </enunciate>
— RAMON GINEL GEA 03/07/2019 10:07