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 2012/10/25 00:49:33 UTC

[3/8] git commit: Extend Messages to supply the available message keys Expose a virtual module, "core/messages/" for each supported locale

Extend Messages to supply the available message keys
Expose a virtual module, "core/messages/<locale>" for each supported locale


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/7b6f8932
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/7b6f8932
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/7b6f8932

Branch: refs/heads/5.4-js-rewrite
Commit: 7b6f8932c3e57dd7551d27678876fb0f35580bb3
Parents: 99c8b31
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Wed Oct 24 12:26:30 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Wed Oct 24 12:26:30 2012 -0700

----------------------------------------------------------------------
 .../tapestry5/internal/services/MapMessages.java   |    9 +-
 .../services/assets/ResourceChangeTracker.java     |   15 ++-
 .../services/assets/ResourceChangeTrackerImpl.java |   14 ++-
 .../internal/util/MessageCatalogResource.java      |  122 +++++++++++++++
 .../tapestry5/internal/util/VirtualResource.java   |   87 ++++++++++
 .../services/javascript/JavaScriptModule.java      |   22 +++
 .../java/org/apache/tapestry5/ioc/Messages.java    |   15 ++-
 .../tapestry5/ioc/internal/util/MessagesImpl.java  |   12 +-
 8 files changed, 283 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MapMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MapMessages.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MapMessages.java
index c34780c..2dbef2d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MapMessages.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MapMessages.java
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2012 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.
@@ -24,6 +24,7 @@ import org.apache.tapestry5.ioc.util.AbstractMessages;
 
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Implementation of {@link Messages} based on a simple Map (of string keys and values).
@@ -49,4 +50,10 @@ public class MapMessages extends AbstractMessages
     {
         return properties.get(key);
     }
+
+    @Override
+    public Set<String> getKeys()
+    {
+        return properties.keySet();
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTracker.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTracker.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTracker.java
index 99b13c7..8e4de90 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTracker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTracker.java
@@ -1,4 +1,4 @@
-// Copyright 2011 The Apache Software Foundation
+// Copyright 2011, 2012 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.
@@ -35,9 +35,20 @@ public interface ResourceChangeTracker extends InvalidationEventHub, ResourceDep
      * {@linkplain InvalidationListener listeners} are notified and the internal state
      * is cleared.
      *
-     * @param resource to track
+     * @param resource
+     *         to track
      * @return last modified time, to nearest second
      * @see URLChangeTracker
      */
     long trackResource(Resource resource);
+
+    /**
+     * Forces an invalidation event. This is required in a rare case, to clear out a {@link org.apache.tapestry5.services.assets.StreamableResource}
+     * generated from the component message catalog; there are some walls in place that prevent the message catalog's underlying
+     * {@link Resource}s from being exposed.
+     *
+     * @see org.apache.tapestry5.internal.util.MessageCatalogResource
+     * @since 5.4
+     */
+    void forceInvalidationEvent();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTrackerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTrackerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTrackerImpl.java
index 55c6cfb..810e96c 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTrackerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/ResourceChangeTrackerImpl.java
@@ -69,12 +69,22 @@ public class ResourceChangeTrackerImpl extends InvalidationEventHubImpl implemen
         trackResource(dependency);
     }
 
+    @Override
+    public void forceInvalidationEvent()
+    {
+        fireInvalidationEvent();
+
+        if (tracker != null)
+        {
+            tracker.clear();
+        }
+    }
+
     public void checkForUpdates()
     {
         if (tracker.containsChanges())
         {
-            fireInvalidationEvent();
-            tracker.clear();
+            forceInvalidationEvent();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MessageCatalogResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MessageCatalogResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MessageCatalogResource.java
new file mode 100644
index 0000000..2b5a016
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MessageCatalogResource.java
@@ -0,0 +1,122 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.util;
+
+import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.messages.ComponentMessagesSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.Locale;
+
+public class MessageCatalogResource extends VirtualResource
+{
+    private final Locale locale;
+
+    private final ComponentMessagesSource messagesSource;
+
+    private final boolean compactJSON;
+
+    private volatile byte[] bytes;
+
+    public MessageCatalogResource(Locale locale, ComponentMessagesSource messagesSource, final ResourceChangeTracker changeTracker, boolean compactJSON)
+    {
+        this.locale = locale;
+        this.messagesSource = messagesSource;
+        this.compactJSON = compactJSON;
+
+        messagesSource.getInvalidationEventHub().addInvalidationCallback(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                bytes = null;
+
+                changeTracker.forceInvalidationEvent();
+            }
+        });
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("MessageCatalogResource[%s]", locale);
+    }
+
+    /**
+     * StreamableResourceSourceImpl needs a file, and a suffix, to determine the content type.
+     */
+    @Override
+    public String getFile()
+    {
+        return String.format("virtual-%s.js", locale);
+    }
+
+    /**
+     * To work as a streamable resource, must return a value (or null) from toURL.
+     */
+    @Override
+    public URL toURL()
+    {
+        return null;
+    }
+
+    @Override
+    public InputStream openStream() throws IOException
+    {
+        return new ByteArrayInputStream(getBytes());
+    }
+
+    private byte[] getBytes()
+    {
+        if (bytes != null)
+        {
+            return bytes;
+        }
+
+        try
+        {
+            bytes = assembleCatalog().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e)
+        {
+            throw new RuntimeException(e);
+        }
+
+        return bytes;
+    }
+
+    private String assembleCatalog()
+    {
+        Messages messages = messagesSource.getApplicationCatalog(locale);
+
+        JSONObject catalog = new JSONObject();
+
+        for (String key : messages.getKeys())
+        {
+            catalog.put(key, messages.get(key));
+        }
+
+        StringBuilder builder = new StringBuilder(2000);
+
+        builder.append("define(").append(catalog.toString(compactJSON)).append(");");
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/VirtualResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/VirtualResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/VirtualResource.java
new file mode 100644
index 0000000..6c76c3a
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/VirtualResource.java
@@ -0,0 +1,87 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.internal.util;
+
+import org.apache.tapestry5.ioc.Resource;
+
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Base class for virtual resources: resources that are not simply mapped to stored files, but are assembled, as necessary,
+ * on the fly. This is used inside Tapestry to expose the application's localized message catalog as a module.
+ * Subclasses should implement the {@link org.apache.tapestry5.ioc.Resource#openStream()} method to return a stream of
+ * the contents of the virtual resource.
+ *
+ * @see org.apache.tapestry5.services.javascript.ModuleManager
+ * @see org.apache.tapestry5.internal.services.javascript.ModuleAssetRequestHandler
+ * @since 5.4
+ */
+public abstract class VirtualResource implements Resource
+{
+    private <T> T unsupported(String name)
+    {
+        throw new UnsupportedOperationException(String.format("Method %s() is not supported for a VirtualResource.", name));
+    }
+
+    @Override
+    public boolean exists()
+    {
+
+        return true;
+    }
+
+    @Override
+    public URL toURL()
+    {
+        return unsupported("toURL");
+    }
+
+    @Override
+    public Resource forLocale(Locale locale)
+    {
+        return unsupported("forLocale");
+    }
+
+    @Override
+    public Resource forFile(String relativePath)
+    {
+        return unsupported("forFile");
+    }
+
+    @Override
+    public Resource withExtension(String extension)
+    {
+        return unsupported("withExtension");
+    }
+
+    @Override
+    public String getFolder()
+    {
+        return unsupported("getFolder");
+    }
+
+    @Override
+    public String getFile()
+    {
+        return unsupported("getFile");
+    }
+
+    @Override
+    public String getPath()
+    {
+        return unsupported("getPath");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
index 4cb8b06..b735715 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/JavaScriptModule.java
@@ -15,23 +15,30 @@
 package org.apache.tapestry5.services.javascript;
 
 import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.annotations.Path;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.services.DocumentLinker;
 import org.apache.tapestry5.internal.services.ajax.JavaScriptSupportImpl;
+import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
 import org.apache.tapestry5.internal.services.javascript.*;
+import org.apache.tapestry5.internal.util.MessageCatalogResource;
 import org.apache.tapestry5.ioc.MappedConfiguration;
 import org.apache.tapestry5.ioc.OrderedConfiguration;
 import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.ServiceBinder;
 import org.apache.tapestry5.ioc.annotations.Contribute;
 import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.util.IdAllocator;
 import org.apache.tapestry5.json.JSONObject;
 import org.apache.tapestry5.services.*;
 import org.apache.tapestry5.services.assets.AssetRequestHandler;
 import org.apache.tapestry5.services.assets.ResourceTransformer;
 import org.apache.tapestry5.services.assets.StreamableResourceSource;
+import org.apache.tapestry5.services.messages.ComponentMessagesSource;
+
+import java.util.Locale;
 
 /**
  * Defines the services related to JavaScript.
@@ -182,4 +189,19 @@ public class JavaScriptModule
         configuration.add("prototype", new ShimModule(prototype, null, null));
     }
 
+    @Contribute(ModuleManager.class)
+    public static void setupApplicationCatalogModules(MappedConfiguration<String, Object> configuration,
+                                                      LocalizationSetter localizationSetter,
+                                                      ComponentMessagesSource messagesSource,
+                                                      ResourceChangeTracker resourceChangeTracker,
+                                                      @Symbol(SymbolConstants.COMPACT_JSON) boolean compactJSON)
+    {
+        for (Locale locale : localizationSetter.getSupportedLocales())
+        {
+            MessageCatalogResource resource = new MessageCatalogResource(locale, messagesSource,  resourceChangeTracker, compactJSON);
+
+            configuration.add("core/messages/" + locale.toString(), new ShimModule(resource, null, null));
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
index 93d13a5..ba7452c 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2012 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.
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry5.ioc;
 
+import java.util.Set;
+
 /**
  * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
  * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
@@ -45,8 +47,15 @@ public interface Messages
     MessageFormatter getFormatter(String key);
 
     /**
-     * Convienience for accessing a formatter and formatting a localized message with arguments.
+     * Convenience for accessing a formatter and formatting a localized message with arguments.
      */
-
     String format(String key, Object... args);
+
+    /**
+     * Returns a set of all the keys for which this instance may provide a value.
+     *
+     * @return set of keys
+     * @since 5.4
+     */
+    Set<String> getKeys();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/7b6f8932/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
index 0c542a8..c06ef90 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 2012 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.
@@ -17,10 +17,7 @@ package org.apache.tapestry5.ioc.internal.util;
 import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.util.AbstractMessages;
 
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.Map;
-import java.util.ResourceBundle;
+import java.util.*;
 
 /**
  * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
@@ -69,4 +66,9 @@ public class MessagesImpl extends AbstractMessages
         return properties.get(key);
     }
 
+    @Override
+    public Set<String> getKeys()
+    {
+        return properties.keySet();
+    }
 }