Created
November 15, 2013 15:50
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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