ClassPKServiceImpl.java

/*
 * Copyright 2018 Global Crop Diversity Trust
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.genesys.blocks.auditlog.service.impl;

import java.util.Optional;

import javax.persistence.PersistenceException;

import org.genesys.blocks.auditlog.service.ClassPKService;
import org.genesys.blocks.model.ClassPK;
import org.genesys.blocks.persistence.ClassPKRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import lombok.extern.slf4j.Slf4j;

/**
 * The Class ClassPKServiceImpl.
 *
 * @author Matija Obreza
 */
@Service
@Transactional(readOnly = true)
@Slf4j
public class ClassPKServiceImpl implements ClassPKService {

	/** The class pk repository. */
	@Autowired
	private ClassPKRepository classPkRepository;

	/*
	 * (non-Javadoc)
	 * @see org.genesys.blocks.auditlog.service.ClassPKService#getClassPk(java.lang.
	 * Class)
	 */
	@Override
	@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRES_NEW)
	@Cacheable(cacheNames = { "classPk" }, unless = "#result == null")
	public ClassPK getClassPk(final Class<?> class1) {
		final ClassPK classPk = classPkRepository.getByClassname(class1.getName());
		if (classPk != null) {
			return classPk;
		}
		return createNewClassPkForClass(class1);
	}

	/**
	 * Generate short pk name.
	 *
	 * @param shortName the short name
	 * @return the string
	 */
	private String generateShortPkName(final String shortName) {
		ClassPK classPk = null;

		String candidate = shortName;
		int i = 0;

		do {
			classPk = classPkRepository.findByShortName(candidate);
			if (classPk == null) {
				// No other candidate, we're good!
				return candidate;
			}
			i++;
			// "shortName1", "shortName2"...
			candidate = shortName + i;
		} while (i < 10);

		throw new PersistenceException("Can't generate a shortName for ClassPK for " + shortName);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.genesys.blocks.auditlog.service.ClassPKService#getClassName(java.lang.
	 * Long)
	 */
	@Override
	@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRES_NEW)
	public String getClassName(final Long id) {
		Optional<ClassPK> classPK = classPkRepository.findById(id);
		return classPK.map(ClassPK::getClassname).orElse(null);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.genesys.blocks.auditlog.service.ClassPKService#findByShortName(java.lang.
	 * String)
	 */
	@Override
	public ClassPK findByShortName(final String classPKShortName) {
		return classPkRepository.findByShortName(classPKShortName);
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.genesys.blocks.auditlog.service.ClassPKService#getClassPkId(java.lang.
	 * String)
	 */
	@Override
	@Transactional
	public Long getClassPkId(final String classname) {
		final Long id = classPkRepository.getClassPkId(classname);

		if (id == null) {
			try {
				final Class<?> aClass = Class.forName(classname);
				return getClassPk(aClass).getId();
			} catch (final ClassNotFoundException e) {
				return null;
			}
		} else {
			return id;
		}
	}

	/**
	 * Creates the new class pk for class.
	 *
	 * @param aClass the a class
	 * @return the class PK
	 */
	private ClassPK createNewClassPkForClass(final Class<?> aClass) {
		final ClassPK classPk = new ClassPK();
		classPk.setClassname(aClass.getName());
		classPk.setShortName(generateShortPkName(aClass.getSimpleName().toLowerCase()));

		log.trace("Persisting new ClassPK for {}", classPk);

		return classPkRepository.save(classPk);
	}
}