/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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.jbpm.services.api.query; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Allow to find mappers by name instead of using their instances * Mappers are discovered by ServiceLoader mechanism - meaning must be defined * in services file:<br> * META-INF/services/org.jbpm.services.api.query.QueryResultMapper * <br> * as fully qualified class names that implement <code>org.jbpm.services.api.query.QueryResultMapper</code> */ public class QueryMapperRegistry { public static final Logger logger = LoggerFactory.getLogger(QueryMapperRegistry.class); private static QueryMapperRegistry INSTANCE = new QueryMapperRegistry(); private ConcurrentMap<String, QueryResultMapper<?>> knownMappers = new ConcurrentHashMap<String, QueryResultMapper<?>>(); protected QueryMapperRegistry() { discoverAndAddMappers(this.getClass().getClassLoader()); } /** * Returns instance of the registry that is already populated with known mappers. * @return */ public static QueryMapperRegistry get() { return INSTANCE; } /** * Returns mapper for given name if found * @param name unique name that mapper is bound to * @param columnMapping provides column mapping (name to type) that can be * shipped to mapper for improved transformation - can be null (accepted types: string, long, integer, date, double) * @return instance of the <code>QueryResultMapper</code> if found * @throws IllegalArgumentException in case there is no mapper found with given name */ public QueryResultMapper<?> mapperFor(String name, Map<String, String> columnMapping) { if (!knownMappers.containsKey(name)) { throw new IllegalArgumentException("No mapper found with name " + name); } if (columnMapping == null) { return knownMappers.get(name); } else { return knownMappers.get(name).forColumnMapping(columnMapping); } } /** * Discovers and adds all <code>QueryResultMappers</code> to the known set * @param cl class laoder used to discover mappers * @return returns list of added (not previously existing) mappers */ @SuppressWarnings("rawtypes") public List<String> discoverAndAddMappers(ClassLoader cl) { List<String> added = new ArrayList<String>(); ServiceLoader<QueryResultMapper> availableProviders = ServiceLoader.load(QueryResultMapper.class, cl); for (QueryResultMapper<?> mapper : availableProviders) { QueryResultMapper<?> existed = knownMappers.putIfAbsent(mapper.getName(), mapper); if (existed == null) { added.add(mapper.getName()); logger.debug("Added mapper {} to the registry", mapper.getName()); } else { logger.debug("Mapper {} already existing in the registry", mapper.getName()); } } return added; } public void addMapper(QueryResultMapper<?> mapper) { QueryResultMapper<?> existed = knownMappers.putIfAbsent(mapper.getName(), mapper); if (existed == null) { logger.debug("Added mapper {} to the registry", mapper.getName()); } else { logger.debug("Mapper {} already existing in the registry", mapper.getName()); } } public void removeMapper(String mapperName) { QueryResultMapper<?> existed = knownMappers.remove(mapperName); if (existed != null) { logger.debug("Removed mapper {} from the registry", mapperName); } else { logger.debug("Mapper {} not found in the registry", mapperName); } } }