TaxonomyManager.java

/**
 * Copyright 2015 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.server.service.impl;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

import javax.annotation.Resource;

import org.apache.commons.text.WordUtils;
import org.apache.commons.lang3.StringUtils;
import org.genesys.server.model.genesys.Taxonomy2;
import org.genesys.server.service.TaxonomyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * Cross JVM taxonomy manager
 * 
 * @author matijaobreza
 *
 */
@Component
public class TaxonomyManager {
	public static final Logger LOG = LoggerFactory.getLogger(TaxonomyManager.class);

	@Autowired
	private TaxonomyService taxonomyService;

	/**
	 * This lock ensures only one member of the cluster can enter taxonomy
	 * update logic
	 */
	@Resource
	@Qualifier("taxonomyUpdateLock")
	private Lock taxonomyUpdateLock;

	public Taxonomy2 ensureTaxonomy2(String genus, String species, String spAuthor, String subtaxa, String subtAuthor) {
		if (StringUtils.isBlank(genus)) {
			throw new RuntimeException("Genus can't be blank");
		}

		// Capitalize
		genus = WordUtils.capitalizeFully(genus).trim();

		species = StringUtils.defaultIfBlank(species, "sp.");
		species = species.trim().toLowerCase();

		spAuthor = StringUtils.defaultIfBlank(spAuthor, "").trim();
		subtaxa = StringUtils.defaultIfBlank(subtaxa, "").trim();

		if (subtaxa != null) {
			subtaxa = subtaxa.toLowerCase();
		}

		subtAuthor = StringUtils.defaultIfBlank(subtAuthor, "").trim();

		if (StringUtils.equalsIgnoreCase(species.trim(), "sp")) {
			species = "sp.";
		}

		final Taxonomy2 existing = taxonomyService.find(genus, species, spAuthor, subtaxa, subtAuthor);
		if (existing == null) {
			try {
				// LOCK
				if (taxonomyUpdateLock.tryLock(10, TimeUnit.SECONDS)) {
					Taxonomy2 taxonomy = taxonomyService.internalEnsure(genus, species, spAuthor, subtaxa, subtAuthor);
					return taxonomy;
				} else {
					throw new RuntimeException("Could not persist Taxonomy2, lock wait timeout occured.");
				}
			} catch (InterruptedException e) {
				LOG.warn("Thread interrupted while waiting for taxonomy lock.", e);
				throw new RuntimeException(e);
			} finally {
				taxonomyUpdateLock.unlock();
			}
		}
		return existing;
	}
}