001: // Copyright 2007 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.tapestry.internal.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
019:
020: import java.util.Map;
021:
022: import org.apache.tapestry.ComponentResources;
023: import org.apache.tapestry.internal.events.InvalidationListener;
024: import org.apache.tapestry.ioc.internal.util.CollectionFactory;
025: import org.apache.tapestry.services.MetaDataLocator;
026:
027: public class MetaDataLocatorImpl implements MetaDataLocator,
028: InvalidationListener {
029: private final Map<String, Map<String, String>> _defaultsByFolder = newCaseInsensitiveMap();
030:
031: private final Map<String, String> _cache = newConcurrentMap();
032:
033: public MetaDataLocatorImpl(Map<String, String> configuration) {
034: loadDefaults(configuration);
035: }
036:
037: public void objectWasInvalidated() {
038: _cache.clear();
039: }
040:
041: private void loadDefaults(Map<String, String> configuration) {
042: for (Map.Entry<String, String> e : configuration.entrySet()) {
043: String key = e.getKey();
044:
045: int colonx = key.indexOf(':');
046:
047: String folderKey = colonx < 0 ? "" : key.substring(0,
048: colonx);
049:
050: Map<String, String> forFolder = _defaultsByFolder
051: .get(folderKey);
052:
053: if (forFolder == null) {
054: forFolder = CollectionFactory.newCaseInsensitiveMap();
055: _defaultsByFolder.put(folderKey, forFolder);
056: }
057:
058: String defaultKey = colonx < 0 ? key : key
059: .substring(colonx + 1);
060:
061: forFolder.put(defaultKey, e.getValue());
062: }
063: }
064:
065: public String findMeta(String key, ComponentResources resources) {
066: // The component's complete id should be sufficient as locale-specific
067: // values don't enter into this.
068:
069: String cacheKey = resources.getCompleteId() + "/" + key;
070:
071: if (_cache.containsKey(cacheKey))
072: return _cache.get(cacheKey);
073:
074: String result = locate(key, resources);
075:
076: _cache.put(cacheKey, result);
077:
078: return result;
079: }
080:
081: private String locate(String key, ComponentResources resources) {
082: ComponentResources cursor = resources;
083:
084: while (true) {
085: String value = cursor.getComponentModel().getMeta(key);
086:
087: if (value != null)
088: return value;
089:
090: ComponentResources next = cursor.getContainerResources();
091:
092: if (next == null)
093: return locateInDefaults(key, cursor);
094:
095: cursor = next;
096: }
097: }
098:
099: private String locateInDefaults(String key,
100: ComponentResources pageResources) {
101: String logicalName = pageResources.getPageName();
102:
103: // We're going to peel this apart, slash by slash. Thus for
104: // "mylib/myfolder/mysubfolder/MyPage" we'll be checking: "mylib/myfolder/mysubfolder",
105: // then "mylib/myfolder", then "mylib", then "".
106:
107: String path = logicalName;
108:
109: while (true) {
110: int lastSlashx = path.lastIndexOf('/');
111:
112: String folderKey = lastSlashx < 0 ? "" : path.substring(0,
113: lastSlashx);
114:
115: Map<String, String> forFolder = _defaultsByFolder
116: .get(folderKey);
117:
118: if (forFolder != null && forFolder.containsKey(key))
119: return forFolder.get(key);
120:
121: if (lastSlashx < 0)
122: break;
123:
124: path = path.substring(0, lastSlashx);
125: }
126:
127: // Perhaps from here into the symbol sources? That may come later.
128:
129: return null;
130: }
131:
132: }
|