You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/07/29 22:01:55 UTC

svn commit: r680819 - in /tapestry/tapestry5/trunk: tapestry-core/src/main/java/org/apache/tapestry5/ tapestry-core/src/main/java/org/apache/tapestry5/annotations/ tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/ tapestry-core/src/main/...

Author: hlship
Date: Tue Jul 29 13:01:53 2008
New Revision: 680819

URL: http://svn.apache.org/viewvc?rev=680819&view=rev
Log:
TAPESTRY-2543: Simplify Tapestry to use UTF-8 (or another, configurable character set) across the entire application

Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ResponseEncoding.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestEncodingInitializerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ResponseEncodingWorker.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestEncodingInitializerImplTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/transform/ResponseEncodingWorkerTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ContentType.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/MetaDataConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/StreamResponse.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ContentType.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStorageImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/JSONObjectEventResultProcessor.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageContentTypeAnalyzerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/localization.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java
    tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImpl.java
    tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/ParametersServletRequestWrapper.java
    tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ContentType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ContentType.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ContentType.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ContentType.java Tue Jul 29 13:01:53 2008
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5;
 
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.Defense;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -53,6 +54,17 @@
     }
 
     /**
+     * Creates a new content type with the given MIME type and charset
+     */
+    public ContentType(String contentType, String charset)
+    {
+        this(contentType);
+
+        setParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER, charset);
+    }
+
+
+    /**
      * Returns true only if the other object is another instance of ContentType, and has the ssame baseType, subType and
      * set of parameters.
      */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/MetaDataConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/MetaDataConstants.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/MetaDataConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/MetaDataConstants.java Tue Jul 29 13:01:53 2008
@@ -1,3 +1,17 @@
+// Copyright 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;
 
 /**
@@ -12,14 +26,9 @@
      * "text/html" when not overridden.
      */
     public static final String RESPONSE_CONTENT_TYPE = "tapestry.response-content-type";
+
     /**
      * Meta data key applied to pages that may only be accessed via secure methods (HTTPS).
      */
     public static final String SECURE_PAGE = "tapestry.secure-page";
-    /**
-     * Meta data key applied to pages that sets the response encoding. A factory default provides the value "UTF-8" when
-     * not overriden. Content type may also be specified in the {@link #RESPONSE_CONTENT_TYPE content type} as parameter
-     * "charset", i.e., "text/html;charset=UTF-8".
-     */
-    public static final String RESPONSE_ENCODING = "tapestry.response-encoding";
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/StreamResponse.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/StreamResponse.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/StreamResponse.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/StreamResponse.java Tue Jul 29 13:01:53 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// 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.
@@ -39,8 +39,8 @@
 
 
     /**
-     * Prepare response before it is sent to the client. This is the place to set any response headers (e.g.
-     * content-disposition)
+     * Prepares the response before it is sent to the client. This is the place to set any response headers (e.g.
+     * content-disposition).
      *
      * @param response Response that will be sent.
      */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java Tue Jul 29 13:01:53 2008
@@ -26,34 +26,41 @@
      * exceptions are reported.
      */
     public static final String PRODUCTION_MODE = "tapestry.production-mode";
+
     /**
      * Symbol which may be set to "true" to force the use of absolute URIs (not relative URIs) exclusively.
      */
     public static final String FORCE_ABSOLUTE_URIS = "tapestry.force-absolute-uris";
+
     /**
      * If set to true, then action requests will render a page markup response immediately, rather than sending a
      * redirect to render the response.
      */
     public static final String SUPPRESS_REDIRECT_FROM_ACTION_REQUESTS = "tapestry.suppress-redirect-from-action-requests";
+
     /**
      * The list of locales supported by the application; locales identified in the incoming request are "narrowed" to
      * one of these values.
      */
     public static final String SUPPORTED_LOCALES = "tapestry.supported-locales";
+
     /**
      * Controls whether whitespace is compressed by default in templates, or left as is. The factory default is to
      * compress whitespace. This can be overridden using the xml:space attribute inside template elements.
      */
     public static final String COMPRESS_WHITESPACE = "tapestry.compress-whitespace";
+
     /**
      * Time interval defining how often Tapestry will check for updates to local files (including classes). This number
      * can be raised in a production environment.
      */
     public static final String FILE_CHECK_INTERVAL = "tapestry.file-check-interval";
+
     /**
      * Time interval that sets how long Tapestry will wait to obtain the exclusive lock needed to check local files.
      */
     public static final String FILE_CHECK_UPDATE_TIMEOUT = "tapestry.file-check-update-timeout";
+
     /**
      * The version number of the core Tapestry framework, or UNKNOWN if the version number is not available (which
      * should only occur when developing Tapestry).
@@ -65,4 +72,10 @@
      * will normally be <code>WEB-INF/app.properties</code>.
      */
     public static final String APPLICATION_CATALOG = "tapestry.app-catalog";
+
+    /**
+     * The  charset used when rendering page markup; the charset is also used as ther request encoding when handling
+     * incoming requests. The default is "UTF-8".
+     */
+    public static final String CHARSET = "tapestry.charset";
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ContentType.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ContentType.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ContentType.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/ContentType.java Tue Jul 29 13:01:53 2008
@@ -21,10 +21,8 @@
  * An annotation on a page component used to identify the content type the page returns. An alternative to the {@link
  * org.apache.tapestry5.annotations.Meta} annotation with the {@link org.apache.tapestry5.MetaDataConstants#RESPONSE_CONTENT_TYPE}
  * key.
- *
- * @see org.apache.tapestry5.annotations.ResponseEncoding
  */
-@Target({ ElementType.TYPE })
+@Target({ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface ContentType

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/mixins/Autocomplete.java Tue Jul 29 13:01:53 2008
@@ -188,7 +188,7 @@
             }
         };
 
-        resources.triggerEvent("providecompletions", new Object[] { input }, callback);
+        resources.triggerEvent("providecompletions", new Object[]{input}, callback);
 
         ContentType contentType = responseRenderer.findContentType(this);
 
@@ -196,7 +196,7 @@
 
         generateResponseMarkup(writer, matchesHolder.get());
 
-        return new TextStreamResponse(contentType.getMimeType(), writer.toString());
+        return new TextStreamResponse(contentType.toString(), writer.toString());
     }
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java Tue Jul 29 13:01:53 2008
@@ -16,7 +16,10 @@
 
 import org.apache.tapestry5.ContentType;
 import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.MarkupWriterFactory;
 import org.apache.tapestry5.services.PartialMarkupRenderer;
@@ -36,13 +39,24 @@
 
     private final PartialMarkupRenderer partialMarkupRenderer;
 
-    public AjaxPartialResponseRendererImpl(MarkupWriterFactory factory, Request request,
-                                           Response response, PartialMarkupRenderer partialMarkupRenderer)
+    private final String outputEncoding;
+
+    public AjaxPartialResponseRendererImpl(MarkupWriterFactory factory,
+
+                                           Request request,
+
+                                           Response response,
+
+                                           PartialMarkupRenderer partialMarkupRenderer,
+
+                                           @Inject @Symbol(SymbolConstants.CHARSET)
+                                           String outputEncoding)
     {
         this.factory = factory;
         this.request = request;
         this.response = response;
         this.partialMarkupRenderer = partialMarkupRenderer;
+        this.outputEncoding = outputEncoding;
     }
 
     public void renderPartialPageMarkup() throws IOException
@@ -51,12 +65,10 @@
         // seperated, and trying to keep stateless and stateful (i.e., perthread scope) services
         // seperated. So we inform the stateful queue service what it needs to do here ...
 
-        ContentType pageContentType = (ContentType) request.getAttribute(
-                InternalConstants.CONTENT_TYPE_ATTRIBUTE_NAME);
-        String charset = pageContentType.getParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER);
+        ContentType pageContentType =
+                (ContentType) request.getAttribute(InternalConstants.CONTENT_TYPE_ATTRIBUTE_NAME);
 
-        ContentType contentType = new ContentType(InternalConstants.JSON_MIME_TYPE);
-        contentType.setParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER, charset);
+        ContentType contentType = new ContentType(InternalConstants.JSON_MIME_TYPE, outputEncoding);
 
         MarkupWriter writer = factory.newMarkupWriter(pageContentType);
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStorageImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStorageImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStorageImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientPersistentFieldStorageImpl.java Tue Jul 29 13:01:53 2008
@@ -117,6 +117,9 @@
 
     public ClientPersistentFieldStorageImpl(Request request)
     {
+        // This, here, is the problem of TAPESTRY-2501; this call can predate
+        // the check to set the character set based on meta data of the page.
+
         String value = request.getParameter(PARAMETER_NAME);
 
         // MIME can encode to a '+' character; the browser converts that to a space; we convert it

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentEventDispatcher.java Tue Jul 29 13:01:53 2008
@@ -51,19 +51,19 @@
 
     private final ContextValueEncoder contextValueEncoder;
 
-    private final RequestEncodingInitializer requestEncodingInitializer;
-
     private final EventContext emptyContext = new EmptyEventContext();
 
-    public ComponentEventDispatcher(@Traditional ComponentEventRequestHandler componentEventRequestHandler,
-                                    ComponentClassResolver componentClassResolver,
-                                    ContextValueEncoder contextValueEncoder,
-                                    RequestEncodingInitializer requestEncodingInitializer)
+    public ComponentEventDispatcher(
+            @Traditional
+            ComponentEventRequestHandler componentEventRequestHandler,
+
+            ComponentClassResolver componentClassResolver,
+
+            ContextValueEncoder contextValueEncoder)
     {
         this.componentEventRequestHandler = componentEventRequestHandler;
         this.componentClassResolver = componentClassResolver;
         this.contextValueEncoder = contextValueEncoder;
-        this.requestEncodingInitializer = requestEncodingInitializer;
     }
 
     // A beast that recognizes all the elements of a path in a single go.
@@ -109,11 +109,6 @@
 
         EventContext eventContext = decodeContext(matcher.group(CONTEXT));
 
-        // Initialize the request encoding BEFORE accessing any query parameters
-        // (TAPESTRY-1605)
-
-        requestEncodingInitializer.initializeRequestEncoding(activePageName);
-
         EventContext activationContext = decodeContext(request.getParameter(InternalConstants.PAGE_CONTEXT_NAME));
 
         // The event type is often omitted, and defaults to "action".

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java Tue Jul 29 13:01:53 2008
@@ -76,7 +76,6 @@
         binder.bind(PageElementFactory.class, PageElementFactoryImpl.class);
         binder.bind(ResourceStreamer.class, ResourceStreamerImpl.class);
         binder.bind(ClientPersistentFieldStorage.class, ClientPersistentFieldStorageImpl.class);
-        binder.bind(RequestEncodingInitializer.class, RequestEncodingInitializerImpl.class);
         binder.bind(PageRenderQueue.class, PageRenderQueueImpl.class);
         binder.bind(AjaxPartialResponseRenderer.class, AjaxPartialResponseRendererImpl.class);
         binder.bind(PageContentTypeAnalyzer.class, PageContentTypeAnalyzerImpl.class);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/JSONObjectEventResultProcessor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/JSONObjectEventResultProcessor.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/JSONObjectEventResultProcessor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/JSONObjectEventResultProcessor.java Tue Jul 29 13:01:53 2008
@@ -14,7 +14,11 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.ContentType;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.ComponentEventResultProcessor;
 import org.apache.tapestry5.services.Response;
@@ -32,14 +36,22 @@
 {
     private final Response response;
 
-    public JSONObjectEventResultProcessor(Response response)
+    private final String outputEncoding;
+
+    public JSONObjectEventResultProcessor(Response response,
+
+                                          @Inject @Symbol(SymbolConstants.CHARSET)
+                                          String outputEncoding)
     {
         this.response = response;
+        this.outputEncoding = outputEncoding;
     }
 
     public void processResultValue(JSONObject value) throws IOException
     {
-        PrintWriter pw = response.getPrintWriter(InternalConstants.JSON_MIME_TYPE);
+        ContentType contentType = new ContentType(InternalConstants.JSON_MIME_TYPE, outputEncoding);
+
+        PrintWriter pw = response.getPrintWriter(contentType.toString());
 
         pw.print(value.toString());
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MarkupWriterFactoryImpl.java Tue Jul 29 13:01:53 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// 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.
@@ -19,6 +19,7 @@
 import org.apache.tapestry5.dom.DefaultMarkupModel;
 import org.apache.tapestry5.dom.MarkupModel;
 import org.apache.tapestry5.dom.XMLMarkupModel;
+import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.services.MarkupWriterFactory;
 
 public class MarkupWriterFactoryImpl implements MarkupWriterFactory
@@ -36,7 +37,7 @@
         // The charset parameter sets the encoding attribute of the XML declaration, if
         // not null and if using the XML model.
 
-        return new MarkupWriterImpl(model, contentType.getParameter("charset"));
+        return new MarkupWriterImpl(model, contentType.getParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER));
     }
 
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MessagesSourceImpl.java Tue Jul 29 13:01:53 2008
@@ -36,7 +36,7 @@
  * any keys inherited form base components and, ultimately, the application global message catalog. At some point we
  * should add support for per-library message catalogs.
  * <p/>
- * Message catalogs are read using the utf-8 character set. This is tricky in JDK 1.5; we read the file into memory then
+ * Message catalogs are read using the UTF-8 character set. This is tricky in JDK 1.5; we read the file into memory then
  * feed that bytestream to Properties.load().
  */
 public class MessagesSourceImpl extends InvalidationEventHubImpl implements MessagesSource
@@ -215,9 +215,7 @@
 
         try
         {
-            is = resource.openStream();
-
-            is = readStreamAsUTF8(is);
+            is = readStreamAsUTF8(resource.openStream());
 
             // Ok, now we have the content read into memory as UTF-8, not ASCII.
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageContentTypeAnalyzerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageContentTypeAnalyzerImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageContentTypeAnalyzerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageContentTypeAnalyzerImpl.java Tue Jul 29 13:01:53 2008
@@ -17,17 +17,25 @@
 import org.apache.tapestry5.ComponentResources;
 import org.apache.tapestry5.ContentType;
 import org.apache.tapestry5.MetaDataConstants;
-import org.apache.tapestry5.internal.InternalConstants;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.structure.Page;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.services.MetaDataLocator;
 
 public class PageContentTypeAnalyzerImpl implements PageContentTypeAnalyzer
 {
     private final MetaDataLocator metaDataLocator;
 
-    public PageContentTypeAnalyzerImpl(MetaDataLocator metaDataLocator)
+    private final String outputCharset;
+
+    public PageContentTypeAnalyzerImpl(MetaDataLocator metaDataLocator,
+
+                                       @Inject @Symbol(SymbolConstants.CHARSET)
+                                       String outputCharset)
     {
         this.metaDataLocator = metaDataLocator;
+        this.outputCharset = outputCharset;
     }
 
     public ContentType findContentType(Page page)
@@ -36,19 +44,9 @@
 
         String contentTypeString = metaDataLocator.findMeta(MetaDataConstants.RESPONSE_CONTENT_TYPE, pageResources,
                                                             String.class);
-        ContentType contentType = new ContentType(contentTypeString);
-
-        // Make sure thre's always a charset specified.
-
-        String encoding = contentType.getParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER);
 
-        if (encoding == null)
-        {
-            encoding = metaDataLocator
-                    .findMeta(MetaDataConstants.RESPONSE_ENCODING, pageResources, String.class);
-            contentType.setParameter(InternalConstants.CHARSET_CONTENT_TYPE_PARAMETER, encoding);
-        }
+        // Draconian but necessary: overwrite the content type they selected with the application-wide output charset.
 
-        return contentType;
+        return new ContentType(contentTypeString, outputCharset);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestImpl.java Tue Jul 29 13:01:53 2008
@@ -36,13 +36,20 @@
 
     private final HttpServletRequest request;
 
-    public RequestImpl(HttpServletRequest request)
+    private final String requestEncoding;
+
+    private boolean encodingSet;
+
+    public RequestImpl(HttpServletRequest request, String requestEncoding)
     {
         this.request = request;
+        this.requestEncoding = requestEncoding;
     }
 
     public List<String> getParameterNames()
     {
+        setupEncoding();
+
         return InternalUtils.toList(request.getParameterNames());
     }
 
@@ -53,11 +60,15 @@
 
     public String getParameter(String name)
     {
+        setupEncoding();
+
         return request.getParameter(name);
     }
 
     public String[] getParameters(String name)
     {
+        setupEncoding();
+
         return request.getParameterValues(name);
     }
 
@@ -100,8 +111,10 @@
         return request.getDateHeader(name);
     }
 
-    public void setEncoding(String requestEncoding)
+    private void setupEncoding()
     {
+        if (encodingSet) return;
+
         try
         {
             request.setCharacterEncoding(requestEncoding);
@@ -110,8 +123,11 @@
         {
             throw new RuntimeException(ex);
         }
+
+        encodingSet = true;
     }
 
+
     public boolean isXHR()
     {
         return XML_HTTP_REQUEST.equals(request.getHeader(REQUESTED_WITH_HEADER));
@@ -141,4 +157,5 @@
     {
         return request.getServerName();
     }
+
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentEventRequestFilter.java Tue Jul 29 13:01:53 2008
@@ -20,8 +20,8 @@
  * Filter interface for {@link ComponentEventRequestHandler}.
  *
  * @see org.apache.tapestry5.services.TapestryModule#contributeComponentEventRequestHandler(org.apache.tapestry5.ioc.OrderedConfiguration,
- *      org.apache.tapestry5.internal.services.RequestEncodingInitializer, ComponentEventRequestHandler ,
- *      org.apache.tapestry5.ioc.ObjectLocator) }
+ *      org.apache.tapestry5.internal.services.RequestSecurityManager, ComponentEventRequestHandler,
+ *      org.apache.tapestry5.ioc.ObjectLocator)
  */
 public interface ComponentEventRequestFilter
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/Request.java Tue Jul 29 13:01:53 2008
@@ -93,13 +93,6 @@
     String getHeader(String name);
 
     /**
-     * Sets the encoding of the request, which must occur before any parameters for the request are read.
-     *
-     * @param requestEncoding charset used when parsing parameters
-     */
-    void setEncoding(String requestEncoding);
-
-    /**
      * Returns true if the request originated on the client using XmlHttpRequest (the core of any Ajax behavior). Ajax
      * action requests may behave quite differently than ordinary, page-based requests.  This implementation currently
      * depends on the client side setting a header: <strong>X-Requested-With=XMLHttpRequest</strong> (this is what

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Tue Jul 29 13:01:53 2008
@@ -286,8 +286,7 @@
      * {@link org.apache.tapestry5.internal.InternalComponentResources#postRenderCleanup()} is invoked after a component
      * finishes rendering</dd> <dt>Secure</dt> <dd>Checks for the {@link org.apache.tapestry5.annotations.Secure}
      * annotation</dd> <dt>ContentType</dt> <dd>Checks for {@link org.apache.tapestry5.annotations.ContentType}
-     * annotation</dd> <dt>ResponseEncoding</dt> <dd>Checks for the {@link org.apache.tapestry5.annotations.ResponseEncoding}
-     * annotation</dd> <dt>GenerateAccessors</dt> <dd>Generates accessor methods if {@link
+     * annotation</dd>  <dt>GenerateAccessors</dt> <dd>Generates accessor methods if {@link
      * org.apache.tapestry5.annotations.Property} annotation is present </dd> <dt>Cached</dt> <dd>Checks for the {@link
      * org.apache.tapestry5.annotations.Cached} annotation</dd><dt>Log</dt> <dd>Checks for the {@link
      * org.apache.tapestry5.annotations.Log} annotation</dd></dl>
@@ -360,7 +359,6 @@
         configuration.add("InvokePostRenderCleanupOnResources", new InvokePostRenderCleanupOnResourcesWorker());
 
         configuration.add("ContentType", new ContentTypeWorker());
-        configuration.add("ResponseEncoding", new ResponseEncodingWorker());
 
         configuration.add("Property", new PropertyWorker());
 
@@ -898,10 +896,14 @@
     }
 
     public HttpServletRequestHandler buildHttpServletRequestHandler(Logger logger,
+
                                                                     List<HttpServletRequestFilter> configuration,
 
                                                                     @Primary
-                                                                    final RequestHandler handler)
+                                                                    final RequestHandler handler,
+
+                                                                    @Inject @Symbol(SymbolConstants.CHARSET)
+                                                                    final String applicationCharset)
     {
         HttpServletRequestHandler terminator = new HttpServletRequestHandler()
         {
@@ -910,7 +912,7 @@
             {
                 requestGlobals.storeServletRequestResponse(servletRequest, servletResponse);
 
-                Request request = new RequestImpl(servletRequest);
+                Request request = new RequestImpl(servletRequest, applicationCharset);
                 Response response = new ResponseImpl(servletResponse);
 
                 // Transition from the Servlet API-based pipeline, to the Tapestry-based pipeline.
@@ -1268,7 +1270,7 @@
     {
         configuration.add(RenderCommand.class, locator.autobuild(RenderCommandComponentEventResultProcessor.class));
         configuration.add(Component.class, locator.autobuild(AjaxComponentInstanceEventResultProcessor.class));
-        configuration.add(JSONObject.class, new JSONObjectEventResultProcessor(response));
+        configuration.add(JSONObject.class, locator.autobuild(JSONObjectEventResultProcessor.class));
         configuration.add(StreamResponse.class, new StreamResponseResultProcessor(response));
     }
 
@@ -1743,7 +1745,8 @@
         configuration.add(PersistentFieldManagerImpl.META_KEY, PersistentFieldManagerImpl.DEFAULT_STRATEGY);
 
         configuration.add(MetaDataConstants.RESPONSE_CONTENT_TYPE, "text/html");
-        configuration.add(MetaDataConstants.RESPONSE_ENCODING, "UTF-8");
+
+        configuration.add(SymbolConstants.CHARSET, "UTF-8");
 
         configuration.add(SymbolConstants.APPLICATION_CATALOG, "WEB-INF/${tapestry.app-name}.properties");
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/localization.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/localization.apt?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/localization.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/localization.apt Tue Jul 29 13:01:53 2008
@@ -46,10 +46,9 @@
 
   If the file <<<WEB-INF/>>><AppName><<<.properties>>> exists in the context, it will be used as an application-wide message catalog.  The <AppName>
   is derived from the name of the filter inside the web.xml file; this is most often just "app", thus <<<WEB-INF/app.properties>>>.
-  The search for the file is case sensitive. The properties file may be localized.
+  The search for the file is case sensitive. The properties files may be localized.
   
-  Individual pages and components
-  can override the values defined in this message catalog.
+  Individual pages and components can override the values defined in the message catalog.
   
 Localized Component Templates
 
@@ -169,10 +168,16 @@
   This information is obtained from meta data on the page itself.  Meta data is specified using the
   {{{../../apidocs/org/apache/tapestry5/annotations/Meta.html}Meta}} annotation.
   
-  First, the response content type is obtained via meta-data key "tapestry.response-content-type".  This value defaults to "text/html".
+  The response content type is obtained via meta-data key "tapestry.response-content-type".  This value defaults to "text/html".
+
+  As a convienence, the {{{../../apidocs/org/apache/tapestry5/annotations/ContentType.html}ContentType}} annotation can be used to specify the response
+  content type.  The value attribute of the annotation is the content type.
+  
+  The character set for all outgoing markup and all incoming requests is "UTF-8".  UTF-8 is a version of Unicode where individual characters are encoded as one
+  or more bytes.  Most western language characters (that is, typical ASCII characters) are encoded in a single byte.  Accented characters or
+  non-western characters (such as Japanese, Arabic, etc.) may be encoded as two or more bytes.
+
   
-  Next, the encoding is obtained via meta-data key "tapestry.response-encoding".  This value defaults to "UTF-8".  This is only necessary if
-  the content type does not provide a charset parameter (i.e., "text/html;charset=ISO-8559-1").  The encoding becomes the charset.
   
   
   
\ No newline at end of file

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentEventDispatcherTest.java Tue Jul 29 13:01:53 2008
@@ -41,24 +41,18 @@
         ComponentEventRequestHandler handler = newComponentEventRequestHandler();
         Request request = mockRequest();
         Response response = mockResponse();
-        RequestEncodingInitializer requestEncodingInitializer = mockRequestEncodingInitializer();
 
         train_getPath(request, "/foo/bar/baz");
 
         replay();
 
-        Dispatcher dispatcher = new ComponentEventDispatcher(handler, null, null, requestEncodingInitializer);
+        Dispatcher dispatcher = new ComponentEventDispatcher(handler, null, null);
 
         assertFalse(dispatcher.dispatch(request, response));
 
         verify();
     }
 
-    protected final RequestEncodingInitializer mockRequestEncodingInitializer()
-    {
-        return newMock(RequestEncodingInitializer.class);
-    }
-
     protected final ComponentEventRequestHandler newComponentEventRequestHandler()
     {
         return newMock(ComponentEventRequestHandler.class);
@@ -138,16 +132,14 @@
         Request request = mockRequest();
         Response response = mockResponse();
         ComponentClassResolver resolver = mockComponentClassResolver();
-        RequestEncodingInitializer requestEncodingInitializer = mockRequestEncodingInitializer();
-
 
         ComponentEventRequestParameters expectedParameters = new ComponentEventRequestParameters("mypage", "mypage", "",
                                                                                                  "eventname",
                                                                                                  new URLEventContext(
                                                                                                          contextValueEncoder,
-                                                                                                         new String[] {
+                                                                                                         new String[]{
                                                                                                                  "alpha",
-                                                                                                                 "beta" }),
+                                                                                                                 "beta"}),
                                                                                                  new EmptyEventContext());
 
         train_getPath(request, "/mypage:eventname");
@@ -158,14 +150,12 @@
 
         train_getParameter(request, InternalConstants.CONTAINER_PAGE_NAME, null);
 
-        requestEncodingInitializer.initializeRequestEncoding("mypage");
-
         handler.handle(expectedParameters);
 
         replay();
 
-        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder,
-                                                             requestEncodingInitializer);
+        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder
+        );
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -179,7 +169,6 @@
         Request request = mockRequest();
         Response response = mockResponse();
         ComponentClassResolver resolver = mockComponentClassResolver();
-        RequestEncodingInitializer requestEncodingInitializer = mockRequestEncodingInitializer();
 
         ComponentEventRequestParameters expectedParameters = new ComponentEventRequestParameters("activepage", "mypage",
                                                                                                  "", "eventname",
@@ -190,8 +179,6 @@
 
         train_isPageName(resolver, "activepage", true);
 
-        requestEncodingInitializer.initializeRequestEncoding("activepage");
-
         train_getParameter(request, InternalConstants.PAGE_CONTEXT_NAME, null);
 
         train_getParameter(request, InternalConstants.CONTAINER_PAGE_NAME, "mypage");
@@ -200,8 +187,8 @@
 
         replay();
 
-        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder,
-                                                             requestEncodingInitializer);
+        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder
+        );
 
         assertTrue(dispatcher.dispatch(request, response));
 
@@ -215,7 +202,6 @@
         Request request = mockRequest();
         Response response = mockResponse();
         ComponentClassResolver resolver = mockComponentClassResolver();
-        RequestEncodingInitializer requestEncodingInitializer = mockRequestEncodingInitializer();
 
         train_getPath(request, "/mypage.foo");
 
@@ -223,7 +209,7 @@
 
         replay();
 
-        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, null, requestEncodingInitializer);
+        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, null);
 
         assertFalse(dispatcher.dispatch(request, response));
 
@@ -237,7 +223,6 @@
         Request request = mockRequest();
         Response response = mockResponse();
         ComponentClassResolver resolver = mockComponentClassResolver();
-        RequestEncodingInitializer requestEncodingInitializer = mockRequestEncodingInitializer();
 
         ComponentEventRequestParameters expectedParameters = new ComponentEventRequestParameters(containerPageName,
                                                                                                  containerPageName,
@@ -256,14 +241,12 @@
 
         train_getParameter(request, InternalConstants.CONTAINER_PAGE_NAME, null);
 
-        requestEncodingInitializer.initializeRequestEncoding(containerPageName);
-
         handler.handle(expectedParameters);
 
         replay();
 
-        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder,
-                                                             requestEncodingInitializer);
+        Dispatcher dispatcher = new ComponentEventDispatcher(handler, resolver, contextValueEncoder
+        );
 
         assertTrue(dispatcher.dispatch(request, response));
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java Tue Jul 29 13:01:53 2008
@@ -23,9 +23,12 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import java.io.UnsupportedEncodingException;
+import java.util.Collections;
 
 public class RequestImplTest extends InternalBaseTestCase
 {
+    public static final String CHARSET = "UTF-8";
+
     @Test
     public void get_session_doesnt_exist()
     {
@@ -35,7 +38,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
 
         assertNull(request.getSession(false));
 
@@ -54,7 +57,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
         Session session = request.getSession(true);
 
         assertEquals(session.getAttribute("foo"), "bar");
@@ -71,9 +74,11 @@
 
         sr.setCharacterEncoding(encoding);
 
+        expect(sr.getParameterNames()).andReturn(Collections.enumeration(Collections.EMPTY_LIST));
+
         replay();
 
-        new RequestImpl(sr).setEncoding(encoding);
+        new RequestImpl(sr, encoding).getParameterNames();
 
         verify();
     }
@@ -93,7 +98,7 @@
 
         try
         {
-            new RequestImpl(sr).setEncoding(encoding);
+            new RequestImpl(sr, encoding).getParameterNames();
             unreachable();
         }
         catch (RuntimeException ex)
@@ -113,7 +118,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
 
         assertEquals(request.isXHR(), expected);
 
@@ -139,7 +144,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
 
         assertEquals(request.getPath(), path);
 
@@ -160,7 +165,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
 
         assertEquals(request.getPath(), path);
 
@@ -178,7 +183,7 @@
 
         replay();
 
-        Request request = new RequestImpl(sr);
+        Request request = new RequestImpl(sr, CHARSET);
 
         assertEquals(request.getPath(), "/");
 

Modified: tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImpl.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImpl.java Tue Jul 29 13:01:53 2008
@@ -19,6 +19,7 @@
 import org.apache.commons.fileupload.FileUploadException;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.ioc.annotations.Inject;
 import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -48,6 +49,8 @@
 
     private final long maxFileSize;
 
+    private final String requestEncoding;
+
     public MultipartDecoderImpl(
 
             @Inject @Symbol(UploadSymbols.REPOSITORY_LOCATION)
@@ -60,12 +63,16 @@
             long maxRequestSize,
 
             @Symbol(UploadSymbols.FILESIZE_MAX)
-            long maxFileSize)
+            long maxFileSize,
+
+            @Inject @Symbol(SymbolConstants.CHARSET)
+            String requestEncoding)
     {
         this.repositoryLocation = repositoryLocation;
         this.repositoryThreshold = repositoryThreshold;
         this.maxRequestSize = maxRequestSize;
         this.maxFileSize = maxFileSize;
+        this.requestEncoding = requestEncoding;
     }
 
     public UploadedFile getFileUpload(String parameterName)
@@ -75,6 +82,15 @@
 
     public HttpServletRequest decode(HttpServletRequest request)
     {
+        try
+        {
+            request.setCharacterEncoding(requestEncoding);
+        }
+        catch (UnsupportedEncodingException ex)
+        {
+            throw new RuntimeException(ex);
+        }
+
         List<FileItem> fileItems = parseRequest(request);
 
         return processFileItems(request, fileItems);
@@ -122,8 +138,6 @@
 
         ParametersServletRequestWrapper wrapper = new ParametersServletRequestWrapper(request);
 
-        String encoding = request.getCharacterEncoding();
-
         for (FileItem item : fileItems)
         {
             if (item.isFormField())
@@ -133,12 +147,11 @@
                 try
                 {
 
-                    fieldValue = encoding == null ? item.getString() : item.getString(encoding);
+                    fieldValue = item.getString(requestEncoding);
                 }
-                catch (UnsupportedEncodingException e)
+                catch (UnsupportedEncodingException ex)
                 {
-                    // TODO maybe log exception with level warn
-                    fieldValue = item.getString();
+                    throw new RuntimeException(ex);
                 }
 
                 wrapper.addParameter(item.getFieldName(), fieldValue);

Modified: tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/ParametersServletRequestWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/ParametersServletRequestWrapper.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/ParametersServletRequestWrapper.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry5/upload/internal/services/ParametersServletRequestWrapper.java Tue Jul 29 13:01:53 2008
@@ -15,7 +15,6 @@
 package org.apache.tapestry5.upload.internal.services;
 
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
-import org.apache.tapestry5.services.Dispatcher;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
@@ -92,9 +91,10 @@
     }
 
     /**
-     * Ignores any attempt to set the character encoding. Tapestry attempts to set the encoding <em>after</em> the page
-     * name has been identified by the correct {@link Dispatcher}, and that's too late from the perspective of the
-     * Servlet API as HttpServlet.getInputStream() will already have been called.
+     * Ignores any attempt to set the character encoding, as it already has been set before the request content was
+     * parsed.
+     *
+     * @see org.apache.tapestry5.SymbolConstants#CHARSET
      */
     @Override
     public void setCharacterEncoding(String enc) throws UnsupportedEncodingException

Modified: tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImplTest.java?rev=680819&r1=680818&r2=680819&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/test/java/org/apache/tapestry5/upload/internal/services/MultipartDecoderImplTest.java Tue Jul 29 13:01:53 2008
@@ -28,10 +28,12 @@
 public class MultipartDecoderImplTest extends TapestryTestCase
 {
 
+    private static final String CHARSET = "UTF-8";
+
     @Test
     public void create_file_upload_gets_configuration_from_symbols() throws Exception
     {
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, 7777, 6666);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, 7777, 6666, CHARSET);
 
         replay();
 
@@ -48,7 +50,7 @@
     public void process_file_items_does_nothing_when_null_file_items() throws Exception
     {
         HttpServletRequest request = mockHttpServletRequest();
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
 
         replay();
 
@@ -63,7 +65,7 @@
     public void process_file_items_does_nothing_when_empty_file_items() throws Exception
     {
         HttpServletRequest request = mockHttpServletRequest();
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
         List<FileItem> fileItems = Collections.emptyList();
 
         replay();
@@ -82,7 +84,7 @@
 
         train_getCharacterEncoding(request, "UTF-8");
 
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
         List<FileItem> fileItems = Arrays.asList(createValueItem("one", "first"), createValueItem("two", "second"));
 
         replay();
@@ -104,7 +106,7 @@
 
         train_getCharacterEncoding(request, null);
 
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
 
         List<FileItem> fileItems = Arrays.asList(createValueItem("one", "first"), createValueItem("two", "second"));
 
@@ -124,7 +126,7 @@
     public void process_file_items_set_file_parameters_with_file_name() throws Exception
     {
         HttpServletRequest request = mockHttpServletRequest();
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
         List<FileItem> fileItems = Arrays.asList(createFileItem("one", "first.txt"),
                                                  createFileItem("two", "second.txt"));
 
@@ -146,7 +148,7 @@
     public void uploaded_file_stored() throws Exception
     {
         HttpServletRequest request = mockHttpServletRequest();
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
         List<FileItem> fileItems = Arrays.asList(createFileItem("one", "first.txt"),
                                                  createFileItem("two", "second.txt"));
 
@@ -168,7 +170,7 @@
     public void file_items_cleaned_up() throws Exception
     {
         HttpServletRequest request = mockHttpServletRequest();
-        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1);
+        MultipartDecoderImpl decoder = new MultipartDecoderImpl("/tmp", 888, -1, -1, CHARSET);
         StubFileItem firstItem = new StubFileItem("one");
         firstItem.setFormField(false);
         StubFileItem secondItem = new StubFileItem("two");