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
015package org.apache.tapestry5.internal.services;
016
017import java.net.URL;
018import java.util.Map;
019
020import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
021import org.apache.tapestry5.ioc.Resource;
022import org.apache.tapestry5.ioc.annotations.PostInjection;
023import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
024import org.apache.tapestry5.services.InvalidationListener;
025import org.apache.tapestry5.services.ResourceDigestGenerator;
026
027public 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}