Spring ldap compounded search requests - java

I am new to Spring LDAP and would like to know the following. Is it possible to "compound" 2 or more searches in a single one, while at the same time using an iterator?
For example, my code right now looks something like this:
List result = ldapTemplate.search(baseDn, encode, searchControls2,
genericContextMapper);
BaseDn points to a certain branch of the LDAP tree, and genericContextMapper has an iterator that I am using throught my code to gradually fetch the results.
But what if I want to pass more than 1 BaseDN, each pointing to completely different LDAP branches, and I expect the iterator to start with the next BaseDN as soon as it is done with the previous one? Can I do this kind of chaining through Spring LDAP?
I know I can achieve this by creating my own custom class that just "sticks together" the results, but I was wondering if there is an easier out of the box solution for this.
Thanks!

You can try this
<bean id="authenticator" class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userSearch" ref="userSearch" />
</bean>
<bean id="userSearch" class="com.security.OUUserSearch">
<property name="userSearches" ref="userSearches" />
</bean>
<util:list id="userSearches">
<ref bean="userSearch1" />
<ref bean="userSearch2" />
</util:list>
<bean id="userSearch1" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg value="OU=test1" />
<constructor-arg value="(uid={0})" />
<constructor-arg ref="contextSource"/>
<property name="searchSubtree" value="true" />
</bean>
<bean id="userSearch2" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg value="OU=test2" />
<constructor-arg value="(uid={0})" />
<constructor-arg ref="contextSource"/>
<property name="searchSubtree" value="true" />
And OUUserSearch is
public class OUUserSearch implements LdapUserSearch
{
List<LdapUserSearch> myUserSearches = null;
public DirContextOperations searchForUser(String theUsername)
{
DirContextOperations theResult = null;
for(LdapUserSearch aSearch : myUserSearches)
{
try
{
theResult = aSearch.searchForUser(theUsername);
if (theResult != null)
{
// we are done
break;
}
}
catch (Exception e)
{
String aMessage = e.getLocalizedMessage();
task.debug(aMessage);
}
}
if (theResult == null)
{
throw new UsernameNotFoundException("Unable to authenticate user (" + theUsername + ")");
}
return theResult;
}
public List<LdapUserSearch> getUserSearches() { return myUserSearches;}
public void setUserSearches(List<LdapUserSearch> theSearches) {myUserSearches = theSearches;}

Related

Handling Exceptions from spring context

How can i handle exceptions from Spring context .
Consider the context
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
<property name="URL" value="jdbc:oracle:thin:#localhost:1521/xe" />
<property name="user" value="abc" />
<property name="password" value="abc" />
</bean>
<bean id="abc" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="default" />
<property name="persistenceXmlLocation" value="classpath*:META-INF/abc-persistence.xml" />
</bean>
And am loading context in main method
public static void main(String[] args) {
ApplicationContext applicationContext = null;
try {
applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/test.xml");
} catch (Exception e) {
System.out.println("Exception caugtht " + e);
}
}
Lets say database is down .now when i load context exceptions are not caught in catch block. Is there any way to handle this ?

Spring batch - How to write data multiple rows after processing single record?

I have bean class as below -
public class Account {
private String strAccNumber = "";
private List<Account> accountList = new ArrayList<Account>();
// getter setter
....
...
#Override
public String toString() {
// code for PassThroughLineAggregator
String data="";
for (int j=0; j<accountList.size(); j++) {
Account bean = accountList.get(j);
data = data + bean.getStrAccNumber();
if (j<(accountList.size()-1)) {
data = data + "\n";
}
}
return data;
}
}
to write data I want to set accountList in my config file.
I'm using below code to set bean property.
<bean id="flatFileReader" class="org.springframework.batch.item.file.FlatFileItemReader"
scope="step">
<property name="resource" value="classpath:springBatch.csv" />
<property name="strict" value="false"></property>
<property name="linesToSkip" value="1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="ACC#" />
</bean>
</property>
<property name="fieldSetMapper">
<bean
class="com.abc.reader.AccountDetailsFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<bean id="flatFileProcessor"
class="com.abc.processor.AccountItemProcessor"
scope="step"></bean>
<bean id="flatFileWriter"
class="com.abc.FlatFileItemWriterListener"
scope="step">
<property name="resource" value="classpath:springBatch1.csv" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names" value="strAccNumber" />
</bean>
</property>
</bean>
</property>
</bean>
AccountItemProcessor -
public class AccountItemProcessor implements ItemProcessor<Account, List<Account>>{
#Override
public List<Account> process(Account accObj) throws Exception {
// logic..
}
After processing single record in the process step I want to write multiple items(list of item) , how can I write multiple item at a time using arraylist. In my case I want to write data from accountlist.
You'll want to implement your own LineAggregator. That is what provides the String to be written to the file. In your case, you'll write one that returns a String that is really multiple lines.
You can read more about the LineAggregator interface in the documentation here: http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/item/file/transform/LineAggregator.html

Entries missing in database when using Spring jdbcTemplate batch insert in a multithreaded environment

I am trying to add multiple records into an Oracle 12c database using a simple spring jdbcTemplate call to batchUpdate() method. The code that makes the batchUpdate() call is in my DAO class. However the code that calls the service method is multi-threaded.
This is what my DAO class looks like (there are more like this):
public void batchInsertSessionSignature(final List<SessionSignature> sessionSignatures, DataSource dataSource) {
Assert.notNull(sessionSignatures, "Checking to see if the SessionSignature objects passed in are null");
if (dataSource != null) {
jdbcTemplate.setDataSource(dataSource);
}
if (!sessionSignatures.isEmpty()) {
log.debug("Inserting batch entries into lev_session_signature_temp of size: " + sessionSignatures.size());
int[] res = jdbcTemplate.batchUpdate(insertSessionSig, new BatchPreparedStatementSetter() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
#Override
public void setValues(PreparedStatement pstmt, int i) throws SQLException {
SessionSignature ss = sessionSignatures.get(i);
String created_date = sdf.format(ss.getCreated_date());
pstmt.setLong(1, ss.getId());
pstmt.setString(2, ss.getHost());
pstmt.setString(3, ss.getSession_id());
pstmt.setString(4, ss.getIp_address());
pstmt.setString(5, ss.getAccountName());
try {
pstmt.setInt(6, sysInfoBean.getSysinfoID(ss.getSysinfo()));
pstmt.setDate(7, new Date(sdf.parse(created_date).getTime()));
} catch (ParseException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
pstmt.setString(8, ss.getCountry());
pstmt.setInt(9, ss.getAccountID());
pstmt.setString(10, ss.getBusinessUnit());
}
#Override
public int getBatchSize() {
return sessionSignatures.size();
}
});
log.debug(res.length + " entries inserted into lev_session_signature_temp");
}
}
This is the service layer method that makes the call to the DAO classes (the method is thread safe)
#Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
public synchronized void writeTargetDaoEntries(TargetDao targetDao, DataSource dataSource, ArrayList<SessionSignature> tgtSessionSignatures,
ArrayList<Session> tgtSession, ArrayList<SearchGroup> tgtSearchGroup, ArrayList<Search> tgtSearches,
ArrayList<LuceneEvent> tgtEvents, ArrayList<EventAnalysisDaoUtil> eventAnalysisList) throws Exception {
targetDao.batchInsertSessionSignatures(tgtSessionSignatures, dataSource);
targetDao.batchInsertUserSessions(tgtSession, dataSource);
targetDao.batchInsertSearchGroups(tgtSearchGroup, dataSource);
targetDao.batchInsertSearches(tgtSearches, dataSource);
targetDao.batchInsertEvents(tgtEvents, dataSource);
targetDao.batchInsertEventAnalysis(eventAnalysisList, dataSource);
}
My spring configuration looks like this
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:annotation-config/>
<context:property-placeholder location="app.properties"/>
<bean id="dataSourceQa" class="oracle.ucp.jdbc.PoolDataSourceFactory"
factory-method="getPoolDataSource" lazy-init="true">
<property name="connectionFactoryClassName"
value="oracle.jdbc.pool.OracleDataSource" />
<property name="user" value="${qaTargetId}" />
<property name="password" value="${qaTargetPswd}" />
<property name="URL" value="${qaTargetURL}" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
</bean>
<bean id="dataSourceProd" class="oracle.ucp.jdbc.PoolDataSourceFactory"
factory-method="getPoolDataSource" lazy-init="true">
<property name="connectionFactoryClassName"
value="oracle.jdbc.pool.OracleDataSource" />
<property name="user" value="${prodSourceId}" />
<property name="password" value="${prodSourcePswd}" />
<property name="URL" value="${prodSourceURL}" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
</bean>
<!-- JDBC Template Configuration -->
<bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name = "dataSource" ref = "dataSourceQa"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceQa" />
</bean>
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="WaitForTasksToCompleteOnShutdown" value="true" />
</bean>
<!-- DAO Bean Configuration -->
<bean id = "eventDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.EventDao" />
<bean id = "searchDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SearchDao" />
<bean id = "searchGroupDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SearchGroupDao" />
<bean id = "userSessionDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.UserSessionDao" />
<bean id = "sessionSignatureDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SessionSignatureDao" />
<bean id = "eventAnalysisDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.EventAnalysisDao" />
<bean id = "dailySummaryDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.DailySummaryDao" />
<bean id = "keyGeneratorBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.KeyGenerator" />
<bean id = "machineLearningDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.MachineLearningDao" />
<bean id = "sourceDaoBean" abstract = "true" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.SourceDao" />
<bean id = "desktopSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.DesktopSourceDao" />
<bean id = "mobileSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.MobileSourceDao" />
<bean id = "webSourceDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.WebSourceDao" />
<bean id = "tempTableDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.TempTableDao" />
<bean id = "targetDaoBean" class = "com.uptodate.lucene.tool.analysis.transfer.oracleDao.TargetDao">
<constructor-arg ref = "eventDaoBean" />
<constructor-arg ref = "searchDaoBean" />
<constructor-arg ref = "searchGroupDaoBean" />
<constructor-arg ref = "userSessionDaoBean" />
<constructor-arg ref = "sessionSignatureDaoBean" />
<constructor-arg ref = "eventAnalysisDaoBean" />
</bean>
<!-- Parser Bean Configuration -->
<bean id = "userSessionParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.UserSessionParser" scope = "prototype" />
<bean id = "searchParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.SearchParser" scope = "prototype" />
<bean id = "searchGroupParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.SearchGroupParser" scope = "prototype" />
<bean id = "eventParserBean" abstract = "true" class = "com.uptodate.lucene.tool.analysis.transfer.parser.EventParser" scope = "prototype" />
<bean id = "mobileEventParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.MobileEventParser" scope = "prototype" />
<bean id = "webEventParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.parser.WebEventParser" scope = "prototype" />
<bean id = "logParserBean" class = "com.uptodate.lucene.tool.analysis.transfer.LogParser" scope = "prototype">
<constructor-arg ref = "keyGeneratorBean" />
<constructor-arg ref = "searchParserBean" />
<constructor-arg ref = "searchGroupParserBean" />
<constructor-arg ref = "userSessionParserBean" />
</bean>
<!-- Transfer Bean Configuration -->
<bean id = "dailySummaryGeneratorBean" class = "com.uptodate.lucene.tool.analysis.transfer.DailySummaryGenerator" />
<!-- Util Bean Configuration -->
<bean id = "sysInfoBean" class = "com.uptodate.lucene.tool.analysis.vo.SysInfo">
<property name = "dataSource" ref = "dataSourceProd" />
</bean>
I have tried adding support for transactions hoping that would help make sure the entries are committed to the database but that did not help. I can see in the code that all entries sent to the database were written to it but when I check the number of records in the database the same number is not reflected. I'm not sure if this is because of the multithreaded nature of the code that a batch of entires is overwritten somehow? Using 1 thread seems to work fine making me believe its a multithreading issue but I'm not sure where the problem is. Any help on this issue is appreciated.

ExchangeTimedOutException: The OUT message was not received

I have a problem the InOnly exchange pattern what I use with aciveMq.
I wrote a module what run in ServiceMix. It works correctly except that it send every message to dead letter queue (ActiveMQ.DLQ). If I check the message then dlqDeliveryFailureCause contains this message: java.lang.Throwable: Message Expired.
I checked the JMSExpiration = 0.
The route:
from("direct:" + reqOutQueue).id("reqInEnritch")
.log("Start dispatch")
.setExchangePattern(ExchangePattern.InOnly)
.recipientList().method(EsbDynamicRouter.class, "systemRoute").parallelProcessing();
The function, what gives back the endpoint list:
#RecipientList
public String[] systemRoute(#Body Object body) throws Exception
{
String[] result = null;
List<DispConfView> targetList;
int cikl = 0;
SystemQueueHelper systemInfo;
MessageHeaderHelper msgHeadHelp = new MessageHeaderHelper(body);
// The object contains the affected elements
targetList = dispHelp.getDispConfByMsgType(msgHeadHelp.getMsgType());
result = new String[targetList.size()];
for (DispConfView element : targetList)
{
// It builds the target andpoints
systemInfo = new SystemQueueHelper(element.getSystemCode(), null, msgHeadHelp.getDirection());
result[cikl] = systemInfo.getQueuName();
cikl++;
}
return result;
}
The list contains these values:
activemq:queue:ERP.req.in?exchangePattern=InOnly
activemq:queue:WF.req.in?exchangePattern=InOnly
As you see, I try to set the correct pattern, but every messages go to dead letter queue.
Please help, what I have to set up!
Thank you!
The solution:
It is settable in context file:
<!-- JMS configuration -->
<bean id="pooledJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="1" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="failover:(tcp://localhost:61616)" />
<property name="redeliveryPolicy">
<bean class="org.apache.activemq.RedeliveryPolicy">
<property name="maximumRedeliveries" value="5"/>
</bean>
</property>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledJmsConnectionFactory"/>
<property name="cacheLevelName" value="CACHE_CONSUMER" />
<property name="disableReplyTo" value="true" />
</bean>
The "jmsConfig bean ""diasbleReplayTo" property solve the problem.

Read/write to database from quartz jobs - transactions not working

I have two Quartz (1.8.3) jobs, configured via Spring (2.5.6), one of them writes (send) to database, and one reads from it (check).
<bean id="scheduleFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="Check"/>
<ref bean="Send"/>
</list>
</property>
</bean>
<bean id="Send" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="sendMessage" />
</bean>
</property>
<property name="cronExpression" value="0 0/1 * * * ?" />
</bean>
<bean id="Check" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="checkAndUpdateStatus" />
</bean>
</property>
<property name="cronExpression" value="30 0/1 * * * ?" />
</bean>
Transaction manager is set up:
<tx:annotation-driven transaction-manager="TransactionManager"/>
In both jobs I explicitly run read/write operations in transactions like this:
#Override
public synchronized void sendMessage() {
try {
TransactionTemplate tt = new TransactionTemplate(ptm);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
statusDAO.update(status);
...
}
});
log.info("Status was updated");
} catch (Exception e) {
...
}
}
where ptm is a TransactionManager bean, injected via Spring.
I see "Status was updated" record in logs, but when I read this record from transactional read method it is outdated sometimes. Moreover, when I use an SQL editor to read this record it is outdated too.
I don't understand, why transactions dont work in this case, do you have any ideas?
Thanks.
For anyone that might be interested. This worked for me
<bean name="applicationDataCollectorControllerJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="org.mypckage.controller.jobs.ApplicationDataCollectorController" />
<property name="jobDataAsMap">
<map>
<!--<entry key="timeout" value="1" />-->
<entry key="genericService" value-ref="genericService" />
<entry key="applicationDataCollectorService" value-ref="applicationDataCollectorService" />
<entry key="transactionManager" value-ref="transactionManager" />
</map>
</property>
</bean>
--- in the scheduler bean---
#Override
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
getApplicationDataCollectorService().collectData(transactionManager);
}
----In the applicationDataCollectorService bean-----
public void collectData( org.springframework.transaction.jta.JtaTransactionManager transactionManager) {
try {
this.transactionManager = transactionManager;
testTransactionalSave();
} catch (Exception e) {
BUSY = false;
e.printStackTrace();
}
}
}
private void testTransactionalSave() throws Exception {
TransactionTemplate tt = new TransactionTemplate(transactionManager);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus ts) {
try {
ApplicationParameter appPara = null;
List<ApplicationParameter> appParaList = genericService.getListFromHQL("select o from ApplicationParameter as o order by o.id desc", false);
if (appParaList != null) {
if (appParaList.size() > 0) {
appPara = (ApplicationParameter) appParaList.get(0);
appPara.setLastBankStatementMailNum(appPara.getLastBankStatementMailNum() + 10);
appPara = (ApplicationParameter) genericService.mergeObject(appPara);
System.out.println(" num is now = " + appPara.getLastBankStatementMailNum());
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
Note: dont forget to declare transactionManager as private properties in both beans with public setter and getter for spring to wire it up. Any Questions? yemiosigbesan#gmail.com

Categories