[prev in list] [next in list] [prev in thread] [next in thread]
List: tapestry-dev
Subject: svn commit: r480728 [1/2] - in /tapestry/tapestry5/tapestry-core/trunk/src:
From: hlship () apache ! org
Date: 2006-11-29 22:02:47
Message-ID: 20061129220250.E35931A984A () eris ! apache ! org
[Download RAW message or body]
Author: hlship
Date: Wed Nov 29 14:02:40 2006
New Revision: 480728
URL: http://svn.apache.org/viewvc?view=rev&rev=480728
Log:
Start adding component messages support.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentMessagesSourceImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MapMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/MultiKey.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentMessagesSource.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentMessagesSourceImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/MultiKeyTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/SimpleComponent.properties
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/SimpleComponent_en_GB.properties
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/SubclassComponent.properties
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/SubclassComponent_en_GB.properties
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/event/InvalidationEventHub.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/event/InvalidationEventHub.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/event/InvalidationEventHub.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/event/InvalidationEventHub.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/event/InvalidationEventHub.java \
Wed Nov 29 14:02:40 2006 @@ -12,16 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.event;
-
-import org.apache.tapestry.events.InvalidationListener;
-
-/**
- * An object which manages a list of {@link \
org.apache.tapestry.events.InvalidationListener}s.
- *
- *
- */
-public interface InvalidationEventHub
-{
- void addInvalidationListener(InvalidationListener listener);
-}
+package org.apache.tapestry.internal.event;
+
+import org.apache.tapestry.events.InvalidationListener;
+
+/**
+ * An object which manages a list of {@link \
org.apache.tapestry.events.InvalidationListener}s. + */
+
+public interface InvalidationEventHub
+{
+ void addInvalidationListener(InvalidationListener listener);
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/model/MutableComponentModelImpl.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/model/MutableComponentModelImpl.java \
Wed Nov 29 14:02:40 2006 @@ -12,251 +12,257 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.model;
-
+package org.apache.tapestry.internal.model;
+
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
import org.apache.tapestry.ioc.Resource;
import org.apache.tapestry.ioc.internal.util.Defense;
import org.apache.tapestry.ioc.internal.util.IdAllocator;
import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.model.ComponentModel;
-import org.apache.tapestry.model.EmbeddedComponentModel;
-import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.model.MutableEmbeddedComponentModel;
-import org.apache.tapestry.model.ParameterModel;
-
-/**
- * Internal implementation of {@link \
org.apache.tapestry.model.MutableComponentModel}.
- */
-public final class MutableComponentModelImpl implements MutableComponentModel
-{
- private final ComponentModel _parentModel;
-
- private final Resource _baseResource;
-
- private final String _componentClassName;
-
- private final IdAllocator _persistentFieldNameAllocator = new IdAllocator();
-
- private final Log _log;
-
- private Map<String, ParameterModel> _parameters;
-
- private Map<String, EmbeddedComponentModel> _embeddedComponents;
-
- /** Maps from field name to strategy. */
- private Map<String, String> _persistentFields;
-
- private List<String> _mixinClassNames;
-
- private boolean _informalParametersSupported;
-
- public MutableComponentModelImpl(String componentClassName, Log log, Resource \
baseResource,
- ComponentModel parentModel)
- {
- _componentClassName = componentClassName;
- _log = log;
- _baseResource = baseResource;
- _parentModel = parentModel;
-
- // Pre-allocate names from the parent, to avoid name collisions.
-
- if (_parentModel != null)
- {
- for (String name : _parentModel.getPersistentFieldNames())
- {
- _persistentFieldNameAllocator.allocateId(name);
- }
- }
- }
-
- @Override
- public String toString()
- {
- return String.format("ComponentModel[%s]", _componentClassName);
- }
-
- public Log getLog()
- {
- return _log;
- }
-
- public Resource getBaseResource()
- {
- return _baseResource;
- }
-
- public String getComponentClassName()
- {
- return _componentClassName;
- }
-
- public void addParameter(String name, boolean required)
- {
- // TODO: Check for conflict with base model
-
- if (_parameters == null)
- _parameters = newMap();
- else
- {
- if (_parameters.containsKey(name))
- throw new IllegalArgumentException(ModelMessages.duplicateParameter(
- name,
- _componentClassName));
- }
-
- Defense.notBlank(name, "name");
-
- _parameters.put(name, new ParameterModelImpl(name, required));
- }
-
- public ParameterModel getParameterModel(String parameterName)
- {
- ParameterModel result = InternalUtils.get(_parameters, parameterName);
-
- if (result == null && _parentModel != null)
- result = _parentModel.getParameterModel(parameterName);
-
- return result;
- }
-
- public List<String> getParameterNames()
- {
- // TODO: Parameters from base model
-
- List<String> names = newList();
-
- if (_parameters != null)
- names.addAll(_parameters.keySet());
-
- if (_parentModel != null)
- names.addAll(_parentModel.getParameterNames());
-
- Collections.sort(names);
-
- return names;
- }
-
- public MutableEmbeddedComponentModel addEmbeddedComponent(String id, String \
type,
- String componentClassName)
- {
- // TODO: Parent compent model? Or would we simply override the parent?
-
- if (_embeddedComponents == null)
- _embeddedComponents = newMap();
- else if (_embeddedComponents.containsKey(id))
- throw new IllegalArgumentException(ModelMessages.duplicateComponentId(
- id,
- _componentClassName));
-
- MutableEmbeddedComponentModel embedded = new \
MutableEmbeddedComponentModelImpl(id, type,
- componentClassName, _componentClassName);
-
- _embeddedComponents.put(id, embedded);
-
- return embedded; // So that parameters can be filled in
- }
-
- public List<String> getEmbeddedComponentIds()
- {
- List<String> result = newList();
-
- if (_embeddedComponents != null)
- result.addAll(_embeddedComponents.keySet());
-
- if (_parentModel != null)
- result.addAll(_parentModel.getEmbeddedComponentIds());
-
- Collections.sort(result);
-
- return result;
- }
-
- public EmbeddedComponentModel getEmbeddedComponentModel(String componentId)
- {
- EmbeddedComponentModel result = InternalUtils.get(_embeddedComponents, \
componentId);
-
- if (result == null && _parentModel != null)
- result = _parentModel.getEmbeddedComponentModel(componentId);
-
- return result;
- }
-
- public String getFieldPersistenceStrategy(String fieldName)
- {
- String result = InternalUtils.get(_persistentFields, fieldName);
-
- if (result == null && _parentModel != null)
- result = _parentModel.getFieldPersistenceStrategy(fieldName);
-
- if (result == null)
- throw new \
IllegalArgumentException(ModelMessages.missingPersistentField(fieldName));
-
- return result;
- }
-
- public List<String> getPersistentFieldNames()
- {
- // The name allocator is
- return _persistentFieldNameAllocator.getAllocatedIds();
- }
-
- public String setFieldPersistenceStrategy(String fieldName, String strategy)
- {
- String stripped = InternalUtils.stripMemberPrefix(fieldName);
-
- String logicalFieldName = \
_persistentFieldNameAllocator.allocateId(stripped);
-
- if (_persistentFields == null)
- _persistentFields = newMap();
-
- _persistentFields.put(logicalFieldName, strategy);
-
- return logicalFieldName;
- }
-
- public boolean isRootClass()
- {
- return _parentModel == null;
- }
-
- public void addMixinClassName(String mixinClassName)
- {
- if (_mixinClassNames == null)
- _mixinClassNames = newList();
-
- _mixinClassNames.add(mixinClassName);
- }
-
- public List<String> getMixinClassNames()
- {
- List<String> result = newList();
-
- if (_mixinClassNames != null)
- result.addAll(_mixinClassNames);
-
- if (_parentModel != null)
- result.addAll(_parentModel.getMixinClassNames());
-
- Collections.sort(result);
-
- return result;
- }
-
- public void enableSupportsInformalParameters()
- {
- _informalParametersSupported = true;
- }
-
- public boolean getSupportsInformalParameters()
- {
- return _informalParametersSupported;
- }
-}
+import org.apache.tapestry.model.ComponentModel;
+import org.apache.tapestry.model.EmbeddedComponentModel;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.model.MutableEmbeddedComponentModel;
+import org.apache.tapestry.model.ParameterModel;
+
+/**
+ * Internal implementation of {@link \
org.apache.tapestry.model.MutableComponentModel}. + */
+public final class MutableComponentModelImpl implements MutableComponentModel
+{
+ private final ComponentModel _parentModel;
+
+ private final Resource _baseResource;
+
+ private final String _componentClassName;
+
+ private final IdAllocator _persistentFieldNameAllocator = new IdAllocator();
+
+ private final Log _log;
+
+ private Map<String, ParameterModel> _parameters;
+
+ private Map<String, EmbeddedComponentModel> _embeddedComponents;
+
+ /** Maps from field name to strategy. */
+ private Map<String, String> _persistentFields;
+
+ private List<String> _mixinClassNames;
+
+ private boolean _informalParametersSupported;
+
+ public MutableComponentModelImpl(String componentClassName, Log log, Resource \
baseResource, + ComponentModel parentModel)
+ {
+ _componentClassName = componentClassName;
+ _log = log;
+ _baseResource = baseResource;
+ _parentModel = parentModel;
+
+ // Pre-allocate names from the parent, to avoid name collisions.
+
+ if (_parentModel != null)
+ {
+ for (String name : _parentModel.getPersistentFieldNames())
+ {
+ _persistentFieldNameAllocator.allocateId(name);
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("ComponentModel[%s]", _componentClassName);
+ }
+
+ public Log getLog()
+ {
+ return _log;
+ }
+
+ public Resource getBaseResource()
+ {
+ return _baseResource;
+ }
+
+ public String getComponentClassName()
+ {
+ return _componentClassName;
+ }
+
+ public void addParameter(String name, boolean required)
+ {
+ // TODO: Check for conflict with base model
+
+ if (_parameters == null)
+ _parameters = newMap();
+ else
+ {
+ if (_parameters.containsKey(name))
+ throw new IllegalArgumentException(ModelMessages.duplicateParameter(
+ name,
+ _componentClassName));
+ }
+
+ Defense.notBlank(name, "name");
+
+ _parameters.put(name, new ParameterModelImpl(name, required));
+ }
+
+ public ParameterModel getParameterModel(String parameterName)
+ {
+ ParameterModel result = InternalUtils.get(_parameters, parameterName);
+
+ if (result == null && _parentModel != null)
+ result = _parentModel.getParameterModel(parameterName);
+
+ return result;
+ }
+
+ public List<String> getParameterNames()
+ {
+ // TODO: Parameters from base model
+
+ List<String> names = newList();
+
+ if (_parameters != null)
+ names.addAll(_parameters.keySet());
+
+ if (_parentModel != null)
+ names.addAll(_parentModel.getParameterNames());
+
+ Collections.sort(names);
+
+ return names;
+ }
+
+ public MutableEmbeddedComponentModel addEmbeddedComponent(String id, String \
type, + String componentClassName)
+ {
+ // TODO: Parent compent model? Or would we simply override the parent?
+
+ if (_embeddedComponents == null)
+ _embeddedComponents = newMap();
+ else if (_embeddedComponents.containsKey(id))
+ throw new IllegalArgumentException(ModelMessages.duplicateComponentId(
+ id,
+ _componentClassName));
+
+ MutableEmbeddedComponentModel embedded = new \
MutableEmbeddedComponentModelImpl(id, type, + componentClassName, \
_componentClassName); +
+ _embeddedComponents.put(id, embedded);
+
+ return embedded; // So that parameters can be filled in
+ }
+
+ public List<String> getEmbeddedComponentIds()
+ {
+ List<String> result = newList();
+
+ if (_embeddedComponents != null)
+ result.addAll(_embeddedComponents.keySet());
+
+ if (_parentModel != null)
+ result.addAll(_parentModel.getEmbeddedComponentIds());
+
+ Collections.sort(result);
+
+ return result;
+ }
+
+ public EmbeddedComponentModel getEmbeddedComponentModel(String componentId)
+ {
+ EmbeddedComponentModel result = InternalUtils.get(_embeddedComponents, \
componentId); +
+ if (result == null && _parentModel != null)
+ result = _parentModel.getEmbeddedComponentModel(componentId);
+
+ return result;
+ }
+
+ public String getFieldPersistenceStrategy(String fieldName)
+ {
+ String result = InternalUtils.get(_persistentFields, fieldName);
+
+ if (result == null && _parentModel != null)
+ result = _parentModel.getFieldPersistenceStrategy(fieldName);
+
+ if (result == null)
+ throw new \
IllegalArgumentException(ModelMessages.missingPersistentField(fieldName)); +
+ return result;
+ }
+
+ public List<String> getPersistentFieldNames()
+ {
+ // The name allocator is
+ return _persistentFieldNameAllocator.getAllocatedIds();
+ }
+
+ public String setFieldPersistenceStrategy(String fieldName, String strategy)
+ {
+ String stripped = InternalUtils.stripMemberPrefix(fieldName);
+
+ String logicalFieldName = \
_persistentFieldNameAllocator.allocateId(stripped); +
+ if (_persistentFields == null)
+ _persistentFields = newMap();
+
+ _persistentFields.put(logicalFieldName, strategy);
+
+ return logicalFieldName;
+ }
+
+ public boolean isRootClass()
+ {
+ return _parentModel == null;
+ }
+
+ public void addMixinClassName(String mixinClassName)
+ {
+ if (_mixinClassNames == null)
+ _mixinClassNames = newList();
+
+ _mixinClassNames.add(mixinClassName);
+ }
+
+ public List<String> getMixinClassNames()
+ {
+ List<String> result = newList();
+
+ if (_mixinClassNames != null)
+ result.addAll(_mixinClassNames);
+
+ if (_parentModel != null)
+ result.addAll(_parentModel.getMixinClassNames());
+
+ Collections.sort(result);
+
+ return result;
+ }
+
+ public void enableSupportsInformalParameters()
+ {
+ _informalParametersSupported = true;
+ }
+
+ public boolean getSupportsInformalParameters()
+ {
+ return _informalParametersSupported;
+ }
+
+ public ComponentModel getParentModel()
+ {
+ return _parentModel;
+ }
+
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentMessagesSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/services/ComponentMessagesSourceImpl.java?view=auto&rev=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentMessagesSourceImpl.java \
(added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentMessagesSourceImpl.java \
Wed Nov 29 14:02:40 2006 @@ -0,0 +1,265 @@
+// Copyright 2006 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.tapestry.internal.services;
+
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
+import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newThreadSafeMap;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.tapestry.events.UpdateListener;
+import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
+import org.apache.tapestry.internal.util.MultiKey;
+import org.apache.tapestry.internal.util.URLChangeTracker;
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.ioc.internal.util.LocalizedNameGenerator;
+import org.apache.tapestry.model.ComponentModel;
+import org.apache.tapestry.services.ComponentMessagesSource;
+
+public class ComponentMessagesSourceImpl extends InvalidationEventHubImpl implements
+ ComponentMessagesSource, UpdateListener
+{
+ private final URLChangeTracker _tracker;
+
+ /** Keyed on component class name + locale. */
+ private final Map<MultiKey, Messages> _messagesByClassAndLocaleCache = \
newThreadSafeMap(); +
+ /**
+ * Keyed on component class name and locale, the coooked properties include \
properties inherited + * from less local-specific properties files, or inherited \
from base classes. + */
+ private final Map<MultiKey, Map<String, String>> _cookedProperties = \
newThreadSafeMap(); +
+ /**
+ * Raw properties represent just the properties read from a specific properties \
file, in + * isolation.
+ */
+ private final Map<Resource, Map<String, String>> _rawProperties = \
newThreadSafeMap(); +
+ private final Map<String, String> _emptyMap = Collections.emptyMap();
+
+ public ComponentMessagesSourceImpl()
+ {
+ this(new URLChangeTracker());
+ }
+
+ ComponentMessagesSourceImpl(URLChangeTracker tracker)
+ {
+ _tracker = tracker;
+ }
+
+ public void checkForUpdates()
+ {
+ if (_tracker.containsChanges())
+ {
+ _messagesByClassAndLocaleCache.clear();
+ _cookedProperties.clear();
+ _rawProperties.clear();
+
+ _tracker.clear();
+
+ fireInvalidationEvent();
+ }
+ }
+
+ public Messages getMessages(ComponentModel componentModel, Locale locale)
+ {
+ MultiKey key = new MultiKey(componentModel.getComponentClassName(), locale);
+
+ Messages result = _messagesByClassAndLocaleCache.get(key);
+
+ if (result == null)
+ {
+ result = buildMessages(componentModel, locale);
+ _messagesByClassAndLocaleCache.put(key, result);
+ }
+
+ return result;
+ }
+
+ private Messages buildMessages(ComponentModel componentModel, Locale locale)
+ {
+ Map<String, String> properties = findComponentProperties(componentModel, \
locale); +
+ return new MapMessages(properties);
+ }
+
+ /**
+ * Assembles a set of properties appropriate for the component in question, and \
the desired + * locale. The properties reflect the properties of the component's \
super class (if any) for the + * locale, overalyed with any properties defined \
for this component and its locale. + *
+ * @param componentModel
+ * @param locale
+ * @return
+ */
+ private Map<String, String> findComponentProperties(ComponentModel \
componentModel, Locale locale) + {
+ if (componentModel == null)
+ return _emptyMap;
+
+ MultiKey key = new MultiKey(componentModel.getComponentClassName(), locale);
+
+ Map<String, String> existing = _cookedProperties.get(key);
+
+ if (existing != null)
+ return existing;
+
+ // What would be cool is if we could maintain a cache of component class \
name + locale --> + // Resource. That would optimize quite a bit of this; may \
need to use an alternative to + // LocalizedNameGenerator.
+
+ Resource propertiesResource = \
componentModel.getBaseResource().withExtension("properties"); +
+ List<Resource> localizations = newList();
+
+ for (String localizedFile : new \
LocalizedNameGenerator(propertiesResource.getFile(), locale)) + {
+ Resource localized = propertiesResource.forFile(localizedFile);
+
+ localizations.add(localized);
+ }
+
+ Collections.reverse(localizations);
+
+ // Localizations are now in least-specific to most-specific order.
+
+ Map<String, String> previous = findComponentProperties(
+ componentModel.getParentModel(),
+ locale);
+
+ for (Resource localization : localizations)
+ {
+ Map<String, String> rawProperties = getRawProperties(localization);
+
+ Map<String, String> properties = extend(previous, rawProperties);
+
+ // Woould be nice to write into the _cookedProperties cache here,
+ // but we can't because we don't know the locale part of the MultiKey.
+
+ previous = properties;
+ }
+
+ _cookedProperties.put(key, previous);
+
+ return previous;
+ }
+
+ /**
+ * Returns a new map consisting of all the properties in previous overlayed with \
all the + * properties in rawProperties. If rawProperties is empty, returns just \
the base map. + */
+ private Map<String, String> extend(Map<String, String> base, Map<String, String> \
rawProperties) + {
+ if (rawProperties.isEmpty())
+ return base;
+
+ Map<String, String> result = newMap(base);
+
+ result.putAll(rawProperties);
+
+ return result;
+ }
+
+ private Map<String, String> getRawProperties(Resource localization)
+ {
+ Map<String, String> result = _rawProperties.get(localization);
+
+ if (result == null)
+ {
+ result = readProperties(localization);
+
+ _rawProperties.put(localization, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates and returns a new map that contains properties read from the \
properties file. + */
+ private Map<String, String> readProperties(Resource resource)
+ {
+ URL url = resource.toURL();
+
+ if (url == null)
+ return _emptyMap;
+
+ _tracker.add(url);
+
+ Map<String, String> result = newMap();
+
+ Properties p = new Properties();
+ InputStream is = null;
+
+ try
+ {
+ is = new BufferedInputStream(url.openStream());
+
+ p.load(is);
+
+ is.close();
+
+ is = null;
+ }
+ catch (Exception ex)
+ {
+ throw new \
RuntimeException(ServicesMessages.failureReadingComponentMessages(url, ex), + \
ex); + }
+ finally
+ {
+ close(is);
+ }
+
+ for (Map.Entry e : p.entrySet())
+ {
+ String key = e.getKey().toString();
+
+ String value = p.getProperty(key);
+
+ // Add new value, or overwrite value inherited from less-specific \
localization, or from + // parent component class.
+
+ result.put(key, value);
+ }
+
+ return result;
+ }
+
+ private final void close(Closeable stream)
+ {
+ if (stream != null)
+ try
+ {
+ stream.close();
+ }
+ catch (IOException ex)
+ { // Ignore.
+
+ }
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImpl.java \
Wed Nov 29 14:02:40 2006 @@ -26,6 +26,7 @@
import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
import org.apache.tapestry.internal.parser.ComponentTemplate;
import org.apache.tapestry.internal.parser.TemplateToken;
+import org.apache.tapestry.internal.util.MultiKey;
import org.apache.tapestry.internal.util.URLChangeTracker;
import org.apache.tapestry.ioc.Resource;
import org.apache.tapestry.ioc.internal.util.ClasspathResource;
@@ -46,7 +47,7 @@
* parsed from the same "foo.html" resource). The resource may end up being \
null, meaning the
* template does not exist in any locale.
*/
- private final Map<String, Resource> _templateResources = newThreadSafeMap();
+ private final Map<MultiKey, Resource> _templateResources = newThreadSafeMap();
/**
* Cache of parsed templates, keyed on resource.
@@ -98,7 +99,7 @@
*/
public ComponentTemplate getTemplate(String componentName, Locale locale)
{
- String key = componentName + ":" + locale.toString();
+ MultiKey key = new MultiKey(componentName, locale);
// First cache is key to resource.
@@ -128,7 +129,7 @@
// 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.
- URL resourceURL = r.getResourceURL();
+ URL resourceURL = r.toURL();
if (resourceURL == null)
return _missingTemplate;
@@ -145,7 +146,7 @@
String path = componentName.replace('.', '/') + ".html";
Resource baseResource = new ClasspathResource(_loader, path);
- Resource localized = baseResource.getLocalization(locale);
+ Resource localized = baseResource.forLocale(locale);
// In a race condition, we may hit this method a couple of times, and \
overwrite previous // results with identical new results.
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MapMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MapMessages.java?view=auto&rev=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MapMessages.java \
(added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MapMessages.java \
Wed Nov 29 14:02:40 2006 @@ -0,0 +1,46 @@
+// Copyright 2006 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.tapestry.internal.services;
+
+/**
+ * An implementation of {@link Messages} that is based on a map.
+ *
+ */
+import java.util.Map;
+
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.util.AbstractMessages;
+
+/**
+ * Implementation of {@link Messages} based on a simple Map (of string keys and \
values). + */
+public class MapMessages extends AbstractMessages
+{
+ private final Map<String, String> _properties;
+
+ /**
+ * A new instance <strong>retaining</strong> (not copying) the provided map.
+ */
+ public MapMessages(final Map<String, String> properties)
+ {
+ _properties = properties;
+ }
+
+ @Override
+ protected String valueForKey(String key)
+ {
+ return _properties.get(key);
+ }
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java \
Wed Nov 29 14:02:40 2006 @@ -14,6 +14,7 @@
package org.apache.tapestry.internal.services;
+import java.net.URL;
import java.util.Collection;
import java.util.List;
@@ -243,5 +244,10 @@
return MESSAGES.format("component-instance-is-not-a-page", \
methodDescription, component
.getComponentResources().getCompleteId(), \
result.getComponentResources()
.getCompleteId());
+ }
+
+ static String failureReadingComponentMessages(URL url, Throwable cause)
+ {
+ return MESSAGES.format("failure-reading-component-message", url, cause);
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/services/TemplateParserImpl.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TemplateParserImpl.java \
Wed Nov 29 14:02:40 2006 @@ -12,511 +12,511 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
+package org.apache.tapestry.internal.services;
+
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
-
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.internal.parser.AttributeToken;
-import org.apache.tapestry.internal.parser.BodyToken;
-import org.apache.tapestry.internal.parser.CDATAToken;
-import org.apache.tapestry.internal.parser.CommentToken;
-import org.apache.tapestry.internal.parser.ComponentTemplate;
-import org.apache.tapestry.internal.parser.ComponentTemplateImpl;
-import org.apache.tapestry.internal.parser.EndElementToken;
-import org.apache.tapestry.internal.parser.ExpansionToken;
-import org.apache.tapestry.internal.parser.StartComponentToken;
-import org.apache.tapestry.internal.parser.StartElementToken;
-import org.apache.tapestry.internal.parser.TemplateToken;
-import org.apache.tapestry.internal.parser.TextToken;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.internal.parser.AttributeToken;
+import org.apache.tapestry.internal.parser.BodyToken;
+import org.apache.tapestry.internal.parser.CDATAToken;
+import org.apache.tapestry.internal.parser.CommentToken;
+import org.apache.tapestry.internal.parser.ComponentTemplate;
+import org.apache.tapestry.internal.parser.ComponentTemplateImpl;
+import org.apache.tapestry.internal.parser.EndElementToken;
+import org.apache.tapestry.internal.parser.ExpansionToken;
+import org.apache.tapestry.internal.parser.StartComponentToken;
+import org.apache.tapestry.internal.parser.StartElementToken;
+import org.apache.tapestry.internal.parser.TemplateToken;
+import org.apache.tapestry.internal.parser.TextToken;
import org.apache.tapestry.ioc.Location;
import org.apache.tapestry.ioc.Resource;
import org.apache.tapestry.ioc.internal.util.InternalUtils;
import org.apache.tapestry.ioc.internal.util.LocationImpl;
import org.apache.tapestry.ioc.internal.util.TapestryException;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * Non-threadsafe implementation.
- */
-public class TemplateParserImpl extends DefaultHandler implements TemplateParser, \
LexicalHandler
-{
- public static final String TAPESTRY_SCHEMA_5_0_0 = \
"http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";
-
- private final SAXParserFactory _parserFactory;
-
- private SAXParser _parser;
-
- // Resource being parsed
- private Resource _templateResource;
-
- private Locator _locator;
-
- private final List<TemplateToken> _tokens = newList();
-
- // A stack of maps, each map contains mappings from prefix to namespace URL
-
- private final List<Map<String, String>> _prefixResolutionStack = newList();
-
- // Non-blank ids from start component (<comp>) elements
-
- private final Set<String> _componentIds = newSet();
-
- // Used to accumulate text provided by the characters(). Even contiguous \
characters may be
- // broken up across multiple invocations due to parser internals. We accumulate \
those together
- // before forming a text token.
-
- private final StringBuilder _textBuffer = new StringBuilder();
-
- private Location _textStartLocation;
-
- private boolean _textIsCData;
-
- private boolean _insideBody;
-
- private boolean _insideBodyErrorLogged;
-
- private boolean _ignoreEvents;
-
- private final Log _log;
-
- private final Pattern EXPANSION_PATTERN = Pattern.compile(
- "\\$\\{\\s*(.*)\\s*\\}",
- Pattern.MULTILINE);
-
- public TemplateParserImpl(Log log)
- {
- _log = log;
-
- _parserFactory = SAXParserFactory.newInstance();
-
- _parserFactory.setNamespaceAware(true);
-
- reset();
- }
-
- private void reset()
- {
- _tokens.clear();
- _prefixResolutionStack.clear();
- _componentIds.clear();
- _templateResource = null;
- _locator = null;
- _textBuffer.setLength(0);
- _textStartLocation = null;
- _textIsCData = false;
- _insideBody = false;
- _insideBodyErrorLogged = false;
- _ignoreEvents = true;
-
- }
-
- public ComponentTemplate parseTemplate(Resource templateResource)
- {
- if (_parser == null)
- {
- try
- {
- _parser = _parserFactory.newSAXParser();
-
- _parser.setProperty("http://xml.org/sax/properties/lexical-handler", \
this);
- }
- catch (Exception ex)
- {
- throw new \
RuntimeException(ServicesMessages.newParserError(templateResource, \
ex),
- ex);
- }
- }
-
- URL resourceURL = templateResource.getResourceURL();
-
- if (resourceURL == null)
- throw new \
RuntimeException(ServicesMessages.missingTemplateResource(templateResource));
-
- Map<String, String> rootPrefixMap = newMap();
- _prefixResolutionStack.add(rootPrefixMap);
-
- _templateResource = templateResource;
-
- try
- {
- InputSource source = new InputSource(resourceURL.openStream());
-
- _parser.parse(source, this);
-
- return new ComponentTemplateImpl(_templateResource, _tokens, \
_componentIds);
- }
- catch (Exception ex)
- {
- // Some parsers get in an unknown state when an error occurs, and are \
are not
- // subsequently useable.
-
- _parser = null;
-
- throw new \
TapestryException(ServicesMessages.templateParseError(templateResource, \
ex),
- getCurrentLocation(), ex);
- }
- finally
- {
- reset();
- }
- }
-
- @Override
- public void setDocumentLocator(Locator locator)
- {
- _locator = locator;
- }
-
- /**
- * Creates a new prefix to URI mapping map and adds this new prefix/URI mapping \
into the map.
- * The new map is pushed onto the stack of such maps.
- */
- @Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException
- {
- Map<String, String> topMap = _prefixResolutionStack.get(0);
- Map<String, String> newMap = newMap(topMap);
- newMap.put(prefix, uri);
-
- _prefixResolutionStack.add(0, newMap);
- }
-
- /** Pops the top prefix mapping map off the stack. */
- @Override
- public void endPrefixMapping(String prefix) throws SAXException
- {
- _prefixResolutionStack.remove(0);
- }
-
- /** Accumulates the characters into a text buffer. */
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException
- {
- if (_ignoreEvents)
- return;
-
- if (insideBody())
- return;
-
- if (_textBuffer.length() == 0)
- _textStartLocation = getCurrentLocation();
-
- _textBuffer.append(ch, start, length);
- }
-
- /**
- * Adds tokens corresponding to the content in the text buffer. For a non-CDATA \
section, we also
- * search for expansions (thus we may add more than one token). Clears the text \
buffer.
- */
- private void processTextBuffer()
- {
- if (_textBuffer.length() == 0)
- return;
-
- String text = _textBuffer.toString();
-
- if (_textIsCData)
- {
- _tokens.add(new CDATAToken(text, _textStartLocation));
- }
- else
- {
- addTokensForText(text);
- }
-
- _textBuffer.setLength(0);
- }
-
- /**
- * Scans the text, using a regular expression pattern, for expansion patterns, \
and adds
- * appropriate tokens for what it finds.
- *
- * @param text
- */
- private void addTokensForText(String text)
- {
- Matcher matcher = EXPANSION_PATTERN.matcher(text);
-
- int startx = 0;
-
- // The big problem with all this code is that everything gets assigned to \
the
- // start of the text block, even if there are line breaks leading up to it.
- // That's going to take a lot more work and there are bigger fish to fry.
-
- while (matcher.find())
- {
- int matchStart = matcher.start();
-
- if (matchStart != startx)
- {
- String prefix = text.substring(startx, matchStart);
-
- _tokens.add(new TextToken(prefix, _textStartLocation));
- }
-
- String expression = matcher.group(1);
-
- _tokens.add(new ExpansionToken(expression, _textStartLocation));
-
- startx = matcher.end();
- }
-
- // Catch anything after the final regexp match.
-
- if (startx < text.length())
- _tokens.add(new TextToken(text.substring(startx, text.length()), \
_textStartLocation));
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes \
attributes)
- throws SAXException
- {
- _ignoreEvents = false;
-
- if (_insideBody)
- throw new IllegalStateException(ServicesMessages
- .mayNotNestElementsInsideBody(localName));
-
- // Add any accumulated text into a text token
- processTextBuffer();
-
- if (TAPESTRY_SCHEMA_5_0_0.equals(uri))
- {
- startTapestryElement(localName, attributes);
- return;
- }
-
- // TODO: Handle tapestry namespace elements
- // TODO: Handle tapestry namespace attributes in ordinary namespace \
elements?
- // TODO: Handle interpolations inside attributes?
-
- Location location = getCurrentLocation();
-
- _tokens.add(new StartElementToken(localName, location));
-
- int count = attributes.getLength();
-
- for (int i = 0; i < count; i++)
- {
- String name = attributes.getLocalName(i);
-
- if (InternalUtils.isBlank(name))
- continue;
-
- String value = attributes.getValue(i);
-
- _tokens.add(new AttributeToken(name, value, location));
- }
- }
-
- /**
- * Checks to see if currently inside a t:body element (which should always be \
empty). Content is
- * ignored inside a body. If inside a body, then a warning is logged (but only \
one warning per
- * body element).
- *
- * @return true if inside t:body, false otherwise
- */
- private boolean insideBody()
- {
- if (_insideBody)
- {
- // Limit to one logged error per infraction.
-
- if (!_insideBodyErrorLogged)
- _log.error(ServicesMessages.contentInsideBodyNotAllowed(getCurrentLocation()));
-
- _insideBodyErrorLogged = true;
- }
-
- return _insideBody;
- }
-
- private void startTapestryElement(String localName, Attributes attributes)
- {
- if (localName.equals("comp"))
- {
- startComponent(localName, attributes);
- return;
- }
-
- if (localName.equals("body"))
- {
- startBody();
- return;
- }
-
- throw new IllegalArgumentException("Unknown localName: '" + localName + \
"'.");
- }
-
- private void startComponent(String localName, Attributes attributes)
- {
- String id = null;
- String type = null;
- String mixins = null;
- int count = attributes.getLength();
- Location location = getCurrentLocation();
- List<TemplateToken> attributeTokens = newList();
-
- for (int i = 0; i < count; i++)
- {
- String name = attributes.getLocalName(i);
- String value = attributes.getValue(i);
-
- // TODO: Validate that the id is a reasonable string.
-
- if (name.equals("id"))
- {
- if (InternalUtils.isNonBlank(value))
- id = value;
- continue;
- }
-
- if (name.equals("type"))
- {
-
- if (InternalUtils.isNonBlank(value))
- type = value;
- continue;
- }
-
- if (name.equals("mixins"))
- {
- if (InternalUtils.isNonBlank(value))
- mixins = value;
- continue;
- }
-
- attributeTokens.add(new AttributeToken(name, value, location));
- }
-
- if (id == null && type == null)
- throw new TapestryException(ServicesMessages.compRequiresIdOrType(), \
location, null);
-
- if (id != null)
- _componentIds.add(id);
-
- // Add the component
- _tokens.add(new StartComponentToken(id, type, mixins, location));
- _tokens.addAll(attributeTokens);
- }
-
- private void startBody()
- {
- _tokens.add(new BodyToken(getCurrentLocation()));
-
- _insideBody = true;
- _insideBodyErrorLogged = false;
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws \
SAXException
- {
- processTextBuffer();
-
- // TODO: Handle tapestry namespace elements?
-
- // Because XML tags are always balanced, we don't even need to know what \
element just closed
- // when we assemble things later.
-
- if (!_insideBody)
- _tokens.add(new EndElementToken(getCurrentLocation()));
-
- _insideBody = false;
- }
-
- private Location getCurrentLocation()
- {
- if (_locator == null)
- return null;
-
- return new LocationImpl(_templateResource, _locator.getLineNumber(), \
_locator
- .getColumnNumber());
- }
-
- public void comment(char[] ch, int start, int length) throws SAXException
- {
- if (_ignoreEvents || insideBody())
- return;
-
- processTextBuffer();
-
- String comment = new String(ch, start, length);
-
- // TODO: Perhaps comments need to be "aggregated" the same way we aggregate \
text and CDATA.
- // Hm. Probably not. Any whitespace between one comment and the next will \
become a
- // TextToken.
- // Unless we trim whitespace between consecutive comments ... and on down \
the rabbit hole.
- // Oops -- unless a single comment may be passed into this method as \
multiple calls
- // (have to check how multiline comments are handled).
- // Tests against Sun's built in parser does show that multiline comments are \
still
- // provided as a single call to comment(), so we're good for the meantime \
(until we find
- // out some parsers aren't so compliant).
-
- _tokens.add(new CommentToken(comment, getCurrentLocation()));
- }
-
- public void endCDATA() throws SAXException
- {
- // Add a token for any accumulated CDATA.
-
- processTextBuffer();
-
- // Again, CDATA doesn't nest, so we know we're back to ordinary markup.
-
- _textIsCData = false;
- }
-
- public void endDTD() throws SAXException
- {
- }
-
- public void endEntity(String name) throws SAXException
- {
- }
-
- public void startCDATA() throws SAXException
- {
- if (_ignoreEvents || insideBody())
- return;
-
- processTextBuffer();
-
- // Because CDATA doesn't mix with any other SAX/lexical events, we can \
simply turn on a flag
- // here and turn it off when we see the end.
-
- _textIsCData = true;
- }
-
- public void startDTD(String name, String publicId, String systemId) throws \
SAXException
- {
- }
-
- public void startEntity(String name) throws SAXException
- {
-
- }
-
- @Override
- public void ignorableWhitespace(char[] ch, int start, int length) throws \
SAXException
- {
- }
-
-}
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Non-threadsafe implementation.
+ */
+public class TemplateParserImpl extends DefaultHandler implements TemplateParser, \
LexicalHandler +{
+ public static final String TAPESTRY_SCHEMA_5_0_0 = \
"http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"; +
+ private final SAXParserFactory _parserFactory;
+
+ private SAXParser _parser;
+
+ // Resource being parsed
+ private Resource _templateResource;
+
+ private Locator _locator;
+
+ private final List<TemplateToken> _tokens = newList();
+
+ // A stack of maps, each map contains mappings from prefix to namespace URL
+
+ private final List<Map<String, String>> _prefixResolutionStack = newList();
+
+ // Non-blank ids from start component (<comp>) elements
+
+ private final Set<String> _componentIds = newSet();
+
+ // Used to accumulate text provided by the characters(). Even contiguous \
characters may be + // broken up across multiple invocations due to parser \
internals. We accumulate those together + // before forming a text token.
+
+ private final StringBuilder _textBuffer = new StringBuilder();
+
+ private Location _textStartLocation;
+
+ private boolean _textIsCData;
+
+ private boolean _insideBody;
+
+ private boolean _insideBodyErrorLogged;
+
+ private boolean _ignoreEvents;
+
+ private final Log _log;
+
+ private final Pattern EXPANSION_PATTERN = Pattern.compile(
+ "\\$\\{\\s*(.*)\\s*\\}",
+ Pattern.MULTILINE);
+
+ public TemplateParserImpl(Log log)
+ {
+ _log = log;
+
+ _parserFactory = SAXParserFactory.newInstance();
+
+ _parserFactory.setNamespaceAware(true);
+
+ reset();
+ }
+
+ private void reset()
+ {
+ _tokens.clear();
+ _prefixResolutionStack.clear();
+ _componentIds.clear();
+ _templateResource = null;
+ _locator = null;
+ _textBuffer.setLength(0);
+ _textStartLocation = null;
+ _textIsCData = false;
+ _insideBody = false;
+ _insideBodyErrorLogged = false;
+ _ignoreEvents = true;
+
+ }
+
+ public ComponentTemplate parseTemplate(Resource templateResource)
+ {
+ if (_parser == null)
+ {
+ try
+ {
+ _parser = _parserFactory.newSAXParser();
+
+ _parser.setProperty("http://xml.org/sax/properties/lexical-handler", \
this); + }
+ catch (Exception ex)
+ {
+ throw new \
RuntimeException(ServicesMessages.newParserError(templateResource, ex), + \
ex); + }
+ }
+
+ URL resourceURL = templateResource.toURL();
+
+ if (resourceURL == null)
+ throw new \
RuntimeException(ServicesMessages.missingTemplateResource(templateResource)); +
+ Map<String, String> rootPrefixMap = newMap();
+ _prefixResolutionStack.add(rootPrefixMap);
+
+ _templateResource = templateResource;
+
+ try
+ {
+ InputSource source = new InputSource(resourceURL.openStream());
+
+ _parser.parse(source, this);
+
+ return new ComponentTemplateImpl(_templateResource, _tokens, \
_componentIds); + }
+ catch (Exception ex)
+ {
+ // Some parsers get in an unknown state when an error occurs, and are \
are not + // subsequently useable.
+
+ _parser = null;
+
+ throw new \
TapestryException(ServicesMessages.templateParseError(templateResource, ex), + \
getCurrentLocation(), ex); + }
+ finally
+ {
+ reset();
+ }
+ }
+
+ @Override
+ public void setDocumentLocator(Locator locator)
+ {
+ _locator = locator;
+ }
+
+ /**
+ * Creates a new prefix to URI mapping map and adds this new prefix/URI mapping \
into the map. + * The new map is pushed onto the stack of such maps.
+ */
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException
+ {
+ Map<String, String> topMap = _prefixResolutionStack.get(0);
+ Map<String, String> newMap = newMap(topMap);
+ newMap.put(prefix, uri);
+
+ _prefixResolutionStack.add(0, newMap);
+ }
+
+ /** Pops the top prefix mapping map off the stack. */
+ @Override
+ public void endPrefixMapping(String prefix) throws SAXException
+ {
+ _prefixResolutionStack.remove(0);
+ }
+
+ /** Accumulates the characters into a text buffer. */
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException
+ {
+ if (_ignoreEvents)
+ return;
+
+ if (insideBody())
+ return;
+
+ if (_textBuffer.length() == 0)
+ _textStartLocation = getCurrentLocation();
+
+ _textBuffer.append(ch, start, length);
+ }
+
+ /**
+ * Adds tokens corresponding to the content in the text buffer. For a non-CDATA \
section, we also + * search for expansions (thus we may add more than one token). \
Clears the text buffer. + */
+ private void processTextBuffer()
+ {
+ if (_textBuffer.length() == 0)
+ return;
+
+ String text = _textBuffer.toString();
+
+ if (_textIsCData)
+ {
+ _tokens.add(new CDATAToken(text, _textStartLocation));
+ }
+ else
+ {
+ addTokensForText(text);
+ }
+
+ _textBuffer.setLength(0);
+ }
+
+ /**
+ * Scans the text, using a regular expression pattern, for expansion patterns, \
and adds + * appropriate tokens for what it finds.
+ *
+ * @param text
+ */
+ private void addTokensForText(String text)
+ {
+ Matcher matcher = EXPANSION_PATTERN.matcher(text);
+
+ int startx = 0;
+
+ // The big problem with all this code is that everything gets assigned to \
the + // start of the text block, even if there are line breaks leading up to \
it. + // That's going to take a lot more work and there are bigger fish to \
fry. +
+ while (matcher.find())
+ {
+ int matchStart = matcher.start();
+
+ if (matchStart != startx)
+ {
+ String prefix = text.substring(startx, matchStart);
+
+ _tokens.add(new TextToken(prefix, _textStartLocation));
+ }
+
+ String expression = matcher.group(1);
+
+ _tokens.add(new ExpansionToken(expression, _textStartLocation));
+
+ startx = matcher.end();
+ }
+
+ // Catch anything after the final regexp match.
+
+ if (startx < text.length())
+ _tokens.add(new TextToken(text.substring(startx, text.length()), \
_textStartLocation)); + }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes \
attributes) + throws SAXException
+ {
+ _ignoreEvents = false;
+
+ if (_insideBody)
+ throw new IllegalStateException(ServicesMessages
+ .mayNotNestElementsInsideBody(localName));
+
+ // Add any accumulated text into a text token
+ processTextBuffer();
+
+ if (TAPESTRY_SCHEMA_5_0_0.equals(uri))
+ {
+ startTapestryElement(localName, attributes);
+ return;
+ }
+
+ // TODO: Handle tapestry namespace elements
+ // TODO: Handle tapestry namespace attributes in ordinary namespace \
elements? + // TODO: Handle interpolations inside attributes?
+
+ Location location = getCurrentLocation();
+
+ _tokens.add(new StartElementToken(localName, location));
+
+ int count = attributes.getLength();
+
+ for (int i = 0; i < count; i++)
+ {
+ String name = attributes.getLocalName(i);
+
+ if (InternalUtils.isBlank(name))
+ continue;
+
+ String value = attributes.getValue(i);
+
+ _tokens.add(new AttributeToken(name, value, location));
+ }
+ }
+
+ /**
+ * Checks to see if currently inside a t:body element (which should always be \
empty). Content is + * ignored inside a body. If inside a body, then a warning is \
logged (but only one warning per + * body element).
+ *
+ * @return true if inside t:body, false otherwise
+ */
+ private boolean insideBody()
+ {
+ if (_insideBody)
+ {
+ // Limit to one logged error per infraction.
+
+ if (!_insideBodyErrorLogged)
+ _log.error(ServicesMessages.contentInsideBodyNotAllowed(getCurrentLocation()));
+
+ _insideBodyErrorLogged = true;
+ }
+
+ return _insideBody;
+ }
+
+ private void startTapestryElement(String localName, Attributes attributes)
+ {
+ if (localName.equals("comp"))
+ {
+ startComponent(localName, attributes);
+ return;
+ }
+
+ if (localName.equals("body"))
+ {
+ startBody();
+ return;
+ }
+
+ throw new IllegalArgumentException("Unknown localName: '" + localName + \
"'."); + }
+
+ private void startComponent(String localName, Attributes attributes)
+ {
+ String id = null;
+ String type = null;
+ String mixins = null;
+ int count = attributes.getLength();
+ Location location = getCurrentLocation();
+ List<TemplateToken> attributeTokens = newList();
+
+ for (int i = 0; i < count; i++)
+ {
+ String name = attributes.getLocalName(i);
+ String value = attributes.getValue(i);
+
+ // TODO: Validate that the id is a reasonable string.
+
+ if (name.equals("id"))
+ {
+ if (InternalUtils.isNonBlank(value))
+ id = value;
+ continue;
+ }
+
+ if (name.equals("type"))
+ {
+
+ if (InternalUtils.isNonBlank(value))
+ type = value;
+ continue;
+ }
+
+ if (name.equals("mixins"))
+ {
+ if (InternalUtils.isNonBlank(value))
+ mixins = value;
+ continue;
+ }
+
+ attributeTokens.add(new AttributeToken(name, value, location));
+ }
+
+ if (id == null && type == null)
+ throw new TapestryException(ServicesMessages.compRequiresIdOrType(), \
location, null); +
+ if (id != null)
+ _componentIds.add(id);
+
+ // Add the component
+ _tokens.add(new StartComponentToken(id, type, mixins, location));
+ _tokens.addAll(attributeTokens);
+ }
+
+ private void startBody()
+ {
+ _tokens.add(new BodyToken(getCurrentLocation()));
+
+ _insideBody = true;
+ _insideBodyErrorLogged = false;
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws \
SAXException + {
+ processTextBuffer();
+
+ // TODO: Handle tapestry namespace elements?
+
+ // Because XML tags are always balanced, we don't even need to know what \
element just closed + // when we assemble things later.
+
+ if (!_insideBody)
+ _tokens.add(new EndElementToken(getCurrentLocation()));
+
+ _insideBody = false;
+ }
+
+ private Location getCurrentLocation()
+ {
+ if (_locator == null)
+ return null;
+
+ return new LocationImpl(_templateResource, _locator.getLineNumber(), \
_locator + .getColumnNumber());
+ }
+
+ public void comment(char[] ch, int start, int length) throws SAXException
+ {
+ if (_ignoreEvents || insideBody())
+ return;
+
+ processTextBuffer();
+
+ String comment = new String(ch, start, length);
+
+ // TODO: Perhaps comments need to be "aggregated" the same way we aggregate \
text and CDATA. + // Hm. Probably not. Any whitespace between one comment and \
the next will become a + // TextToken.
+ // Unless we trim whitespace between consecutive comments ... and on down \
the rabbit hole. + // Oops -- unless a single comment may be passed into this \
method as multiple calls + // (have to check how multiline comments are \
handled). + // Tests against Sun's built in parser does show that multiline \
comments are still + // provided as a single call to comment(), so we're good \
for the meantime (until we find + // out some parsers aren't so compliant).
+
+ _tokens.add(new CommentToken(comment, getCurrentLocation()));
+ }
+
+ public void endCDATA() throws SAXException
+ {
+ // Add a token for any accumulated CDATA.
+
+ processTextBuffer();
+
+ // Again, CDATA doesn't nest, so we know we're back to ordinary markup.
+
+ _textIsCData = false;
+ }
+
+ public void endDTD() throws SAXException
+ {
+ }
+
+ public void endEntity(String name) throws SAXException
+ {
+ }
+
+ public void startCDATA() throws SAXException
+ {
+ if (_ignoreEvents || insideBody())
+ return;
+
+ processTextBuffer();
+
+ // Because CDATA doesn't mix with any other SAX/lexical events, we can \
simply turn on a flag + // here and turn it off when we see the end.
+
+ _textIsCData = true;
+ }
+
+ public void startDTD(String name, String publicId, String systemId) throws \
SAXException + {
+ }
+
+ public void startEntity(String name) throws SAXException
+ {
+
+ }
+
+ @Override
+ public void ignorableWhitespace(char[] ch, int start, int length) throws \
SAXException + {
+ }
+
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/MultiKey.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/MultiKey.java?view=auto&rev=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/MultiKey.java \
(added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/MultiKey.java \
Wed Nov 29 14:02:40 2006 @@ -0,0 +1,83 @@
+// Copyright 2006 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.tapestry.internal.util;
+
+import java.util.Arrays;
+
+/** A general purpose key for multiple values. */
+public final class MultiKey
+{
+ private static final int PRIME = 31;
+
+ private final Object[] _values;
+
+ private final int _hashCode;
+
+ /**
+ * Creates a new instance from the provided values. It is assumed that the \
values provided are + * good map keys themselves (i.e., immutable, and implement \
equals() and hashCode() ). + *
+ * @param values
+ */
+ public MultiKey(Object... values)
+ {
+ _values = values;
+
+ _hashCode = PRIME * Arrays.hashCode(_values);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final MultiKey other = (MultiKey) obj;
+
+ return Arrays.equals(_values, other._values);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("MultiKey[");
+
+ boolean first = true;
+
+ for (Object o : _values)
+ {
+ if (!first)
+ builder.append(", ");
+
+ builder.append(o);
+
+ first = false;
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/internal/util/URLChangeTracker.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/util/URLChangeTracker.java \
Wed Nov 29 14:02:40 2006 @@ -99,4 +99,15 @@
}
+ /**
+ * Needed for testing; changes file timestamps so that a change will be detected \
by + * {@link #containsChanges()}.
+ */
+ public void forceChange()
+ {
+ for (Map.Entry<URL, Long> e : _urlToTimestamp.entrySet())
+ {
+ e.setValue(0l);
+ }
+ }
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/model/ComponentModel.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/model/ComponentModel.java \
Wed Nov 29 14:02:40 2006 @@ -12,98 +12,108 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.model;
-
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.annotations.ComponentClass;
-import org.apache.tapestry.annotations.Persist;
-import org.apache.tapestry.annotations.SupportsInformalParameters;
+package org.apache.tapestry.model;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Persist;
+import org.apache.tapestry.annotations.SupportsInformalParameters;
import org.apache.tapestry.ioc.Resource;
-
-/**
- * Defines a component in terms of its capabilities, parameters, sub-components, \
etc. During
- * <em>runtime</em>, the component model is immutable. During <em>construction</em> \
time, when
- * the class is being transformed and loaded, the model is mutable.
- *
- * @see MutableComponentModel
- */
-public interface ComponentModel
-{
- /**
- * Returns the resource corresponding to the class file for this component. This \
is used to find
- * related resources, such as the component's template and message catalog.
- */
- Resource getBaseResource();
-
- /** The FQCN of the component. */
- String getComponentClassName();
-
- /**
- * Returns the ids of all embedded components defined within the component class \
(via the
- * {@link org.apache.tapestry.annotations.Component} annotation).
- */
- List<String> getEmbeddedComponentIds();
-
- /**
- * Returns an embedded component.
- *
- * @param componentId
- * the id of the embedded component
- * @return the embedded component model, or null if no component exists with \
that id
- */
- EmbeddedComponentModel getEmbeddedComponentModel(String componentId);
-
- /**
- * Returns the persistent strategy associated with the field.
- *
- * @param fieldName
- * @return the corresponding strategy
- * @throw IllegalArgumentException if the named field is not marked as \
persistent
- */
- String getFieldPersistenceStrategy(String fieldName);
-
- /** Returns object that will be used to log warnings and errors related to this \
component. */
- Log getLog();
-
- /** Returns a list of the class names of mixins that are part of the component's \
implementation. */
- List<String> getMixinClassNames();
-
- /** Return a single parameter model by parameter name, or null if the parameter \
is not defined. */
- ParameterModel getParameterModel(String parameterName);
-
- /**
- * Returns an alphabetically sorted list of the names of all formal parameters. \
This includes
- * parameters defined by a base class.
- */
-
- List<String> getParameterNames();
-
- /**
- * Returns a list of the names of all persistent fields (within this class, or \
any super-class).
- * The names are sorted alphabetically.
- *
- * @see Persist
- */
- List<String> getPersistentFieldNames();
-
- /**
- * Returns true if the modeled component is a root class, a component class \
whose parent does
- * not have the {@link ComponentClass} annotation. This is often used to \
determine whether to
- * invoke the super-class implementation of certain methods.
- *
- * @return true if a root class, false if a subclass
- */
- boolean isRootClass();
-
- /**
- * Returns true if the model indicates that informal parameters, additional \
parameters beyond
- * the formal parameter defined for the component, are supported. This is false \
in most cases,
- * but may be set to true for specific classes (when the {@link \
SupportsInformalParameters}
- * annotation is present, or inherited from a super-class).
- *
- * @return true if this component model supports informal parameters
- */
- boolean getSupportsInformalParameters();
-}
+
+/**
+ * Defines a component in terms of its capabilities, parameters, sub-components, \
etc. During + * <em>runtime</em>, the component model is immutable. During \
<em>construction</em> time, when + * the class is being transformed and loaded, the \
model is mutable. + *
+ * @see MutableComponentModel
+ */
+public interface ComponentModel
+{
+ /**
+ * Returns the resource corresponding to the class file for this component. This \
is used to find + * related resources, such as the component's template and \
message catalog. + */
+ Resource getBaseResource();
+
+ /** The FQCN of the component. */
+ String getComponentClassName();
+
+ /**
+ * Returns the ids of all embedded components defined within the component class \
(via the + * {@link org.apache.tapestry.annotations.Component} annotation).
+ */
+ List<String> getEmbeddedComponentIds();
+
+ /**
+ * Returns an embedded component.
+ *
+ * @param componentId
+ * the id of the embedded component
+ * @return the embedded component model, or null if no component exists with \
that id + */
+ EmbeddedComponentModel getEmbeddedComponentModel(String componentId);
+
+ /**
+ * Returns the persistent strategy associated with the field.
+ *
+ * @param fieldName
+ * @return the corresponding strategy
+ * @throw IllegalArgumentException if the named field is not marked as \
persistent + */
+ String getFieldPersistenceStrategy(String fieldName);
+
+ /** Returns object that will be used to log warnings and errors related to this \
component. */ + Log getLog();
+
+ /** Returns a list of the class names of mixins that are part of the component's \
implementation. */ + List<String> getMixinClassNames();
+
+ /** Return a single parameter model by parameter name, or null if the parameter \
is not defined. */ + ParameterModel getParameterModel(String parameterName);
+
+ /**
+ * Returns an alphabetically sorted list of the names of all formal parameters. \
This includes + * parameters defined by a base class.
+ */
+
+ List<String> getParameterNames();
+
+ /**
+ * Returns a list of the names of all persistent fields (within this class, or \
any super-class). + * The names are sorted alphabetically.
+ *
+ * @see Persist
+ */
+ List<String> getPersistentFieldNames();
+
+ /**
+ * Returns true if the modeled component is a root class, a component class \
whose parent does + * not have the {@link ComponentClass} annotation. This is \
often used to determine whether to + * invoke the super-class implementation of \
certain methods. + *
+ * @return true if a root class, false if a subclass
+ */
+ boolean isRootClass();
+
+ /**
+ * Returns true if the model indicates that informal parameters, additional \
parameters beyond + * the formal parameter defined for the component, are \
supported. This is false in most cases, + * but may be set to true for specific \
classes (when the {@link SupportsInformalParameters} + * annotation is present, \
or inherited from a super-class). + *
+ * @return true if this component model supports informal parameters
+ */
+ boolean getSupportsInformalParameters();
+
+ /**
+ * Returns the component model for this component's super-class, if it exists. \
Remember that + * only classes with the {@link ComponentClass} annotation, and in \
the correct packages, are + * considered component classes.
+ *
+ * @return the parent class model, or null if this component's super class is \
not itself a + * component class
+ */
+ ComponentModel getParentModel();
+}
Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentMessagesSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentMessagesSource.java?view=auto&rev=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentMessagesSource.java \
(added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/ComponentMessagesSource.java \
Wed Nov 29 14:02:40 2006 @@ -0,0 +1,36 @@
+// Copyright 2006 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.tapestry.services;
+
+import java.util.Locale;
+
+import org.apache.tapestry.internal.event.InvalidationEventHub;
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.model.ComponentModel;
+
+public interface ComponentMessagesSource extends InvalidationEventHub
+{
+ /**
+ * Used to obtain a {@link Messages} instance for a particular component, within \
a particular + * locale. If the component extends from another component, then \
its localized properties will + * merge with its parent's properties (with the \
subclass overriding the super class on any + * conflicts).
+ *
+ * @param componentModel
+ * @param locale
+ * @return
+ */
+ Messages getMessages(ComponentModel componentModel, Locale locale);
+}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java \
/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java \
Wed Nov 29 14:02:40 2006 @@ -38,8 +38,9 @@
import org.apache.tapestry.MarkupWriter;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.ioc.Location;
+import org.apache.tapestry.ioc.Resource;
import org.apache.tapestry.ioc.ServiceLocator;
-import org.apache.tapestry.ioc.services.ThreadLocale;
+import org.apache.tapestry.ioc.internal.util.ClasspathResource;
import org.apache.tapestry.ioc.test.IOCTestCase;
import org.apache.tapestry.model.ComponentModel;
import org.apache.tapestry.model.MutableComponentModel;
@@ -63,6 +64,9 @@
public abstract class TapestryTestCase extends IOCTestCase
{
+ protected final Resource _simpleComponentResource = new ClasspathResource(
+ "org/apache/tapestry/internal/services/SimpleComponent.class");
+
protected final void train_findFieldsWithAnnotation(ClassTransformation \
transformation,
Class<? extends Annotation> annotationClass, String... fieldNames)
{
@@ -382,10 +386,7 @@
return newMock(WebRequestHandler.class);
}
- protected final ThreadLocale newThreadLocale()
- {
- return newMock(ThreadLocale.class);
- }
+
protected final void train_service(WebRequestHandler handler, WebRequest \
request, WebResponse response, boolean result) throws IOException {
@@ -395,5 +396,15 @@
protected final void train_getLocale(WebRequest request, Locale locale)
{
expect(request.getLocale()).andReturn(locale).atLeastOnce();
+ }
+
+ protected final void train_getParentModel(ComponentModel model, ComponentModel \
parentModel) + {
+ expect(model.getParentModel()).andReturn(parentModel).atLeastOnce();
+ }
+
+ protected final void train_getBaseResource(ComponentModel model, Resource \
resource) + {
+ expect(model.getBaseResource()).andReturn(resource).atLeastOnce();
}
}
Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/reso \
urces/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=480728&r1=480727&r2=480728
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties \
(original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties \
Wed Nov 29 14:02:40 2006 @@ -58,4 +58,5 @@
could-not-resolve-mixin-type=Unable to resolve mixin type '%s' to a component class \
name. parameter-name-must-be-unique=Parameter names are required to be unique. \
Parameter '%s' already has the value '%s'. page-is-dirty=Page %s is dirty, and will \
be discarded (rather than returned to the page pool).
-component-instance-is-not-a-page=Method %s (for component %s) returned component %s, \
which is not a page component. The page containing the component will render the \
client response. \ No newline at end of file
+component-instance-is-not-a-page=Method %s (for component %s) returned component %s, \
which is not a page component. The page containing the component will render the \
client response. +failure-reading-component-messages=Unable to read component message \
catalog from %s: %s \ No newline at end of file
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic