Bitsmi Blog
OCP7 11 – Hilos (01) – Introducción
20-06-2014 - Antonio Archilla
En este apartado se exponen los conceptos básicos referentes del diseño de programas concurrentes y paralelos y los mecanismos que la especificación estándar de Java pone a disposición del programador para conseguirlo.
Se tratarán los siguientes conceptos:
- Cómo el sistema operativo gestiona los procesos e hilos.
- Ciclo de vida de un hilo de ejecución.
- Sincronización y comunicación de datos entre hilos de ejecución.
OCP7 07 – Manejo de Cadenas
18-06-2014 - Xavsal
Argumentos y formatos de cadenas
El método main contiene el parámetro String[] args
. Puede recibir cero o más argumentos.
La implementación de la clase es la siguiente.
public class Echo {
public static void main(String[] args) {
for (String s: args) {
System.out.println(s);
}
}
}
La clase Echo
puede recibir los siguientes parámetros por línea de consola de comandos.
java Echo Enero Febrero Marzo Abril
Pasándole como argumentos en la línea de comandos los cuatro primeros meses del año.
Cada uno de los meses separados por un salto de línea. Esto es así debido a que el carácter espacio se utiliza para separar los parámetros unos de otros mediante un salto de línea entre cada uno.
Si se quiere mostrar un frase o texto completo, por ejemplo
java Echo "Enero, Febrero, Marzo, Abril son los cuatro primeros meses..."
se debe indicar la apertura y el cierre del texto mediante comillas dobles ""
.
Debe tenerse en cuenta que los arrays SIEMPRE empiezan con el valor 0, nunca con el 1.
Para recuperar los parámetros recibidos mediante el método main se utilizan los indices del vector.
Así con el código args[0]
se recupera el primer parámetro, con args[1]
se recupera el segundo, etc.
Adicionalmente, si una aplicación necesita recibir argumentos de tipo numérico, debe convertirse el argumento de tipo String
a un argumento que represente un número,
como por ejemplo el 34
, a su valor numérico equivalente, el 34
.
Este snippet transforma un argumento de consola de comandos en un tipo entero:
int primerArg;
if (args.length > 0) {
try {
primerArg = Integer.parseInt(args[0]);
System.out.println("Se ha convertido la cadena "+args[0]+" en el número siguiente -> "+primerArg);
} catch (NumberFormatException e) {
System.err.println("Argumento " + args[0] + " debe ser un número entero.");
System.exit(1);
}
}
primerArg
lanza una excepción del tipo NumberFormatException si el formato de args[0]
no es valido.
Todas las clases de tipo Number
— Integer
, Float
, Double
y demás — disponen de métodos de conversión que transforman un String representando un número en un objeto de su tipo específico.
Formatos de cadena
Los distintos argumentos de conversión que podemos utilizar para modificar el aspecto de una objeto String son los siguientes:
Cómo ejemplo inicial para limitar el número de caracteres que se visualizan por pantalla es suficiente con utilizar %2.2x
dónde x
corresponde al argumento de conversión que se haya pasado.
PrintWriter
PrintWriter
es una nueva clase de impresión bastante similar a Printf
perteneciente a la librería java.io
. Puede encontrarse su Javadoc aquí.
PrintWriter pw = new PrintWriter(System.io, true);
pw.printf("Texto escrito mediante Pw");
Procesamiento de Cadenas
Dentro del JDK en su versión del Java 7 existen varias clases Java que permiten manipular y tratar los elementos de tipo cadena. Son clases ya existentes en versiones anteriores del JDK.
String
Representa una cadena de caracteres inalterable. Al modificar un objeto String
lo que estamos haciendo en realidad es crear otro objeto String
. No es la más eficiente ni la mejor.
Ideal para tratar con cadenas de texto cuyo valor sabemos que no se modificará: mensajes de alerta, texto, informativo, etc.
StringBulider / StringBuffer
Debe utilizarse cuándo debamos trabajar con cadenas de texto que deban modificar su contenido en tiempo de ejecución.
Ambas disponen del mismo API de desarrollo.
Como norma general utilizaremos StringBuilder
en lugar de StringBuffer
.
Razón: Los métodos de StringBuffer
son sincronizados por lo que pueden ser utilizados de forma segura en un ambiente multihilo.
Los métodos de StringBuilder
no son sincronizados por lo que su uso implica un mejor rendimiento cuándo se usan localmente.
En general, la concatenación de Strings ocurre con variables locales a un método por lo que es recomendable utilizar de forma general StringBuilder
en lugar de StringBuffer
.
Cuan rápido es StringBuilder sobre StringBuffer?
StringBuilder
puede resultar un 50% más rápido para concatenar String
.
Para esta implementación.
public class StringBuilder_vs_StringBuffer {
public static void main(String[] args) {
StringBuffer sbuffer = new StringBuffer();
long inicio = System.currentTimeMillis();
for (int n = 0; n < 1000000; n++) {
sbuffer.append("zim");
}
long fin = System.currentTimeMillis();
System.out.println("Time using StringBuffer: " + (fin - inicio));
StringBuilder sbuilder = new StringBuilder();
inicio = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
sbuilder.append("zim");
}
fin = System.currentTimeMillis();
System.out.println("Time using StringBuilder: " + (fin - inicio));
}
}
Obteniendo casi una mejora del 50% utilizando StringBuilder
.
Clases Auxiliares en la Manipulación de cadenas
StringTokenizer
Extrae información (en forma de tokens) de una cadena de texto cuyos caracteres están separados por un carácter o símbolo especial o separador. Recorre la cadena de texto y obtiene las cadenas obtenidas (tokens) a partir del símbolo especial o separador indicado en la llamada al método.
// Inicialización
StringTokenizer st = new StringTokenizer("this is a test");
// Utilización
while(st.hasMoreTokens()) {
System.out.println(st.nextToken())
}
Puede encontrarse información más detallada dentro de la API de Java 7 en la siguiente dirección.
Scanner
Extrae información de una cadena o flujo de datos como StringTokenizer. Cambia el tipo de dato a las divisiones mientras se itera sobre ellas (StringTokenizer
no puede),
es decir, ante un flujo de datos podremos capturar enteros, decimales, etc en función de nuestro método de iteración utilizando Scanner
.
Error de codificación Unicode en un mensaje Javascript
16-06-2014 - xavsal
Descripción del Problema
Cuando se publica un mensaje que contiene un carácter en formato Unicode no muestra el texto correctamente. No se renderiza el carácter Unicode en Javascript sino que se muestra directamente la codificación
Análisia del Problema
En el fichero JSP contenedor se encuentra la siguiente llamada:
<a onclick="return(confirm('Mensaje de llamada previo al mu00E9todo?'));"
href="<ruta_web_navegacion>"
>
Cuando el navegador renderiza el botón y procesa la funcionalidad del atributo onclick no renderiza correctamente el texto contenido dentro de los confirm como carácter Unicode desde el Javascript, sino que lo interpreta como un string que forma parte de la cadena contenida dentro del confirm .
Solución
Hay que añadir en el JSP una sección Javascript donde se implementa la siguiente función:
<script>
function metodo() {
return confirm("Mensaje de llamada previo al mu00E9todo?");
}
</script>
Esta nueva función renderiza directamente el texto contenido en el mensaje desde Javascript no desde HTML.
En el código HTML del enlace hay que indicar en el atributo onclick el siguiente código para ejecutar correctamente la ventana confirm y posteriormente el envío del resultado al onclick del botón:
<a onclick="return(metodo());"
href="<ruta_web_navegacion>"
>
Esto permite que la codificación Unicode sea interpretada correctamente y se obtiene el carácter é lugar de la codificación ue00E9 cuando se muestra el mensaje por pantalla.
Detalle
El método confirm devuelve el resultado de la opción elegida cuando se abre la ventana mediante Javascript.
Lo que se está haciendo se redirigir este regreso (sea true o false) hacia el botón onclick de manera que se ejecute directamente o no según la selección de las opciones del confirm Javascript que se haya efectuado.
Error Adobe AcroExch. al insertar un PDF en un documento de Word
09-05-2014 - Xavsal
Se dispone de un documento PDF de unos 2 Mb i es desea incrustar en un documento de Word estándar (independiente de versión de Office).
Al intentar realizar la incrustación se abre una ventana de alerta con el siguiente mensaje de error:
El programa usado para crear este objetivo es AcroExch. Dicho programa no está instalada en el equipo o no responde. Para editar este Objeto, Instale AcroExch o asegúrese de que todos los cuadros de diálogo de AcroExch están cerrados.
Es un problema relacionado con una opción de seguridad del Adobe Acrobat Reader. El programa por defecto dispuesta de la opción Activar modo protegido al iniciar. Así para solucionar el problema lo que hay que hacer es seguir los siguientes pasos:
- Abrir la Adode PDF Reader (múltiples versiones)
- Acceder a la opción Editar
- Acceder a la opción Preferencias
- Dependiendo de la versión del Acrobat puede ser la opción de General (Adobe Acrobat X) o la opción Seguridad (mejorada) (Adobe Acrobat XI). En otras versiones el nombre de la opción es el mismo, hay que buscarlo para encontrar el lugar donde aparezca.
- Hay que desactivar la opción Activar modo protegido al iniciar.
Ahora si se realiza de nuevo la inserción del documento PDF dentro del documento de Word no se volverá a mostrar el error y finalizará la incrustación correctamente.
Cálculo del tamaño de una BBDD Oracle
08-05-2014 - xavsal
Incluye el tamaño de los archivos de datos en la búsqueda
El tamaño total incluye tablas, campos, procedimientos almacenados y otros objetos de la base de datos.
Calcula el tamaño de la vista «dba_data_files»:
SELECT SUM(bytes)/1024/1024/1024 data_size FROM dba_data_files;
Calcula el tamaño de los archivos temporales
Estos conservan datos durante el proceso pero no es un almacenamiento permanente.
Calcula el tamaño del archivo temporal:
SELECT NVL(SUM(bytes),0)/1024/1024/1024 temp_size FROM dba_temp_files;
Obtener el tamaño del redo log
Esto almacena cualquier cambio en la base de datos antes de ser aplicado en los datos actuales de la base de datos.
Esto ofrece una manera de almacenar la base de datos en su estado orignal previo a una consulta diseñada para modificar cualquier información.
SELECT SUM(bytes)/1024/1024/1024 redo_size FROM sys.v_$log;
Tamaño del archivo de control usado por Oracle utilizando la vista V$CONTROLFILE
Esta vista se utiliza para obtener información del esquema de la base de datos i de los objetos contenidos en la misma.
Para obtener el tamaño del archivo de control hace falta ejecutar:
SELECT SUM(BLOCK_SIZE*FILE_SIZE_BLKS)/1024/1024/1024 controlfile_size
FROM v$controlfile;
Combinar las anteriores consultas para obtener el tamaño de la base de datos
Resultado obtenido el tamaño total de la base de datos en gigabytes:
SELECT d.data_size, t.temp_size, r.redo_size
FROM ( SELECT NVL(bytes)/1024/1024/1024 data_size FROM dba_data_files) d,
( SELECT NVL(sum(bytes),0)/1024/1024/1024 temp_size FROM dba_temp_files ) t,
( SELECT SUM(bytes)/1024/1024/1024 redo_size FROM sys.v_$log ) r;
Errores comunes del servidor OC4J
08-05-2014 - Xavsal
Errores JMS
A través de la consola de comandos se muestra un error como el siguiente:
2013-11-13 15:49:56.330 ERROR J2EE OJR-00011 Excepción al iniciar el servidor JMS: Error parsing jms-server config at file:/C:/PRO_MAVEN/OC4J_10g_TRUNK/j2ee/home/config/jms.xml: /C:/PRO_MAVEN/OC4J_10g_TRUNK/j2ee/home/config/jms.xml, Fatal error at line 27 offset 12 in file:/C:/PRO_MAVEN/OC4J_10g_TRUNK/j2ee/home/config/jms.xml: .<Line 27, Column 12>: XML-20211: (Error Fatal) No está permitido '--' en comments.
Solución
- Parar el servidor de aplicaciones.
- Acceder a la ruta
<PATH>/j2ee/home/persistence/
de la instalación del servidor OC4J. - Borrar el fichero
jms.state
. - Reiniciar el servidor.
Error ParserConfigurationException
A través de la consola de comandos se muestra un error como el siguiente:
ERROR [2013-12-03 15:18:55,759] [Digester] Digester.getParser:
javax.xml.parsers.ParserConfigurationException: XML document validation is not s
upported
at com.bluecast.xml.JAXPSAXParserFactory.newSAXParser(JAXPSAXParserFacto
ry.java:105)
at org.apache.commons.digester.Digester.getParser(Digester.java:686)
at org.apache.commons.digester.Digester.getXMLReader(Digester.java:902)
at org.apache.commons.digester.Digester.parse(Digester.java:1548)
at org.apache.struts.action.ActionServlet.parseModuleConfigFile(ActionServlet.java:1006)
Solución
No se está utilizando una JDK compatible con el servidor. OC4J es compatible solamente con la JDK 1.4 y este es un error correspondiente al uso del servidor con una JDK superior.
Error “Not in an application scope – start OC4J with the -userThreads switch if using user-created threads”
Este error se produce dentro de un proyecto J2EE que dispone de código fuente que genera hilos bajo demanda del programador. El servidor detecta dicha generación manual y muestra el mensaje de error dando una pista sobre cómo solucionar el problema de compatibilidad.
Solución
En el caso concreto comentado es obligatorio utilizar el atributo -userThreads
(Enable context lookup support from user-created threads) del servidor OC4J.
Esto permite que el servidor sea capaz de gestionar además de los hilos internos propios también los creados manualmente por el usuario desde la aplicación J2EE.
Este parámetro debe indicarse en el Script de arranque del servidor (en caso de ejecutarse des de consola también debe añadirse como parámetro):
java -jar oc4j.jar -userthreads
Referencias
Rutas de instalación del servidor OC4J
07-05-2014 - Xavsal
Las rutas de instalación por defecto del servidor OC4J son las siguientes:
- En la ruta
OC4J_10g_TRUNK/j2ee/home/applications/<nombre_aplicación>/APP-INFlib/
, se pueden encontrar las librerías compartidas por todas las aplicaciones y que el servidor lo carga en su classpath. - En la ruta
OC4J_10g_TRUNK/j2ee/home/applications/<nombre_aplicación>/
, ruta dónde se encuentra todas las aplicaciones desplegadas en el servidor. - En la ruta
OC4J_10g_TRUNK/j2ee/home/application-deployments/
, se encuentra la CACHE de las aplicaciones (en generar se puede dejar vacía si quiere disponer más espacio libre).
Variables de entorno para OC4J
11-04-2014 - Xavsal
Para realizar la instalación de un servidor de aplicaciones OC4J en un entorno Windows es necesario habilitar las siguientes variables de entorno para obtener una instalación correcta y estable.
La variables a definir son las siguientes:
- J2EE_HOME
- Valor:
<Directorio_Instalacion_OC4j>/OC4J_TRUNK/j2ee/home
- Descripción: Opcional. Acceso a los ficheros oc4j.jar y admin.jar. Estableciendo estas variables podrán invocarse estos Jars des de cualquier directorio.
- Valor:
- OC4J_JVM_ARGS
- Valor: -XX:PermSize=256m -XX:MaxPermSize=256m -Xms512m -Xmx768m
- Descripción: Obligatoria. Pueden agregarse cualquier tipo de parámetros a la máquina virtual de Java al iniciar el servidor.
En el caso de ejemplo se aumenta la memoria reservada para el cargador de clases-XX:PermSize=256m -XX:MaxPermSize=256m
y para la para la pila-Xms512m -Xmx768m
- ORACLE_HOME
- Valor:
<Directorio_Instalacion_OC4j>/OC4J_TRUNK
. Dentro del Path del sistema debe incluirse el siguiente valor%ORACLE_HOME%bin;
permitiendo el arranque y parada del servidor des de la consola de comandos de Windows. - Descripción: Obligatoria. Apunta al directorio raíz de la instalación del OC4J. Es obligatorio definir esta variable si se desea ejecutar un script ejecutable del servidor mediante el fichero OC4J.
- Valor:
Imágenes con atributos alt
10-04-2014 - xavsal
En desarrollos donde se emplee el tag img
para que aparezca correctamente el mensaje al pasar por encima el ratón, será necesario añadir también el atributo title
.
En el siguiente enlace se puede comprobar cómo funciona correctamente:
En la documentación oficial del W3Schools no aparece el atributo title
. Todo parece indicar que es una especificación del IE10. No he sido capaz de encontrar un enlace donde oficialmente reste documentada esta implementación específica.
Sin embargo se confirma que si se utilizan los dos atributos (alt
y title
) conjuntamente se muestra correctamente el tip allí donde se haya aplicado y al pasar el ratón por encima aparece el mensaje de texto correctamente.
Método Unscape en Javascript
10-04-2014 - xavsal
En el proyecto actual en el que estoy trabajando, se ha creado una URL mediante la API de Java y se ha transmitido mediante una petición al navegador web.
Se ha producido un error en la transformación y su interpretación del navegador web de dicha URL dado que la cadena de texto obtenida por el navegador ha sido ésta:
http://www.direccion.es/dominio?param1=valor1¶m2=valor2
Para solucionar el problema basta con utilizar el método unescape
de Javascript.