    001// Copyright 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.dynamic;
    016
    017import org.apache.tapestry5.commons.Resource;
    018import org.apache.tapestry5.commons.util.CollectionFactory;
    019import org.apache.tapestry5.internal.services.PageSource;
    020import org.apache.tapestry5.internal.services.TemplateParser;
    021import org.apache.tapestry5.ioc.annotations.PostInjection;
    022import org.apache.tapestry5.ioc.internal.util.URLChangeTracker;
    023import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
    024import org.apache.tapestry5.ioc.services.UpdateListener;
    025import org.apache.tapestry5.ioc.services.UpdateListenerHub;
    026import org.apache.tapestry5.services.BindingSource;
    027import org.apache.tapestry5.services.dynamic.DynamicTemplate;
    028import org.apache.tapestry5.services.dynamic.DynamicTemplateParser;
    029
    030import java.util.Map;
    031
    032public class DynamicTemplateParserImpl implements DynamicTemplateParser, UpdateListener
    033{
    034    private final Map<Resource, DynamicTemplate> cache = CollectionFactory.newConcurrentMap();
    035
    036    private final BindingSource bindingSource;
    037
    038    private final PageSource pageSource;
    039
    040    private final URLChangeTracker tracker;
    041
    042    private final TemplateParser componentTemplateParser;
    043
    044    public DynamicTemplateParserImpl(ClasspathURLConverter converter, BindingSource bindingSource, PageSource pageSource, TemplateParser componentTemplateParser)
    045    {
    046        this.bindingSource = bindingSource;
    047        this.pageSource = pageSource;
    048        this.componentTemplateParser = componentTemplateParser;
    049
    050        tracker = new URLChangeTracker(converter);
    051    }
    052
    053    @PostInjection
    054    public void registerAsUpdateListener(UpdateListenerHub hub)
    055    {
    056        hub.addUpdateListener(this);
    057    }
    058
    059    public DynamicTemplate parseTemplate(Resource resource)
    060    {
    061        DynamicTemplate result = cache.get(resource);
    062
    063        if (result == null)
    064        {
    065            result = doParse(resource);
    066            cache.put(resource, result);
    067
    068            tracker.add(resource.toURL());
    069        }
    070
    071        return result;
    072    }
    073
    074    private DynamicTemplate doParse(Resource resource)
    075    {
    076        return new DynamicTemplateSaxParser(resource, bindingSource, componentTemplateParser.getDTDURLMappings()).parse();
    077    }
    078
    079    public void checkForUpdates()
    080    {
    081        if (tracker.containsChanges())
    082        {
    083            tracker.clear();
    084            cache.clear();
    085
    086            // A typical case is that a "context:" or "asset:" binding is used with the Dynamic component's template
    087            // parameter. This causes the Asset to be converted to a Resource and parsed. However, those are invariant
    088            // bindings, so even if it is discovered that the underlying file has changed, the parsed template
    089            // is still cached inside the component. Clearing the page pool forces the page instance to be
    090            // rebuilt, which is a crude way of clearing out that data. Other alternatives exist, such as
    091            // yielding up a proxy to the DynamicTemplate that is more change-aware.
    092
    093            pageSource.clearCache();
    094        }
    095    }
    096
    097}