    001    // Copyright 2006, 2007, 2008, 2009, 2011 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 java.net.URL;
    018    import java.util.Map;
    019
    020    import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
    021    import org.apache.tapestry5.ioc.Resource;
    022    import org.apache.tapestry5.ioc.annotations.PostInjection;
    023    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    024    import org.apache.tapestry5.services.InvalidationListener;
    025    import org.apache.tapestry5.services.ResourceDigestGenerator;
    026
    027    public class ResourceDigestManagerImpl implements ResourceDigestManager, InvalidationListener
    028    {
    029        private final ResourceDigestGenerator digestGenerator;
    030
    031        private final ResourceChangeTracker resourceChangeTracker;
    032
    033        private final Map<Resource, Cached> cache = CollectionFactory.newConcurrentMap();
    034
    035        final static long MISSING_RESOURCE_TIME_MODIFIED = -1L;
    036
    037        private class Cached
    038        {
    039            final boolean requiresDigest;
    040
    041            final String digest;
    042
    043            final long timeModified;
    044
    045            Cached(Resource resource)
    046            {
    047                requiresDigest = digestGenerator.requiresDigest(resource.getPath());
    048
    049                URL url = resource.toURL();
    050
    051                digest = (requiresDigest && url != null) ? digestGenerator.generateDigest(url) : null;
    052
    053                timeModified = url != null ? resourceChangeTracker.trackResource(resource) : MISSING_RESOURCE_TIME_MODIFIED;
    054            }
    055        }
    056
    057        public ResourceDigestManagerImpl(ResourceDigestGenerator digestGenerator,
    058                ResourceChangeTracker resourceChangeTracker)
    059        {
    060            this.digestGenerator = digestGenerator;
    061            this.resourceChangeTracker = resourceChangeTracker;
    062        }
    063
    064        @PostInjection
    065        public void listenForInvalidations()
    066        {
    067            resourceChangeTracker.addInvalidationListener(this);
    068        }
    069
    070        private Cached get(Resource resource)
    071        {
    072            Cached result = cache.get(resource);
    073
    074            if (result == null)
    075            {
    076                result = new Cached(resource);
    077                cache.put(resource, result);
    078            }
    079
    080            return result;
    081        }
    082
    083        public String getDigest(Resource resource)
    084        {
    085            return get(resource).digest;
    086        }
    087
    088        public long getTimeModified(Resource resource)
    089        {
    090            return get(resource).timeModified;
    091        }
    092
    093        public boolean requiresDigest(Resource resource)
    094        {
    095            return get(resource).requiresDigest;
    096        }
    097
    098        public void addInvalidationListener(InvalidationListener listener)
    099        {
    100            resourceChangeTracker.addInvalidationListener(listener);
    101        }
    102
    103        public void objectWasInvalidated()
    104        {
    105            cache.clear();
    106        }
    107
    108    }