    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    }