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

org.apache.myfaces.resource.ClassLoaderResourceLoaderIterator Maven / Gradle / Ivy

Go to download

The private implementation classes of the Apache MyFaces Core JSF-2.3-next Implementation

There is a newer version: 4.1.0-RC2
Show newest version
/*
 * 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.apache.myfaces.resource;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.ResourceVisitOption;
import org.apache.myfaces.util.lang.ClassUtils;

/**
 *
 * @author lu4242
 */
public class ClassLoaderResourceLoaderIterator implements Iterator
{
    private Iterator delegate = null;

    public ClassLoaderResourceLoaderIterator(URL url, String basePath, 
            int maxDepth, ResourceVisitOption... options)
    {
        if (url == null)
        {
            // This library does not exists for this
            // ResourceLoader
            delegate = null;
        }
        else
        {
            if (url.getProtocol().equals("file"))
            {
                try
                {
                    File directory = new File(url.toURI());
                    delegate = new FileDepthIterator(directory, basePath, maxDepth, options);
                }
                catch (URISyntaxException e)
                {
                    Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
                    if (log.isLoggable(Level.WARNING))
                    {
                        log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "
                                +e.getMessage(), e);
                    }
                }
            }
            else if (isJarResourceProtocol(url.getProtocol()))
            {
                url = getClassLoader().getResource(basePath);

                if (url != null)
                {
                    delegate = new JarDepthIterator(url, basePath, maxDepth, options);
                }
            }
        }
    }

    @Override
    public boolean hasNext()
    {
        if (delegate != null)
        {
            return delegate.hasNext();
        }
        return false;
    }

    @Override
    public String next()
    {
        if (delegate != null)
        {
            return delegate.next();
        }
        return null;
    }

    @Override
    public void remove()
    {
        //No op
    }
    
    protected ClassLoader getClassLoader()
    {
        return ClassUtils.getContextClassLoader();
    }
 
    private static class JarDepthIterator implements Iterator
    {
        private URL directory;
        private String basePath;
        private int maxDepth;
        private ResourceVisitOption[] options;
        
        private Deque stack = new LinkedList();
        
        Iterator iterator = null;

        public JarDepthIterator(URL directory, String basePath, int maxDepth, ResourceVisitOption... options)
        {
            this.directory = directory;
            this.basePath = basePath;
            this.maxDepth = maxDepth;
            this.options = options;
            
            if (basePath.endsWith("/"))
            {
                basePath = basePath.substring(0, basePath.length()-1);
            }

            try
            {
                JarURLConnection conn = (JarURLConnection)directory.openConnection();
                // See DIGESTER-29 for related problem
                conn.setUseCaches(false);

                try
                {
                    if (conn.getJarEntry().isDirectory())
                    {
                        // Unfortunately, we have to scan all entry files
                        JarFile file = conn.getJarFile();
                        for (Enumeration en = file.entries(); en.hasMoreElements();)
                        {
                            JarEntry entry = en.nextElement();
                            String entryName = entry.getName();
                            String path;

                            if (entryName.startsWith(basePath + '/'))
                            {
                                if (entryName.length() == basePath.length() + 1)
                                {
                                    // the same string, just skip it
                                    continue;
                                }
                                
                                path = entryName.substring(basePath.length(), entryName.length());
    
                                if (path.endsWith("/"))
                                {
                                    // Inner Directory
                                    continue;
                                }

                                //TODO: scan listFiles
                                int depth = ResourceLoaderUtils.getDepth(path);
                                if (depth < maxDepth)
                                {
                                    stack.add(path);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    //See TRINIDAD-73
                    //just close the input stream again if
                    //by inspecting the entries the stream
                    //was let open.
                    try
                    {
                        conn.getInputStream().close();
                    }
                    catch (Exception exception)
                    {
                        // Ignored
                    }
                }
            }
            catch (IOException e)
            {
                // Just return null, because library version cannot be
                // resolved.
                Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName()); 
                if (log.isLoggable(Level.WARNING))
                {
                    log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
                }
            }
            iterator = stack.iterator();
        }

        @Override
        public boolean hasNext()
        {
            return iterator.hasNext();
        }

        @Override
        public String next()
        {
            return iterator.next();
        }

        @Override
        public void remove()
        {
            //No op
        }
    }
    
    private static class FileDepthIterator implements Iterator
    {
        private File directory;
        private String basePath;
        private int maxDepth;
        private ResourceVisitOption[] options;
        
        private Deque stack;
        private String basePathName;

        public FileDepthIterator(File directory, String basePath, int maxDepth, ResourceVisitOption... options)
        {
            this.directory = directory;
            this.basePath = basePath;
            this.maxDepth = maxDepth;
            this.options = options;
            
            File[] list = this.directory.listFiles();
            if (list != null && list.length > 0)
            {
                stack = new LinkedList<>();
                Collections.addAll(stack, list);
            }

            this.basePathName = this.directory.getPath().replace(File.separatorChar, '/');
        }
        
        @Override
        public boolean hasNext()
        {
            if (stack == null || stack.isEmpty())
            {
                return false;
            }
 
            File file = stack.peek();
            do 
            {
                if (file.isDirectory())
                {
                    file = stack.pop();
                    int depth = ResourceLoaderUtils.getDepth(calculatePath(file));
                    if (depth < maxDepth)
                    {
                        File[] list = file.listFiles();
                        stack.addAll(Arrays.asList(list));
                    }
                    if (!stack.isEmpty())
                    {
                        file = stack.peek();
                    }
                    else
                    {
                        file = null;
                    }
                }
            }
            while (file != null && file.isDirectory() && !stack.isEmpty());

            return !stack.isEmpty();
        }

        @Override
        public String next()
        {
            if (stack == null || stack.isEmpty())
            {
                return null;
            }

            File file = stack.pop();
            do 
            {
                if (file.isDirectory())
                {
                    int depth = ResourceLoaderUtils.getDepth(calculatePath(file));
                    if (depth < maxDepth)
                    {
                        File[] list = file.listFiles();
                        stack.addAll(Arrays.asList(list));
                    }
                    if (!stack.isEmpty())
                    {
                        file = stack.pop();
                    }
                    else
                    {
                        file = null;
                    }
                }
            }
            while (file != null && file.isDirectory() && !stack.isEmpty());
            if (file != null)
            {
                // Calculate name based on url, basePath.
                String path = calculatePath(file);
                return path;
            }

            return null;
        }
        
        private String calculatePath(File file)
        {
            return (file.getPath()).substring(this.basePathName.length()).replace(File.separatorChar, '/');
        }

        @Override
        public void remove()
        {
            //No op
        }
    }

    /**
     * 

Determines whether the given URL resource protocol refers to a JAR file. Note that * BEA WebLogic and IBM WebSphere don't use the "jar://" protocol for some reason even * though you can treat these resources just like normal JAR files, i.e. you can ignore * the difference between these protocols after this method has returned.

* * @param protocol the URL resource protocol you want to check * * @return true if the given URL resource protocol refers to a JAR file, * false otherwise */ private static boolean isJarResourceProtocol(String protocol) { // Websphere uses the protocol "wsjar://" and Weblogic uses the protocol "zip://". return "jar".equals(protocol) || "wsjar".equals(protocol) || "zip".equals(protocol); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy