/*
* Copyright (c) 2016-2017 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.support.io;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import javax.batch.api.BatchProperty;
import javax.batch.api.chunk.ItemReader;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.Query;
/**
* An implementation of {@code javax.batch.api.chunk.ItemReader} that reads
* data with Java Persistence API (JPA).
*
* @see JpaItemWriter
* @since 1.3.0
*/
@Named
@Dependent
public class JpaItemReader extends JpaItemReaderWriterBase implements ItemReader {
/**
* {@code javax.enterprise.inject.Instance} that holds optional injection of
* {@code javax.persistence.Query}.
*/
@Inject
protected Instance<Query> queryInstance;
/**
* a Java Persistence query string. Optional properties, and defaults to null.
*/
@Inject
@BatchProperty
protected String jpqlQuery;
/**
* The name of a query defined in JPA metadata.
* Optional property, and defaults to null.
*/
@Inject
@BatchProperty
protected String namedQuery;
/**
* A native SQL query string. Optional property, and defaults to null.
*/
@Inject
@BatchProperty
protected String nativeQuery;
/**
* A name of the stored procedure in the database.
* Optional procedure, and defaults to null.
*/
@Inject
@BatchProperty
protected String storedProcedureQuery;
/**
* A name assigned to the stored procedure query in JPA metadata.
* Optional property, and defaults to null.
*/
@Inject
@BatchProperty
protected String namedStoredProcedureQuery;
/**
* The Java type of the query result object.
* Optional properties, and defaults to null.
*/
@Inject
@BatchProperty
protected Class beanType;
/**
* Name of the resultset mapping. Optional properties, and defaults to null.
* If specified, it is used to create native query or stored procedure query.
*/
@Inject
@BatchProperty
protected String resultSetMapping;
/**
* Query hint properties, as a list of key-value pairs separated by comma (,).
* Optional property, and defaults to null.
*/
@Inject
@BatchProperty
protected Map<String, String> hints;
/**
* Position of the first result, numbered from 0. Optional property, and
* defaults to 0.
*/
@Inject
@BatchProperty
protected int firstResult;
/**
* Maximum number of results to retrieve by the query. Optional property, and
* defaults to 0 (no limit).
*/
@Inject
@BatchProperty
protected int maxResults;
/**
* The JPA query object
*/
protected Query query;
/**
* List to hold query result objects
*/
protected List<?> resultList;
/**
* Current read position
*/
protected int readPosition;
/**
* {@inheritDoc}
*/
@Override
public void open(final Serializable checkpoint) throws Exception {
query = getQuery();
if (firstResult != 0) {
query.setFirstResult(firstResult);
}
if (maxResults != 0) {
query.setMaxResults(maxResults);
}
resultList = query.getResultList();
if (checkpoint == null) {
readPosition = 0;
} else {
readPosition = (Integer) checkpoint;
}
}
/**
* {@inheritDoc}
*/
@Override
public void close() throws Exception {
}
/**
* {@inheritDoc}
*/
@Override
public Object readItem() throws Exception {
if (readPosition >= resultList.size()) {
return null;
}
return resultList.get(readPosition++);
}
/**
* {@inheritDoc}
*/
@Override
public Serializable checkpointInfo() throws Exception {
return readPosition;
}
/**
* Creates and initializes the JPA query object based on the configuration
* in this reader class, in the following order of precedence:
* <ol>
* <li>{@link #queryInstance}
* <li>{@link #jpqlQuery}
* <li>{@link #namedQuery}
* <li>{@link #nativeQuery}
* <li>{@link #storedProcedureQuery}
* <li>{@link #namedStoredProcedureQuery}
* </ol>
* @return JPA query object
*/
protected Query getQuery() {
Query q = null;
if (queryInstance != null && !queryInstance.isUnsatisfied()) {
q = queryInstance.get();
}
if (q == null) {
if (jpqlQuery != null) {
q = beanType != null ? em.createQuery(jpqlQuery, beanType) :
em.createQuery(jpqlQuery);
} else if (namedQuery != null) {
q = beanType != null ? em.createNamedQuery(namedQuery, beanType) :
em.createNamedQuery(namedQuery);
} else if (nativeQuery != null) {
q = beanType != null ? em.createNativeQuery(nativeQuery, beanType) :
resultSetMapping != null ? em.createNativeQuery(nativeQuery, resultSetMapping) :
em.createNativeQuery(nativeQuery);
} else if (storedProcedureQuery != null) {
q = beanType != null ? em.createStoredProcedureQuery(storedProcedureQuery, beanType) :
resultSetMapping != null ? em.createStoredProcedureQuery(storedProcedureQuery, resultSetMapping) :
em.createStoredProcedureQuery(storedProcedureQuery);
} else if (namedStoredProcedureQuery != null) {
q = em.createNamedStoredProcedureQuery(namedStoredProcedureQuery);
}
}
if (firstResult != 0) {
q.setFirstResult(firstResult);
}
if (maxResults != 0) {
q.setMaxResults(maxResults);
}
if (hints != null) {
for (final Map.Entry<String, String> e : hints.entrySet()) {
q.setHint(e.getKey(), e.getValue());
}
}
return q;
}
}