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    }