Skip to content

Instantly share code, notes, and snippets.

@picodotdev
Created November 15, 2013 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save picodotdev/7486550 to your computer and use it in GitHub Desktop.
Save picodotdev/7486550 to your computer and use it in GitHub Desktop.
Ejemplo del patrón de diseño Command y programación concurrente en Java http://elblogdepicodev.blogspot.com/2012/04/ejemplo-del-patron-de-diseno-command-y.html
package com.blogspot.elblogdepicodev.services.commands;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.Callable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.blogspot.elblogdepicodev.domain.Producto;
import com.blogspot.elblogdepicodev.services.Service;
class ActualizarDatosProductoCallable implements Callable<Object> {
private static Logger logger = LoggerFactory.getLogger(ActualizarDatosProductoCallable.class);
private Service service;
private Producto producto;
public ActualizarDatosProductoCallable(Service service, Producto producto) {
this.service = service;
this.producto = producto;
}
@Override
public Object call() {
long start = System.currentTimeMillis();
logger.info("Actualizando datos del producto ({})", producto.getId());
Producto p = service.getCrudServiceDAO().get(Producto.class, producto.getId());
// Recalcular datos
...
service.getCrudServiceDAO().update(p);
long end = System.currentTimeMillis();
logger.info("Datos del producto actualizados ({}) [{} ms]", p.getId(), end - start);
return null;
}
}
package com.blogspot.elblogdepicodev.services.commands;
import java.util.concurrent.Callable;
import com.blogspot.elblogdepicodev.domain.Producto;
import com.blogspot.elblogdepicodev.misc.Mensaje;
import com.blogspot.elblogdepicodev.services.Service;
public class CallableFactory {
private CallableFactory() {
}
public static Callable<Object> createActualizarDatosProductoCallable(Service service, Producto producto) {
return new ActualizarDatosProductoCallable(service, producto);
}
public static Callable<Object> createEnviarEmailCallable(Service service, Mensaje mensaje) {
return new EnviarEmailCallable(service, mensaje);
}
}
package com.blogspot.elblogdepicodev.services;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
public interface CallableService<T> {
public void submit(Callable<T> callable);
public void submit(Collection<Callable<T>> callables) throws InterruptedException;
}
package com.blogspot.elblogdepicodev.services;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CallableServiceImpl implements CallableService<Object> {
private static Logger logger = LoggerFactory.getLogger(CallableServiceImpl.class);
private ExecutorService executorService;
public CallableServiceImpl(ExecutorService executorService) {
this.executorService = executorService;
}
public ExecutorService getExecutorService() {
return executorService;
}
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public void submit(Callable<Object> tarea) {
logger.info("Añadiendo una tarea a la cola (Clase: {})", tarea.getClass().getName());
executorService.submit(tarea);
}
@Override
public void submit(Collection<Callable<Object>> tareas) throws InterruptedException {
logger.info("Añadiendo {} tareas a la cola", tareas.size());
executorService.invokeAll(tareas);
}
}
package com.blogspot.elblogdepicodev.services.commands;
import java.io.StringWriter;
import java.util.concurrent.Callable;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.blogspot.elblogdepicodev.misc.Constantes;
import com.blogspot.elblogdepicodev.misc.Mensaje;
import com.blogspot.elblogdepicodev.services.Service;
public class EnviarEmailCallable implements Callable<Object> {
private static Logger logger = LoggerFactory.getLogger(EnviarEmailCallable.class);
private Service service;
private Mensaje mensaje;
public EnviarEmailCallable(Service service, Mensaje mensaje) {
this.service = service;
this.mensaje = mensaje;
}
@Override
public Object call() {
try {
long start = System.currentTimeMillis();
logger.info("Obteniendo sesión para enviar correos electrónicos");
Context ic = new InitialContext();
Session session = (Session) ic.lookup(Constantes.JNDI_MAIL);
// Obtener el contenido del email
StringWriter out = new StringWriter();
service.getFreemarkerService().procesar(mensaje.getPlantilla(), mensaje.getLocale(), mensaje.getDatos(), out);
String texto = out.toString();
// Construir el mensaje a enviar
MimeMessage mm = new MimeMessage(session);
mm.setFrom(new InternetAddress(Constantes.EMAIL_REMITENTE));
if (mensaje.getDesinatarios().size() == 1) {
String destinatario = mensaje.getDesinatarios().iterator().next();
mm.addRecipient(Message.RecipientType.TO, new InternetAddress(destinatario));
} else {
mm.addRecipient(Message.RecipientType.TO, new InternetAddress(Constantes.EMAIL_REMITENTE));
for (String d : mensaje.getDesinatarios()) {
mm.addRecipient(Message.RecipientType.BCC, new InternetAddress(d));
}
}
mm.setSubject(mensaje.getAsunto());
mm.setText(texto, "utf-8", "html");
// Enviar el mensaje
logger.info("Enviando correo electrónico a {} destinatarios", mm.getAllRecipients().length);
Transport.send(mm);
long end = System.currentTimeMillis();
logger.info("Correo electrónico enviado [{} ms]", end - start);
} catch (MessagingException e) {
logger.warn(e.getMessage(), e);
// Devolver el comando al final de la cola para un posterior intento
service.getCallableService().submit(this);
} catch (Exception e) {
// Ha ocurrido algo grave, descartar el mensaje
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
return null;
}
}
package com.blogspot.elblogdepicodev.misc;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class Mensaje {
private String plantilla;
private Locale locale;
private Set<String> desinatarios;
private String asunto;
private Map datos;
public Mensaje(String plantilla, Locale locale, String destinatario, String asunto, Map datos) {
this(plantilla, locale, Collections.singleton(destinatario), asunto, datos);
}
public Mensaje(String plantilla, Locale locale, Set<String> destinatarios, String asunto, Map datos) {
this.plantilla = plantilla;
this.locale = locale;
this.desinatarios = destinatarios;
this.asunto = asunto;
this.datos = datos;
}
public String getPlantilla() {
return plantilla;
}
public Locale getLocale() {
return locale;
}
public Set<String> getDesinatarios() {
return desinatarios;
}
public String getAsunto() {
return asunto;
}
public Map getDatos() {
return datos;
}
}
package com.blogspot.elblogdepicodev.services;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
...
public interface Service {
...
public CrudServiceDAO getCrudServiceDAO();
public DataService getDataService();
public CacheManager getCacheManager();
public FreeMarkerService getFreemarkerService();
public CallableService getCallableService();
public SchedulerService getSchedulerService();
//
...
//
public void actualizarDatos(Evento evento);
//
public void enviarMail(String layout, String plantilla, Locale locale, String destinatario, String asunto, Map datos);
public void enviarMail(String layout, String plantilla, Locale locale, Set destinatarios, String asunto, Map datos);
}
package com.blogspot.elblogdepicodev.services;
...
public class ServiceImpl implements Service {
private static Logger logger = LoggerFactory.getLogger(ServiceImpl.class);
private CrudServiceDAO crudServiceDAO;
private DataService dataService;
private CacheManager cacheManager;
private FreeMarkerService freemarkerService;
private CallableService callableService;
private SchedulerService schedulerService;
...
public ServiceImpl(CrudServiceDAO crudServiceDAO, DataService dataService, CacheManager cacheManager, FreeMarkerService freemarkerService,
CallableService callableService, SchedulerService schedulerService, DatosPlantillaSource datosPlantillaSource) {
this.crudServiceDAO = crudServiceDAO;
this.dataService = dataService;
this.cacheManager = cacheManager;
this.freemarkerService = freemarkerService;
this.callableService = callableService;
this.schedulerService = schedulerService;
this.datosPlantillaSource = datosPlantillaSource;
}
@Override
public CrudServiceDAO getCrudServiceDAO() {
return crudServiceDAO;
}
@Override
public DataService getDataService() {
return dataService;
}
@Override
public CacheManager getCacheManager() {
return cacheManager;
}
@Override
public FreeMarkerService getFreemarkerService() {
return freemarkerService;
}
@Override
public CallableService getCallableService() {
return callableService;
}
@Override
public SchedulerService getSchedulerService() {
return schedulerService;
}
...
@Override
public void reinicializarContrasena(Usuario usuario) {
logger.info("Enviando solicitud de reinicialización de contraseña para el usuario {}", usuario.getId());
// Preparar la reinicialización de la contraseña
usuario.setTokenReinicializarContrasena(RandomStringUtils.randomAlphanumeric(Constantes.LONGITUD_TOKEN));
usuario.setFechaSolicitudReinicializarContrasena(DateTime.now());
crudServiceDAO.update(usuario);
// Enviar correo electrónico de solicitud
Locale l = Utilidades.decodeLocale(usuario.getIdioma());
Map datos = Utilidades.map("usuario", usuario);
enviarMail(LAYOUT_PRINCIPAL, PLANTILLA_EMAIL_SOLICITUD_REINICIALIZAR_CONTRASENA, l, usuario.getEmail(), "Solicitud_de_reinicializacion_de_contrasena", datos);
}
@Override
public boolean confirmarReinicializarContrasena(Usuario usuario, String token) {
// Validar el cambio de contraseña
DateTime d = DateTime.now().minusDays(Constantes.DIAS_VALIDEZ_SOLICITUD_CAMBIO_CONTRASENA);
boolean b1 = usuario.getTokenReinicializarContrasena() != null && usuario.getTokenReinicializarContrasena().equals(token);
boolean b2 = usuario.getFechaSolicitudReinicializarContrasena() != null && usuario.getFechaSolicitudReinicializarContrasena().isAfter(d);
boolean b = b1 && b2;
if (b) {
logger.info("Reinicializando contraseña para el usuario {}", usuario.getId());
// Realizar el cambio de contraseña
String contrasena = RandomStringUtils.randomAlphanumeric(Constantes.LONGITUD_TOKEN);
usuario.setTokenReinicializarContrasena(null);
usuario.setFechaSolicitudReinicializarContrasena(null);
usuario.setContrasena(DigestUtils.md5Hex(contrasena));
crudServiceDAO.update(usuario);
// Enviar correo electrónico de confirmación
Locale l = Utilidades.decodeLocale(usuario.getIdioma());
Map datos = Utilidades.map("usuario", usuario, "contrasena", usuario.getContrasena());
enviarMail(LAYOUT_PRINCIPAL, PLANTILLA_EMAIL_CONTRASENA_REINICIALIZADA, l, usuario.getEmail(), "Contrasena_reinicizalizada", datos);
} else {
logger.info("Reinicializanción de contraseña para el usuario {} fallida (Token: {}, Fecha: {})", new Object[] { usuario.getId(), b1, b2 });
}
return b;
}
...
@Override
public void actualizarDatos(Evento evento) {
Callable c = CallableFactory.createActualizarDatosEventoCallable(this, evento);
callableService.submit(c);
}
...
public void enviarMail(String layout, String plantilla, Locale locale, String destinatario, String asunto, Map datos) {
enviarMail(layout, plantilla, locale, Collections.singleton(destinatario), asunto, datos);
}
public void enviarMail(String layout, String plantilla, Locale locale, Set destinatarios, String asunto, Map datos) {
// Enviar correo electrónico de la solicitud
String a = ServiciosUtils.getBundle(locale).getString(asunto);
DatosPlantilla ddp = datosPlantillaSource.getDatos(layout);
DatosPlantilla dp = datosPlantillaSource.getDatos(plantilla);
dp.setDatosPlantilla(ddp.getMap());
dp.setDatos(datos);
Mensaje m = new Mensaje(plantilla, locale, destinatarios, a, dp.getMap());
Callable c = CallableFactory.createEnviarEmailCallable(this, m);
callableService.submit(c);
}
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment