public enum StoreCode {
BR(Language.pt_BR, Subdomain.BR, Language.pt_BR, Language.en),
US(Language.en_US, Subdomain.WWW, Language.en_US)
// ....
;
private final Language defaultLanguage;
private final Language [] supportedLanguages;
private final Subdomain subdomain;
StoreCode(Language defaultLanguage, Subdomain subdomain, Language ... supportedLanguages) {
this.defaultLanguage = defaultLanguage;
this.subdomain = subdomain;
this.supportedLanguages = supportedLanguages;
}
public Language getDefaultLanguage() {
return defaultLanguage;
}
public Subdomain getSubdomain() {
return subdomain;
}
public Language[] getSupportedLanguages() {
return supportedLanguages;
}
}
Mostrando entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java. Mostrar todas las entradas
lunes, 14 de marzo de 2016
Enums: Campos de arreglo
Usando arreglos en campos del enum. En este ejemplo utilizado para agragar los lenguajes soportados por una tienda.
martes, 15 de abril de 2014
Java: URL de archivo localizado en el classpath
Una manera de averiguar el URL de un archivo localizado en el classpth (útil en casos como tests de unidad de classes que consumen datos por la web):
getClass().getClassLoader();
String url = ClassLoader.getSystemResource("path/to/file").toString();
miércoles, 14 de agosto de 2013
Java: Conviertiendo String a Enum
A veces es necesario convertir un valor String a un Enum porque quizás el valor lo tenemos en la base de datos como un String, pero deseamos manipularlo en el código como un Enum.
En el siguiente código muesto como obtener el valor Enum de un String. Básicamente se agrega un método estático a la clase Enum que retorna el valor específico mediante una iteración de todos sus valores para comparar el valor String con el pasado por parámetro. Si no se encuentra o se pasa un valor nulo, se retorna una excepción de argumento inválido.
public enum Volcano {
IRAZU("Irazu"), POAS("Poas"), ARENAL("Arenal"), RINCON_DE_LA_VIEJA("Rincon de la vieja");
private String name;
private Volcano(String name) {
this.name = name;
}
public static Volcano fromString(String name) {
if (name == null) {
throw new IllegalArgumentException();
}
for (Volcano volcano : values()) {
if (name.equalsIgnoreCase(volcano.getName())) {
return volcano;
}
}
// Passed string value does not correspond to a valid enum value.
throw new IllegalArgumentException();
}
public String getName() {
return this.name;
}
public static void main(String[] args) {
Volcano volcano1 = Volcano.fromString("Poas");
System.out.println(volcano1);
Volcano volcano2 = Volcano.fromString("rincon de la vieja");
System.out.println(volcano2);
Volcano volcano3 = Volcano.fromString("Fuji");
}
}
Salida:
POAS RINCON_DE_LA_VIEJA java.lang.IllegalArgumentException at com.bodybuilding.common.enums.Volcano.fromString(Volcano.java:22) at com.bodybuilding.common.enums.Volcano.main(Volcano.java:36)
lunes, 22 de julio de 2013
Flyway Validate: Cannot determine latest applied migration. Was the metadata table manually modified?
En nuestro proyecto utilizamos Flyway para el control de las modificaciones a la base de datos. Hace poco me comenzó a dar este error que no daba mucha pista de por qué fallaba:
Siendo un proyecto Open Source me encontré el código con facilidad y pude ver qué tipo de consulta estaba tratando de ejecutar. Podemos ver en el código que busca por la columna "CURRENT_VERSION":
Flyway Validate: Cannot determine latest applied migration. Was the metadata table manually modified?
Siendo un proyecto Open Source me encontré el código con facilidad y pude ver qué tipo de consulta estaba tratando de ejecutar. Podemos ver en el código que busca por la columna "CURRENT_VERSION":
/**
* @return The latest migration applied on the schema. {@code null} if no migration has been applied so far.
*/
public MetaDataTableRow latestAppliedMigration() {
if (!hasRows()) {
return null;
}
String query = getSelectStatement() + " where current_version=" + dbSupport.getBooleanTrue();
@SuppressWarnings({"unchecked"})
final List metaDataTableRows = jdbcTemplate.query(query, new MetaDataTableRowMapper());
if (metaDataTableRows.isEmpty()) {
if (hasRows()) {
throw new FlywayException("Cannot determine latest applied migration. Was the metadata table manually modified?");
}
return null;
}
return metaDataTableRows.get(0);
}
...
/**
* @return The select statement for reading the metadata table.
*/
private String getSelectStatement() {
return "select VERSION, DESCRIPTION, TYPE, SCRIPT, CHECKSUM, INSTALLED_ON, EXECUTION_TIME, STATE from " + schema + "." + table;
}
Así que indetifiqué la última versión aplicada y manualmente le puse el valor de la columna en 1. Problema resuelto.
lunes, 22 de abril de 2013
Ejemplo de uso de librería Jackson de Spiring para consumir JSON por servicio REST
Un breve ejemplo de cómo utilizar la librería Jackson de Spring para consumir un JSON que retorna un servicio REST. La clase de abajo es un Singleton que inicializa el RestTemplate una sola vez.
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
public class RestJsonTest {
private static RestJsonTest instance;
private RestTemplate restTemplate;
private String url ="http://rest.service.url";
public static RestJsonTest getInstance() {
if (instance == null) {
instance = new RestJsonTest();
}
return instance;
}
private RestJsonTest() {
// Setup the RestTemplate configuration.
restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new CommonsClientHttpRequestFactory());
List<HttpMessageConverter<?>> messageConverterList = restTemplate.getMessageConverters();
// Set HTTP Message converter using a JSON implementation.
MappingJacksonHttpMessageConverter jsonMessageConverter = new MappingJacksonHttpMessageConverter();
// Add supported media type returned by BI API.
List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
supportedMediaTypes.add(new MediaType("text", "plain"));
supportedMediaTypes.add(new MediaType("application", "json"));
jsonMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
messageConverterList.add(jsonMessageConverter);
restTemplate.setMessageConverters(messageConverterList);
}
public SearchResults searchResults() {
return restTemplate.getForObject(url, SearchResults.class);
}
public static void main(String[] args) {
RestJsonTest jsonTest = RestJsonTest.getInstance();
SearchResults results = jsonTest.searchResults();
}
}
El mapeo del JSON a clases Java se puede hacer por medio de anotaciones como se muestra a continuación.ç
package com.bodybuilding.api.commerce.clientservice;
import java.util.List;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
/**
*{
* "search_keywords":"Social Networks",
* "total_time":200,
* "results":{
* "result_01":{
* "url":"http://www.facebook.com",
* "rank": "1"
* },
* "result_02":{
* "url":"http://www.twitter.com",
* "rank": "2"
* }
* }
* }
*/
@JsonIgnoreProperties(ignoreUnknown=true)
public class SearchResults {
@JsonProperty("search_keywords")
private String keywords;
@JsonProperty("total_time")
private long totalTime;
@JsonProperty("results")
private List<SearchResult> results;
public String getKeywords() {
return keywords;
}
public void setKeywords(String keywords) {
this.keywords = keywords;
}
public long getTotalTime() {
return totalTime;
}
public void setTotalTime(long totalTime) {
this.totalTime = totalTime;
}
public List<SearchResult> getResults() {
return results;
}
public void setResults(List<SearchResult> results) {
this.results = results;
}
}
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
@JsonIgnoreProperties(ignoreUnknown=true)
public class SearchResult {
@JsonProperty("url")
private String url;
@JsonProperty("rank")
private int rank;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
}
También se puede configurar el bean de RestTemplate por medio de una inyección de Spring:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="requestFactory">
<bean id="clientHttpRequestFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory" />
</property>
<property name="messageConverters">
<list>
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<bean id="jsonMediaTypeTextPlain" class="org.springframework.http.MediaType">
<constructor-arg value="text"/>
<constructor-arg value="plain"/>
</bean>
<bean id="jsonMediaTypeApplicationJson" class="org.springframework.http.MediaType">
<constructor-arg value="application"/>
<constructor-arg value="json"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
martes, 29 de enero de 2013
Instalando JAD (Java Decompiler) en Ubuntu 12
Estaba instalando JAD (decompilador para Java) en mi distribución de Ubuntu, descargándolo de este sitio web. Descargué el ejecutable y lo moví a /usr/local/bin, pero cuando lo llamé desde la consola me dió este error:
jad: error while loading shared libraries: libstdc++-libc6.2-2.so.3: cannot open shared object file: No such file or directory
El problema se saba porque descargué la versión incorrecta. Bajé la que dice ¨Jad 1.5.8e for Linux (statically linked) ¨ y listo, funcionando correctamente.
sábado, 5 de enero de 2013
Aplicaciones Web y Frameworks
La web hoy en día se ha vuelto un ecosistema donde las personas cada vez más se mueven mucho más naturalmente a través de las diversas interacciones que se dan en este complejo ambiente. Los usuarios finales navegan, suben archivos, hacen consultas, realizan búsquedas, en fin, las interfaces de la web cada vez son más comunes a los ojos de las personas, que esa sensación de tiempos antiguos de que todo lo que tenía que ver con computadoras era super complejo, y solo los "nerds" lo entendían, esta prácticamente en extinción.
Para aquellos que nos ganamos la vida produciendo “1’s y 0’s” para que otros usuarios puedan seguir habitando el mundo de la web, resultamos ser un poco más orgullosos porque podemos “jactarnos” que conocemos algunas capas más abajo del subsuelo de la web. Pero la verdad es que la web es tan compleja que los mismos desarrolladores, debido a las herramientas que nos hemos acostumbrado a usar, somos muchas veces grandes desconocedores de todo lo que sucede más allá de las capas superficiales de la web.
En este post, que es más una traducción libre del capítulo 1 del libro Struts 2 In Action: “Struts 2: the modern web application framework" (Struts 2: el framework de aplicaciones web moderno), quiero describir algunos puntos básicos que todo ingeniero de la web, particularmente el ingeniero que desarrolla aplicaciones web en la plataforma de Java, debería conocer. Examinaremos la pila tecnológica sobre la cual los frameworks de aplicaciones se montan para poder ocultar y facilitar todas esas funciones, que de lo contrario harían la vida muy difícil a los desarrolladores.
La pila tecnológica
La API de Servlet maneja todas las comunicaciones de bajo nivel con la capa HTTP. En tiempos modernos no es considerado una buena práctica programar usando directamente la API, pero conocer lo básico de ella nos ayuda a entender mejor la arquitectura sobre la cual construimos nuestras aplicaciones.
Ya que se menciona el protocolo HTTP, cabe destacar los conceptos básicos que se encierran en este protocolo tan común en nuestra vida diaria. Sin él no podríamos hacer ningún tipo de navegación en Internet. El protocolo HTTP es un protocolo que no guarda estado. Consiste en una serie de mensajes entre un cliente, típicamente un navegador, y un servidor, que puede ser una web o aplicación web, por medio de los cuales se solicitan distintos tipos de datos que al final se despliegan para un usuario. Cabe mencionar que el protocolo HTTP no fue originalmente pensado para considerar la cantidad de información compleja e interacciones de usuarios que ahora se utilizan actualmente en la Internet. Este es un tipo de problema que las aplicaciones web deben solucionar en tiempos modernos.
Debido a la falta de estado entre las peticiones, y al hecho de que todas las peticiones son basadas en texto plano, las aplicaciones web deben ingeniárselas para resolver esa brecha resultante de seguir trabajando sobre un protocolo que fue pensado para servir documentos HTML. Los casos de uso más complicados, como una simple validación de usuario, sería como programar en ensamblador (bueno, tal vez no tanto) si no tuviéramos la ayuda de los frameworks web. Otro detalle quizás desapercibido a la hora de utilizar un framework como Struts es la conversión de datos en la comunicación. Esto se vuelve bastante transparente para la mayoría de los desarrolladores. El protocolo es muy tieso en su comunicación por medio de texto plano, mientras que Java es un lenguaje altamente tipeado. Si tuviéramos que pensar todo el tiempo en nuestras aplicaciones web como convertir texto a entero, por dar un ejemplo, pasaríamos menos tiempo resolviendo los verdaderos casos de uso de la aplicación, y más tiempo haciendo tareas repetitivas y aburridas.
La Java Servlet API
La API de Servlets de Java da un paso más adelante para resolver la gran complejidad de lidiar directamente con el protocolo HTTP. Por medio de la API un programador Java puede interactuar con el protocolo usando una encapsulación en el típico paradigma de programación orientación a objetos. Es por ello que en la API hayamos objetos como el HTTPRequest o el HTTPResponse. En síntesis la API permite recibir requests HTTP, incluyendo los parámetros del query string y datos de formularios, hacer un proceso back-end, y retornar una respuesta al usuario. Todo a traves de código Java.
La unidad básica de empaquetamiento de un servlet se conoce como una aplicación web. Aunque parece una definición simple, esto tiene un sentido en el contexto de servlets. La especificación de servlets define una aplicación web como una colección de servlets, páginas HTML, clases, y otros recursos. Típicamente, una aplicación web requiere de más de un servlet para satisfacer todas las solicitudes de sus clientes. Los servlets y recursos de una aplicación web son empacados en una estructura de directorio estándar y nombrado con una extensión .war. Un archivo WAR es una versión especializada de un archivo .jar. Significa archivo de aplicación web (Web Application Archive).
Una vez que se tiene este archivo web empaquetado, hay que desplegarlo (deploy) en un contenedor de servlets. El servlet es un tipo especial de aplicación llamado aplicación manejada por ciclo de vida. En este tipo de aplicación uno no ejecuta directamente el servlet sino que el contenedor es el encargado de ejecutar el servlet a través de sus métodos de ciclo de vida, donde el principal es el llamado service(). Cuando una solicitud llega al contenedor, este primero determina cuál servlet es el que tiene que usarse para satisfacerla.
En la siguiente figura se muestra un contenedor con tres aplicaciones web y como a través de una URL se determina cual aplicación y servlet debe satisfacer la solicitud
Otra funcionalidad que agrega la API es la capacidad de manejar sesiones. Como se había mencionado, el protocolo HTTP no tiene estado, lo cual significa que no se puede correlacionar las distintas solicitudes a un servidor con un cliente específico. Sino fuera por la API, habría que ingeniarselas con el uso de galletas y llaves de sesión empotradas en el query string para poder mantener una sesión activa con un usuario específico. Aparte de esta funcionalidad, la API no provee más funciones adicionales, pero es el fundamento a partir del cual se construyen sólidas aplicaciones web, incluyendo los frameworks.
Siguiente nivel
Habiendo entendido, de una manera sintetizada, cuáles son las labores de bajo nivel de la API de servlets, podemos entonces continuar con las tareas que no son tomadas en cuenta por la API, y que por tanto son los frameworks web los que suministran estas capacidades a los desarrolladores.
Ligación (binding) de los parámetros de la solicitud (request) y validación de datos.
Recordamos de nuevo que los parámetros del request viajan en texto plano en el protocolo HTTP, y la API de servlets no provee un proceso automático de conversión a distintos tipos de variables en Java. Puede que esto no sea algo extremadamente complejo de implementar por cuenta de un desarrollador, pero es lo suficientemente repetitivo y monótono como para no dejarlo como una funcionalidad de un framework. La necesidad de la validación de datos es obvio de entender para cualquier desarrollador. El framework lo que permite es definir una manera estructurada y consistente para la validación de formularios.
Llamados a las capas de lógica de negocio y datos
Esta es una de las facultades que no son específicas de una aplicación web. Cualquier aplicación sin importar si es web o de escritorio necesita manejar un tipo de flujo de trabajo donde una solicitud de usuario pasa por las capas de presentación, lógica de negocio y acceso a base de datos, y luego viceversa para enviar la respuesta. Este flujo representa algún tipo de tarea que debe completarse. En algunos frameworks web como Struts, a estas tareas se le conoce como acciones, y el framework es conocido como un framework orientado a acciones.
Lejos estamos de los días aquellos del comienzo de la web donde utilizabamos páginas simples construidas en HTML. Cada vez más los sitios web son mucho más complejos en su interfaz para dar una experiencia mucho más rica al usuario. Tecnologías como Ajax, HTML5 y la creciente penetración de los dispositivos móviles, hacen que sea necesario el soporte de un framework para aliviar la complejidad de la capa de presentación.
Agregado a esto tenemos la necesidad de la internacionalización que es la capacidad de una aplicación de adaptar varios elementos de la misma para acomodarse a una región, país o localidad. Ejemplo simples son el texto desplegado para cambiar a un idioma según el país, el formato de la hora y fecha, la moneda, etc. Ciertamente esto es algo que buscamos que un framework nos lo probea.
¿Qué es un framework?
Un framework es una pieza de software estructural. Se dice que es estructural porque la estructura es quizás la meta principal del framework, más que cualquier otro requerimiento funcional. Un framework trata hacer generalizaciones acerca de las tareas comunes y el flujo de trabajo de un dominio específico. El framework entonces intenta proveer una plataforma sobre la cual las aplicaciones de un dominio pueden ser construidas de manera rapida y eficaz. El framework hace esto de dos maneras principales. Primero, el framework trata de automatizar todas aquellas tareas tediosas del dominio. Segundo, el framework intenta introducir una solución arquitectural elegante al flujo de trabajo común del dominio en cuestión.
En una sola definición podemos decir que un framework es una pieza de software estructural que provee automatización de tareas comunes al dominio, así como una incorporación de una solución arquitectural que puede ser fácilmente extendida por aplicaciones que implementan el framework.
¿Por qué utilizar un framework?
Uno necesariamente no tiene la obligación de utilizar un framework, pero pensar en la alternativas que son omitir el uso de un framework, o crear uno propio, realmente acarrea más desventajas que beneficios.
En el primer caso, al menos que sea una aplicación sea sencilla, el hecho de tener que implementar todas las tareas tediosas y repetitivas del dominio en cuestión, resulta en un código altamente complejo y difícil de mantener, sin mencionar que cansado y agotante. Lo ideal en un proyecto de desarrollo de software es gastar la mayor cantidad de esfuerzo en tareas de alto nivel acorde con el negocio, en lugar de invertirlas en reinventar el agua tibia.
En el segundo caso, son muy limitados los escenarios donde es necesario tener que desarrollar un framework desde cero en lugar de utilizar uno existente, principalmente porque deben darse varias raras condiciones en disponibilidad de recursos: desarrolladores sumamente hábiles, tiempo y dinero, todo esto para gastarlo en un proyecto en primera instancia, sin retorno de inversión a corto o mediano plazo. Y aún si estas condiciones se dan, siguen habiendo desventajas con esta estrategia. Hay que invertir tiempo y dinero en preparar nuevos desarrolladores en una solución local, mientras que si se utiliza un framework popular se pueden contratar desarrolladores ya entrenados. Además los frameworks caseros tienden a erosionarse con el tiempo, mientras que los modernos se mantienen en continua actualización.
Sin duda los frameworks web son casi mandatorios para cualquier proyecto de desarrollo web en la actualidad, sin embargo conocer los pilares de las soluciones web nos ayudan a entender mejor la arquitectura para solucionar los problemas que no son triviales, como rendimiento y escalabilidad.
Etiquetas:
Arquitectura,
Frameworks,
HTTP,
Java,
Servlets,
Web Programming
martes, 18 de diciembre de 2012
Cálculo de días vividos desde fecha de nacimiento
Cómo calcular el total de días transcurridos desde la fecha de nacimiento a la fecha actual.
import java.util.Calendar;
import java.util.GregorianCalendar;
public class TotalLifeTimeDays {
public int getLifeTimeDays(int birthYear, int birthMonth, int birthDay) {
Calendar birthDayCal = new GregorianCalendar();
Calendar currentDayCal = Calendar.getInstance();
birthDayCal.set(birthYear, birthMonth, birthDay);
return (int)((currentDayCal.getTime().getTime() - birthDayCal.getTime().getTime())
/ (1000 * 60 * 60 * 24));
}
public static void main(String[] args) {
TotalLifeTimeDays totalLifeTimeDays = new TotalLifeTimeDays();
int totalDays = totalLifeTimeDays.getLifeTimeDays(1982, 11, 20);
System.out.println("Total days lived: " + totalDays);
}
}
miércoles, 5 de diciembre de 2012
JSP: Obtener la fecha actual
Dejo este pequeño código mostrando como se puede obtener la fecha actual usando código JSP. En ocasiones es preferible utilizar código del lado del servidor, en lugar de usar JavaScript, para no depender de que un usuario tiene bien configurada la fecha en su ordenador, o si hay diferencias de huso horario.
<%@ page import="java.util.*" %>
<%@ page import="java.text.SimpleDateFormat"%>
<%
Date dNow = new Date();
SimpleDateFormat ft =
new SimpleDateFormat ("MM/dd/yyyy");
String currentDate = ft.format(dNow);
%>
<p>The current date is: <%=currentDate%></p>
miércoles, 3 de octubre de 2012
JSTL: Ruta actual de una página
Para obtener por medio de JSTL el path actual de una página incluyendo el query string, si lo tiene:
<c:set var="url"><c:out value="${pageContext.request.scheme}://${pageContext.request.serverName}${pageContext.request.contextPath}${pageContext.request.servletPath}"/><c:if test="${not empty pageContext.request.queryString}"><c:out value="?${pageContext.request.queryString}"/></c:if>
</c:set>
martes, 21 de agosto de 2012
Versión de Java de un .class
Hace poco tuve un pequeño problema con un código que nos enviaron ya compilado. A la hora de hacer deployment en el servidor obteníamos una excepción de tipo:
javax.servlet.ServletException: Bad version number in .class file
Según lo que leí la excepción se da porque la clase fue compilada con una versión más alta de Java que la que corre en la máquina virtual. Por ejemplo que la clase fue compilada en Java 6 y la máquina virtual corre Java 5.
Para confirmar esto indague un poco en Google como averiguar la versión de una clase. Para ello existe un comando: javap -verbose ClassName
(El .exe se puede encontrar en la carpeta bin del JDK)
Es conveniente guardar en un archivo el resultado del comando pues tira bastante información. Dentro de esa información hay que buscar la combinación de minor y major version que se encuentra al puro comienzo para determinar la versión de Java utilizada.
major minor Java platform version 45 3 1.0 45 3 1.1 46 0 1.2 47 0 1.3 48 0 1.4 49 0 1.5 50 0 1.6
jueves, 17 de noviembre de 2011
Búsqueda de letras faltantes del abecedario en una oración
Creo que siempre es bueno salvar cualquier código que uno haya hecho por más simple o trivial que parezca. Puede ser que en el momento menos esperado lo requiramos y realmente es frustrante acordarse de que ya uno lo había hecho y luego desechado a la basura.
Dejo para el historial un pequeño código que hice como parte del proceso para aplicar a una empresa. El planteamiento es simple. Codificar un programa que busque las letras faltantes del abecedario en una oración.
import java.util.HashSet;Salida del programa:
import java.util.Set;
/**
* Test code to find missing letters of the alphabet from a String sentence.
* @author gabriel.solano
*
*/
public class MissingLetters {
private final int ASCII_CODE_FOR_LETTER_A = 97;
private final int ASCII_CODE_FOR_LETTER_Z = 122;
/**
* Gets the missing letters of a sentence in lower case.
* @param sentence
* @return String having all the letters that the sentence is missing from the alphabet.
*/
public String getMissingLetters(String sentence){
/*
* 1. Let's populate a set with the unique characters of the sentence.
* This approach avoids having two nested for's in the code (better performance).
*/
Set<Integer> uniqueASCIICodes = new HashSet<Integer>();
for (char character : sentence.toLowerCase().toCharArray() ) {
if (character >= ASCII_CODE_FOR_LETTER_A
&& character <= ASCII_CODE_FOR_LETTER_Z) { // Range of lower case letters.
uniqueASCIICodes.add((int)character);
if (uniqueASCIICodes.size() == 26) {
break; // Sentence already covered all letter from the alphabet.
}
}
}
/*
* 2. Move in the range of ascii codes of lower case alphabet
* and check if letter was present in sentence.
*/
StringBuilder misingLettersBuilder = new StringBuilder();
for (int i=ASCII_CODE_FOR_LETTER_A; i <= ASCII_CODE_FOR_LETTER_Z; i++) {
if (!uniqueASCIICodes.contains(i)) {
misingLettersBuilder.append((char)i);
}
}
return misingLettersBuilder.toString();
}
public static void main(String[] args) {
String case1 = "A quick brown fox jumps over the lazy dog";
String case2 = "bjkmqz";
String case3 = "cfjkpquvwxz";
String case4 = "";
MissingLetters missingLetters = new MissingLetters();
System.out.println("Missing letters for[" + case1 + "]: " +
missingLetters.getMissingLetters(case1));
System.out.println("Missing letters for[" + case2 + "]: " +
missingLetters.getMissingLetters(case2));
System.out.println("Missing letters for[" + case3 + "]: " +
missingLetters.getMissingLetters(case3));
System.out.println("Missing letters for[" + case4 + "]: " +
missingLetters.getMissingLetters(case4));
}
}
Missing letters for[A quick brown fox jumps over the lazy dog]:
Missing letters for[bjkmqz]: acdefghilnoprstuvwxy
Missing letters for[cfjkpquvwxz]: abdeghilmnorsty
Missing letters for[]: abcdefghijklmnopqrstuvwxyz
martes, 25 de octubre de 2011
Expression Language (EL): Activación
El "expression language" es un tipo de notación en JSP que permite navegar sobre beans de una manera más simplificada y sencilla.
Si tengo por ejemplo un bean "Foo" con una propiedad llamada "prop" y a su vez esta contiene otra propiedad llamada prop2, la forma anticuada de accesar la propiedad sería:
"myFoo.getProp1().getProp2()"
Con EL podemos omitir los "get" de esta forma:
"${myFoo.prop1.prop2}"
Recientemente estaba teniendo un conflicto porque el JSP no me interpretaba el EL. Lo que me estaba faltando era un buena declaración del web.xml que indicara que estamos usando la versión 2.4 de Servlets:
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
Quería dejar esto documentato porque me tomó rato averiguar como se activaba.
lunes, 24 de octubre de 2011
Sin temor a lucir "fuera de onda"
A veces pareciera que el mundo del desarrollo de software se comporta parecido al mundo de la moda. No lo digo porque piense que esté sujeto completamente a condiciones triviales como la influencia de una estrella pop sobre las jóvenes adolecentes, pero en menor escala, los frameworks estrella más populares tienden a monopolizar la atención de los ingenieros de software con recetas, a veces al punto de pensar que cualquier cosas distinta de la receta está fuera de moda.
Frameworks como Struts, Spring o Hibernate son herramientas exelentes para muchos de los desarrollos de software. El problema considero que comienza cuando un desarrollador cría un esquema en su mente, de que todos los proyectos deben implementarse con la receta estandar "para todas la tallas" que él utiliza. Si alguien más sugiere hacer algo diferente, o solamente menciona en alguna conversación amistosa a otro colega que está utilizando una técnica diferente, el chico receta framework podría verlo como el fuera de onda o inclusive hasta molestarlo por ser un dinosaurio a su parecer.
He estado viendo las exposiciones de la reciente conferencia de Java Zone 2011. Dos presentaciones en particular llamaron mi atención por su valentía para cuestionar el “status-quo”. Una expone un acercamiento diferente a la inyección de dependencias:
He estado viendo las exposiciones de la reciente conferencia de Java Zone 2011. Dos presentaciones en particular llamaron mi atención por su valentía para cuestionar el “status-quo”. Una expone un acercamiento diferente a la inyección de dependencias:
Dependency injection when you only have one dependency from JavaZone on Vimeo.
Hibernate should be to programmers what cake mixes are to bakers: beneath their dignity. from JavaZone on Vimeo.
No estoy tomando partido en ninguna de estas dos presentaciones. Debo confesar que me falta experiencia como para tomar una posición informada en los tópicos mencionados, pero realmente admiro a estos dos por mostrar sin ningún titubeo, dos formas alternativas a técnicas actuales del desarrollo de software. La innovación aparece frequentemente en situaciones donde alguien se aparta de los demás.
Creo que como latinoamericanos tenemos mucho que aprender de estos dos ejemplos. Estamos muy acostumbrados a ser consumidores de tecnologías pero no a ser productores de ellas. Debemos tener la mente abierta para experimentar con nuevas alternativas, utilizando un criterio racional y mucha humildad para examinarlo todo, y ejercitar el jucio informático, el cual es clave en nuestro desarrollo profesional.
martes, 20 de septiembre de 2011
Servlet para descargar archivos
Dejo a disposición como utilizar un servlet para descargar archivos.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A simple Servlet to download a file.
* @author gabriel.solano
*
*/
public class DownloadServlet extends HttpServlet{
private static final long serialVersionUID = 4440011247408877539L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
downloadFile(resp,
this.getServletContext().getRealPath("/WEB-INF/myFile.pdf"));
}
protected void downloadFile(HttpServletResponse response, String filePath)
throws ServletException, IOException {
File fileToDownload = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(fileToDownload);
ServletOutputStream out = response.getOutputStream();
String mimeType = new MimetypesFileTypeMap().getContentType(filePath);
response.setContentType(mimeType);
response.setContentLength(fileInputStream.available());
response.setHeader( "Content-Disposition", "attachment; filename=\""
+ fileToDownload.getName() + "\"" );
int c;
while((c=fileInputStream.read()) != -1){
out.write(c);
}
out.flush();
out.close();
fileInputStream.close();
}
}
martes, 6 de septiembre de 2011
Parser de HTML con Java
Quería compartir un código de ejemplo mostrando como "analizar gramaticalmente" (esa fue la traducción que me dio Google Translate para el verbo "parse", de ahora en adelante me quedo con el incorrectamente-usado-pero-mejormente-conocido-verbo: "parsear") una página HTML utilizando la librería de código abierto: HTML Parser. Me ha tocado utilizar esta librería en el pasado para un proyecto en donde necesitábamos extraer todos los enlaces de un sitio, y ahora me tocar usarla para otro proyecto donde necesito validar unas reglas de código en ciertas páginas HTML.
Así que vamos a asumir que necesitamos encontrar todos los enlaces absolutos de una página de un sitio. Primeramente creamos nuestra clase parseadora:
Como podrán notar, la última función de esta clase es la encargada de moverse a través de todos los nodos HTML de la página. Simplemente dejo a la clase "TagHandler" hacer lo que tenga que hacer con la etiqueta que encuentra.
Esta es la interface TagHandler:
Y aquí está la implementación para procesar las etiquetas de ancla:
La función "processTag" simplemente extrae el atributo "href" y verifica si es un URL absoluto. Finalmente creamos la clase principal para correr este código:
Usando el sitio de la comunidad de usuarios de Java de Costa Rica obtenemos los siguientes URLs:
http://www.facebook.com/pages/costa-rica-jug/107081646760
http://www.oreilly.com/
http://www.java.net/
Esta es la dependencia de Maven en caso necesiten utilizar esta útil librería:
Así que vamos a asumir que necesitamos encontrar todos los enlaces absolutos de una página de un sitio. Primeramente creamos nuestra clase parseadora:
import java.io.IOException;
import java.net.URL;
import org.htmlparser.Node;
import org.htmlparser.Tag;
import org.htmlparser.lexer.Lexer;
import org.htmlparser.util.ParserException;
/**
* Parses the HTML code of the page specified by it's URL.
* @author gabriel.solano
*
*/
public class URLHTMLParser {
/*
* Tag handler that will be used to process the tags.
* (This could be improved by implementing an observer
* pattern to be able to add more than one TagHandler)
*/
private TagHandler tagHandler;
/**
* Constructor.
* @param tagHandler
*/
public URLHTMLParser(TagHandler tagHandler) {
this.tagHandler = tagHandler;
}
/**
* Scans the specified URL.
* @param url
* @throws ParserException
* @throws IOException
*/
public void scanURL(URL url) throws ParserException, IOException {
Lexer lexer = new Lexer(url.openConnection());
extractHTMLNodes(lexer);
}
/**
* Extracts the HTML nodes and lets the TagHandler to do something
* with the tags.
* @param lexer
* @throws ParserException
*/
private void extractHTMLNodes(Lexer lexer) throws ParserException {
Node node;
while (null != (node = lexer.nextNode(false))) {
if (node instanceof Tag) {
Tag tag = (Tag) node;
tagHandler.handleTag(tag);
}
}
}
}
Como podrán notar, la última función de esta clase es la encargada de moverse a través de todos los nodos HTML de la página. Simplemente dejo a la clase "TagHandler" hacer lo que tenga que hacer con la etiqueta que encuentra.
Esta es la interface TagHandler:
import org.htmlparser.Tag;
/**
* Defines the interface for a TagHandler.
* @author gabriel.solano
*
*/
public interface TagHandler {
/**
* Handles the process of an HTML tag.
* @param tag
*/
public void handleTag(Tag tag);
}
Y aquí está la implementación para procesar las etiquetas de ancla:
import java.util.HashSet;
import java.util.Set;
import org.htmlparser.Tag;
/**
* Handles the event when an anchor tag is found while parsing
* HTML code of a page.
* This class has a functionality to count all absolute URLs
* found in the parsing process.
* @author gabriel.solano
*
*/
public class AnchorTagHandler implements TagHandler{
private Set<String> absoluteURLs; // All URLs found.
/**
* Constructor.
*/
public AnchorTagHandler() {
absoluteURLs = new HashSet<String> ();
}
/**
* Gets the found absolute URLs.
* The collection is filled only during the scanning process
* of an HTML page.
* @return
*/
public Set<String>getAbsoluteURLs() {
return absoluteURLs;
}
/**
* Handles the tag only if it is an anchor tag.
*/
public void handleTag(Tag tag) {
if (tag.getTagName().equalsIgnoreCase("a")) {
// Process only if it's an anchor tag.
processTag(tag);
}
}
/**
* Processes the anchor tag. In this case
* adds all absolute URL's found.
* @param tag
*/
private void processTag(Tag tag) {
String href = tag.getAttribute("href");
if (href != null) {
href = href.toLowerCase();
if (href.startsWith("http://") || href.startsWith("https://")) {
// Add all URLs with HTTP protocol.
absoluteURLs.add(href);
}
}
}
}
La función "processTag" simplemente extrae el atributo "href" y verifica si es un URL absoluto. Finalmente creamos la clase principal para correr este código:
import java.net.URL;
import java.util.Set;
public class FindAbsoluteURLs {
public static void main(String[] args) {
AnchorTagHandler anchorTagHandler = new AnchorTagHandler();
URLHTMLParser htmlParser = new URLHTMLParser(anchorTagHandler);
try {
htmlParser.scanURL(new URL("http://www.crjug.org/"));
Set<String>urls = anchorTagHandler.getAbsoluteURLs();
for(String url : urls) {
System.out.println(url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Usando el sitio de la comunidad de usuarios de Java de Costa Rica obtenemos los siguientes URLs:
http://www.facebook.com/pages/costa-rica-jug/107081646760
http://www.oreilly.com/
http://www.java.net/
Esta es la dependencia de Maven en caso necesiten utilizar esta útil librería:
<dependency>
<groupId>org.htmlparser</groupId>
<artifactId>htmlparser</artifactId>
<version>1.6</version>
</dependency>
viernes, 19 de agosto de 2011
Struts 1: Descargando la excepción en un DownloadAction
En un proyecto para el cliente requeríamos descargar un PDF que se generaba de manera dinámica. Así que decidimos usar el DownloadAction de Struts 1 que está disponible en un paquete llamado "struts-extras". Por ciertos inconvenientes en el proyecto la aplicación fallaba en el ambiente del cliente y teníamos que estar visitando los logs para ver las excepciones. Dependiendo de la configuración de un servidor, buzear en logs puede ser una tarea sumamente laboriosa lo cual fue en mi caso particular.
Así que para facilitar el análisis decidí agregar un pedazo de código que cuando atajara la excepción, esta misma se pudiera descargar como un ".txt". Utilizé una función que me encontré en Internet que convierte el StackTrace a un String. Después el String se convierte a un arreglo de Bytes que se descarga finalmente como un TXT. Dejo el código a disposición.
Así que para facilitar el análisis decidí agregar un pedazo de código que cuando atajara la excepción, esta misma se pudiera descargar como un ".txt". Utilizé una función que me encontré en Internet que convierte el StackTrace a un String. Después el String se convierte a un arreglo de Bytes que se descarga finalmente como un TXT. Dejo el código a disposición.
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DownloadAction;
public class OutputPDFAction extends DownloadAction {
@Override
protected StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
// Code might throw an exception.
response.setHeader("Content-disposition", "attachment; filename=patient_diary.pdf");
String contentType = "application/x-download";
return new ByteDownloadStreamInfo(contentType,abyte0);
}
catch(Throwable throwable)
{
response.setHeader("Content-disposition", "attachment; filename=error.txt");
String contentType = "application/x-download";
return new ByteDownloadStreamInfo(contentType,
stackTraceToString(throwable).getBytes());
}
}
private String stackTraceToString(Throwable e) {
String retValue = null;
StringWriter sw = null;
PrintWriter pw = null;
try {
sw = new StringWriter();
pw = new PrintWriter(sw);
e.printStackTrace(pw);
retValue = sw.toString();
} finally {
try {
if(pw != null) pw.close();
if(sw != null) sw.close();
} catch (IOException ignore) {}
}
return retValue;
}
class ByteDownloadStreamInfo implements StreamInfo {
private byte[] bytes;
private String contentType;
public ByteDownloadStreamInfo(String contentType, byte[] bytes) {
this.bytes = bytes;
this.contentType=contentType;
}
public String getContentType() {
return this.contentType;
}
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.bytes);
}
}
}
martes, 9 de agosto de 2011
Eclipse: Configurar dos carpetas fuentes con un mismo destino de deploy
Hace poco tuve que correr para acomodar un proyecto que el cliente pedía con cierta estructura de carpetas. Aparentemente el cliente tiene como norma separar en dos carpetas el código de la aplicación. En una pone todo el código que corre del lado del cliente: “htdocs”, y en otra carpeta todo el código que corre del lado del servidor (JSP’s, Structs actions, etc): “Java”.
Lo interesante es que los JSP’s igual tenían que llamar códigos de CSS y JavaScript que están situados en la carpeta de htdocs la cual está fuera del directorio raíz de la aplicación Java. Me puso a pensar un buen rato hasta que caí en razón que al final el cliente hace un deploy de las dos carpetas en una misma. Así que descubrí como hacer esto con Eclipse. Igualmente se puede hacer con cualquier herramienta de construcción como ANT o Maven, pero para los fines propios la opción que muestro a continuación fue suficiente.
Se hace clic derecho sobre el proyecto web, se va a propiedades y en la opción de “Deployment Assembly”, simplemente se agregan las dos carpetas fuentes con un mismo path de deploy. Así de sencillo.
Lo interesante es que los JSP’s igual tenían que llamar códigos de CSS y JavaScript que están situados en la carpeta de htdocs la cual está fuera del directorio raíz de la aplicación Java. Me puso a pensar un buen rato hasta que caí en razón que al final el cliente hace un deploy de las dos carpetas en una misma. Así que descubrí como hacer esto con Eclipse. Igualmente se puede hacer con cualquier herramienta de construcción como ANT o Maven, pero para los fines propios la opción que muestro a continuación fue suficiente.
Se hace clic derecho sobre el proyecto web, se va a propiedades y en la opción de “Deployment Assembly”, simplemente se agregan las dos carpetas fuentes con un mismo path de deploy. Así de sencillo.
viernes, 24 de junio de 2011
Eclipse IAM: Instalación para Eclipse Helios
Hay dos formas generales de usar Maven:
Es muy sencillo de instalar en la versión Helios de Eclipse:
1. Copiar el URL de actualización del sitio:
http://q4e.googlecode.com/svn/trunk/updatesite-iam/
2. Ir a la opción de menú: "Ayuda->Instalar Nuevo Software"
3. Pegar el URL en la opción de "Agregar Sitio". Dar clic a "Siguiente"

4. Seleccionar los paquetes deseados. Preferiblemente elegirlos todos para menos complicación.

5. Después de reiniciar el eclipse probar el plugin creando un nuevo proyecto Maven.

6. Seleccionar el checkbox de crear un proyecto simple de Java.

7. Si examinamos el archivo pom.xml observamos que se agregó una dependencia de JUnit.

8. Podemos probar la integración de la dependencia al proyecto corriendo la clase de prueba que se generó de ejemplo: "AppTest".

- "A lo macho" a punta de comandos.
- O a lo no tan macho usando un plugin de Maven.
Es muy sencillo de instalar en la versión Helios de Eclipse:
1. Copiar el URL de actualización del sitio:
http://q4e.googlecode.com/svn/trunk/updatesite-iam/
2. Ir a la opción de menú: "Ayuda->Instalar Nuevo Software"
3. Pegar el URL en la opción de "Agregar Sitio". Dar clic a "Siguiente"

4. Seleccionar los paquetes deseados. Preferiblemente elegirlos todos para menos complicación.

5. Después de reiniciar el eclipse probar el plugin creando un nuevo proyecto Maven.

6. Seleccionar el checkbox de crear un proyecto simple de Java.

7. Si examinamos el archivo pom.xml observamos que se agregó una dependencia de JUnit.

8. Podemos probar la integración de la dependencia al proyecto corriendo la clase de prueba que se generó de ejemplo: "AppTest".

lunes, 13 de junio de 2011
Patrón de diseño: Prototype
Estuve estudiando este patrón de diseño para enseñarlo en una clase. Este patrón en resumen permite crear nuevos objetos al hacer una copia exacta de un objeto prototípico.
El principal uso que le encuentro al patrón, al menos de primera impresión ya que los patrones se van digiriendo con el tiempo, es el ahorro que se logra en casos donde la instanciación de un objeto es costoso en términos de recursos del sistema (memoria, tiempo, procesamiento, etc).
En el ejemplo de abajo simulo esta aplicación. La clase Sheep (oveja) cuando se instancia require la construcción de su cadena de ADN; este es el supuesto proceso pesado. Java ya incluye una interface llamada "Cloneable" que cuando se implementa en una clase, las instancias de la clase se pueden clonar. Cuando hablamos de clonar nos referimos a crear una copia exacta de un objeto al dejar los mismos valores de sus atributos de clases en una instancia aparte.
La clase Sheep implementa por tanto esta interface con lo cual crear otra oveja similar es asunto simplemente de llamar el método "clone()".
public class Sheep implements Cloneable {
protected String dna;
protected final char [] DNA_ALPHABET = {'A','C','T','G'};
public String getDNA() {
return dna;
}
public Sheep() {
// Simulates extremely long process to create a sheep.
StringBuilder dnaBuilder = new StringBuilder();
for(int i=0; i < 30; i++) {
int alphabetIndex = (int) (Math.random() * 10 % 4);
dnaBuilder.append(DNA_ALPHABET[alphabetIndex]);
}
dna = dnaBuilder.toString();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
Sheep dolly = new Sheep();
System.out.println("Dolly was born: " + dolly.getDNA());
try {
Sheep dollyClon = (Sheep) dolly.clone();
System.out.println("Dolly Clon: " + dollyClon.getDNA());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
Resultado:
Dolly was born: CAAACGGGACACTTATACTTGTTCGCCCAT
Dolly Clon: CAAACGGGACACTTATACTTGTTCGCCCAT
Suscribirse a:
Entradas (Atom)