Apache

Active MQ – java.io.IOException: tmpFile.renameTo(classFile) failed

Posted on

I downloaded the latest version of Apache ActiveMQ. Post download followed the simple steps for installation and then followed the starting ActiveMQ. It started and I tried accessing the admin console @ http://localhost:8161/admin/.

It opened by showed an error message:

Error!

Exception occurred while processing this request, check the log for more information!

What do you want to do next?

ActiveMQ Console

And my command prompt had this stacktrace:

jvm 1    | java.io.IOException: tmpFile.renameTo(classFile) failed
jvm 1    |      at org.apache.jasper.compiler.SmapUtil$SDEInstaller.install(SmapUtil.java:235)
jvm 1    |      at org.apache.jasper.compiler.SmapUtil.installSmap(SmapUtil.java:158)
jvm 1    |      at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:390)
jvm 1    |      at org.apache.jasper.compiler.Compiler.compile(Compiler.java:437)
jvm 1    |      at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:608)
jvm 1    |      at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:360)
jvm 1    |      at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:486)
jvm 1    |      at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:380)
jvm 1    |      at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:652)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:445)
jvm 1    |      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
jvm 1    |      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:574)
jvm 1    |      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:227)
jvm 1    |      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1044)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:372)
jvm 1    |      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:189)
jvm 1    |      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:978)
jvm 1    |      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
jvm 1    |      at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:293)
jvm 1    |      at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:120)
jvm 1    |      at org.eclipse.jetty.servlet.DefaultServlet.doGet(DefaultServlet.java:566)
jvm 1    |      at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
jvm 1    |      at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:652)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1320)
jvm 1    |      at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
jvm 1    |      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1291)
jvm 1    |      at org.apache.activemq.web.filter.ApplicationContextFilter.doFilter(ApplicationContextFilter.java:102)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1291)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:443)
jvm 1    |      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
jvm 1    |      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:521)
jvm 1    |      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:227)
jvm 1    |      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1044)
jvm 1    |      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:372)
jvm 1    |      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:189)
jvm 1    |      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:978)
jvm 1    |      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
jvm 1    |      at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:154)
jvm 1    |      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:521)
jvm 1    |      at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:154)
jvm 1    |      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
jvm 1    |      at org.eclipse.jetty.server.Server.handle(Server.java:367)
jvm 1    |      at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:486)
jvm 1    |      at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926)
jvm 1    |      at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988)
jvm 1    |      at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:640)
jvm 1    |      at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
jvm 1    |      at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
jvm 1    |      at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
jvm 1    |      at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
jvm 1    |      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
jvm 1    |      at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
jvm 1    |      at java.lang.Thread.run(Thread.java:744)

Fix is very simple, if you are on Windows 7 then while launching ActiveMQ:

  1. Stop ActiveMQ if it is running
  2. Start command prompt as Administrator (Start Menu -> Type cmd -> Right click on cmd -> choose Run as Administrator
  3. Or go to the /bin/(win32 or win64 based on your system and right click on activemq.bat and choose Run as Administrator

Now again access the admin console. BINGO problem solved!!!

Happy coding….

Search Lucene Index created in database using JdbcDirectory

Posted on Updated on

In our last excercise we created Lucene index in database using JdbcDirectory which comes with Compass in this post we will search against index created. With this much of text let’s get our hand dirty and write some code.

Please note following files will be used from create lucene index post

  1. pom.xml
  2. MyJDBCDirectory.java
  3. JDBCBatchInsert.java
  4. JDBCIndexer.java (without creating index we cannot search against it ;), so in our test case below we will create an index before searching)
  5. JDBCDatabaseUtil.java
  6. Database schema

Now with some code from our backyard with let’s finish up search quickly. Below is JDBCSearcher.java which has a very simple search method which takes the name of the index field and value which we want to search. It returns true if valid search is performed or else false. Please note with this search we are only interested in search result with highest hit, others we don’t care.

package com.mumz.test.lucene.jdbc;

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;

/**
 * The Class InMemoryDirectorySearcher.
 * 
 * @author prabhat.jha
 */
public class JDBCSearcher {

	/** The directory. */
	private Directory	directory	= null;

	/**
	 * The Constructor.
	 * 
	 * @param directory
	 *            the directory
	 */
	public JDBCSearcher(Directory directory) {
		this.directory = directory;
	}

	/**
	 * Search.
	 * 
	 * @param fileName
	 *            the file name
	 * @return the string
	 */
	public boolean search(String columnName, String value) {
		IndexSearcher indexSearcher = null;
		try {
			/**
			 * Specify the version
			 */
			Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_36);
			/**
			 * Create query columnname (index name passed), we built out index for name, author and publisher so
			 * we have to search against the same.
			 */
			Query query = new QueryParser(Version.LUCENE_36, columnName, analyzer).parse(value);
			IndexReader indexReader = IndexReader.open(directory);
			indexSearcher = new IndexSearcher(indexReader);
			/**
			 * This will hold all the results which results from the search
			 * operation
			 */
			TopDocs topDocs = indexSearcher.search(query, 1);
			if (topDocs.scoreDocs.length > 0) {
				System.out.println("Found :  Book with id = " + indexSearcher.doc(topDocs.scoreDocs[0].doc).get("BOOKID") + " , Name = "
						+ indexSearcher.doc(topDocs.scoreDocs[0].doc).get("name") + " ,Author = "
						+ indexSearcher.doc(topDocs.scoreDocs[0].doc).get("author") + " ,Publisher = "
						+ indexSearcher.doc(topDocs.scoreDocs[0].doc).get("publisher") + " with hits : " + topDocs.scoreDocs[0].doc);
				return true;
			} else {
				System.out.println("No Record found");
				return false;
			}
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (indexSearcher != null) {
				try {
					indexSearcher.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			indexSearcher = null;
		}
		return false;
	}
}

In you want to see all the hits you can use below code snippet.

TopScoreDocCollector results = TopScoreDocCollector.create(100, true);
TopDocs topDocs = indexSearcher.search(query, 1);
indexSearcher.search(query, results);
ScoreDoc[] scores = results.topDocs().scoreDocs;
for (ScoreDoc scoreDoc : scores) {
	System.out.println("Found :  Book with id = " + indexSearcher.doc(scoreDoc.doc).get("id") + " ,        
    Name = " + indexSearcher.doc(scoreDoc.doc).get("name") + " ,Author = " + 
    indexSearcher.doc(scoreDoc.doc).get("author") + " ,Publisher = " +   
    indexSearcher.doc(scoreDoc.doc).get("publisher") + " with hits : " + scoreDoc.score);

}

And finally here is our JUnit test case, please note this test case assumes that you also have indexer code with you.

package com.mumz.test.lucene.jdbc;

import org.apache.lucene.store.Directory;
import org.apache.lucene.store.jdbc.dialect.MySQLDialect;

import junit.framework.TestCase;

/**
 * The Class LuceneJDBCTest.
 * @author prabhat.jha
 */
public class LuceneJDBCTest extends TestCase {

	/** The directory. */
	private Directory	directory	= null;

       /** (non-Javadoc)
	 * @see junit.framework.TestCase#setUp()
	 */
	protected void setUp() throws Exception {
		directory = new MyJDBCDirectory(JDBCDatabaseUtil.getDataSource(), new MySQLDialect(), "LUCENE_INDEX_TABLE");
		super.setUp();
	}

	/**
	 * Test insert record.
	 */
	public void testInsertRecord() {		
		new JDBCBatchInsert().insertRecords();
	}

	/**
	 * Test build index.
	 */
	public void testBuildIndex() {
		new JDBCIndexer(directory).buildIndex();
	}

	/**
	 * Test search record on name.
	 */
	public void testSearchRecordOnName() {
		boolean found = new JDBCSearcher(directory).search("name", "Spring In Action");
		assertEquals(found, true);
	}

	/**
	 * Test search record fail on name.
	 */
	public void testSearchRecordFailOnName() {
		boolean found = new JDBCSearcher(directory).search("name", "No Such BookName");
		assertEquals(found, false);
	}

	/**
	 * Test search record on author.
	 */
	public void testSearchRecordOnAuthor() {
		boolean found = new JDBCSearcher(directory).search("author", "Test Author Hibernate In Action10");
		assertEquals(found, true);
	}

	/**
	 * Test search record fail on author.
	 */
	public void testSearchRecordFailOnAuthor() {
		boolean found = new JDBCSearcher(directory).search("name", "No Such Author");
		assertEquals(found, false);
	}

	/**
	 * Test search record on publisher.
	 */
	public void testSearchRecordOnPublisher() {
		boolean found = new JDBCSearcher(directory).search("publisher", "Test Publisher Spring Bible7");
		assertEquals(found, true);
	}

	/**
	 * Test search record fail on publisher.
	 */
	public void testSearchRecordFailOnPublisher() {
		boolean found = new JDBCSearcher(directory).search("name", "No Such Publisher");
		assertEquals(found, false);
	}
	
	/* (non-Javadoc)
	 * @see junit.framework.TestCase#tearDown()
	 */
	protected void tearDown() throws Exception {
		if(directory != null) {
			directory.close();
		}
		super.tearDown();
	}
}

Integrate LDAP and Spring Security 3.1 for Authentication and Authorization in a JSF 2.0 Application.

Posted on Updated on

Backtracking all our previous tutorial you will notice we always had our user definition with password placed in our database. Not every time this will be the case and frequently we will have to integrate our application with LDAP. In this tutorial we will integrate our earlier application with Apache Directory Services. If you don’t know how to configure Apache DS then take look at Configuring Apache DS.

In this post we are not implementing anything for remember-me service which we did earlier. Let’s get started with code changes to cater to LDAP Spring Security Integration for both Authentication and Authorization

First We will clean up jsfspring-sec-bean-config.xml as we don’t need anything related to database.

jsfspring-sec-bean-config.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
	   http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/security
	   http://www.springframework.org/schema/security/spring-security-3.1.xsd">
       
	<beans:bean id="navigator" name="navigator" class="com.mumz.jsfspringsec.beans.Navigator" scope="session">
		<beans:property name="businessModel" ref="businessModel"></beans:property>
	</beans:bean>
	
	<beans:bean id="loginBean" name="loginBean" class="com.mumz.jsfspringsec.beans.LoginBean" scope="prototype">
		<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
	</beans:bean>
	
	<beans:bean id="securityBean" class="com.mumz.jsfspringsec.beans.SecurityHolderBean" scope="session">
	</beans:bean>
	
	<beans:bean id="businessModel" class="com.mumz.jsfspringsec.business.model.BusinessModel" scope="prototype"></beans:bean>
	
	<beans:bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	 	<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<beans:property name="url" value="jdbc:mysql://localhost:3306/jsf-spring-security" />
		<beans:property name="username" value="root" />
		<beans:property name="password" value="root" />
   </beans:bean>
</beans:beans>

Notice that configuration is very simple and all information related to custom database and user details service have been removed.

Second we will update jsfspring-sec-security-config.xml. We will define LdapAuthenticationProvider which uses BindAuthenticator. This won’t work where LDAP is secured and logging to LDAP is disabled. In those cases use PasswordComparisonAuthenticator.

jsfspring-sec-security-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans:beans
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:sec="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
	  http://www.springframework.org/schema/beans
	  http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	  http://www.springframework.org/schema/security
	  http://www.springframework.org/schema/security/spring-security-3.1.xsd">
	  
	<sec:http auto-config="true" use-expressions="true">
		<sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" />
		<sec:intercept-url pattern="/pages/unsecure/**" access="permitAll"/>
		<sec:intercept-url pattern="/pages/common/**" access="permitAll"/>
		<sec:intercept-url pattern="/**" access="permitAll"/>
		<sec:form-login login-page="/pages/common/login.jsf"/>
		<sec:logout 
			invalidate-session="true" 
			delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE" 
			logout-success-url="/pages/common/login.jsf"></sec:logout>
	</sec:http>
	
	<sec:authentication-manager alias="authenticationManager">
		<sec:authentication-provider ref="ldapAuthProvider"></sec:authentication-provider>
	</sec:authentication-manager>
	
	<beans:bean id="ldapContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  		<beans:constructor-arg value="ldap://localhost:12389/o=mycompany"/>
  		<beans:property name="userDn" value="uid=admin,ou=system"/>
  		<beans:property name="password" value="secret"/>
	</beans:bean>
	
	<beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
 		<beans:constructor-arg>
   			<beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
     			<beans:constructor-arg ref="ldapContextSource"/>
     			<beans:property name="userDnPatterns">
	       			<beans:list>
	       				<beans:value>uid={0},ou=Users</beans:value>
	       			</beans:list>
     			</beans:property>
   			</beans:bean>
 		</beans:constructor-arg>
 		<beans:constructor-arg>
   			<beans:bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
     			<beans:constructor-arg ref="ldapContextSource"/>
     			<beans:constructor-arg value="ou=Groups"/>
     			<beans:property name="groupRoleAttribute" value="cn"/>
   			</beans:bean>
 		</beans:constructor-arg>
	</beans:bean>

	<sec:global-method-security pre-post-annotations="enabled"/>
		
</beans:beans>

Finally our sleek LoginBean.java which just does the login, remember me has been removed.

LoginBean.java

package com.mumz.jsfspringsec.beans;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;

/**
 * The Class LoginBean.
 */
@ManagedBean(name = "loginMgmtBean")
@RequestScoped
public class LoginBean {

	/** The user name. */
	private String					userName				= null;

	/** The password. */
	private String					password				= null;

	/** The remember me. */
	private String					rememberMe				= null;

	/** The authentication manager. */
	@ManagedProperty(value = "#{authenticationManager}")
	private AuthenticationManager	authenticationManager	= null;
	
	/**
	 * Login.
	 * 
	 * @return the string
	 */
	public String login() {
		try {
			Authentication result = null;
			Authentication request = new UsernamePasswordAuthenticationToken(this.getUserName(), this.getPassword());
			result = authenticationManager.authenticate(request);
			SecurityContextHolder.getContext().setAuthentication(result);
		} catch (AuthenticationException e) {
			e.printStackTrace();
		}
		return "Secured";
	}

	/**
	 * Cancel.
	 * 
	 * @return the string
	 */
	public String cancel() {
		return null;
	}

	/**
	 * Logout.
	 * 
	 * @return the string
	 */
	public String logout() {
		SecurityContextHolder.clearContext();
		/**
		 * Delete Cookies
		 */
		HttpServletRequest httpServletRequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
		HttpServletResponse httpServletResponse = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext()
				.getResponse();
		Cookie cookie = new Cookie("SPRING_SECURITY_REMEMBER_ME_COOKIE", null);
		cookie.setMaxAge(0);
		cookie.setPath(httpServletRequest.getContextPath().length() > 0 ? httpServletRequest.getContextPath() : "/");
		httpServletResponse.addCookie(cookie);
		return "loggedout";
	}

	/**
	 * Gets the user name.
	 * 
	 * @return the user name
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * Sets the user name.
	 * 
	 * @param userName
	 *            the new user name
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}

	/**
	 * Gets the password.
	 * 
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * Sets the password.
	 * 
	 * @param password
	 *            the new password
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * Gets the remember me.
	 * 
	 * @return the remember me
	 */
	public String getRememberMe() {
		return rememberMe;
	}

	/**
	 * Sets the remember me.
	 * 
	 * @param rememberMe
	 *            the new remember me
	 */
	public void setRememberMe(String rememberMe) {
		this.rememberMe = rememberMe;
	}

	/**
	 * Gets the authentication manager.
	 * 
	 * @return the authentication manager
	 */
	public AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	/**
	 * Sets the authentication manager.
	 * 
	 * @param authenticationManager
	 *            the new authentication manager
	 */
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}
}

That’s all we need for integration Spring Security and LDAP (Apache DS in this case) for both Authorization and Authentication. There is every possibility that LDAP may be used for Authentication and Authorization will be done from database, in another post we will look at one way of implementing such a solution.

References:

  1. Spring Source Documentation

Configuring Apache DS in Eclipse

Posted on Updated on

Lightweight Directory Access Protocol aka LDAP is a protocol used for maintaining data over distributed ENV. Most of the organization will use LDAP for holding there user information and more often then not in almost all our application we will authenticate user against LDAP. In this post we will configure Apache Directory which is built completely in Java and is an open source project of Apache.

First download and install Apache DS

Second install Apache DS plugin from Eclipse Marketplace or using Install New Software option in Eclipse.

Third change your Eclipse Perspective to LDAP

Fourth Right Click under Servers view and New -> New Server and give some name for your server.


Fifth Right click on your server and select LDAP Browser -> Create a connection. You should get a message saying “Connection Created”.


Sixth Double click on your server, this should open server.xml which is the configuration file, change port number of LDAP and LDAPS (since 10389 and 10636 is default port and is used by default server which is part of Apache DS installation).


Seventh Right click on your server and select Run, similarly Right Click on your connection and select Open Connection. Once your connection is open you can expand DIT under LDAP Browser to see the default values.


Eigth Now we will create an organization struture inside our LDAP Server, for that again Double Click on your server this will open up server.xml, in the tabbed pane choose Partitions. Click on Add and provide ID = mycompany, Cache Size = 100 and suffix = o=mycompany
and save.You may have to restart your server and refresh your connection to see updated values.


Ninth Double click on Root DSE this will open up Root DSE editor which will display new Partition that we created.

Tenth Right Click on Root DSE and Select New -> New Context Entry -> Create entry from scratch.

Eleventh choose Organization from Available classes and click on Add.


Twelfth Select o=mycompany as Distinguished Name.


Thirteenth Click on Finish


Fourteenth we will create user and groups under our partition mycompany. To create user right click on mycompany and choose New -> New Entry -> Create entry from scrath.

Fifteenth Select organizationUnit from available classes and click on Add, click on next and then fill in RDN as ou = Groups



Click on Finish and repeat the steps to create organizationUnit for Users

Sixteenth Select Users and then right click select New -> New Entry -> Create Entry from scratch and select inetOrgPerson from available classes and click on Add.


Seventeenth Fill in RDN as uid = testNormalUser and click on Next.


Eighteenth Fill in values for Common Name (cn) and Last Name (sn)


Nineteenth Right click on the editor and choose New Attribute, in the subsequent page type in userPassword and click on Finish



Twentieth Choose Plain Text as Hash Method and type in user password and click on Ok and then click on Finish in user creation page.


Twenty First Right click on Groups and select New -> New Entry -> Create entry from scratch and select groupOfNames, click on Next and then fill in RDN as ou=testNormalGroup.



Twenty Second In DN Editor browse to testNormalUser which we created. Click on OK and then fill in Common Name (cn) for Group and then click finish.




In similar way we can create multiple users and groups. We didn’t use Apache Directory Studio since it is not available for 64 bit machine.

Create Lucene Index in database using JdbcDirectory

Posted on Updated on

In our last post we built a simple index over file system. While our example works fine but cannot be extended over clustered environment and also cannot be used for a large document because of memory foot print. Lucene doesn’t provide a direct in built JDBC interface but Compass does, though the JDBC interface of Compass is not compatible with Lucene 3.6. We will extend Compass JDBC interface as per Lucene 3.6 changes.

First we will create our Maven Project in Eclipse and add required dependencies.

pom.xml

<project 
	xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=
		"http://maven.apache.org/POM/4.0.0 
		http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mumz.test.lucene</groupId>
	<artifactId>ApacheLuceneTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>ApacheLuceneTest</name>
	<description>ApacheLuceneTest</description>
	<dependencies>
		<dependency>
			<artifactId>lucene-core</artifactId>
			<groupId>org.apache.lucene</groupId>
			<type>jar</type>
			<version>3.6.1</version>
		</dependency>
		<dependency>
			<groupId>org.compass-project</groupId>
			<artifactId>compass</artifactId>
			<version>2.2.0</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
	</dependencies>
</project>

Second since JdbcDirectory provided with Compass 2.2.0 doesn’t implement all the methods defined in abstract class Directory, we will provide our own implementation which will extend JdbcDirectory.

JdbcDirectory

package com.mumz.test.lucene.jdbc;

import java.io.IOException;

import javax.sql.DataSource;

import org.apache.lucene.store.jdbc.JdbcDirectory;
import org.apache.lucene.store.jdbc.JdbcDirectorySettings;
import org.apache.lucene.store.jdbc.JdbcStoreException;
import org.apache.lucene.store.jdbc.dialect.Dialect;
import org.apache.lucene.store.jdbc.support.JdbcTable;

/**
 * The Class MyJDBCDirectory.
 * 
 * @author prabhat.jha
 */
public class MyJDBCDirectory extends JdbcDirectory {

	/**
	 * Instantiates a new my jdbc directory.
	 * 
	 * @param dataSource
	 *            the data source
	 * @param dialect
	 *            the dialect
	 * @param settings
	 *            the settings
	 * @param tableName
	 *            the table name
	 */
	public MyJDBCDirectory(DataSource dataSource, Dialect dialect, JdbcDirectorySettings settings, String tableName) {
		super(dataSource, dialect, settings, tableName);
	}

	/**
	 * Instantiates a new my jdbc directory.
	 *
	 * @param dataSource the data source
	 * @param dialect the dialect
	 * @param tableName the table name
	 */
	public MyJDBCDirectory(DataSource dataSource, Dialect dialect, String tableName) {
		super(dataSource, dialect, tableName);
	}

	/**
	 * Instantiates a new my jdbc directory.
	 *
	 * @param dataSource the data source
	 * @param settings the settings
	 * @param tableName the table name
	 * @throws JdbcStoreException the jdbc store exception
	 */
	public MyJDBCDirectory(DataSource dataSource, JdbcDirectorySettings settings, String tableName) throws JdbcStoreException {
		super(dataSource, settings, tableName);
	}

	/**
	 * Instantiates a new my jdbc directory.
	 *
	 * @param dataSource the data source
	 * @param table the table
	 */
	public MyJDBCDirectory(DataSource dataSource, JdbcTable table) {
		super(dataSource, table);
	}

	/**
	 * Instantiates a new my jdbc directory.
	 *
	 * @param dataSource the data source
	 * @param tableName the table name
	 * @throws JdbcStoreException the jdbc store exception
	 */
	public MyJDBCDirectory(DataSource dataSource, String tableName) throws JdbcStoreException {
		super(dataSource, tableName);
	}

	/**
	 * (non-Javadoc).
	 *
	 * @return the string[]
	 * @throws IOException Signals that an I/O exception has occurred.
	 * @see org.apache.lucene.store.Directory#listAll()
	 */
	@Override
	public String[] listAll() throws IOException {
		return super.list();
	}
}

JdbcDirectory has a predefined table structure where it works on a clob field.

Third we will write our Indexer code. In our code we will achieve following:

  1. Add few records in our database by using JDBCBatchInsert.java
  2. Create table to be used by JdbcDirectory using createIndexTable method
  3. Build an index on this record by using index method

Let’s add some records in our database for testing our application.
JDBCBatchInsert.java

package com.mumz.test.lucene.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * The Class JDBCBatchInsert.
 * @author prabhat.jha
 */
public class JDBCBatchInsert {
	
	/** The Constant QUERY. */
	private static final String		QUERY			= "INSERT INTO BOOKS (BOOK_ID, BOOK_NAME, BOOK_AUTHOR, BOOK_PUBLISHER) VALUES (?, ?, ?, ?)";

	/** The Constant BOOK_FIRST_PART. */
	private final static String[]	BOOK_FIRST_PART	= {"Spring", "Hibernate", "Lucene", "Mahout", "JPA", "JSF", "Swing", "Hadoop", "Hbase"};

	/** The Constant BOOK_LAST_PART. */
	private final static String[]	BOOK_LAST_PART	= {"In Action", "Complete Reference", "Demystified", "Tutorial", "Explained",
			"Simplified", "Bible", "Cook Book", "Crash Course"};

	/** The Constant BLANK_SPACE. */
	private final static String		BLANK_SPACE		= " ";

	/**
	 * Insert records.
	 */
	public void insertRecords() {
		Connection connection = null;
		PreparedStatement pstmt = null;
		ResultSet resultSet = null;
		try {
			connection = JDBCDatabaseUtil.getConnection();
			pstmt = connection.prepareStatement(QUERY);
			int index = 0;
			for (String firstPart : BOOK_FIRST_PART) {
				for (String lastPart : BOOK_LAST_PART) {
					pstmt.setInt(1, ++index);
					pstmt.setString(2, firstPart + BLANK_SPACE + lastPart);
					pstmt.setString(3, "Test Author" + BLANK_SPACE + firstPart + BLANK_SPACE + lastPart + index);
					pstmt.setString(4, "Test Publisher" + BLANK_SPACE + firstPart + BLANK_SPACE + lastPart + index);
					pstmt.addBatch();
				}
			}
			pstmt.executeBatch();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (resultSet != null) {
					resultSet.close();
				}
				if (pstmt != null) {
					pstmt.close();
				}
				if (connection != null) {
					connection.close();
				}
				resultSet = null;
				pstmt = null;
				connection = null;
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

Next we will add index in our database.
JDBCIndexer.java

package com.mumz.test.lucene.jdbc;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.jdbc.JdbcDirectory;
import org.apache.lucene.store.jdbc.dialect.MySQLDialect;
import org.apache.lucene.util.Version;

/**
 * The Class JDBCIndexer.
 * 
 * @author prabhat.jha
 */
public class JDBCIndexer {

	/** The jdbc directory. */
	private Directory	jdbcDirectory	= null;

	/**
	 * Instantiates a new jDBC indexer.
	 * 
	 * @param jdbcDirectory
	 *            the jdbc directory
	 */
	public JDBCIndexer(Directory jdbcDirectory) {
		super();
		this.jdbcDirectory = jdbcDirectory;
	}
	/**
	 * Gets the jdbc directory.
	 * 
	 * @return the jdbc directory
	 */
	public Directory getJdbcDirectory() {
		if (jdbcDirectory == null) {
			throw new IllegalStateException("Index not yet build, rerun indexing");
		}
		return jdbcDirectory;
	}

	/**
	 * Sets the jdbc directory.
	 * 
	 * @param jdbcDirectory
	 *            the new jdbc directory
	 */
	public void setJdbcDirectory(Directory jdbcDirectory) {
		this.jdbcDirectory = jdbcDirectory;
	}

	/**
	 * Builds the index.
	 */
	public void buildIndex() {
		createAndBuildIndex();
	}

	/**
	 * Creates the and build index.
	 */
	private void createAndBuildIndex() {
		createIndexTable();
		index();
	}

	/**
	 * Index.
	 */
	private void index() {
		Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_36);
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
		IndexWriter indexWriter = null;
		try {
			indexWriter = new IndexWriter(getJdbcDirectory(), indexWriterConfig);
			addIndex(indexWriter);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (indexWriter != null) {
				try {
					indexWriter.close();
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					indexWriter = null;
				}
			}
		}
	}

	/**
	 * Add index on records present in BOOKS table
	 * 
	 * @param indexWriter
	 *            the index writer
	 */
	private void addIndex(IndexWriter indexWriter) {
		try {
			Connection connection = JDBCDatabaseUtil.getConnection();
			String query = "SELECT BOOK_ID, BOOK_NAME, BOOK_AUTHOR, BOOK_PUBLISHER FROM BOOKS";
			PreparedStatement pstmt = connection.prepareStatement(query);
			ResultSet resultSet = pstmt.executeQuery();
			while (resultSet.next()) {
				Document document = new Document();
				document.add(new Field("name", String.valueOf(resultSet.getString(2)), Field.Store.YES, Field.Index.ANALYZED));
				document.add(new Field("author", String.valueOf(resultSet.getString(3)), Field.Store.YES, Field.Index.ANALYZED));
				document.add(new Field("publisher", String.valueOf(resultSet.getString(4)), Field.Store.YES, Field.Index.ANALYZED));
                indexWriter.addDocument(document);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Creates the index table.
	 */
	private void createIndexTable() {
		if (this.jdbcDirectory == null) {
			setJdbcDirectory(new MyJDBCDirectory(JDBCDatabaseUtil.getDataSource(), new MySQLDialect(), "LUCENE_INDEX_TABLE"));
		}
		try {
			/**
			 * No need to manually create index table, create method will
			 * automatically create it.
			 */
			((JdbcDirectory) getJdbcDirectory()).create();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Last we have used getDataSource and getConnection methods while inserting records and building index, these two methods are utility methods part of our database util.

JDBCDatabaseUtil.java


package com.mumz.test.lucene.jdbc;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

/**
 * The Class JDBCDatabaseUtil.
 * @author prabhat.jha
 */
public class JDBCDatabaseUtil {
	/**
	 * Gets the data source.
	 * 
	 * @return the data source
	 */
	public static DataSource getDataSource() {
		MysqlDataSource dataSource = new MysqlDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("root");
		dataSource.setUrl("jdbc:mysql://localhost:3306/search_schema?emulateLocators=true&useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false");
		return dataSource;
	}

	/**
	 * Gets the connection.
	 * 
	 * @return the connection
	 * @throws SQLException
	 *             the sQL exception
	 */
	public static Connection getConnection() throws SQLException {
		return getDataSource().getConnection();
	}
}

Finally sql script to create our database schema which will be used in this tutorial.


SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `search_schema` ;
CREATE SCHEMA IF NOT EXISTS `search_schema` DEFAULT CHARACTER SET utf8 ;
USE `search_schema` ;

-- -----------------------------------------------------
-- Table `search_schema`.`books`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `search_schema`.`books` ;

CREATE  TABLE IF NOT EXISTS `search_schema`.`books` (
  `BOOK_ID` INT(11) NOT NULL AUTO_INCREMENT ,
  `BOOK_NAME` VARCHAR(45) NOT NULL ,
  `BOOK_AUTHOR` VARCHAR(45) NOT NULL ,
  `BOOK_PUBLISHER` VARCHAR(45) NOT NULL ,
  PRIMARY KEY (`BOOK_ID`) )
ENGINE = InnoDB
AUTO_INCREMENT = 82
DEFAULT CHARACTER SET = utf8;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Integrating Apache Lucene and Maven in Eclipse

Posted on

In two steps we will integrate Apache Lucene and Maven in Eclipse.

First Create Java Project using Maven in Eclipse

Second add lucene dependency in your pom.xml, so you pom.xml should look like this:
pom.xml

<project 
	xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=
		"http://maven.apache.org/POM/4.0.0 
		http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mumz.test.lucene</groupId>
	<artifactId>ApacheLuceneTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>ApacheLuceneTest</name>
	<description>ApacheLuceneTest</description>
	<dependencies>
		<dependency>
			<artifactId>lucene-core</artifactId>
			<groupId>org.apache.lucene</groupId>
			<type>jar</type>
			<version>3.6.1</version>
		</dependency>
	</dependencies>
</project>

That’s all.

Index and Search a Directory using Apache Lucene

Posted on

Building a custom search is a common requirement in almost every application. Building such a system can be complex and tedious with numerous use cases around. Apache Lucene is a search framework built in Java. In this tutorial we will write a small application which will use Lucene to search a given directory.

Lucene works on mainly two concepts:

  1. Index : Lucene provides great search throughput by building an index on the content and then searching those indexes. Content is divided into smaller units and indexed.
  2. Search : Once indexing is complete any query can be compared with the indexes and result is obtained.

First we will build our Eclipse Maven Project. Below is our pom.xml.

pom.xml

<project 
	xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=
		"http://maven.apache.org/POM/4.0.0 
		http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mumz.test.lucene</groupId>
	<artifactId>ApacheLuceneTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>ApacheLuceneTest</name>
	<description>ApacheLuceneTest</description>
	<dependencies>
		<dependency>
			<artifactId>lucene-core</artifactId>
			<groupId>org.apache.lucene</groupId>
			<type>jar</type>
			<version>3.6.1</version>
		</dependency>
	</dependencies>
</project>

Second we will write out Indexer. Indexer accepts a path to directory and then recursively reads content of that directory and builds an in-memory index. Smaller units in Lucene is called as Document and you can add multiple Fields to your document. Here we are adding file name to our index and we are calling it as title.

InMemoryDirectoryIndexer.java


package com.mumz.test.lucene.first;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

/**
 * The Class InMemoryDirectoryIndexer.
 * @author prabhat.jha
 */
public class InMemoryDirectoryIndexer {
	
	/** The directory. */
	private Directory	directory	= null;

	/**
	 * The Constructor.
	 * 
	 * @param path
	 *            the path
	 */
	public InMemoryDirectoryIndexer(String path) {
		indexDirectory(path);
	}

	/**
	 * Gets the directory.
	 * 
	 * @return the directory
	 */
	public Directory getDirectory() {
		if (directory == null) {
			throw new IllegalStateException("Index hasn't been built, check configratuion and reIndex");
		}
		return directory;
	}

	/**
	 * Index directory.
	 * 
	 * @param path
	 *            the path
	 */
	private void indexDirectory(String path) {
		/**
		 * We will create an in memory search, don't do this if you are indexing a huge amount of data
		 * as this can lead to heavy memory foot print.
		 */
		directory = new RAMDirectory();
		/**
		 * Specify the version, if there is a change in lucene version we have to reindex
		 */
		Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_36);
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
		IndexWriter indexWriter = null;
		try {
			/** 
			 * Create index writer
			 */
			indexWriter = new IndexWriter(directory, indexWriterConfig);
			File root = new File(path);
			/**
			 * Add files recursively to index writer
			 */
			addIndex(indexWriter, root);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (indexWriter != null) {
					indexWriter.close();
				}
				indexWriter = null;
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * Adds the index.
	 * 
	 * @param indexWriter
	 *            the index writer
	 * @param root
	 *            the root
	 * @throws CorruptIndexException
	 *             the corrupt index exception
	 * @throws IOException
	 *             the IO exception
	 */
	private void addIndex(IndexWriter indexWriter, File root) throws CorruptIndexException, IOException{
		for (File file : root.listFiles()) {
			if(file.isDirectory()){
				addIndex(indexWriter, file);
			}
			Document document = new Document();
			document.add(new Field("title", file.getName(), Field.Store.YES, Field.Index.ANALYZED));
			indexWriter.addDocument(document);
		}
	}
}

Third we will write our Searcher, code which searches against the index built in the last step.
InMemoryDirectorySearcher.java


package com.mumz.test.lucene.first;

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;

/**
 * The Class InMemoryDirectorySearcher.
 * @author prabhat.jha
 */
public class InMemoryDirectorySearcher {
	
	/** The directory. */
	private Directory	directory	= null;

	/**
	 * The Constructor.
	 * 
	 * @param directory
	 *            the directory
	 */
	public InMemoryDirectorySearcher(Directory directory) {
		this.directory = directory;
	}

	/**
	 * Search.
	 * 
	 * @param fileName
	 *            the file name
	 * @return the string
	 */
	public void search(String fileName) {
		IndexSearcher indexSearcher = null;
		try {
			/**
			 * Specify the version
			 */
			Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_36);
			/**
			 * Create query from the file name, we built out index for title so we have to search against the same.
			 */
			Query query = new QueryParser(Version.LUCENE_36, "title", analyzer).parse(fileName);
			IndexReader indexReader = IndexReader.open(directory);
			indexSearcher = new IndexSearcher(indexReader);
			/**
			 * This will hold all the results which results from the search operation
			 */
			TopScoreDocCollector results = TopScoreDocCollector.create(100, true);
			indexSearcher.search(query, results);
			ScoreDoc[] scores = results.topDocs().scoreDocs;
			for (ScoreDoc scoreDoc : scores) {
				System.out.println("Found : " + indexSearcher.doc(scoreDoc.doc).get("title") + " with hits : " + scoreDoc.score);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(indexSearcher != null){
				try {
					indexSearcher.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			indexSearcher = null;
		}
	}
}

Final step is to write a simple java class to showcase our indexer and searcher in action.
InMemoryMainApp.java


package com.mumz.test.lucene.first;

import java.util.Scanner;

/**
 * The Class InMemoryMainApp.
 * @author prabhat.jha
 */
public class InMemoryMainApp {
	
	/**
	 * The main method.
	 * 
	 * @param args
	 *            the args
	 */
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		System.out.println("Enter directory name");
		String directory = scanner.next();
		System.out.println("Should Index ? Enter Y for Yes or else q or quit to exit.");
		String response = scanner.next();
		if("q".equalsIgnoreCase(response) || "quit".equalsIgnoreCase(response)){
			scanner.close();
			System.exit(1);
		}
		if("y".equalsIgnoreCase(response)){
			InMemoryDirectoryIndexer inMemoryDirectoryIndexer = new InMemoryDirectoryIndexer(directory);
			while(true){
				System.out.println("Enter fileName to query or quit to exit.");
				String fileName = scanner.next();
				if("Quit".equalsIgnoreCase(fileName)){
					scanner.close();
					System.exit(1);
				}
				InMemoryDirectorySearcher inMemoryFileSearcher = new InMemoryDirectorySearcher(inMemoryDirectoryIndexer.getDirectory());
				inMemoryFileSearcher.search(fileName);
			}
		}
	}
}

That’s all, we have just touched tip of the iceberg. It is a vast and very interesting space, let’s see how much we can cover in coming days.