All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tapestry5.internal.services.ComponentTemplateSourceImpl Maven / Gradle / Ivy

Go to download

Central module for Tapestry, containing interfaces to the Java Servlet API and all core services and components.

There is a newer version: 5.8.6
Show newest version
// Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry5.internal.services;

import org.apache.tapestry5.TapestryConstants;
import org.apache.tapestry5.internal.event.InvalidationEventHubImpl;
import org.apache.tapestry5.internal.parser.ComponentTemplate;
import org.apache.tapestry5.internal.parser.TemplateToken;
import org.apache.tapestry5.internal.util.MultiKey;
import org.apache.tapestry5.ioc.Location;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.annotations.Primary;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.URLChangeTracker;
import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
import org.apache.tapestry5.model.ComponentModel;
import org.apache.tapestry5.services.InvalidationEventHub;
import org.apache.tapestry5.services.UpdateListener;
import org.apache.tapestry5.services.templates.ComponentTemplateLocator;

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Service implementation that manages a cache of parsed component templates.
 */
public final class ComponentTemplateSourceImpl extends InvalidationEventHubImpl implements ComponentTemplateSource,
        UpdateListener
{
    private final TemplateParser parser;

    private final ComponentTemplateLocator locator;

    private final URLChangeTracker tracker;

    /**
     * Caches from a key (combining component name and locale) to a resource. Often, many different keys will point to
     * the same resource (i.e., "foo:en_US", "foo:en_UK", and "foo:en" may all be parsed from the same "foo.tml"
     * resource). The resource may end up being null, meaning the template does not exist in any locale.
     */
    private final Map templateResources = CollectionFactory.newConcurrentMap();

    /**
     * Cache of parsed templates, keyed on resource.
     */
    private final Map templates = CollectionFactory.newConcurrentMap();

    private final ComponentTemplate missingTemplate = new ComponentTemplate()
    {
        public Map getComponentIds()
        {
            return Collections.emptyMap();
        }

        public Resource getResource()
        {
            return null;
        }

        public List getTokens()
        {
            return Collections.emptyList();
        }

        public boolean isMissing()
        {
            return true;
        }

        public List getExtensionPointTokens(String extensionPointId)
        {
            return null;
        }

        public boolean isExtension()
        {
            return false;
        }
    };

    public ComponentTemplateSourceImpl(TemplateParser parser, @Primary
    ComponentTemplateLocator templateLocator, ClasspathURLConverter classpathURLConverter)
    {
        this(parser, templateLocator, new URLChangeTracker(classpathURLConverter));
    }

    ComponentTemplateSourceImpl(TemplateParser parser, ComponentTemplateLocator locator, URLChangeTracker tracker)
    {
        this.parser = parser;
        this.locator = locator;
        this.tracker = tracker;
    }

    /**
     * Resolves the component name to a localized {@link Resource} (using the {@link ComponentTemplateLocator} chain of
     * command service). The localized resource is used as the key to a cache of {@link ComponentTemplate}s.
     * 

* If a template doesn't exist, then the missing ComponentTemplate is returned. */ public ComponentTemplate getTemplate(ComponentModel componentModel, Locale locale) { String componentName = componentModel.getComponentClassName(); MultiKey key = new MultiKey(componentName, locale); // First cache is key to resource. Resource resource = templateResources.get(key); if (resource == null) { resource = locateTemplateResource(componentModel, locale); templateResources.put(key, resource); } // If we haven't yet parsed the template into the cache, do so now. ComponentTemplate result = templates.get(resource); if (result == null) { result = parseTemplate(resource); templates.put(resource, result); } return result; } private ComponentTemplate parseTemplate(Resource r) { // In a race condition, we may parse the same template more than once. This will likely add // the resource to the tracker multiple times. Not likely this will cause a big issue. if (!r.exists()) return missingTemplate; tracker.add(r.toURL()); return parser.parseTemplate(r); } private Resource locateTemplateResource(ComponentModel initialModel, Locale locale) { ComponentModel model = initialModel; while (model != null) { Resource localized = locator.locateTemplate(model, locale); if (localized != null) return localized; // Otherwise, this component doesn't have its own template ... lets work up to its // base class and check there. model = model.getParentModel(); } // This will be a Resource whose URL is null, which will be picked up later and force the // return of the empty template. return initialModel.getBaseResource().withExtension(TapestryConstants.TEMPLATE_EXTENSION); } /** * Checks to see if any parsed resource has changed. If so, then all internal caches are cleared, and an * invalidation event is fired. This is brute force ... a more targeted dependency management strategy may come * later. */ public void checkForUpdates() { if (tracker.containsChanges()) { tracker.clear(); templateResources.clear(); templates.clear(); fireInvalidationEvent(); } } public InvalidationEventHub getInvalidationEventHub() { return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy