001    // Copyright 2006, 2007, 2008 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.internal.services;
016    
017    import org.apache.commons.codec.binary.Hex;
018    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
019    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
020    import org.apache.tapestry5.services.ResourceDigestGenerator;
021    
022    import java.io.BufferedInputStream;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.net.URL;
026    import java.security.MessageDigest;
027    import java.util.Collection;
028    import java.util.Set;
029    
030    /**
031     * Implementation of {@link ResourceDigestGenerator} that generates MD5 digests.
032     */
033    public class ResourceDigestGeneratorImpl implements ResourceDigestGenerator
034    {
035        private static final int BUFFER_SIZE = 5000;
036    
037        private final Set<String> digestExtensions;
038    
039        public ResourceDigestGeneratorImpl(Collection<String> configuration)
040        {
041            digestExtensions = CollectionFactory.newSet(configuration);
042        }
043    
044        public String generateDigest(URL url)
045        {
046            InputStream stream = null;
047    
048            try
049            {
050                MessageDigest digest = MessageDigest.getInstance("MD5");
051    
052                stream = new BufferedInputStream(url.openStream());
053    
054                digestStream(digest, stream);
055    
056                stream.close();
057                stream = null;
058    
059                byte[] bytes = digest.digest();
060                char[] encoded = Hex.encodeHex(bytes);
061    
062                return new String(encoded);
063            }
064            catch (Exception ex)
065            {
066                throw new RuntimeException(ex);
067            }
068            finally
069            {
070                InternalUtils.close(stream);
071            }
072        }
073    
074        private void digestStream(MessageDigest digest, InputStream stream) throws IOException
075        {
076            byte[] buffer = new byte[BUFFER_SIZE];
077    
078            while (true)
079            {
080                int length = stream.read(buffer);
081    
082                if (length < 0) return;
083    
084                digest.update(buffer, 0, length);
085            }
086        }
087    
088        /**
089         * Current implementation is based on the path extension, and a configured list of extensions.
090         */
091        public boolean requiresDigest(String path)
092        {
093            int dotx = path.lastIndexOf('.');
094            String extension = path.substring(dotx + 1).toLowerCase();
095    
096            return digestExtensions.contains(extension);
097        }
098    
099    }