/** * AnalyzerBeans * 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.eobjects.analyzer.util.convert; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eobjects.analyzer.beans.api.Converter; import org.eobjects.analyzer.util.ReflectionUtils; import org.apache.metamodel.util.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A converter for {@link Resource}s. Because of different {@link Resource} * implementations, this converter delegates to a number of 'handlers' which * implement part of the conversion for a specific type of resource. */ public class ResourceConverter implements Converter<Resource> { private static final Logger logger = LoggerFactory.getLogger(ResourceConverter.class); /** * Represents the default "default scheme", for representations that does * not have a scheme in the path. This default scheme is "file". */ public static final String DEFAULT_DEFAULT_SCHEME = FileResourceTypeHandler.DEFAULT_SCHEME; private static final Pattern RESOURCE_PATTERN = Pattern.compile("\\b([a-zA-Z]+)://(.+)"); private static final Collection<ResourceTypeHandler<?>> DEFAULT_HANDLERS = Arrays.<ResourceTypeHandler<?>> asList( new FileResourceTypeHandler(), new UrlResourceTypeHandler(), new ClasspathResourceTypeHandler(), new VfsResourceTypeHandler()); /** * Represents a component capable of handling the parsing and serializing of * a single type of resource. */ public static interface ResourceTypeHandler<E extends Resource> { public boolean isParserFor(Class<? extends Resource> resourceType); public String getScheme(); public E parsePath(String path); public String createPath(Resource resource); } /** * Represents the parsed structure of a serialized resource */ public static class ResourceStructure { private final String scheme; private final String path; public ResourceStructure(String scheme, String path) { this.scheme = scheme; this.path = path; } public String getPath() { return path; } public String getScheme() { return scheme; } } private final Map<String, ResourceTypeHandler<?>> _parsers; private final String _defaultScheme; /** * Constructs a {@link ResourceConverter} using a default set of handlers */ public ResourceConverter() { this(DEFAULT_HANDLERS, DEFAULT_DEFAULT_SCHEME); } /** * Constructs a {@link ResourceConverter} using a set of handlers. * * @param handlers * @param defaultScheme */ public ResourceConverter(Collection<? extends ResourceTypeHandler<?>> handlers, String defaultScheme) { _defaultScheme = defaultScheme; _parsers = new ConcurrentHashMap<String, ResourceConverter.ResourceTypeHandler<?>>(); for (ResourceTypeHandler<?> handler : handlers) { String scheme = handler.getScheme(); _parsers.put(scheme, handler); } } public ResourceConverter(ResourceTypeHandler<?>... handlers) { this(Arrays.asList(handlers), DEFAULT_DEFAULT_SCHEME); } @Override public Resource fromString(Class<?> type, String serializedForm) { final ResourceStructure structure = parseStructure(serializedForm); if (structure == null) { throw new IllegalStateException("Invalid resource format: " + serializedForm); } final String scheme = structure.getScheme(); final ResourceTypeHandler<?> handler = _parsers.get(scheme); if (handler == null) { throw new IllegalStateException("No handler found for scheme of resource: " + serializedForm); } final Resource resource = handler.parsePath(structure.getPath()); return resource; } @Override public String toString(Resource resource) { final Class<? extends Resource> resourceType = resource.getClass(); final Collection<ResourceTypeHandler<?>> values = _parsers.values(); for (ResourceTypeHandler<?> handler : values) { if (handler.isParserFor(resourceType)) { final String path = handler.createPath(resource); final String scheme = handler.getScheme(); return scheme + "://" + path; } } throw new IllegalStateException("Could not find a resource handler for resource: " + resource); } @Override public boolean isConvertable(Class<?> type) { return ReflectionUtils.is(type, Resource.class); } /** * Parses a string in order to produce a {@link ResourceStructure} object * * @param str * @return */ public ResourceStructure parseStructure(String str) { Matcher matcher = RESOURCE_PATTERN.matcher(str); if (!matcher.find()) { logger.info("Did not find any scheme definition in resource path: {}. Using default scheme: {}.", str, _defaultScheme); return new ResourceStructure(_defaultScheme, str); } String scheme = matcher.group(1); String path = matcher.group(2); return new ResourceStructure(scheme, path); } }