001 // Copyright 2011, 2012 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.assets;
016
017 import org.apache.tapestry5.SymbolConstants;
018 import org.apache.tapestry5.internal.event.InvalidationEventHubImpl;
019 import org.apache.tapestry5.ioc.Resource;
020 import org.apache.tapestry5.ioc.annotations.PostInjection;
021 import org.apache.tapestry5.ioc.annotations.Symbol;
022 import org.apache.tapestry5.ioc.internal.util.URLChangeTracker;
023 import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
024 import org.apache.tapestry5.services.UpdateListener;
025 import org.apache.tapestry5.services.UpdateListenerHub;
026
027 public class ResourceChangeTrackerImpl extends InvalidationEventHubImpl implements ResourceChangeTracker,
028 UpdateListener
029 {
030 private final URLChangeTracker tracker;
031
032 /**
033 * Used in production mode as the last modified time of any resource exposed to the client. Remember that
034 * all exposed assets include a URL with a version number, and each new deployment of the application should change
035 * that version number.
036 */
037 private final long fixedLastModifiedTime = Math.round(System.currentTimeMillis() / 1000d) * 1000L;
038
039 public ResourceChangeTrackerImpl(ClasspathURLConverter classpathURLConverter,
040 @Symbol(SymbolConstants.PRODUCTION_MODE)
041 boolean productionMode)
042 {
043 super(productionMode);
044
045 // Use granularity of seconds (not milliseconds) since that works properly
046 // with response headers for identifying last modified. Don't track
047 // folder changes, just changes to actual files.
048 tracker = productionMode ? null : new URLChangeTracker(classpathURLConverter, true, false);
049 }
050
051 @PostInjection
052 public void registerWithUpdateListenerHub(UpdateListenerHub hub)
053 {
054 hub.addUpdateListener(this);
055 }
056
057 public long trackResource(Resource resource)
058 {
059 if (tracker == null)
060 {
061 return fixedLastModifiedTime;
062 }
063
064 return tracker.add(resource.toURL());
065 }
066
067 public void addDependency(Resource dependency)
068 {
069 trackResource(dependency);
070 }
071
072 public void checkForUpdates()
073 {
074 if (tracker.containsChanges())
075 {
076 fireInvalidationEvent();
077 tracker.clear();
078 }
079 }
080
081 }