jueves, 25 de agosto de 2011

PHP Cache

Una estrategia de cache es siempre una de las primeras opciones a tomar cuando se requiere mejorar el desempeño de una aplicación. Recientemente tuve que buscar una opción disponible para una aplicación web que estabamos trabajando en PHP, y de las que consulté por Internet, me quedé con la que ofrece este amigo en este artículo.

Esta clase PHPCache utiliza una tabla en base de datos con tres columnas como mecanismo de almacenamiento del cache:
  • PHPCache_key: la llave del objeto a guardar
  • PHPCache_value: el valor a guardar
  • PHPCache_expires: cuando expira el objeto en cache
Nuestro amigo ofrece un código que ejemplifica muy bien el uso de la clase:

require_once 'phpcache.class.php'; // Se incluye la clase de PHPCache.

// Parametros de conexión de la Base de datos.
$database = array(
'type' => 'mysql',
'name' => 'YOUR DATABASE NAME',
'table' => 'PHPCache',
'user' => 'YOUR DATABASE USERNAME',
'pass' => 'YOUR DATABASE USERNAME\'S PASSWORD',
'host' => 'localhost' /* Or maybe IP address of your database server */
);

// Llamado de configuración de la base de datos.
PHPCache::configure($database);
// Se obtiene una única instancia (patrón Singleton).
$cache = PHPCache::instance();

// Se pregunta primero si los resultados ya están en cache.
if( ($results = $cache->get('result_of_some_nasty_code')) !== false ) {
$tpl->assign($results);
/* Or maybe return $results or whatever depending on where you use this */
} else {
// Los datos todavía no estan en cache. Hay que obtenerlos de la manera lenta.
/***********************
* Your slow code here
***********************/
// Inmediatamente se guardan en cache. La siguiente vez no se hará de la forma lenta.
$cache->store('result_of_some_nasty_code', $results_of_your_slow_code, PHPCACHE_1_HOUR * 5); /* Cache for 5 hours */
}

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.


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);
}
}
}


miércoles, 10 de agosto de 2011

PHP: Cálculo de semana laboral actual

Dejo a disposición un código que permite obtener la semana laboral actual (lunes a viernes tomando domingo como inicio de semana).

Salida del código:

From: 08-08-2011 To: 08-12-2011


<?php


class DateUtils {

public static function get_current_date() {
return substr(DateUtils::get_current_date_time(), 0, 10);
}

public static function get_current_date_time() {
return date('Y-m-d H:i:s');
}

public static function get_day_of_current_week_as_number() {
return date("w",mktime());
}

public static function get_day_of_week_as_number($date_as_string) {
return date("w", strtotime($date_as_string));
}

public static function substract_days_to_current_date($days) {
$operation = "-";

if ($days < 0) {
$operation = "+";
$days = abs($days);
}
$newdate = strtotime ( $operation. $days .' day' ,strtotime ( date('Y-m-d') )) ;
return date ( 'm-d-Y' , $newdate );
}

public static function substract_days_to_date($date_as_string, $days) {

$operation = "-";

if ($days < 0) {
$operation = "+";
$days = abs($days);
}
$newdate = strtotime ( $operation . $days .' day' , strtotime ( $date_as_string) ) ;
$newdate = date ( 'm-d-Y' , $newdate );
return $newdate;
}

public static function get_start_day_of_current_work_week() {
$monday_delta = 0;
$current_day_of_week = DateUtils::get_day_of_current_week_as_number();

if($current_day_of_week > 1) {
$monday_delta = $current_day_of_week-1;
} else if($current_day_of_week == 0){
$monday_delta = -1;
}
return DateUtils::substract_days_to_current_date($monday_delta);
}

public static function get_start_day_of_work_week($date_as_string) {
$monday_delta = 0;
$day_of_week = DateUtils::get_day_of_week_as_number($date_as_string);

if($day_of_week > 1) {
$monday_delta = $day_of_week-1;
} else if($day_of_week == 0){
$monday_delta = -1;
}
return DateUtils::substract_days_to_date($date_as_string, $monday_delta);
}

public static function get_delta_for_end_day_of_work_week($current_day_of_week) {
$friday_delta = 0;

switch ($current_day_of_week) {
case 0: // Sunday.
$friday_delta=-5;
break;
case 1: // Monday.
$friday_delta=-4;
break;
case 2: // Tuesday.
$friday_delta=-3;
break;
case 3: // Wednesday.
$friday_delta=-2;
break;
case 4: // Thursday.
$friday_delta=-1;
break;
case 5: // Friday.
$friday_delta=0;
break;
case 6: // Saturday.
$friday_delta=1;
break;
}
return $friday_delta;
}

public static function get_end_day_of_current_work_week() {
$friday_delta = 0;
$current_day_of_week = DateUtils::get_day_of_current_week_as_number();

return DateUtils::
substract_days_to_current_date(DateUtils::
get_delta_for_end_day_of_work_week($current_day_of_week ));
}

public static function get_end_day_of_work_week($date_as_string) {
$friday_delta = 0;
$current_day_of_week = DateUtils::get_day_of_week_as_number($date_as_string);

return DateUtils::
substract_days_to_date($date_as_string, DateUtils::
get_delta_for_end_day_of_work_week($current_day_of_week ));
}

public static function get_current_work_week_range() {
return "From: " . DateUtils::get_start_day_of_current_work_week() . " To: "
. DateUtils::get_end_day_of_current_work_week();
}

}
echo "<h1>" . DateUtils::get_current_work_week_range() . "</h1>";
?>


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.