All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wicketstuff.config.MatchingResources Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.wicketstuff.config;

import org.slf4j.*;
import org.springframework.core.io.*;
import org.springframework.core.io.support.*;
import org.springframework.core.type.*;
import org.springframework.core.type.classreading.*;

import java.io.*;
import java.lang.annotation.*;
import java.net.*;
import java.util.*;

/**
 * Class to get matching resources - uses Spring's {@link PathMatchingResourcePatternResolver}.
 *
 * @see PathMatchingResourcePatternResolver
 *
 * @author Doug Donohoe
 */
public class MatchingResources
{
    private static Logger logger = LoggerFactory.getLogger(MatchingResources.class);

    private Resource[] resources;
    private String pattern;

    /**
     * Initialize list of matching {@link Resource} as found by
     * {@link PathMatchingResourcePatternResolver#getResources(String)}.
     *
     * @param sPattern the pattern to search for
     * @see PathMatchingResourcePatternResolver
     */
    public MatchingResources(String sPattern)
    {
        pattern = sPattern.replace('\\', '/'); // fix DOS paths
        PathMatchingResourcePatternResolver match = new PathMatchingResourcePatternResolver();
        try
        {
            resources = match.getResources(pattern);
            logger.debug("Found " + resources.length + " resource(s) for: " + pattern);
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * Get all matching resources
     * @return A {@link Resource} array of all matches.  If no matches are found this is a zero-length array.
     */
    public Resource[] getAllMatches()
    {
        return resources;
    }

    /**
     * Get all matching resources as URLs.
     * @return {@link URL} array detemined by calling {@link #getURL(Resource)} on each resource.
     */
    public URL[] getAllMatchesURL()
    {
        URL urls[] = new URL[resources.length];
        for (int i = 0; i < resources.length; i++)
        {
            urls[i] = getURL(resources[i]);
        }
        return urls;
    }


    /**
     * Get all matching classes that are annotated with the given Annotation.
     * @param annotation an annotation class
     * @param includeSubclasses if true, this will also return classes whose superclass has the specified annotation
     * @return List of all classes that have the given annotation.  List is empty if non matches found.
     */
    public List> getAnnotatedMatches(Class annotation, boolean includeSubclasses) 
    {
        List> matches = new ArrayList>();
        MetadataReaderFactory f = new SimpleMetadataReaderFactory();
        for (Resource r : resources)
        {
            MetadataReader meta = null;
            try
            {
                meta = f.getMetadataReader(r);
            }
            catch (IOException e)
            {
                throw new RuntimeException("Unable to get MetadataReader for " + r, e);
            }
            AnnotationMetadata anno = meta.getAnnotationMetadata();
            Set types = anno.getAnnotationTypes();
            if (types.contains(annotation.getName()) || (includeSubclasses && anySuperHas(getClass(anno.getSuperClassName()), annotation)))
            {
                matches.add(getClass(anno.getClassName()));
            }
        }
        return matches;
    }

    /**
     * Get all matching classes that are annotated with the given Annotation.  Note that this method only returns
     * those classes that actually contain the annotation, and does not return classes whose superclass contains 
     * the annotation.
     *  
     * @param annotation an annotation class
     * @return List of all classes that have the given annotation.  List is empty if non matches found.
     * @see MatchingResources#getAnnotatedMatches(Class, boolean)
     */
    public List> getAnnotatedMatches(Class annotation)
    {
        return getAnnotatedMatches(annotation, false);
    }

    private boolean anySuperHas(Class clz, Class annotation) 
    {
        return clz != null && (clz.isAnnotationPresent(annotation) || anySuperHas(clz.getSuperclass(), annotation));
    }

    private Class getClass(String className) {
        try
        {
            return Class.forName(className);
        }
        catch (ClassNotFoundException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * Get a single matching resource.  Throws an exception if multiple are found.  This is useful if you
     * are expecting to find only one instance of an item on the classpath.
     * @return The single matching {@link Resource}
     * @throws RuntimeException if more than one {@link Resource} was found
     */
    public Resource getSingleResource()
    {
        if (resources.length > 1)
        {
            throw new RuntimeException("Found more than one resource in classpath for " + pattern + ": " + toString());
        }

        if (resources.length == 0) return null;
        return resources[0];
    }

    /**
     * Similar to {@link #getSingleResource()}, but returns result as an {@link URL}.
     * @return The single matching {@link Resource} as an {@link URL}
     * @throws RuntimeException if more than one {@link Resource} was found
     */
    public URL getSingleResourceURL()
    {
        Resource r = getSingleResource();
        if (r == null) return null;
        return getURL(r);
    }

    /**
     * Get a single required matching resource.  Throws an exception if zero or multiple are found.  This is useful if you
     * are expecting to find one and only one instance of an item on the classpath.
     * @return The single matching {@link Resource}
     * @throws RuntimeException if zero or more than one {@link Resource} was found
     */
    public Resource getSingleRequiredResource()
    {
        if (resources.length == 0)
        {
            throw new RuntimeException("Cound not find required resource for " + pattern);
        }

        if (resources.length > 1)
        {
            throw new RuntimeException("Found more than one resource in classpath for " + pattern + ": " + toString());
        }

        if (resources.length == 0) return null;
        return resources[0];
    }

    /**
     * Similar to {@link #getSingleRequiredResource()}, but returns result as an {@link URL}.
     * @return The single matching {@link Resource} as an {@link URL}
     * @throws RuntimeException if zero or more than one {@link Resource} was found
     */
    public URL getSingleRequiredResourceURL()
    {
        Resource r = getSingleRequiredResource();
        if (r == null) return null;
        return getURL(r);
    }

    /**
     * Get URL from resource.
     * @param r a {@link Resource}
     * @return its URL
     * @throws RuntimeException if {@link Resource#getURL()} throws {@link IOException}
     */
    public URL getURL(Resource r)
    {
        if (r == null) return null;
        try
        {
            return r.getURL();
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * @return string representing all matching resouces as URLs
     */
    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        for (Resource r : resources)
        {
            if (sb.length() > 0) sb.append('\n');
            sb.append(getURL(r).toString());
        }
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy