/* * deadmethods - A unused methods detector * Copyright 2011-2017 MeBigFatGuy.com * Copyright 2011-2017 Dave Brosius * * 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 com.mebigfatguy.deadmethods; import java.io.BufferedInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.stream.Collectors; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.ResourceCollection; public abstract class AbstractClassPathIterator implements Iterator<String> { Iterator<Resource> frIt; Iterator<String> subIt = null; public AbstractClassPathIterator(ResourceCollection classPath) { frIt = classPath.iterator(); } public abstract boolean validPath(String path, boolean isDirectory); public abstract String adjustPath(String path); @Override public boolean hasNext() { do { if (subIt == null) { initializeSubIterator(); } if (subIt.hasNext()) { return true; } subIt = null; } while (frIt.hasNext()); return false; } @Override public String next() { do { if (subIt == null) { initializeSubIterator(); } if (subIt.hasNext()) { return subIt.next(); } subIt = null; } while (frIt.hasNext()); throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException("remove not supported"); } private void initializeSubIterator() { while ((subIt == null) && frIt.hasNext()) { try { Resource fr = frIt.next(); Path dir = Paths.get(fr.toString()); if (!Files.isDirectory(dir)) { Path jar = dir; if (jar.toString().endsWith(".jar")) { subIt = new JarIterator(jar); } } else { subIt = new DirectoryIterator(dir); } } catch (IOException ioe) { // hasNext() will return false/next() will throw } } if (subIt == null) { subIt = new Iterator<String>() { @Override public boolean hasNext() { return false; } @Override public String next() { throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } class JarIterator implements Iterator<String> { private JarInputStream jis; private String nextEntry; public JarIterator(Path jar) throws IOException { jis = new JarInputStream(new BufferedInputStream(Files.newInputStream(jar))); nextEntry = null; } @Override public boolean hasNext() { if (nextEntry == null) { nextEntry = getNextEntry(); } if (nextEntry == null) { Closer.close(jis); jis = null; } return nextEntry != null; } @Override public String next() { if (nextEntry == null) { nextEntry = getNextEntry(); } if (nextEntry == null) { Closer.close(jis); jis = null; throw new NoSuchElementException(); } String className = nextEntry; nextEntry = null; return className; } @Override public void remove() { throw new UnsupportedOperationException(); } private String getNextEntry() { if (jis == null) { return null; } try { JarEntry entry = jis.getNextJarEntry(); while (entry != null) { if (validPath(entry.getName(), false)) { return adjustPath(entry.getName()); } entry = jis.getNextJarEntry(); } return null; } catch (IOException ioe) { return null; } } } class DirectoryIterator implements Iterator<String> { private final String root; private final List<Path> paths; private String nextFile; public DirectoryIterator(Path dir) { root = dir.toAbsolutePath().toString(); paths = new ArrayList<>(); paths.add(dir); nextFile = null; } @Override public boolean hasNext() { if (nextFile == null) { try { nextFile = getNextFile(); } catch (IOException e) { return false; } } if (nextFile == null) { paths.clear(); } return nextFile != null; } @Override public String next() { if (nextFile == null) { try { nextFile = getNextFile(); } catch (IOException e) { NoSuchElementException nsee = new NoSuchElementException("failed to fetch file"); nsee.initCause(e); throw nsee; } } if (nextFile == null) { paths.clear(); throw new NoSuchElementException(); } String className = nextFile; nextFile = null; return className; } @Override public void remove() { throw new UnsupportedOperationException(); } private String getNextFile() throws IOException { while (!paths.isEmpty()) { Path file = paths.remove(paths.size() - 1); if (Files.exists(file)) { if (Files.isDirectory(file)) { List<Path> children = Files.list(file).filter(f -> { String name = f.toString(); name = name.substring(root.length()); return validPath(name, Files.isDirectory(f)); }).collect(Collectors.toList()); if (children != null) { paths.addAll(children); } } else { String fileName = file.toAbsolutePath().toString(); fileName = "/" + fileName.substring(root.length() + 1).replaceAll("\\\\", "/"); if (validPath(fileName, Files.isDirectory(file))) { return adjustPath(fileName); } } } else { TaskFactory.getTask().log("Classpath element doesn't exist - ignored: " + file.toString()); } } return null; } } }