Spring Mail com VRaptor 3

36 respostas
Guevara

Oi gente! o/
Tô seguindo o manual do spring mail (http://static.springsource.org/spring/docs/2.5.x/reference/mail.html), mas além de estar mal explicado, manda colocar configuração no aplicationContext.xml. Como eu uso VRaptor 3 pensei numa forma melhor de usar isso através de DI.
Achei este tutorial, mas tb não me dá a pista de como fazer a integração do spring mail com Vraptor 3.
http://lucastex.com.br/category/spring/

Fiz aqui seguindo o manual:

public interface Email {
	
	void enviar(Contato contato);

}

E a classe Newsletter:

@Component
public class Newsletter implements Email  {
	
	private MailSender mailSender;
    private SimpleMailMessage templateMessage;
    private ImovelDAO imovelDAO;

    public void setMailSender(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void setTemplateMessage(SimpleMailMessage templateMessage) {
        this.templateMessage = templateMessage;
    }
    
    public Newsletter(ImovelDAO imovelDAO) {
    	this.imovelDAO = imovelDAO;    	
    }

    public void enviar(Contato contato) {        

        // Create a thread safe "copy" of the template message and customize it        
        List <Imovel> imoveis = imovelDAO.listaDestaque();
        
        for (Imovel imovel : imoveis) {
            
        // Formatando a data de inclusao
        DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
        String dataInclusao = formatter.format(imovel.getDataInclusao());
             
        // Formatando o valor
        BigDecimal valor = imovel.getValor();
        NumberFormat nf = NumberFormat.getCurrencyInstance();
        
        
        SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
        msg.setTo(contato.getEmail());
        msg.setSubject("Newsletter - Imobiliária");
        msg.setText(
        		"Código: " + imovel.getCodImovel() + "<br>" +            
                "Título: " + imovel.getTitulo() + "<br>" + 
                "Tipo: " + imovel.getTipo().getNome() + "<br>" + 
                "Modalidade: " + imovel.getModalidade().getTipoModalidade() + "<br>" +
                "Bairro: " + imovel.getEndereco().getBairro() + "<br>" + 
                "Estado: " + imovel.getEndereco().getEstado() + "<br>" +
                "Área: " + imovel.getArea() + "<br>" + 
                "Valor: " +  nf.format(valor) + "<br>" +
                "Quartos: " +  imovel.getQuartos() + "<br>" +
                "Data de inclusão: " + dataInclusao + "<br/><br/>"); 
        
        
        try{
            this.mailSender.send(msg);
        }
        catch(MailException ex) {
            // simply log it and go on...
            System.err.println(ex.getMessage());            
        }
    }

  }
}

Criando a pasta templates em WEB-INF/templates como posso integrar td com VRaptor sem usar o xml do spring?
Tipo, as configurações da conta:

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
  <property name="host" value="${mail.smtp.host}" />
  <property name="username" value="${mail.smtp.user}" />
  <property name="password" value="${mail.smtp.pass}" />
  <property name="port" value="${mail.smtp.port}" />
</bean>

Até tenho um aplicationContext.xml, mas será usado pro spring security, já não queria usá-lo pra não ficar muita coisa em xml, agora veio essa ai do spring mail pra atrapalhar. =/
Abraço!!

36 Respostas

Lucas_Cavalcanti

vc pode criar uma ComponentFactory de MailSender

algo assim:

@Component
//@ApplicationScope?
public class MailSenderFactory implements ComponentFactory<MailSender> {
      // instancia um JavaMailSenderImpl, seta as propriedades e guarda num field

      public MailSender getInstance() {
           return mailSender;
      }
}
Guevara

Oi Lucas!!
Antes de usar o spring mail, tô fazendo o teste do scheduler com commons mail, só falta resolver este probleminha pra dar certo.
Está injetando nulo o DAO de contatos:

INFO: Server startup in 3910 ms
13:40:00,090 ERROR [JobRunShell         ] Job DEFAULT.schedulerJob threw an unhandled Exception: 
java.lang.NullPointerException
	at br.com.imobiliaria.quartz.SchedulerTask.run(SchedulerTask.java:40)
	at br.com.imobiliaria.quartz.SchedulerJob.executeInternal(SchedulerJob.java:28)
	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
	at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
13:40:00,092 ERROR [ErrorLogger         ] Job (DEFAULT.schedulerJob threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException]
	at org.quartz.core.JobRunShell.run(JobRunShell.java:227)
	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
Caused by: java.lang.NullPointerException
	at br.com.imobiliaria.quartz.SchedulerTask.run(SchedulerTask.java:40)
	at br.com.imobiliaria.quartz.SchedulerJob.executeInternal(SchedulerJob.java:28)
	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
	at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
	... 1 more
23/09/2010 13:40:36 org.apache.coyote.http11.Http11Protocol pause
INFO: Pausing Coyote HTTP/1.1 on http-8080
23/09/2010 13:40:37 org.apache.catalina.core.StandardService stop

A linha SchedulerTask.java:40 é esta:

List <Contato> contatos = contatoDAO.listaContatos();

A lista funciona pq estou usando em outras classes, já tentei anotar o costrutor com @Autowired e não deu certo, continua injetando nulo. =/
Sabe o que pode ser?
Abraço!!

Lucas_Cavalcanti

quem instancia a task?

Guevara

Está td no AplicationContext.xml:

<!-- Scheduler task -->
   <beans:bean name="schedulerTask" class="br.com.imobiliaria.quartz.SchedulerTask" />

<!-- Scheduler job -->
  <beans:bean name="schedulerJob" class="org.springframework.scheduling.quartz.JobDetailBean"> 
     <beans:property name="jobClass" value="br.com.imobiliaria.quartz.SchedulerJob" /> 
     <beans:property name="jobDataAsMap">
	    <beans:map>
	      <beans:entry key="schedulerTask" value-ref="schedulerTask" />
	     </beans:map>
      </beans:property>
   </beans:bean>	

<!-- Cron Trigger -->
	<beans:bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
		<beans:property name="jobDetail" ref="schedulerJob" />
		<beans:property name="cronExpression" value="0 * * * * ?" /> 
	</beans:bean>
	
	<!-- Scheduler -->
   <beans:bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<beans:property name="jobDetails">
	   <beans:list>
	      <beans:ref bean="schedulerJob" />
	   </beans:list>
	</beans:property>
 
	<beans:property name="triggers">
	    <beans:list>
		<beans:ref bean="cronTrigger" />
	    </beans:list>
	</beans:property>
   </beans:bean>

Ai tenho a classe Schedulertask, que é a classe que será executada:

public class SchedulerTask {
	
	private ImovelDAO imovelDAO;
	private ContatoDAO contatoDAO;
	
	public SchedulerTask() {
	}
	
	public SchedulerTask(ImovelDAO imovelDAO, ContatoDAO contatoDAO) {
		this.imovelDAO = imovelDAO;
		this.contatoDAO = contatoDAO;
	}
	
	public void run() throws MalformedURLException {
		
		
		HtmlEmail email = new HtmlEmail();
		
		List <Contato> contatos = contatoDAO.listaContatos(); // AQUI É O PROBLEMA  
		for(Contato contato: contatos) {
			
		try {
			email.setDebug(true);
			email.setHostName("smtp.gmail.com");			
			email.setFrom("[email removido]", "Gerente");
			email.setAuthentication("eu","senha");  
			email.setSSL(true);  			
			email.addTo(contato.getEmail(), contato.getPessoa().getNome());
			email.setSubject("Newsletter - Imobiliária");

			// embed the image and get the content id
			URL url = new URL("http://www.tabetealmeida.com.br/_imagens/logo.png");
			String cid = email.embed(url, "Imobiliária logo");

			// set the html message
			List <Imovel> imoveis = imovelDAO.lista();	// AQUI É O PROBLEMA		
            StringBuilder html = new StringBuilder();
            html.append("<html><body><img src=\"cid:"+cid+"\"><br><body>Olá " + contato.getPessoa().getNome() +"!" + "<br>" +
            "Estamos enviando as últimas novidades, Confira!" + "<br>" +  "<br/>");
            for (Imovel imovel : imoveis) {
            
           // Formatando a data de inclusao
            DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
            String dataInclusao = formatter.format(imovel.getDataInclusao());
            
            // Formatando o valor
            BigDecimal valor = imovel.getValor();
            NumberFormat nf = NumberFormat.getCurrencyInstance();
            	
            html.append(
            "Código: " + imovel.getCodImovel() + "<br>" +            
            "Título: " + imovel.getTitulo() + "<br>" + 
            "Tipo: " + imovel.getTipo().getNome() + "<br>" + 
            "Modalidade: " + imovel.getModalidade().getTipoModalidade() + "<br>" +
            "Bairro: " + imovel.getEndereco().getBairro() + "<br>" + 
            "Estado: " + imovel.getEndereco().getEstado() + "<br>" +
            "Área: " + imovel.getArea() + "<br>" + 
            "Valor: " +  nf.format(valor) + "<br>" +
            "Quartos: " +  imovel.getQuartos() + "<br>" +
            "Data de inclusão: " + dataInclusao + "<br/><br/>");           
			}
            html.append("Att. <br/> Bruno - Gerente de vendas - =P"+"</body></html>");
            email.setHtmlMsg(html.toString());
			
			//enviando conteudo em HTML que vem por parametro
			//email.setContent("conteudo", "text/html");
			// set the alternative message
			email.setTextMsg("Seu servidor de e-mail não suporta mensagem HTML");
			// send the email
			email.send();
			
			
			
		} catch (EmailException e) {
			System.out.println(e.getMessage()); 
		}	
	}
  }
}

E no SchedulerJob:

public class SchedulerJob extends QuartzJobBean {
	
	private SchedulerTask schedulerTask;
	
	public SchedulerJob() {
	}
	
	public SchedulerJob(SchedulerTask schedulerTask) {
		this.schedulerTask = schedulerTask;
	}		
	 
	public void setSchedulerTask(SchedulerTask schedulerTask) {
		this.schedulerTask = schedulerTask;
	}
 
	protected void executeInternal(JobExecutionContext context)
	throws JobExecutionException {	
	
		try {
			schedulerTask.run(); // aqui executo o metodo de envio de emails
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	
	}
}

Tanto a lista de contato como de imóveis está injetando nulo.
Abraço!

Lucas_Cavalcanti

o problema é que vc tem dois construtores e o spring vai usar o sem argumentos, por isso que o dao fica nulll…

um problema é que os componentes registrados no VRaptor não são visíveis no Spring =*(

tem alguma forma programática de configurar o Spring Mail? ou programática ou via anotações?

Guevara

Então, no spring é pelo xml mesmo, estou seguindo esta dica:
http://www.mkyong.com/struts2/struts-2-spring-quartz-scheduler-integration-example/

Eu tive que criar o construtor vazio pq ele acusava erro, dizendo que não existia o construtor, mesmo existindo o construtor preenchido, doidera. O.o
Aí tentei mandar uma anotação @Autowired no construtor preenchido, mas nem se abalou. =/

Mas ai descobri que o VRaptor 3 conseque startar uma task desde que quem implemente as interfaces esteja anotado com @Component e @ApplicationScoped:
http://vraptor.caelum.com.br/cookbook/job-scheduling-com-vraptor3-e-spring/

Vou tentar adaptar pro meu caso…

Lucas_Cavalcanti

isso, era a minha proxima opção =)

Guevara

Acho que têm alguma coisa errada no tutorial, a classe Runnable possui método run(), a classe que herda possui método schedule(), beleza, agora a classe MyFirstApplicationTask acusa:

The type MyFirstApplicationTask must implement the inherited abstract method Runnable.run()

Não está enxergando o método schedule() da classe Task. Ai neste método:

public void schedule(TaskScheduler scheduler) {
        scheduler.schedule(this, new CronTrigger("0 0 23 * * *")); // aqui
        //Neste caso, a task rodará sempre às 23h0min0s
    }

Manda esta mensagem:

The method schedule(Runnable, Trigger) in the type TaskScheduler is not applicable for the arguments (MyFirstApplicationTask, CronTrigger)

Agora ferrou, preciso sobrescrever esse método que está como Trigger para CronTrigger, como posso fazer isso Lucas?

Lucas_Cavalcanti

MyFirstApplicationTask implementa Runnable?
deveria

Guevara

Então, o autor fez uma herança lá, está assim:
Runnable << Task << ApplicationTask <-- MyFirstApplicationTask
Onde << é herança e <-- é implementação da interface. O component MyFirstApplicationTask deveria enxergar o método na interface Task:

public interface Task extends Runnable {
	void schedule(TaskScheduler scheduler);
}

Está ignorando este método e exigindo o método run() na Runnable. =/

Lucas_Cavalcanti

tah compilando no eclipse mas qdo vc roda dah esse erro de compilação?

dá um clean no projeto e no servidor, e vê se roda

Guevara

Continua a mensagem:

The method schedule(Runnable, Trigger) in the type TaskScheduler is not applicable for the arguments (Newsletter, CronTrigger)

O método schedule está esperando trigger, mas o autor da receita usou CronTrigger (que é o que eu queria usar mesmo), como ele conseguiu essa façanha?? O.o

Lucas_Cavalcanti

Newsletter é um Runnable?
CronTrigger é um Trigger?

Guevara

Veja o que o autor da receita postou:

@Component
@ApplicationScoped
public class MyFirstApplicationTask implements ApplicationTask {
    public MyFirstApplicationTask(TaskScheduler scheduler) {
        //Aqui você poderá receber componentes que não estejam em
        //escopo de request ou session
        ...
        this.schedule(scheduler);
    }
    public void schedule(TaskScheduler scheduler) {
        scheduler.schedule(this, new CronTrigger("0 0 23 * * *")); // aqui espera trigger e ele colocou CronTrigger.
        //Neste caso, a task rodará sempre às 23h0min0s
    }
}

A minha classe Newsletter:

@Component
@ApplicationScoped
public class Newsletter implements ApplicationTask {
	
	public Newsletter(TaskScheduler scheduler) {
        this.schedule(scheduler);
    }
	
    public void schedule(TaskScheduler scheduler) {
        scheduler.schedule(this, new CronTrigger("0 0 23 * * *")); 
        //Neste caso, a task rodará sempre às 23h0min0s
    }

}

Fiz igual… =/

Lucas_Cavalcanti

Lucas Cavalcanti:
Newsletter é um Runnable?
CronTrigger é um Trigger?

Lucas_Cavalcanti

Pergunta melhor: vc tah usando o CronTrigger do spring ou o do quartz?

tenta trocar

Guevara

Refiz td de novo, o certo era:

Agora não entendi este construtor dentro do MyFirstRequestTask:

Criei essa classe e manda implementar o método run() tb, não tô entendendo com funciona isso não. Se já tenho a MyFirstApplicationTask, pra que essa outra?
Abraço!

Lucas_Cavalcanti

o construtor é só pra dizer q vc pode receber qqer dependência

vc precisa implementar o método run, que é o que a sua task vai fazer de fato

o método schedule é só pra vc agendar sua task, entendeu?

Guevara

Entendi, o que não entendi é pq ele colocou o nome do construtor diferente do nome da classe:

public class MyFirstRequestTask implements RequestTask {
public MyFirstApplicationTask() { 
}

Tá certo isso?

Quem vai de fato executar a minha classe de envio de email? MyFirstApplicationTask ou MyFirstRequestTask? Fiquei confuso com isso agora. O.o

Lucas_Cavalcanti

acho que foi erro de Ctrl+C e Ctrl+V :stuck_out_tongue:

Guevara

Beleza! :smiley:

Coloquei o código de envio de email no método run() da MyFirstApplicationTask:

@Component
@ApplicationScoped
public class MyFirstApplicationTask implements ApplicationTask {

	private ImovelDAO imovelDAO;
	private ContatoDAO contatoDAO;

	
	 public MyFirstApplicationTask(TaskScheduler scheduler, ImovelDAO imovelDAO
			 , ContatoDAO contatoDAO) {
	        //Aqui você poderá receber componentes que não estejam em
	        //escopo de request ou session
	        this.schedule(scheduler);
	        this.contatoDAO = contatoDAO;
	        this.imovelDAO = imovelDAO;
	    }
	    public void schedule(TaskScheduler scheduler) {
	        scheduler.schedule(this, new CronTrigger("0 * * * * ?"));
	    }
		public void run(){		
			HtmlEmail email = new HtmlEmail();
			
			List<Contato> contatos = contatoDAO.listaContatos();
			for(Contato contato : contatos) {
			try {
				email.setDebug(true);
				email.setHostName("smtp.gmail.com");			
				email.setFrom("[email removido]", "Gerente");
				email.setAuthentication("eu","senha");  
				email.setSSL(true);  
				email.addTo(contato.getEmail());
				email.setSubject("Newsletter - Imobiliária");

				// embed the image and get the content id
				URL url = new URL("http://www.tabetealmeida.com.br/_imagens/logo.png");
				String cid = email.embed(url, "Imobiliária logo");

				// set the html message
				List <Imovel> imoveis = imovelDAO.lista();
	            StringBuilder html = new StringBuilder();
	            html.append("<html><body><img src=\"cid:"+cid+"\"><br><body>Olá " + contato.getPessoa().getNome() +"!" + "<br>" +
	            "Estamos enviando as últimas novidades, Confira!" + "<br>" +  "<br/>");
	            for (Imovel imovel : imoveis) {
	            
	           // Formatando a data de inclusao
	            DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
	            String dataInclusao = formatter.format(imovel.getDataInclusao());
	            
	            // Formatando o valor
	            BigDecimal valor = imovel.getValor();
	            NumberFormat nf = NumberFormat.getCurrencyInstance();
	            	
	            html.append(
	            "Código: " + imovel.getCodImovel() + "<br>" +            
	            "Título: " + imovel.getTitulo() + "<br>" + 
	            "Tipo: " + imovel.getTipo().getNome() + "<br>" + 
	            "Modalidade: " + imovel.getModalidade().getTipoModalidade() + "<br>" +
	            "Bairro: " + imovel.getEndereco().getBairro() + "<br>" + 
	            "Estado: " + imovel.getEndereco().getEstado() + "<br>" +
	            "Área: " + imovel.getArea() + "<br>" + 
	            "Valor: " +  nf.format(valor) + "<br>" +
	            "Quartos: " +  imovel.getQuartos() + "<br>" +
	            "Data de inclusão: " + dataInclusao + "<br/><br/>");           
				}
	            html.append("Att. <br/> Bruno - Gerente de vendas - =P"+"</body></html>");
	            email.setHtmlMsg(html.toString());
				
				//enviando conteudo em HTML que vem por parametro
				//email.setContent("conteudo", "text/html");
				// set the alternative message
				email.setTextMsg("Seu servidor de e-mail não suporta mensagem HTML");
				// send the email
				email.send();
				
				
			} catch (EmailException e) {
				System.out.println(e.getMessage()); 
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
		}
		}
}

A saida é esta:

20:56:38,805  INFO [DefaultListableBeanFactory] Overriding bean definition for bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor': replacing [Root bean: class [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [br.com.caelum.vraptor.ioc.spring.InjectionBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
20:56:38,806 DEBUG [VRaptorApplicationContext] Bean factory for Root WebApplicationContext: org.springframework.beans.factory.support.DefaultListableBeanFactory@1389b3f: defining beans [defaultTypeFinder,defaultResourceNotFoundHandler,XStreamXMLDeserializer,noRoutesConfiguration,emptyElementsRemoval,defaultInterceptorRegistry,defaultTypeNameExtractor,asmBasedTypeCreator,defaultMethodNotAllowedHandler,encodingHandlerFactory,hibernateProxyInitializer,defaultAcceptHeaderToFormat,objenesisProxifier,defaultMultipartConfig,JSR303ValidatorFactory,validatorFactoryCreator,defaultRestDefaults,defaultRouter,messageInterpolatorFactory,defaultDeserializers,paranamerNameProvider,pathAnnotationRoutesParser,defaultResourceTranslator,defaultRoutes,defaultConverters,stereotypeHandler,converterHandler,interceptorStereotypeHandler,deserializesHandler,stereotypedBeansRegistrar,defaultSpringLocator,resourceLookupInterceptor,executeMethodInterceptor,HTMLSerialization,applicationConfiguration,defaultHttpResult,jsonDeserializer,defaultPageResult,emptyResult,instantiateInterceptor,flashInterceptor,interceptorListPriorToExecutionExtractor,ognlParametersProvider,downloadInterceptor,defaultValidationViewsFactory,defaultRepresentationResult,defaultRefererResult,defaultFormatResolver,defaultResult,defaultRestHeadersHandler,outjectResult,forwardToDefaultViewInterceptor,parametersInstantiatorInterceptor,XStreamXMLSerialization,defaultStatus,JSR303Validator,jstlLocalization,commonsUploadMultipartInterceptor,deserializingInterceptor,replicatorOutjector,XStreamJSONSerialization,defaultLogicResult,defaultValidator,defaultPathResolver,defaultMethodInfo,bigDecimalConverter,bigIntegerConverter,booleanConverter,byteConverter,characterConverter,doubleConverter,enumConverter,floatConverter,integerConverter,localeBasedCalendarConverter,localeBasedDateConverter,longConverter,primitiveBooleanConverter,primitiveByteConverter,primitiveCharConverter,primitiveDoubleConverter,primitiveFloatConverter,primitiveIntConverter,primitiveLongConverter,primitiveShortConverter,shortConverter,uploadedFileConverter,VRaptorRequestProvider,httpServletRequestProvider,httpServletResponseProvider,httpSessionProvider,defaultRequestExecution,defaultInterceptorStack,entityManagerCreator,entityManagerFactoryCreator,JPATransactionInterceptor,modalidadeDAO,tipoDAO,usuarioDAO,fotoDAO,statusDAO,contatoDAO,proprietarioDAO,imovelDAO,loginController,tipoController,empresaController,fotoController,usuarioController,statusController,proprietarioController,modalidadeController,contatoController,newsletterController,indexController,relatoriosController,homeController,imovelController,noCacheInterceptor,newsletter,imagens,taskSchedulerFactory,myFirstRequestTask,customMultipartConfig,jasperMaker,myFirstApplicationTask,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,localeBasedBigDecimalConverter,localeBasedDoubleConverter,localeBasedFloatConverter,org.springframework.aop.config.internalAutoProxyCreator,cacheBasedTypeCreator]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@10fe2b9
20:56:39,126 DEBUG [VRaptorApplicationContext] Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@1dfd90f]
20:56:39,127 DEBUG [VRaptorApplicationContext] Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@1238785]
20:56:39,140  INFO [DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1389b3f: defining beans [defaultTypeFinder,defaultResourceNotFoundHandler,XStreamXMLDeserializer,noRoutesConfiguration,emptyElementsRemoval,defaultInterceptorRegistry,defaultTypeNameExtractor,asmBasedTypeCreator,defaultMethodNotAllowedHandler,encodingHandlerFactory,hibernateProxyInitializer,defaultAcceptHeaderToFormat,objenesisProxifier,defaultMultipartConfig,JSR303ValidatorFactory,validatorFactoryCreator,defaultRestDefaults,defaultRouter,messageInterpolatorFactory,defaultDeserializers,paranamerNameProvider,pathAnnotationRoutesParser,defaultResourceTranslator,defaultRoutes,defaultConverters,stereotypeHandler,converterHandler,interceptorStereotypeHandler,deserializesHandler,stereotypedBeansRegistrar,defaultSpringLocator,resourceLookupInterceptor,executeMethodInterceptor,HTMLSerialization,applicationConfiguration,defaultHttpResult,jsonDeserializer,defaultPageResult,emptyResult,instantiateInterceptor,flashInterceptor,interceptorListPriorToExecutionExtractor,ognlParametersProvider,downloadInterceptor,defaultValidationViewsFactory,defaultRepresentationResult,defaultRefererResult,defaultFormatResolver,defaultResult,defaultRestHeadersHandler,outjectResult,forwardToDefaultViewInterceptor,parametersInstantiatorInterceptor,XStreamXMLSerialization,defaultStatus,JSR303Validator,jstlLocalization,commonsUploadMultipartInterceptor,deserializingInterceptor,replicatorOutjector,XStreamJSONSerialization,defaultLogicResult,defaultValidator,defaultPathResolver,defaultMethodInfo,bigDecimalConverter,bigIntegerConverter,booleanConverter,byteConverter,characterConverter,doubleConverter,enumConverter,floatConverter,integerConverter,localeBasedCalendarConverter,localeBasedDateConverter,longConverter,primitiveBooleanConverter,primitiveByteConverter,primitiveCharConverter,primitiveDoubleConverter,primitiveFloatConverter,primitiveIntConverter,primitiveLongConverter,primitiveShortConverter,shortConverter,uploadedFileConverter,VRaptorRequestProvider,httpServletRequestProvider,httpServletResponseProvider,httpSessionProvider,defaultRequestExecution,defaultInterceptorStack,entityManagerCreator,entityManagerFactoryCreator,JPATransactionInterceptor,modalidadeDAO,tipoDAO,usuarioDAO,fotoDAO,statusDAO,contatoDAO,proprietarioDAO,imovelDAO,loginController,tipoController,empresaController,fotoController,usuarioController,statusController,proprietarioController,modalidadeController,contatoController,newsletterController,indexController,relatoriosController,homeController,imovelController,noCacheInterceptor,newsletter,imagens,taskSchedulerFactory,myFirstRequestTask,customMultipartConfig,jasperMaker,myFirstApplicationTask,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,localeBasedBigDecimalConverter,localeBasedDoubleConverter,localeBasedFloatConverter,org.springframework.aop.config.internalAutoProxyCreator,cacheBasedTypeCreator]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@10fe2b9
20:56:39,194  INFO [ThreadPoolTaskScheduler] Initializing ExecutorService 
20:56:39,257  INFO [DefaultListableBeanFactory] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1389b3f: defining beans [defaultTypeFinder,defaultResourceNotFoundHandler,XStreamXMLDeserializer,noRoutesConfiguration,emptyElementsRemoval,defaultInterceptorRegistry,defaultTypeNameExtractor,asmBasedTypeCreator,defaultMethodNotAllowedHandler,encodingHandlerFactory,hibernateProxyInitializer,defaultAcceptHeaderToFormat,objenesisProxifier,defaultMultipartConfig,JSR303ValidatorFactory,validatorFactoryCreator,defaultRestDefaults,defaultRouter,messageInterpolatorFactory,defaultDeserializers,paranamerNameProvider,pathAnnotationRoutesParser,defaultResourceTranslator,defaultRoutes,defaultConverters,stereotypeHandler,converterHandler,interceptorStereotypeHandler,deserializesHandler,stereotypedBeansRegistrar,defaultSpringLocator,resourceLookupInterceptor,executeMethodInterceptor,HTMLSerialization,applicationConfiguration,defaultHttpResult,jsonDeserializer,defaultPageResult,emptyResult,instantiateInterceptor,flashInterceptor,interceptorListPriorToExecutionExtractor,ognlParametersProvider,downloadInterceptor,defaultValidationViewsFactory,defaultRepresentationResult,defaultRefererResult,defaultFormatResolver,defaultResult,defaultRestHeadersHandler,outjectResult,forwardToDefaultViewInterceptor,parametersInstantiatorInterceptor,XStreamXMLSerialization,defaultStatus,JSR303Validator,jstlLocalization,commonsUploadMultipartInterceptor,deserializingInterceptor,replicatorOutjector,XStreamJSONSerialization,defaultLogicResult,defaultValidator,defaultPathResolver,defaultMethodInfo,bigDecimalConverter,bigIntegerConverter,booleanConverter,byteConverter,characterConverter,doubleConverter,enumConverter,floatConverter,integerConverter,localeBasedCalendarConverter,localeBasedDateConverter,longConverter,primitiveBooleanConverter,primitiveByteConverter,primitiveCharConverter,primitiveDoubleConverter,primitiveFloatConverter,primitiveIntConverter,primitiveLongConverter,primitiveShortConverter,shortConverter,uploadedFileConverter,VRaptorRequestProvider,httpServletRequestProvider,httpServletResponseProvider,httpSessionProvider,defaultRequestExecution,defaultInterceptorStack,entityManagerCreator,entityManagerFactoryCreator,JPATransactionInterceptor,modalidadeDAO,tipoDAO,usuarioDAO,fotoDAO,statusDAO,contatoDAO,proprietarioDAO,imovelDAO,loginController,tipoController,empresaController,fotoController,usuarioController,statusController,proprietarioController,modalidadeController,contatoController,newsletterController,indexController,relatoriosController,homeController,imovelController,noCacheInterceptor,newsletter,imagens,taskSchedulerFactory,myFirstRequestTask,customMultipartConfig,jasperMaker,myFirstApplicationTask,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,localeBasedBigDecimalConverter,localeBasedDoubleConverter,localeBasedFloatConverter,org.springframework.aop.config.internalAutoProxyCreator,cacheBasedTypeCreator]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@10fe2b9
20:56:39,258  INFO [ThreadPoolTaskScheduler] Shutting down ExecutorService
23/09/2010 20:56:39 org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter vraptor
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myFirstApplicationTask' defined in file [/home/bruno/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/imobiliaria/WEB-INF/classes/br/com/imobiliaria/component/MyFirstApplicationTask.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [br.com.imobiliaria.dao.ImovelDAO]: : Error creating bean with name 'imovelDAO': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'imovelDAO': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:718)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:194)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:993)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:897)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:574)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
	at br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.start(SpringBasedContainer.java:68)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.start(SpringProvider.java:82)
	at br.com.caelum.vraptor.VRaptor.init(VRaptor.java:110)
	at br.com.caelum.vraptor.VRaptor.init(VRaptor.java:103)
	at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:295)
	at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
	at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
	at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3838)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4488)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
	at org.apache.catalina.core.StandardService.start(StandardService.java:519)
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'imovelDAO': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:339)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:838)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:780)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:697)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:784)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:711)
	... 34 more
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
	at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:123)
	at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:40)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
	... 40 more
23/09/2010 20:56:39 org.apache.catalina.core.StandardContext start
SEVERE: Error filterStart
23/09/2010 20:56:39 org.apache.catalina.core.StandardContext start
SEVERE: Context [/imobiliaria] startup failed due to previous errors
23/09/2010 20:56:39 org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext
20:56:39,269  INFO [XmlWebApplicationContext] Closing Root WebApplicationContext: startup date [Thu Sep 23 20:56:37 BRT 2010]; root of context hierarchy
20:56:39,269  INFO [DefaultListableBeanFactory] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@10fe2b9: defining beans [org.springframework.security.web.PortMapperImpl#0,org.springframework.security.web.context.HttpSessionSecurityContextRepository#0,org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy#0,org.springframework.security.authentication.ProviderManager#0,org.springframework.security.access.vote.AffirmativeBased#0,org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0,org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator#0,org.springframework.security.authentication.AnonymousAuthenticationProvider#0,org.springframework.security.web.savedrequest.HttpSessionRequestCache#0,org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#0,org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0,org.springframework.security.config.http.UserDetailsServiceInjectionBeanPostProcessor#0,org.springframework.security.filterChainProxy,org.springframework.security.provisioning.JdbcUserDetailsManager#0,org.springframework.security.authentication.dao.DaoAuthenticationProvider#0,org.springframework.security.authentication.DefaultAuthenticationEventPublisher#0,org.springframework.security.authenticationManager,dataSource]; root of factory hierarchy
23/09/2010 20:56:39 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: A web application registered the JBDC driver [org.postgresql.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
log4j:ERROR LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.

Implementei no lugar certo agora né? hehe :smiley:

Lucas_Cavalcanti

Implementou no lugar certo sim, só tem um problema:
Vc não pode receber componentes Request scoped (o Dao) dentro de componentes ApplicationScoped =(

tem várias maneiras de resolver isso, uma delas é receber uma SessionFactory no construtor da Task e instanciar os Daos na mão

Guevara

SessionFactory na MyFirstApplicationTask? Mas se vou instanciar na mão preciso dessa session, a unica SessionFactory que existe aqui é a do Hibernate…

Guevara

Deu boa Lucas, mandou o email, instanciei na mão lá:

List<Contato> contatos = new ContatoDAO().listaContato();
List <Imovel> imoveis = new ImovelDAO().lista();

Vc tinha outra idéia pra não ter que instanciar dessa forma?

Lucas_Cavalcanti

seus daos recebem session no construtor?

da onde eles pegam a session?

se não forem eles que tomam conta da session, vc pode tentar anotá-los com @PrototypeScoped,
que vai funcionar tanto pra ApplicationScope quanto para RequestScope

Guevara

Isso, meus DAO’s pegam session no construtor:

public ContatoDAO(Session session) {
		this.session = session;
	}

Vou deixar assim então, está funcionando.
Já que é a MyFirstApplicationTask que executa o envio de emails, como poderia aproveitar a MyFirstRequestTask e MyResource?
Valeu!!

Lucas_Cavalcanti

o que vc quer dizer por aproveitar?

Guevara

Acho que entendi o esquema Lucas, fiz o seguinte:
Na classe MyFirstApplicationTask eu injetei no cnstrutor e declarei a minha classe News, que é a que possui o código de envio de email, e na News que é a tarefa a ser executada anotei com:

@Component
@PrototypeScoped
public class News {
// código de envio de email
}

Agora posso executar várias tarefas, basta colocar lá no método run() da MyFirstApplicationTask.
Tá enviando os email normalmente. \o/
Uma dúvida nesse envio é que a conexão fica aberta até terminar de enviar para todos os contatos, se tiver uns 1.000 contatos vai demorar bastante, vc já viu alguém usar o método com cópia oculta addBcc() ?

email.addBcc(email);

Ai iria enviar um email só com cópia oculta para os outros 999, só que para implementar isso fica complicado, na lista de contatos vêm a galera toda e o envio é feito usando um for, onde para cada contato é enviado um email.
Abraço!!

Lucas_Cavalcanti

de que conexão vc tá falando?

vc precisa que todos sejam feitos ao mesmo tempo?

Guevara

É na conexão com a conta de email, pois para cada contato é enviado um email, achei que com um envio fosse possível enviar um email com cópia oculta para os demais contatos. =)
Já tô com o esquema do Velocity + Sitemesh pra decorar a mensagem de email, como eu crio o arquivo .vm ? Eu criei uma JSP e depois renomeei para .vm, aí o texto ficou sem destaque, é isso mesmo??
Abraço!!

Lucas_Cavalcanti

vc precisa criar um email html pra isso funcionar…
e só renomear JSP pra VM não vai rolar… vc tem que usar as tags do VM

Guevara

Não entendi Lucas… =/
Eu crio uma JSP e renomeio para .vm ou crio uma pagina HTML e renomeio para .vm?
A dúvida é só essa mesmo, como criar e se o texto fica sem destaque, o lance do VTL eu já vi como é. =)
Abraço!!

Guevara

Pelo que eu tô lendo o velocity não é o que eu pensava, ele faz o que a jstl faz na JSP, sendo que arquivo .vm não fica com o texto em destaque (colorido), se eu entregar uma página vm pra um webdesigner enfeitar, vai me matar. =/
Não vi nada referente a estilos CSS no manual dele. Pelo menos no sitemesh, o estilo css pode ser usado normalmente nas páginas, já que se trata de páginas JSP, o webdesigner pode colocar as

e aplicar os estilos.
Lucas_Cavalcanti

não dá pra usar css em emails…
tem q fazer os estilos na mão ou fazendo com imagens

Guevara

Pois é… =/
Consegui colocar o avatar dos imóveis no corpo do email, mas reparei que para cada contato, o tempo de envio é de aproximadamente 2min, para conectar à conta, pegar a lista dos imóveis, colocar os dados no email e adicionar o avatar, se eu tiver uns 1000 contatos no banco o tempo seria de 2000min ou 33 Horas e meia. É assim que funciona mesmo esse lance? hehe
Abraço! o/

G

Lucas Cavalcanti:
não dá pra usar css em emails…
tem q fazer os estilos na mão ou fazendo com imagens

Dá sim :smiley:

Você pode escrever inline ou via attachment associando o CID no URL do CSS.

Criado 22 de setembro de 2010
Ultima resposta 27 de set. de 2010
Respostas 36
Participantes 3