/**
* DataCleaner (community edition)
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.datacleaner.descriptors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang.ArrayUtils;
import org.datacleaner.api.Analyzer;
import org.datacleaner.api.ComponentSuperCategory;
import org.datacleaner.api.Filter;
import org.datacleaner.api.Renderer;
import org.datacleaner.api.RenderingFormat;
import org.datacleaner.api.Transformer;
import com.google.common.collect.Iterables;
/**
* Abstract descriptor provider implementation that implements most trivial
* methods.
*/
public abstract class AbstractDescriptorProvider implements DescriptorProvider {
private final boolean _autoDiscover;
private final Collection<DescriptorProviderListener> _listeners;
/**
* Creates an {@link AbstractDescriptorProvider}
*
* @param autoLoadDescriptorClasses
* whether or not to automatically load descriptors when they are
* requested by class names. This typically happens in
* {@link #getAnalyzerDescriptorForClass(Class)},
* {@link #getTransformerDescriptorForClass(Class)} or
* {@link #getFilterDescriptorForClass(Class)}
*/
public AbstractDescriptorProvider(final boolean autoLoadDescriptorClasses) {
_autoDiscover = autoLoadDescriptorClasses;
_listeners = new ArrayList<>();
}
@Override
public final AnalyzerDescriptor<?> getAnalyzerDescriptorByDisplayName(final String name) {
return getComponentDescriptorByDisplayName(name, getAnalyzerDescriptors(), true, true);
}
@Override
public ComponentDescriptor<?> getComponentDescriptorByDisplayName(final String name) {
final Iterable<ComponentDescriptor<?>> allComponentDescriptors =
Iterables.concat(getAnalyzerDescriptors(), getTransformerDescriptors(), getFilterDescriptors());
ComponentDescriptor<?> match = getComponentDescriptorByDisplayName(name, allComponentDescriptors, true, false);
if (match == null) {
match = getComponentDescriptorByDisplayName(name, allComponentDescriptors, false, true);
}
return match;
}
@SuppressWarnings("unchecked")
@Override
public final <A extends Analyzer<?>> AnalyzerDescriptor<A> getAnalyzerDescriptorForClass(
final Class<A> analyzerBeanClass) {
for (final AnalyzerDescriptor<?> descriptor : getAnalyzerDescriptors()) {
if (descriptor.getComponentClass() == analyzerBeanClass) {
return (AnalyzerDescriptor<A>) descriptor;
}
}
return notFoundAnalyzer(analyzerBeanClass);
}
@Override
public final FilterDescriptor<?, ?> getFilterDescriptorByDisplayName(final String name) {
return getComponentDescriptorByDisplayName(name, getFilterDescriptors(), true, true);
}
@SuppressWarnings("unchecked")
@Override
public final <F extends Filter<C>, C extends Enum<C>> FilterDescriptor<F, C> getFilterDescriptorForClass(
final Class<F> filterClass) {
return (FilterDescriptor<F, C>) getFilterBeanDescriptorForClassUnbounded(filterClass);
}
/**
* Alternative getter method used when sufficient type-information about the
* class is not available.
*
* This method is basically a hack to make the compiler happy, see Ticket
* #417.
*
* @see http://eobjects.org/trac/ticket/417
*
* @param filterClass
* @return
*/
protected final FilterDescriptor<?, ?> getFilterBeanDescriptorForClassUnbounded(final Class<?> filterClass) {
for (final FilterDescriptor<?, ?> descriptor : getFilterDescriptors()) {
if (filterClass == descriptor.getComponentClass()) {
return descriptor;
}
}
return notFoundFilter(filterClass);
}
@Override
public final <R extends Renderer<?, ?>> RendererBeanDescriptor<R> getRendererBeanDescriptorForClass(
final Class<R> rendererBeanClass) {
for (final RendererBeanDescriptor<?> descriptor : getRendererBeanDescriptors()) {
if (descriptor.getComponentClass() == rendererBeanClass) {
@SuppressWarnings("unchecked") final RendererBeanDescriptor<R> result =
(RendererBeanDescriptor<R>) descriptor;
return result;
}
}
return notFoundRenderer(rendererBeanClass);
}
@Override
public final TransformerDescriptor<?> getTransformerDescriptorByDisplayName(final String name) {
return getComponentDescriptorByDisplayName(name, getTransformerDescriptors(), true, true);
}
@SuppressWarnings("unchecked")
@Override
public final <T extends Transformer> TransformerDescriptor<T> getTransformerDescriptorForClass(
final Class<T> transformerClass) {
for (final TransformerDescriptor<?> descriptor : getTransformerDescriptors()) {
if (descriptor.getComponentClass() == transformerClass) {
return (TransformerDescriptor<T>) descriptor;
}
}
return notFoundTransformer(transformerClass);
}
@Override
public final Collection<RendererBeanDescriptor<?>> getRendererBeanDescriptorsForRenderingFormat(
final Class<? extends RenderingFormat<?>> renderingFormat) {
final List<RendererBeanDescriptor<?>> result = new ArrayList<>();
final Collection<RendererBeanDescriptor<?>> descriptors = getRendererBeanDescriptors();
for (final RendererBeanDescriptor<?> descriptor : descriptors) {
final Class<? extends RenderingFormat<?>> descriptorsRenderingFormat = descriptor.getRenderingFormat();
if (descriptorsRenderingFormat == renderingFormat) {
result.add(descriptor);
}
}
return result;
}
private <D extends ComponentDescriptor<?>> D getComponentDescriptorByDisplayName(String name,
final Iterable<D> descriptors, final boolean searchPrimaryNames, final boolean searchAliases) {
if (name == null) {
return null;
}
// Ticket #951 : trim descriptor names
name = name.trim();
if (name.length() == 0) {
return null;
}
if (searchPrimaryNames) {
for (final D descriptor : descriptors) {
final String displayName = descriptor.getDisplayName();
if (name.equals(displayName)) {
return descriptor;
}
}
}
if (searchAliases) {
for (final D descriptor : descriptors) {
final String[] aliases = descriptor.getAliases();
if (ArrayUtils.contains(aliases, name)) {
return descriptor;
}
}
}
return null;
}
private <A extends Analyzer<?>> AnalyzerDescriptor<A> notFoundAnalyzer(final Class<A> analyzerClass) {
if (!_autoDiscover) {
return null;
}
return Descriptors.ofAnalyzer(analyzerClass);
}
private FilterDescriptor<?, ?> notFoundFilter(final Class<?> filterClass) {
if (!_autoDiscover) {
return null;
}
return Descriptors.ofFilterUnbound(filterClass);
}
private <R extends Renderer<?, ?>> RendererBeanDescriptor<R> notFoundRenderer(final Class<R> rendererClass) {
if (!_autoDiscover) {
return null;
}
return Descriptors.ofRenderer(rendererClass);
}
private <T extends Transformer> TransformerDescriptor<T> notFoundTransformer(final Class<T> transformerClass) {
if (!_autoDiscover) {
return null;
}
return Descriptors.ofTransformer(transformerClass);
}
@Override
public Collection<? extends ComponentDescriptor<?>> getComponentDescriptors() {
final List<ComponentDescriptor<?>> result = new ArrayList<>();
result.addAll(getTransformerDescriptors());
result.addAll(getFilterDescriptors());
result.addAll(getAnalyzerDescriptors());
return result;
}
@Override
public Set<ComponentSuperCategory> getComponentSuperCategories() {
final Set<ComponentSuperCategory> result = new TreeSet<>();
final Collection<? extends ComponentDescriptor<?>> descriptors = getComponentDescriptors();
for (final ComponentDescriptor<?> componentDescriptor : descriptors) {
final ComponentSuperCategory superCategory = componentDescriptor.getComponentSuperCategory();
result.add(superCategory);
}
return result;
}
@Override
public Collection<? extends ComponentDescriptor<?>> getComponentDescriptorsOfSuperCategory(
final ComponentSuperCategory category) {
if (category == null) {
return Collections.emptyList();
}
final List<ComponentDescriptor<?>> result = new ArrayList<>();
final Collection<? extends ComponentDescriptor<?>> descriptors = getComponentDescriptors();
for (final ComponentDescriptor<?> componentDescriptor : descriptors) {
if (category.equals(componentDescriptor.getComponentSuperCategory())) {
result.add(componentDescriptor);
}
}
return result;
}
protected void notifyListeners() {
synchronized (_listeners) {
for (final DescriptorProviderListener listener : _listeners) {
listener.onDescriptorsUpdated(this);
}
}
}
@Override
public void addListener(final DescriptorProviderListener listener) {
synchronized (_listeners) {
_listeners.add(listener);
}
}
@Override
public void removeListener(final DescriptorProviderListener listener) {
synchronized (_listeners) {
_listeners.remove(listener);
}
}
}