001    package com.github.sarxos.webcam;
002    
003    import java.io.File;
004    import java.io.IOException;
005    import java.net.URL;
006    import java.util.ArrayList;
007    import java.util.Enumeration;
008    import java.util.List;
009    
010    import org.slf4j.Logger;
011    import org.slf4j.LoggerFactory;
012    
013    
014    public class WebcamDriverUtils {
015    
016            private static final Logger LOG = LoggerFactory.getLogger(WebcamDriverUtils.class);
017    
018            private WebcamDriverUtils() {
019            }
020    
021            /**
022             * Find webcam driver. Scan packages to search drivers specified in the
023             * argument.
024             * 
025             * @param names array of driver names to search for
026             * @return Driver if found or throw exception
027             * @throw WebcamException
028             */
029            protected static WebcamDriver findDriver(List<String> names, List<Class<?>> classes) {
030    
031                    for (String name : names) {
032    
033                            LOG.info("Searching driver {}", name);
034    
035                            Class<?> clazz = null;
036    
037                            for (Class<?> c : classes) {
038                                    if (c.getCanonicalName().equals(name)) {
039                                            clazz = c;
040                                            break;
041                                    }
042                            }
043    
044                            if (clazz == null) {
045                                    try {
046                                            clazz = Class.forName(name);
047                                    } catch (ClassNotFoundException e) {
048                                            LOG.trace("Class not found {}, fall thru", name);
049                                    }
050                            }
051    
052                            if (clazz == null) {
053                                    LOG.debug("Driver {} not found", name);
054                                    continue;
055                            }
056    
057                            LOG.info("Webcam driver {} has been found", name);
058    
059                            try {
060                                    return (WebcamDriver) clazz.newInstance();
061                            } catch (InstantiationException e) {
062                                    throw new RuntimeException(e);
063                            } catch (IllegalAccessException e) {
064                                    throw new RuntimeException(e);
065                            }
066                    }
067    
068                    return null;
069            }
070    
071            /**
072             * Scans all classes accessible from the context class loader which belong
073             * to the given package and subpackages.
074             * 
075             * @param packageName The base package
076             * @param flat scan only one package level, do not dive into subdirectories
077             * @return The classes
078             * @throws ClassNotFoundException
079             * @throws IOException
080             */
081            protected static Class<?>[] getClasses(String pkgname, boolean flat) {
082    
083                    List<File> dirs = new ArrayList<File>();
084                    List<Class<?>> classes = new ArrayList<Class<?>>();
085    
086                    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
087                    String path = pkgname.replace('.', '/');
088    
089                    Enumeration<URL> resources = null;
090                    try {
091                            resources = classLoader.getResources(path);
092                    } catch (IOException e) {
093                            throw new RuntimeException("Cannot read path " + path, e);
094                    }
095    
096                    while (resources.hasMoreElements()) {
097                            URL resource = resources.nextElement();
098                            dirs.add(new File(resource.getFile()));
099                    }
100    
101                    for (File directory : dirs) {
102                            try {
103                                    classes.addAll(findClasses(directory, pkgname, flat));
104                            } catch (ClassNotFoundException e) {
105                                    throw new RuntimeException("Class not found", e);
106                            }
107                    }
108    
109                    return classes.toArray(new Class<?>[classes.size()]);
110            }
111    
112            /**
113             * Recursive method used to find all classes in a given directory and
114             * subdirectories.
115             * 
116             * @param dir base directory
117             * @param pkgname package name for classes found inside the base directory
118             * @param flat scan only one package level, do not dive into subdirectories
119             * @return Classes list
120             * @throws ClassNotFoundException
121             */
122            private static List<Class<?>> findClasses(File dir, String pkgname, boolean flat) throws ClassNotFoundException {
123    
124                    List<Class<?>> classes = new ArrayList<Class<?>>();
125                    if (!dir.exists()) {
126                            return classes;
127                    }
128    
129                    File[] files = dir.listFiles();
130                    for (File file : files) {
131                            if (file.isDirectory() && !flat) {
132                                    classes.addAll(findClasses(file, pkgname + "." + file.getName(), flat));
133                            } else if (file.getName().endsWith(".class")) {
134                                    classes.add(Class.forName(pkgname + '.' + file.getName().substring(0, file.getName().length() - 6)));
135                            }
136                    }
137    
138                    return classes;
139            }
140    }