All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jk.data.dataaccess.orm.JKObjectDataAccessImpl Maven / Gradle / Ivy

/*
 * Copyright 2002-2022 Dr. Jalal Kiswani. 
 * Email: [email protected]
 * Check out https://smart-api.com for more details
 * 
 * All the opensource projects of Dr. Jalal Kiswani are free for personal and academic use only, 
 * for commercial usage and support, please contact the author.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jk.data.dataaccess.orm;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.hibernate.CacheMode;
import org.hibernate.query.spi.QueryImplementor;

import com.jk.core.cache.JKCacheFactory;
import com.jk.core.cache.JKCacheManager;
import com.jk.core.config.JKConfig;
import com.jk.core.config.JKConstants;
import com.jk.core.context.JKContextFactory;
import com.jk.core.jpa.BaseEntity;
import com.jk.core.logging.JKLogger;
import com.jk.core.logging.JKLoggerFactory;
import com.jk.core.util.JK;
import com.jk.data.dataaccess.JKDataAccessFactory;
import com.jk.data.dataaccess.orm.meta.JKColumnWrapper;
import com.jk.data.dataaccess.orm.meta.JKSortInfo;
import com.jk.data.datasource.JKDataSource;
import com.jk.data.datasource.JKDataSourceFactory;
import com.jk.data.exceptions.JKDataAccessManyRowsException;

import jakarta.persistence.EntityManager;

// TODO: Auto-generated Javadoc
/**
 * The Class JKObjectDataAccessImpl.
 */
public class JKObjectDataAccessImpl implements JKObjectDataAccess {

	/** The max results. */
	int maxResults = JKConfig.get().getPropertyAsInteger(JKConstants.Database.ORM_RESULTS_MAX, 1000);
	/** The logger. */
	JKLogger logger = JKLoggerFactory.getLogger(getClass());
	
	/** The cache manager. */
	JKCacheManager cacheManager = JKCacheFactory.getCacheManager();

	/** The data source. */
	private JKDataSource dataSource;

	/** The entity manager. */
	private EntityManager entityManager;

	/** The roll back current transaction. */
	private boolean rollBackCurrentTransaction;

	/**
	 * Instantiates a new JK object data access impl.
	 */
	public JKObjectDataAccessImpl() {
	}

	/**
	 * Instantiates a new JK object data access impl.
	 *
	 * @param dataSourcePrefix the data source prefix
	 */
	public JKObjectDataAccessImpl(String dataSourcePrefix) {
		this(JKDataSourceFactory.getDataSource(dataSourcePrefix));
	}

	/**
	 * Instantiates a new JK object data access impl.
	 *
	 * @param dataSource the data source
	 */
	public JKObjectDataAccessImpl(JKDataSource dataSource) {
		this.dataSource = dataSource;
	}

	/**
	 * Insert.
	 *
	 * @param     the generic type
	 * @param object the object
	 * @return the t
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#insert(java.lang.Object)
	 */
	@Override
	public  T insert(T object) {
		logger.debug("Insert object ({})", object.getClass().getName());
		EntityManager manager = getEntityManager(true);
		boolean commit = false;
		try {
			handleTimeStamps(object);
			manager.persist(object);
			manager.flush();
			commit = true;
			return object;
//			return JKObjectUtil.getPropertyValue(object, "id");
		} finally {
			close(manager, commit);
			logger.debug("/Insert object ({})", object.getClass().getName());
		}
	}

	/**
	 * Update.
	 *
	 * @param     the generic type
	 * @param object the object
	 * @return the t
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#update(java.lang.Object)
	 */
	@Override
	public  T update(T object) {
		logger.debug("Update object ({})", object.getClass().getName());
		EntityManager manager = getEntityManager(true);
		boolean commit = false;
		try {
			handleTimeStamps(object);
			T merge = manager.merge(object);
			manager.flush();
			commit = true;
			return merge;
		} finally {
			close(manager, commit);
			logger.debug("/Update object ({})", object.getClass().getName());
		}
	}

	/**
	 * Handle time stamps.
	 *
	 * @param     the generic type
	 * @param object the object
	 */
	public  void handleTimeStamps(T object) {
		logger.debug("handleTimeStamps");
		if (object instanceof BaseEntity) {
			BaseEntity baseEntity = (BaseEntity) object;
			baseEntity.setModDate(new Date());
			baseEntity.setModUser(JKContextFactory.getCurrentContext().getUserName());
			if (baseEntity.getCrtDate() == null) {
				// for backword compatibility
				baseEntity.setCrtDate(new Date());
				baseEntity.setCrtUser(JKContextFactory.getCurrentContext().getUserName());
			}
		}
		logger.debug("/handleTimeStamps");
	}

	/**
	 * Find.
	 *
	 * @param   the generic type
	 * @param clas the clas
	 * @param id   the id
	 * @return the t
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.jk.db.test.dataaccess.orm.JKObjectDataAccess#find(java.lang.Class,
	 * java.lang.Object)
	 */
	@Override
	public  T find(Class clas, Object id) {
		logger.debug("Find object ({}) with id ({})", clas.getName(), id);
		EntityManager manager = getEntityManager(false);
		try {
			return manager.find(clas, id);
		} finally {
			close(manager, false);
			logger.debug("/Find object ({}) with id ({})", clas.getName(), id);
		}
	}

	/**
	 * Delete.
	 *
	 * @param     the generic type
	 * @param object the object
	 * @return the t
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#delete(java.lang.Object)
	 */
	@Override
	public  T delete(T object) {
		logger.debug("delete object ({})", object.getClass().getName());
		EntityManager manager = getEntityManager(true);
		boolean commit = false;
		try {
			object = manager.merge(object);
			manager.remove(object);
			manager.flush();
			commit = true;
			return object;
		} finally {
			close(manager, commit);
			logger.debug("/delete object ({})", object.getClass().getName());
		}
	}

	/**
	 * Delete.
	 *
	 * @param   the generic type
	 * @param type the type
	 * @param id   the id
	 * @return the t
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#delete(java.lang.Object,
	 * java.lang.Class)
	 */
	@Override
	public  T delete(Class type, Object id) {
		logger.debug("Delete object ({}) with id ({})", type.getName(), id);
		EntityManager manager = getEntityManager(true);
		boolean commit = false;
		try {
			T object = (T) manager.find(type, id);
			manager.remove(object);
			manager.flush();
			commit = true;
			return object;
		} finally {
			close(manager, commit);
			logger.debug("/Delete object ({}) with id ({})", type.getName(), id);
		}
	}

	/**
	 * Gets the list.
	 *
	 * @param   the generic type
	 * @param clas the clas
	 * @return the list
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#getList(java.lang.Class)
	 */
	@Override
	public  List getList(Class clas) {
		logger.debug("getList ({}) ", clas.getName());
		return getList(clas, null);
	}
	
	/**
	 * Gets the list and cache.
	 *
	 * @param  the generic type
	 * @param clas the clas
	 * @return the list and cache
	 */
	@Override
	public  List getListAndCache(Class clas) {
		logger.debug("getListAndCache ({}) ", clas.getName());
		String key = clas.getName()+"-list";

		List list = cacheManager.get(key, List.class);
		if(list!=null) {
			logger.debug("List with key ({}) found in cache", key);
		}else {
			list=getList(clas, null);
			cacheManager.cache(key, list, List.class);
		}
		
		return list;
	}


	/**
	 * Gets the list.
	 *
	 * @param        the generic type
	 * @param clas      the clas
	 * @param paramters the paramters
	 * @return the list
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jk.db.test.dataaccess.orm.JKObjectDataAccess#getList(java.lang.Class,
	 * java.util.Map)
	 */
	@Override
	public  List getList(Class clas, Map paramters) {
		logger.debug("getList for entity ({}) with paramters ({}) ", clas.getName(), paramters);
//		EntityManager manager = getEntityManager();
		try {
			StringBuffer buf = new StringBuffer("SELECT c FROM ".concat(clas.getSimpleName()).concat(" c "));
			buf.append(" WHERE 1=1 ");
			if (paramters != null) {
				Set keySet = paramters.keySet();
				int counter = 1;
				for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
					String paramName = (String) iterator.next();
					buf.append(String.format(" AND c.%s=?%d", paramName, counter++));
				}
				// TODO : check the paramters for order
				return executeQuery(clas, buf.toString(), paramters.values().toArray());
			}
			return executeQuery(clas, buf.toString());
		} finally {
			logger.debug("/getList for entity ({}) with paramters ({}) ", clas.getName(), paramters);
//			close(manager, true);
		}
	}

	/**
	 * Execute query.
	 *
	 * @param          the generic type
	 * @param clas        the clas
	 * @param queryString the query string
	 * @param paramters   the paramters
	 * @return the list
	 */
	@Override
	public  List executeQuery(final Class clas, final String queryString, final Object... paramters) {
		logger.debug("executeQuery for class ({}) with query ({}) with params ({})", clas.getName(), queryString,
				Arrays.toString(paramters));
		EntityManager em = getEntityManager(false);
		try {
			QueryImplementor query = (QueryImplementor) em.createQuery(queryString, clas);
			if (JKConfig.get().getPropertyAsBoolean("jk.data.jpa.query.cache", true)) {
				query.setCacheable(true);
				query.setCacheMode(CacheMode.NORMAL);
				query.setCacheRegion(queryString + Arrays.toString(paramters));
			}
			for (int i = 0; i < paramters.length; i++) {
				Object object = paramters[i];
				query.setParameter(i + 1, object);
			}
			query.setMaxResults(maxResults);
			logger.debug("executeQuery query.getResultList() for class ({}) with query ({}) with params ({})",
					clas.getName(), queryString, Arrays.toString(paramters));
			List resultList = query.getResultList();
			if (resultList == null) {
				return new Vector<>();
			}
			return resultList;
		} finally {
			logger.debug("/executeQuery for class ({}) with query ({}) with params ({})", clas.getName(), queryString,
					Arrays.toString(paramters));
			close(em, true);
		}
	}

	/**
	 * Gets the entity manager.
	 *
	 * @param withTrx the with trx
	 * @return the entity manager
	 */
	protected EntityManager getEntityManager(boolean withTrx) {
		logger.debug("getEntityManager with trx({})", withTrx);
		EntityManager manager = null;
		if (this.entityManager != null) {
			manager = this.entityManager;
		} else {
			manager = getDataSource().createEntityManager();
			if (withTrx) {
				manager.getTransaction().begin();
			}
		}
		logger.debug("/getEntityManager with trx({})", withTrx);
		return manager;
	}

	/**
	 * Gets the data source.
	 *
	 * @return the data source
	 */
	protected JKDataSource getDataSource() {
		logger.debug("getDataSource()");
		JKDataSource dataSource = this.dataSource;
		if (this.dataSource == null) {
			dataSource = JKDataAccessFactory.getDefaultDataSource();
		}
		logger.debug("/getDataSource()");
		return dataSource;
	}

	/**
	 * Close.
	 *
	 * @param manager the manager
	 * @param commit  the commit
	 */
	private void close(EntityManager manager, boolean commit) {
		logger.debug("closeEntityManager(commit={})", commit);
		if (entityManager == manager) {
			if (!commit) {
				rollBackCurrentTransaction = true;
			}
		} else {
			getDataSource().close(manager, commit);
		}
		logger.debug("/closeEntityManager(commit={})", commit);
//		try {
//			if (manager.isOpen() && manager.isJoinedToTransaction()) {
//				if (commit) {
//					manager.getTransaction().commit();
//				} else {
//					manager.getTransaction().rollback();
//				}
//			}
//		} finally {
//		}
	}

	/**
	 * Gets the query order.
	 *
	 * @param clas the clas
	 * @return the query order
	 * @throws NoSuchMethodException     the no such method exception
	 * @throws IllegalAccessException    the illegal access exception
	 * @throws InvocationTargetException the invocation target exception
	 */
	protected String getQueryOrder(final Class clas)
			throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		logger.debug("getQueryOrder({})", clas.getName());
		JK.fixMe("check this");
		Method method = clas.getMethod("getSortInfo", Class.class);
		JKSortInfo info = (JKSortInfo) method.invoke(null, clas);
		StringBuffer buf2 = new StringBuffer();
		if (info != null) {
			buf2.append("ORDER BY ");
			JKColumnWrapper col = (JKColumnWrapper) info.column();
			buf2.append("c." + col.getFieldName());
			buf2.append(" " + info.sortOrder().toString());
		}
		logger.debug("/getQueryOrder({})", clas.getName());
		return buf2.toString();
	}

	/**
	 * Find single entity.
	 *
	 * @param          the generic type
	 * @param clas        the clas
	 * @param queryString the query string
	 * @param paramters   the paramters
	 * @return the t
	 */
	public  T findSingleEntity(Class clas, final String queryString, final Object... paramters) {
		logger.debug("findSingleEntity(query={}, paramters{})", queryString, paramters);
		List list = executeQuery(clas, queryString, paramters);
		try {
			if (list.size() == 0) {
				return null;
			}
			if (list.size() == 1) {
				return list.get(0);
			}
			throw new JKDataAccessManyRowsException(queryString, paramters);
		} finally {
			logger.debug("/findSingleEntity(query={}, paramters{})", queryString, paramters);
		}
	}

	/**
	 * Gets the first record.
	 *
	 * @param   the generic type
	 * @param clas the clas
	 * @return the first record
	 */
	// ///////////////////////////////////////////////////////////////////////////////////////
	public  T getFirstRecord(Class clas) {
		logger.debug("getFirstRecord({})", clas.getName());
		List all = getList(clas);
		T record = null;
		if (all.size() > 0) {
			record = all.get(0);
		}
		logger.debug("/getFirstRecord({})", clas.getName());
		return record;
	}

	/**
	 * Find by field name.
	 *
	 * @param        the generic type
	 * @param clas      the clas
	 * @param fieldName the field name
	 * @param value     the value
	 * @return the list
	 */
	@Override
	// ///////////////////////////////////////////////////////////////////////////////////////
	public  List findByFieldName(Class clas, String fieldName, Object value) {
		logger.debug("findByFieldName for class ({}) with field ({}) and value ({})", clas.getSimpleName(), fieldName,
				value);
		String query = String.format("SELECT c FROM %s c WHERE c.%s=?1", clas.getSimpleName(), fieldName);
		try {
			return executeQuery(clas, query, value);
		} finally {
			logger.debug("/findByFieldName for class ({}) with field ({}) and value ({})", clas.getSimpleName(),
					fieldName, value);
		}
	}

	/**
	 * Insert or update.
	 *
	 * @param     the generic type
	 * @param object the object
	 * @return the t
	 */
	@Override
	public  T insertOrUpdate(T object) {
		logger.debug("insertOrUpdate({})", object.getClass().getName());
		EntityManager manager = getEntityManager(true);
		boolean commit = false;
		try {
			handleTimeStamps(object);
			T merge = manager.merge(object);
			commit = true;
			return merge;
		} finally {
			close(manager, commit);
			logger.debug("insertOrUpdate({})", object.getClass().getName());
		}
	}

	/**
	 * Find one by field name.
	 *
	 * @param         the generic type
	 * @param clas       the clas
	 * @param fieldName  the field name
	 * @param fieldValue the field value
	 * @return the t
	 */
	@Override
	public  T findOneByFieldName(Class clas, String fieldName, Object fieldValue) {
		logger.debug("findOneByFieldName(class={},fieldName={},value={})", clas, fieldName, fieldValue);
		try {
			List list = findByFieldName(clas, fieldName, fieldValue);
			if (list.size() == 0) {
				return null;
			}
			if (list.size() > 1) {
				JK.error("Results returned more than one row");
			}
			return list.get(0);
		} finally {
			logger.debug("/findOneByFieldName(class={},fieldName={},value={})", clas, fieldName, fieldValue);
		}
	}

	/**
	 * Sets the max results.
	 *
	 * @param maxResults the new max results
	 */
	@Override
	public void setMaxResults(int maxResults) {
		this.maxResults = maxResults;
	}

	/**
	 * Detach.
	 *
	 * @param model the model
	 */
	@Override
	public void detach(Object model) {
		logger.debug("detach({})",model);
		getEntityManager(false).detach(model);
		logger.debug("/detach({})",model);
	}

	/**
	 * Clone.
	 *
	 * @param    the generic type
	 * @param model the model
	 * @return the t
	 */
	@Override
	public  T clone(T model) {
		logger.debug("clone({})", model);
		detach(model);
		logger.debug("/clone({})", model);
		return model;
	}

	/**
	 * Start transaction.
	 */
	@Override
	public void startTransaction() {
		logger.debug("startTransaction()");
		entityManager = getDataSource().createEntityManager();
		entityManager.getTransaction().begin();
		logger.debug("/startTransaction()");
	}

	/**
	 * Close transaction.
	 *
	 * @param commit the commit
	 */
	@Override
	public void closeTransaction(boolean commit) {
		logger.debug("closeTransaction({})", commit);
		if (this.entityManager == null) {
			JK.exception("EntityManager shouldnt be null at this point");
		}
		try {
			getDataSource().close(entityManager, rollBackCurrentTransaction ? rollBackCurrentTransaction : commit);
		} finally {
			this.entityManager = null;
			this.rollBackCurrentTransaction = false;
		}
		logger.debug("/closeTransaction({})", commit);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy