You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by th...@apache.org on 2014/06/30 20:08:43 UTC
git commit: TAP5-1515 : Support for external assets
Repository: tapestry-5
Updated Branches:
refs/heads/master ef7f9c43e -> 37a801d97
TAP5-1515 : Support for external assets
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/37a801d9
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/37a801d9
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/37a801d9
Branch: refs/heads/master
Commit: 37a801d975de8d76c3123c3a9b14efda56db7d10
Parents: ef7f9c4
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Mon Jun 30 15:08:27 2014 -0300
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Mon Jun 30 15:08:27 2014 -0300
----------------------------------------------------------------------
.../tapestry5/internal/AssetConstants.java | 16 +++
.../internal/services/AssetSourceImpl.java | 58 +++++++++-
.../services/ExternalUrlAssetFactory.java | 70 ++++++++++++
.../tapestry5/internal/services/UrlAsset.java | 44 ++++++++
.../internal/services/UrlResource.java | 112 +++++++++++++++++++
.../apache/tapestry5/modules/AssetsModule.java | 4 +
.../tapestry5/integration/app1/AssetTests.java | 12 ++
.../app1/pages/nested/AssetDemo.java | 22 +++-
.../integration/app1/services/AppModule.java | 8 +-
.../integration/app1/pages/nested/AssetDemo.tml | 14 +++
10 files changed, 353 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/internal/AssetConstants.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/AssetConstants.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/AssetConstants.java
index 7ea1431..647b3b6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/AssetConstants.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/AssetConstants.java
@@ -14,6 +14,9 @@
package org.apache.tapestry5.internal;
+import java.net.MalformedURLException;
+import java.net.URL;
+
/**
* Defines constants for the two basic asset prefixes.
*
@@ -26,4 +29,17 @@ public class AssetConstants
/** For assets that are stored in the classpath (i.e., inside 3rd party component library JARs). */
public static final String CLASSPATH = "classpath";
+
+ /** For assets that are external (stored in another service) and have a non-secure URL (http://...) */
+ public static final String HTTP = "http";
+
+ /** For assets that are external (stored in another service) and have a secure URL (https://...) */
+ public static final String HTTPS = "https";
+
+ /** For assets that are external (stored in another service) and have a protocol-relative URL (//...) */
+ public static final String PROTOCOL_RELATIVE = "//";
+
+ /** For assets that are external (stored in another service) and stored in a publicly available FTP server (ftp://...) */
+ public static final String FTP = "ftp";
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetSourceImpl.java
index cd9b4af..bac9e0c 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AssetSourceImpl.java
@@ -31,9 +31,14 @@ import org.apache.tapestry5.ioc.services.ThreadLocale;
import org.apache.tapestry5.ioc.util.StrategyRegistry;
import org.apache.tapestry5.services.AssetFactory;
import org.apache.tapestry5.services.AssetSource;
+import org.apache.tapestry5.services.Request;
import org.slf4j.Logger;
import java.lang.ref.SoftReference;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
@@ -42,6 +47,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
@SuppressWarnings("all")
public class AssetSourceImpl extends LockSupport implements AssetSource
{
+
+ private final List<String> EXTERNAL_URL_PREFIXES = Arrays.asList(
+ AssetConstants.HTTP, AssetConstants.HTTPS, AssetConstants.PROTOCOL_RELATIVE, AssetConstants.FTP);
+
private final StrategyRegistry<AssetFactory> registry;
private final ThreadLocale threadLocale;
@@ -57,15 +66,29 @@ public class AssetSourceImpl extends LockSupport implements AssetSource
private final AtomicBoolean firstWarning = new AtomicBoolean(true);
private final OperationTracker tracker;
+
+ private final Request request;
+
+ private final Map<String, AssetFactory> configuration;
- public AssetSourceImpl(ThreadLocale threadLocale,
+ public AssetSourceImpl(ThreadLocale threadLocale,
- Map<String, AssetFactory> configuration, SymbolSource symbolSource, Logger logger, OperationTracker tracker)
+ Map<String, AssetFactory> configuration, SymbolSource symbolSource, Logger logger, OperationTracker tracker)
{
+ this(threadLocale, configuration, symbolSource, logger, tracker, null);
+ }
+
+
+ public AssetSourceImpl(ThreadLocale threadLocale,
+
+ Map<String, AssetFactory> configuration, SymbolSource symbolSource, Logger logger, OperationTracker tracker, Request request)
+ {
+ this.configuration = configuration;
this.threadLocale = threadLocale;
this.symbolSource = symbolSource;
this.logger = logger;
this.tracker = tracker;
+ this.request = request;
Map<Class, AssetFactory> byResourceClass = CollectionFactory.newMap();
@@ -141,9 +164,36 @@ public class AssetSourceImpl extends LockSupport implements AssetSource
// We special case the hell out of 'classpath:' so that we can provide warnings today (5.4) and
// blow up in a useful fashion tomorrow (5.5).
- if (dotx > 0 && !expanded.substring(0, dotx).equalsIgnoreCase(AssetConstants.CLASSPATH))
+ if (expanded.startsWith("//") || (dotx > 0 && !expanded.substring(0, dotx).equalsIgnoreCase(AssetConstants.CLASSPATH)))
{
- return getAssetInLocale(resources.getBaseResource(), expanded, resources.getLocale());
+ final String prefix = dotx >= 0 ? expanded.substring(0, dotx) : AssetConstants.PROTOCOL_RELATIVE;
+ if (EXTERNAL_URL_PREFIXES.contains(prefix))
+ {
+
+ String url;
+ if (prefix.equals(AssetConstants.PROTOCOL_RELATIVE))
+ {
+ url = (request != null && request.isSecure() ? "https:" : "http:") + expanded;
+ }
+ else
+ {
+ url = expanded;
+ }
+
+ try
+ {
+ UrlResource resource = new UrlResource(new URL(url));
+ return new UrlAsset(url, resource);
+ }
+ catch (MalformedURLException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ else
+ {
+ return getAssetInLocale(resources.getBaseResource(), expanded, resources.getLocale());
+ }
}
// No prefix, so implicitly classpath:, or explicitly classpath:
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ExternalUrlAssetFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ExternalUrlAssetFactory.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ExternalUrlAssetFactory.java
new file mode 100644
index 0000000..738984e
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ExternalUrlAssetFactory.java
@@ -0,0 +1,70 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.internal.services;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.internal.AssetConstants;
+import org.apache.tapestry5.ioc.Resource;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.AssetFactory;
+
+public class ExternalUrlAssetFactory implements AssetFactory {
+
+ final private String protocol;
+
+ final private UrlResource rootResource;
+
+ final private Map<URL, Asset> cache = CollectionFactory.newMap();
+
+ public ExternalUrlAssetFactory(String protocol)
+ {
+ super();
+ this.protocol = protocol;
+// try
+// {
+ if (protocol.equals(AssetConstants.PROTOCOL_RELATIVE)) {
+ protocol = "http";
+ }
+ this.rootResource = new UrlResource();
+// }
+// catch (MalformedURLException e)
+// {
+// throw new RuntimeException(e);
+// }
+ }
+
+ @Override
+ public Resource getRootResource()
+ {
+ return rootResource;
+ }
+
+ @Override
+ public Asset createAsset(Resource resource)
+ {
+ final URL url = resource.toURL();
+ Asset asset = cache.get(url);
+ if (asset == null)
+ {
+ asset = new UrlAsset(url.toExternalForm(), resource);
+ cache.put(url, asset);
+ }
+ return asset;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlAsset.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlAsset.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlAsset.java
new file mode 100644
index 0000000..1441af8
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlAsset.java
@@ -0,0 +1,44 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.internal.services;
+
+import org.apache.tapestry5.ioc.Resource;
+
+public class UrlAsset extends AbstractAsset
+{
+
+ final private String url;
+
+ final private Resource resource;
+
+ public UrlAsset(String url, Resource resource)
+ {
+ super(true);
+ this.url = url;
+ this.resource = resource;
+ }
+
+ @Override
+ public String toClientURL()
+ {
+ return url;
+ }
+
+ @Override
+ public Resource getResource()
+ {
+ return resource;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlResource.java
new file mode 100644
index 0000000..d897f4a
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/UrlResource.java
@@ -0,0 +1,112 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.internal.services;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
+
+import org.apache.tapestry5.internal.util.VirtualResource;
+import org.apache.tapestry5.ioc.Resource;
+
+public class UrlResource extends VirtualResource {
+
+ final public static URL PLACEHOLDER_URL;
+
+ static {
+ try
+ {
+ PLACEHOLDER_URL = new URL("http://tapestry.apache.org");
+ }
+ catch (MalformedURLException e)
+ {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ final private URL url;
+
+ private Boolean exists;
+
+ private InputStream inputStream;
+
+ public UrlResource()
+ {
+ this(PLACEHOLDER_URL);
+ exists = true;
+ }
+
+ public UrlResource(URL url)
+ {
+ super();
+ this.url = url;
+ }
+
+ @Override
+ public InputStream openStream() throws IOException
+ {
+ if (exists == null)
+ {
+ try
+ {
+ inputStream = url.openStream();
+ exists = true;
+ }
+ catch (IOException e)
+ {
+ exists = false;
+ throw e;
+ }
+ }
+ return inputStream;
+ }
+
+ @Override
+ public URL toURL()
+ {
+ return url;
+ }
+
+ @Override
+ public boolean exists()
+ {
+ if (exists == null)
+ {
+ try
+ {
+ openStream();
+ }
+ catch (IOException e)
+ {
+ // openStream() will always set the exists field.
+ }
+ }
+ return exists;
+ }
+
+ @Override
+ public Resource forLocale(Locale locale)
+ {
+ return this;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "UrlResource [url=" + url + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/main/java/org/apache/tapestry5/modules/AssetsModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/AssetsModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/AssetsModule.java
index 4ec8207..aa98e5b 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/AssetsModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/AssetsModule.java
@@ -60,6 +60,10 @@ public class AssetsModule
{
configuration.add(AssetConstants.CONTEXT, contextAssetFactory);
configuration.add(AssetConstants.CLASSPATH, classpathAssetFactory);
+ configuration.add(AssetConstants.HTTP, new ExternalUrlAssetFactory(AssetConstants.HTTP));
+ configuration.add(AssetConstants.HTTPS, new ExternalUrlAssetFactory(AssetConstants.HTTPS));
+ configuration.add(AssetConstants.FTP, new ExternalUrlAssetFactory(AssetConstants.FTP));
+ configuration.add(AssetConstants.PROTOCOL_RELATIVE, new ExternalUrlAssetFactory(AssetConstants.PROTOCOL_RELATIVE));
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/AssetTests.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/AssetTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/AssetTests.java
index 3c03253..6848223 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/AssetTests.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/AssetTests.java
@@ -53,6 +53,18 @@ public class AssetTests extends App1TestCase
compareDownloadedAsset(assetURL, localPath);
}
+
+ // TAP5-1515
+ @Test
+ public void external_url_asset_bindings()
+ {
+ openLinks("AssetDemo");
+
+ assertEquals("http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js", getText("httpAsset"));
+ assertEquals("https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js", getText("httpsAsset"));
+ assertEquals("http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js", getText("protocolRelativeAsset"));
+ assertEquals("ftp://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js", getText("ftpAsset"));
+ }
private void compareDownloadedAsset(String assetURL, String localPath) throws Exception
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.java
index c8a781b..e2b3705 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010 The Apache Software Foundation
+// Copyright 2006, 2007, 2010, 2014 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.
@@ -48,6 +48,26 @@ public class AssetDemo
@Inject
@Path("context:css/ie-only.css")
private Asset ieOnly;
+
+ @Property
+ @Inject
+ @Path("http://${d3.url}")
+ private Asset httpAsset;
+
+ @Property
+ @Inject
+ @Path("https://${d3.url}")
+ private Asset httpsAsset;
+
+ @Property
+ @Inject
+ @Path("//${d3.url}")
+ private Asset protocolRelativeAsset;
+
+ @Property
+ @Inject
+ @Path("ftp://${d3.url}")
+ private Asset ftpAsset;
@Environmental
private JavaScriptSupport javascriptSupport;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
index a6cfe30..85e0fcc 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
@@ -1,4 +1,4 @@
-// Copyright 2006-2013 The Apache Software Foundation
+// Copyright 2006-2014 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.
@@ -11,7 +11,6 @@
// 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.integration.app1.services;
import org.apache.tapestry5.SymbolConstants;
@@ -49,6 +48,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*/
public class AppModule
{
+
+ final public static String D3_URL_SYMBOL = "d3.url";
+
/**
* Used to disambiguate services in this module from services in other modules that share the
* same service
@@ -151,6 +153,8 @@ public class AppModule
// This is the emphasis of testing at this point.
configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER, "jquery");
+
+ configuration.add(D3_URL_SYMBOL, "cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.js");
}
public static void contributeIgnoredPathsFilter(Configuration<String> configuration)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/37a801d9/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.tml b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.tml
index 17df073..969031e 100644
--- a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.tml
+++ b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/pages/nested/AssetDemo.tml
@@ -45,6 +45,14 @@
Context asset via context: binding
</p>
+<p>External asset using "asset:http: " binding: <span id="httpAsset">${httpAsset.toClientURL()}</span></p>
+
+<p>External asset using "asset:https:" binding: <span id="httpsAsset">${httpsAsset.toClientURL()}</span></p>
+
+<p>External asset using "asset://:" binding: <span id="protocolRelativeAsset">${protocolRelativeAsset.toClientURL()}</span></p>
+
+<p>External asset using "asset:ftp:" binding: <span id="ftpAsset">${ftpAsset.toClientURL()}</span></p>
+
<img id="viaContext" src="${context:images/asf_logo_wide.gif}"/>
<p>
@@ -71,4 +79,10 @@
</a>
</p>
+<p>
+ Using d3, loaded directly from a CDN using external asset support:
+</p>
+
+<div id="viz"/>
+
</html>
\ No newline at end of file