Skip to content

Commit

Permalink
change batch job from a print demo to lucene demo
Browse files Browse the repository at this point in the history
  • Loading branch information
mincong-h committed May 21, 2016
1 parent b72158b commit aaf0441
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 5 deletions.
@@ -1,17 +1,151 @@
package io.github.mincongh.batch;

import java.io.Serializable;

import javax.batch.api.chunk.ItemProcessor;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.Session;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.search.backend.AddLuceneWork;
import org.hibernate.search.bridge.TwoWayFieldBridge;
import org.hibernate.search.bridge.spi.ConversionContext;
import org.hibernate.search.bridge.util.impl.ContextualExceptionBridgeHelper;
import org.hibernate.search.engine.impl.HibernateSessionLoadingInitializer;
import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;
import org.hibernate.search.engine.spi.EntityIndexBinding;
import org.hibernate.search.hcore.util.impl.ContextHelper;
import org.hibernate.search.spi.InstanceInitializer;

import io.github.mincongh.entity.Address;

@Named
public class AddressProcessor implements ItemProcessor {

// Entity manager is used for fetching entities from persistence context.
@PersistenceContext(unitName = "us-address")
private EntityManager em;

// Hibernate session
private Session session;

// Interface which gives access to runtime configuration
// Intended to be used by Search components
private ExtendedSearchIntegrator searchIntegrator;

// Entity index binding specifies the relation and options from an indexed
// entity to its index(es).
// private Map<Class<?>, EntityIndexBinding> entityIndexBindings;
private EntityIndexBinding entityIndexBinding;

// The document builder for indexed entity (Address)
private DocumentBuilderIndexedEntity docBuilder;

// TODO: what is a session initializer ?
private InstanceInitializer sessionInitializer;

// TODO: add description
private ConversionContext conversionContext;

/**
* Builds the Lucene {@code Document} for a given entity instance and its id
* using +org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity+.
*
*/
@Override
public Object processItem(Object item) throws Exception {

// TODO: initialization should be placed in a better location
if (entityIndexBinding == null) {
init();
}

Address address = (Address) item;
System.out.printf("Processing item %d ...%n", address.getAddressId());
return address;

// // This is a test. At the very beginning, this processor do nothing
// // but print the entity (address) id:
// System.out.printf("Processing item %d ...%n", address.getAddressId());
// return address;

// Builds the Lucene {@code Document} for a given entity.

// Tenant-aware
// Hibernate Search supports multi-tenancy on top of Hibernate ORM,
// it stores the tenant identifier in the document and automatically
// filters the query results. The FullTextSession will be bound to
// the specific tenant ("client-A" in the example) and the mass indexer
// will only index the entities associated to that tenant identifier.
// TODO: can it be null for a single-tenancy db ?
String tenantId = null;

Serializable id = session.getIdentifier(address);
TwoWayFieldBridge idBridge = docBuilder.getIdBridge();
conversionContext.pushProperty(docBuilder.getIdKeywordName());
String idInString = null;
try {
idInString = conversionContext
.setClass(Address.class)
.twoWayConversionContext(idBridge)
.objectToString(id);
} finally {
conversionContext.popProperty();
}
AddLuceneWork addWork = docBuilder.createAddWork(
tenantId,
Address.class,
address,
id,
idInString,
sessionInitializer,
conversionContext
);
return addWork;
}

/**
* Initialization for different classes required for the the Lucene
* document conversion.
*
*/
private void init() {

// Get Hibernate session from JPA entity manager
session = em.unwrap(Session.class);

// TODO: construct SessionImplementor before getting searchIntegrator
// but how should I use it ? This class belongs to org.hibernate.engine.
// ...
// get extendedSearchIntegrator via ContextHelper using hibernate
// session
searchIntegrator = ContextHelper.getSearchintegrator(session);

// In the previous implementation (currently used in HSERACH), the class
// IdentifierConsumerDocumentProducer is used to get the index bindings
// but this time, reader interacts directly with searchIntegrator to
// these bindings. Once bindings assigned, we need to find out the
// matched binding for the target class:
//
// io.github.mincongh.entity.Address
//
entityIndexBinding = searchIntegrator
.getIndexBindings()
.get(Address.class);

// TODO: There should be optimizations here, but they're omitted at the
// first time for simply the process
// ...
// Get the document builder
docBuilder = entityIndexBinding.getDocumentBuilder();

// initialize conversion context
conversionContext = new ContextualExceptionBridgeHelper();

// initialize session initializer
sessionInitializer = new HibernateSessionLoadingInitializer(
(SessionImplementor) session
);
}
}
Expand Up @@ -12,6 +12,8 @@
import io.github.mincongh.entity.Address;

/**
* The item reader, which reads entities from Hibernate session and more
* TODO: add more explicit explanations
*
* @author Mincong HUANG
*/
Expand Down
Expand Up @@ -6,7 +6,7 @@
import javax.batch.api.chunk.ItemWriter;
import javax.inject.Named;

import io.github.mincongh.entity.Address;
import org.hibernate.search.backend.AddLuceneWork;

@Named
public class AddressWriter implements ItemWriter {
Expand All @@ -27,11 +27,21 @@ public void open(Serializable arg0) throws Exception {
// TODO Auto-generated method stub
}

/**
* Write items to destination :
* TODO: add more description here
* For instance, they do nothing but print to the console.
*
* @param items items to write. This is a list of AddLuceneWorks processed
* previously by the AddressProcessor.
*/
@Override
public void writeItems(List<Object> items) throws Exception {
System.out.println("----------wirteItems(List<Object>) start----------");
for (Object item: items) {
System.out.printf("%d,", ((Address) item).getAddressId());
// System.out.printf("%d,", ((Address) item).getAddressId());
System.out.println((AddLuceneWork) item);
}
System.out.printf("%n");
System.out.println("----------wirteItems(List<Object>) end----------");
}
}
Expand Up @@ -6,6 +6,9 @@
import javax.batch.runtime.JobExecution;
import javax.ejb.Asynchronous;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

/**
* Session bean for different batch processes.
Expand All @@ -15,8 +18,17 @@
@Stateful
public class BatchSession {

// Job operator is used to control different batch jobs
private JobOperator jobOperator;

// This particular EntityManager is injected as an EXTENDED persistence
// context, which simply means that the EntityManager is created when the
// @Stateful bean is created and destroyed when the @Stateful bean is
// destroyed. Simply put, the data in the EntityManager is cached for the
// lifetime of the @Stateful bean
@PersistenceContext(unitName = "us-address", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

public BatchSession() {
this.jobOperator = BatchRuntime.getJobOperator();
}
Expand Down

0 comments on commit aaf0441

Please sign in to comment.