spring receive emails without xml (using annotations only) - email

I need to periodically check about 30 mailboxes and want to do this with annotations only. I know how to do it with XML files, it looks like this:
<mail:inbound-channel-adapter id="ImapAdapter"
store-uri="imaps://${login}:${pass}#${host}:993/inbox"
channel="testReceiveEmailChannel"
should-delete-messages="false"
should-mark-messages-as-read="true"
auto-startup="true"
java-mail-properties="javaMailProperties">
<int:poller fixed-delay="200"
time-unit="SECONDS"
task-executor="asyncTaskExecutor"/>
</mail:inbound-channel-adapter>
<int:channel id="testReceiveEmailChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:service-activator input-channel="testReceiveEmailChannel"
ref="testMailReceiverService"
method="receive"/>
<bean id="testMailReceiverService" class="com.myproject.email.EmailReceiverService">
<property name="mailBox" value="${login}"/>
</bean>
<int:logging-channel-adapter id="logger" level="DEBUG"/>
I know that Spring 4+ have #InboundChannelAdapter but I dont know how to use it. Actually I am new in Spring, so any helps very appreciated!

You are looking into the correct way - #InboundChannelAdapter. If you take a look to the Documentation properly, you'll see something like this:
#Bean
#InboundChannelAdapter(value = "testReceiveEmailChannel", poller = #Poller(fixedDelay = "200000", taskExecutor = "asyncTaskExecutor"))
public MessageSource<javax.mail.Message> mailMessageSource(MailReceiver mailReceiver) {
MailReceivingMessageSource mailReceivingMessageSource = new MailReceivingMessageSource(mailReceiver);
// other setters here
return mailReceivingMessageSource;
}
Where MailReceiver is something like this:
#Bean
public MailReceiver imapMailReceiver(#Value("imaps://${login}:${pass}#${host}:993/inbox") storeUrl) {
ImapMailReceiver imapMailReceiver = new ImapMailReceiver(storeUrl);
// other setters here
return imapMailReceiver;
}
and so with other #Beans for MessageChannel and #ServiceActivator for your EmailReceiverService.
Consider as a tool for Java Configuration the Spring Integration Java DSL.

Related

Scheduler Spring boot

#Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
#Bean
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))
.build();
}
My requirement is to run only single scheduler at only one instance in clustered enviroment. For this i am using shedlock, but problem is that at server startup i am getting the below exception, "java.lang.ClassCastException: net.javacrumbs.shedlock.spring.SpringLockableTaskSchedulerFactoryBean cannot be cast to org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler"
Help me on this.
You can easily do this with dlock. You simply do the following and add registrar to your xml config.
Java Code
#TryLock(name = "doSomeWork", owner = "serviceA", lockFor = ONE_MINUTE)
public void doSomeWork() {
//...
}
XML Config
<!-- A bean for the lock implementation. Note that there should be only one global implementation-->
<bean id="postgresLock" class="com.yusufaytas.dlock.jdbc.PostgresIntervalLock">
<constructor-arg type="javax.sql.DataSource" ref="lockDataSource"/>
</bean>
<!-- The lock gets auto-registered to the registrar -->
<bean id="lockRegistrar" class="com.yusufaytas.dlock.spring.IntervalLockRegistrar"/>

Spring3+mybatis3 generic dao(or mapper)

I have integrated spring3 + mybatis3,and it worked good.
Then I found that many SQLs will be written like this:
select * from table1 where id=#{id}
select * from table2 where id=#{id}
We don't need repeat as a programmer!
So,Can we defined a genric dao or mapper to avoid this repeat? Provide a demo is better.
Some links can help is kindly too.
It bothers me for a long time,need a hand.
I want to write my code like this:
Test.java:
just a enity.
TestMapper.java:
public interface TestMapper extends GenericMapper {
public void testMethod1(String..);
//other methods here
}
GenericMapper.java:
public interface GenericMapper<T, PK> {
public T select(PK id);
public boolean update(T t);
public boolean delete(PK id);
public boolean insert(T t);
}
defind bean in spring-xx.xml:
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="com.jackson.mapper.TestMapper" />
</bean>
Call in my service layer like this:
// Please**NOTICE**:method select is defined in GenericMapper.
TestService.java:
public TestMapper testMapper;
public Test get(Integer id) {
Test test = testMapper.select(id);
doSmth(test);
}
Just a few minutes ago,Someone said we can use a Interceptor interface. And I am trying now.
Thanks!
--jackson
One of the options is to use mybatis-generator.
http://classnotfound.net/blog/mybatisspringgenerics/
I think this tutorial has exactly what you are looking for. I am not sure what version of Java (or editor config) he is running but I had to add on the Dao methods and suppress the unchecked castings (T) and raw types warnings to get it work on eclipse mars 2 using java 8.
I know I might be late but this library from google will address your issue. I have been using it in over 10 projects.

Write a Spring batch custom item writer

I need to write a Spring batch custom item writer that uses a footer, but I can't use the delegate pattern.
Is there another way to write a Spring batch custom item writer?
Thank you in advance.
Create a custom ItemWriter that implements ItemStream (to manage restartability and footer writing) and overwrite the next methods:
ItemWrite.write(List<> items): write items and during writing perform necessary data calculation for footer
ItemStream.update(ExecutionContext): save calculated footer data in write() method
ItemStream.open(ExecutionContext): restore previously saved footer data
ItemStream.close(): do real footer writing (directly in your own writer or using a callback)
Check here
Basically you need to create a class that implements ItemWriter<YourModel> and FlatFileFooterCallback
In the write method, enter how data will be written and in the writeFooter the footer of the file.
Then declare your class as a bean and put it as a writer in your job.
I've found the solution. I can't write a custom itemwriter, but I created a bean out and I have overridden the toString method. In this method I have set the output to the file as needed. Then, I created a PassThroughLineAggregator type itemwriter. This itemwriter calls the toString method of the bean output. And that's all!!
Here's the code:
MOH_Diaria_Bean_Out.java:
package es.lac.absis.batch.app.percai.domain;
import java.util.ArrayList;
import java.util.List;
public class MOH_Diaria_Bean_Out {
List<MOH_Diaria_Bean> listaBeans = new ArrayList<MOH_Diaria_Bean>();
public List<MOH_Diaria_Bean> getListaBeans() {
return listaBeans;
}
public void setListaBeans(List<MOH_Diaria_Bean> listaBeans) {
this.listaBeans = listaBeans;
}
public void add (MOH_Diaria_Bean bean){
listaBeans.add(bean);
}
#Override
public String toString() {
// TODO Auto-generated method stub
String salida="";
for (int j=0; j<listaBeans.size(); j++) {
MOH_Diaria_Bean bean = listaBeans.get(j);
salida = salida + bean.toString();
if (j<(listaBeans.size()-1)) {
salida = salida + "\n";
}
}
return salida;
}
}
ItemWriter:
<bean id="MOH_FusionadoFicheros_Writer" class="es.lac.absis.batch.arch.internal.writer.AbsisFlatFileItemWriter">
<property name="resource">
<bean class="es.lac.absis.batch.arch.internal.util.AbsisFileSystemResource">
<constructor-arg ref="filePCA00020"></constructor-arg>
</bean>
</property>
<property name="encoding" value="ISO8859_1"></property>
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator">
</bean>
</property>
</bean>

Spring Data MongoDB: Unit tests with repositories

How is it supposed to build some tests with the repository approach in Spring Data MongoDB? I would like to set the test database for my tests since I don't want to use the production database for this purpose. It should be probably possible but I have no idea. This is my application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation=
"http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/data/neo4j
http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="${mongo.host}" port="${mongo.port}">
<mongo:options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="${mongo.connect-timeout}"
max-wait-time="${mongo.max-wait-time}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="${mongo.socket-timeout}"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg name="databaseName" value="${mongo.db}" />
</bean>
<context:component-scan base-package="domain.company.group.project.data.repositories"/>
<!-- MongoDB repositories -->
<mongo:repositories base-package="domain.company.group.project.data.repositories.mongodb"/>
<!-- some other stuff -->
</beans>
And let's say I have a simple repository as follows:
public interface LocationRepository extends MongoRepository<Location, String>, LocationRepositoryCustom {
}
where LocationRepositoryImpl is the class implementing all my custom methods for a certain Location (domain object) class. My test class looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/test-context.xml"})
public class LocationRepositoryTest {
#Autowired
private LocationRepository locationRepository;
/* Some tests... */
}
I have tried to embed a MongoDB instance within my running tests (as explained here) but it does not work: the connection to the test database is established but the mongo template seems not able to be overwritten as all save methods keep inserting data to the "production" database.
I am using Spring 3.2.0 and Spring Data Mongo 1.1.0.RELEASE. I am using Junit for testing.
Any suggestions?
Thank you in advance.
Jaranda,
I faced the same problem last week and coincidentally I heard about Fongo, "an in-memory java implementation of mongo."
So I decide to use it to test my custom repositories and worked perfectly to me. Below is an example of how to configure Spring to use Fongo in JUnit tests. Note that I'm not using xml configuration.
Hope that will be useful!
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class LocationRepositoryTest {
private static final String PLAYER_ID = ObjectId.get().toString();
#Autowired private LocationRepositoryCustom playerRepository;
#Autowired private MongoTemplate mongoTemplate;
/* Some tests... */
#Configuration
static class LocationRepositoryTestConfiguration {
#Bean
public Mongo mongo() {
// Configure a Fongo instance
return new Fongo("mongo-test").getMongo();
}
#Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongo(), "collection-name");
}
#Bean
public LocationRepositoryCustom playerRepository() {
// This is necessary if MongoTemplate is an argument of custom implementation constructor
return new LocationRepositoryCustomImpl(mongoTemplate());
}
}
}

Spring MVC Restful App: Redirect a form result to another page

I'm new to Spring MVC Restful.
Suppose I have index.jsp which forwards user to a form page where user could submit a term to search. I catch the term with a POST handler method, and then do some calculation and hope to redirect the result to be used at another page (/WEB-INF/jsp), for example, we say build a graph based on the result. The problem is how to gather the results and redirect the URL at the same time.
The Controllers like below:
#RequestMapping(value="/termForm", method = RequestMethod.GET)
public ModelAndView setupForm() {
Term termClass = new Term();
return new ModelAndView("term", "command", termClass);
}
#RequestMapping(value="/getTerm", method=RequestMethod.POST)
public String getTerms(#ModelAttribute("term") Term term, BindingResult result)
{
String label = term.getTerm();
//doing some calculation to term here
result = ....
return "redirect:"+ "graphPage.jsp";
}
By searching, I found that Spring View Resolver only could process the redirected jsp under root directory (as same with index.jsp). In this case, the "result" seems not accepted by "graphPage". I also included UrlBasedViewResolver in XXX-servlet.xml as following:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Sorry for the long question, please give any hint to do this. Thanks a lot.
There are two parts of my question. One is redirecting POST method to another page, graphPage.jsp. Since we go to graph, we need the data from POST method as well to create graph. This is the other concern. Hope it's clear. I already solved the first one by adding a handler method, see below. But how to package the result and pass it to Graph.jsp? Thanks
#RequestMapping(value="/graphPage", method=RequestMethod.GET)
public String showGraph()
{
return "graphPage";
}
You will get a better controll over the redirect if you use the RedirectView instead of the String. See this example.
#Contoller
#RequestMapping("/your")
public class YourController
#RequestMapping(value="/getTerm", method=RequestMethod.POST)
public ModelAndView getTerms(#ModelAttribute("term") Term term, BindingResult result) {
...
return new ModelAndView(new RedirectView("/your/other", true));
}
#RequestMapping(value="/other", method=RequestMethod.POST)
public String otherMethod() {...}
}
But maybe you asked something different, then please rewrite your question. It is very hard to understand what your problem is./
BTW. test that you can request your "graphPage" directly