/** * Copyright (c) 2016 Lemur Consulting Ltd. * <p> * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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 uk.co.flax.biosolr.elasticsearch; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.threadpool.ThreadPool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.co.flax.biosolr.elasticsearch.mapper.ontology.ElasticOntologyHelperFactory; import uk.co.flax.biosolr.elasticsearch.mapper.ontology.OntologySettings; import uk.co.flax.biosolr.ontology.core.OntologyHelper; import uk.co.flax.biosolr.ontology.core.OntologyHelperException; import java.io.Closeable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Created by mlp on 09/02/16. * @author mlp */ public class OntologyHelperBuilder implements Closeable { private static final Logger LOGGER = LoggerFactory.getLogger(OntologyHelperBuilder.class); private ThreadPool threadPool; private static OntologyHelperBuilder instance; private Map<String, OntologyHelper> helpers = new ConcurrentHashMap<>(); @Inject OntologyHelperBuilder(ThreadPool threadPool) { this.threadPool = threadPool; setInstance(this); } private static void setInstance(OntologyHelperBuilder odb) { instance = odb; } static OntologyHelperBuilder getInstance() { return instance; } private OntologyHelper getHelper(OntologySettings settings) throws OntologyHelperException { String helperKey = buildHelperKey(settings); OntologyHelper helper = helpers.get(helperKey); if (helper == null) { helper = new ElasticOntologyHelperFactory(settings).buildOntologyHelper(); OntologyCheckRunnable checker = new OntologyCheckRunnable(helperKey, settings.getThreadCheckMs()); threadPool.scheduleWithFixedDelay(checker, TimeValue.timeValueMillis(settings.getThreadCheckMs())); helpers.put(helperKey, helper); helper.updateLastCallTime(); } return helper; } public static OntologyHelper getOntologyHelper(OntologySettings settings) throws OntologyHelperException { OntologyHelperBuilder builder = getInstance(); return builder.getHelper(settings); } @Override public void close() { // Explicitly dispose of any remaining helpers for (Map.Entry<String, OntologyHelper> helperEntry : helpers.entrySet()) { if (helperEntry.getValue() != null) { LOGGER.info("Disposing of helper for {}", helperEntry.getKey()); helperEntry.getValue().dispose(); } } } private static String buildHelperKey(OntologySettings settings) { String key; if (StringUtils.isNotBlank(settings.getOntologyUri())) { key = settings.getOntologyUri(); } else { if (StringUtils.isNotBlank(settings.getOlsOntology())) { key = settings.getOlsBaseUrl() + "_" + settings.getOlsOntology(); } else { key = settings.getOlsBaseUrl(); } } return key; } private final class OntologyCheckRunnable implements Runnable { final String threadKey; final long deleteCheckMs; public OntologyCheckRunnable(String threadKey, long deleteCheckMs) { this.threadKey = threadKey; this.deleteCheckMs = deleteCheckMs; } @Override public void run() { OntologyHelper helper = helpers.get(threadKey); if (helper != null) { // Check if the last call time was longer ago than the maximum if (System.currentTimeMillis() - deleteCheckMs > helper.getLastCallTime()) { // Assume helper is out of use - dispose of it to allow memory to be freed helper.dispose(); helpers.remove(threadKey); } } } } }