blob: 3fa3d5b891df89a7f84bc07265168f48549ccb70 [file] [log] [blame]
// Copyright 2007, 2008 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.ComponentResources;
import org.apache.tapestry5.internal.events.InvalidationListener;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.SymbolSource;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.services.MetaDataLocator;
import java.util.Map;
public class MetaDataLocatorImpl implements MetaDataLocator, InvalidationListener
{
private final SymbolSource symbolSource;
private final TypeCoercer typeCoercer;
private final Map<String, Map<String, String>> defaultsByFolder = CollectionFactory.newCaseInsensitiveMap();
private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
public MetaDataLocatorImpl(SymbolSource symbolSource, TypeCoercer typeCoercer, Map<String, String> configuration)
{
this.symbolSource = symbolSource;
this.typeCoercer = typeCoercer;
loadDefaults(configuration);
}
public void objectWasInvalidated()
{
cache.clear();
}
private void loadDefaults(Map<String, String> configuration)
{
for (Map.Entry<String, String> e : configuration.entrySet())
{
String key = e.getKey();
int colonx = key.indexOf(':');
String folderKey = colonx < 0 ? "" : key.substring(0, colonx);
Map<String, String> forFolder = defaultsByFolder.get(folderKey);
if (forFolder == null)
{
forFolder = CollectionFactory.newCaseInsensitiveMap();
defaultsByFolder.put(folderKey, forFolder);
}
String defaultKey = colonx < 0 ? key : key.substring(colonx + 1);
forFolder.put(defaultKey, e.getValue());
}
}
public <T> T findMeta(String key, ComponentResources resources, Class<T> expectedType)
{
String value = getSymbolExpandedValueFromCache(key, resources);
return typeCoercer.coerce(value, expectedType);
}
private String getSymbolExpandedValueFromCache(String key, ComponentResources resources)
{
String cacheKey = resources.getCompleteId() + "/" + key;
if (cache.containsKey(cacheKey)) return cache.get(cacheKey);
String value = locate(key, resources);
if (value == null)
{
value = symbolSource.valueForSymbol(key);
}
else
{
value = symbolSource.expandSymbols(value);
}
cache.put(cacheKey, value);
return value;
}
private String locate(String key, ComponentResources resources)
{
ComponentResources cursor = resources;
while (true)
{
String value = cursor.getComponentModel().getMeta(key);
if (value != null) return value;
ComponentResources next = cursor.getContainerResources();
if (next == null) return locateInDefaults(key, cursor);
cursor = next;
}
}
private String locateInDefaults(String key, ComponentResources pageResources)
{
// We're going to peel this apart, slash by slash. Thus for
// "mylib/myfolder/mysubfolder/MyPage" we'll be checking: "mylib/myfolder/mysubfolder",
// then "mylib/myfolder", then "mylib", then "".
String path = pageResources.getPageName();
while (true)
{
int lastSlashx = path.lastIndexOf('/');
String folderKey = lastSlashx < 0 ? "" : path.substring(0, lastSlashx);
Map<String, String> forFolder = defaultsByFolder.get(folderKey);
if (forFolder != null && forFolder.containsKey(key)) return forFolder.get(key);
if (lastSlashx < 0) break;
path = path.substring(0, lastSlashx);
}
// Perhaps from here into the symbol sources? That may come later.
return null;
}
}