You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Bård Magnus Kvalheim <ma...@kvalheim.eu> on 2012/10/04 12:54:30 UTC

Why is AssetPathConverter not called for javascript stacks

Hi good people.

We were looking into serving assets from aws cloudfront and could quite
easily make a AssetPathConverter to support that thanks to previous
mailinglist discussions and examples.

The only issue now is that stacks (js) don't seem to go through the
AssetPathConverter. Applies to both custom and core stacks.

Tapestry 5.3.4
I've done this in module:
*binder.bind(AssetPathConverter.class,
CDNAssetPathConverter.class).withId("CDNAssetPathConverter");*
*
*
*public static void
contributeServiceOverride(MappedConfiguration<Class,Object> configuration,*
* @Local AssetPathConverter assetPathConverter) { *
* configuration.add(AssetPathConverter.class, assetPathConverter);*
*}*
*
*
Any idea how to convert paths for javascript stacks?

Many thanks in advance
Magnus Kvalheim

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Howard Lewis Ship <hl...@gmail.com>.
Sounds nice; that's how I've always assumed CDNs worked (lazily)
though I'm told other require an explicit load of assets into the CDN,
which is tricky in the Tapestry world where many of those assets are
dynamically generated (or compiled, or aggregated).

On Thu, Oct 4, 2012 at 11:37 PM, Bård Magnus Kvalheim
<ma...@kvalheim.eu> wrote:
> Hi Howard - thanks for your reply.
>
> Looks like an oversight.  I'm not familiar with CloudFront; can you
>> give me a thumbnail overview of how your CDN hooks work?
>>
>> Sure.
>
> Well Cloudfront is at heart a CDN.
> It has many features, but how it works is that it delivers content from
> edges that are close to end users.
> If it don't have the content (or it is expired) it will proxy back to an
> 'origin' (there can be several) get the content, store it at the edge and
> deliver to user.
>
> It is a lazy CDN approach that works well as there is no need to first
> upload content to a CDN - like S3.
> http://aws.amazon.com/cloudfront/
>
>
> How it works in the tapestry application is that we have configured a
> cookieless domain against the CloudFront with the tapestry app as origin.
> It all works great - apart from the stack assets where the
> AssetPathConverter#convertAssetPath is never called.
>
> *public class CDNAssetPathConverter implements AssetPathConverter {*
> * private IParameter ip;*
> * private String applicationVersion;*
> *
> *
> *    public CDNAssetPathConverter(@Inject
> @Symbol(SymbolConstants.APPLICATION_VERSION) String applicationVersion,*
> *                    @Inject IParameter ip){*
> *        this.applicationVersion = applicationVersion;*
> *        this.ip = ip;*
> *    }    *
> *    String getCDNDomain() {*
> *    return ip.getString(PKey.DOMAIN_CDN_VERSIONED, null);*
> *    }    *
> *    @Override*
> *    public String convertAssetPath(String assetPath) {*
> *    String domain = getCDNDomain();*
> *    if(domain==null) return assetPath;*
> *    *
> *    String result = convertToCDN(assetPath, domain);*
> *    return result;*
> *    }*
> *    private String convertToCDN(String path, String domain) {*
> *        String _path = path.replaceFirst("^/+", "");*
> *        return String.format("http://%s/%s", domain, _path);*
> *    }*
> *    @Override*
> *    public boolean isInvariant() {*
> *        return false;*
> *    }*
> *} *



-- 
Howard M. Lewis Ship

Creator of Apache Tapestry

The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!

(971) 678-5210
http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
> I did try to implement my own proposed solution with Advice

>
> That's a lot of messy byte code manipulation for a single method interface.
>

Yes, I have to agree. Delegate is probably a better choice in this case.
Cleaner and also typesafe.

Tried your suggestion - and it works just as well as the advice.

Thanks - I'm quite happy with that solution and will update the Jira with
the workaround as well.

cheers
Magnus

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Lance Java <la...@googlemail.com>.
> I would then get 'cdn' urls for the different scripts that make up the
stack, and not the stack url itself

Oops, I think you're right



> I did try to implement my own proposed solution with Advice

That's a lot of messy byte code manipulation for a single method interface.
I'm a bit old fashioned when it comes to using byte code manipulation. You
can also solve this with a simple delegate.

public static JavaScriptStackPathConstructor
decorateJavaScriptStackPathConstructor(

   JavaScriptStackPathConstructor delegate,

   final AssetPathConverter assetPathConverter)

{

   return new JavaScriptStackPathConstructor {

      public List<String> constructPathsForJavaScriptStack(String
stackName) {

         List<String> newList = new ArrayList<String>(paths.size());

         for (String path :
delegate.constructPathsForJavaScriptStack(stackName)) {
            new list. add(assetPathConverter.convertAssetPath(path));
         }

      }
   };
}

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
Hi.
On Thu, May 23, 2013 at 11:31 AM, Lance Java <la...@googlemail.com>wrote:

> I think the easiest way would be to decorate the JavaScriptStackSource
> service. Wrap the default implementation with a version which decorates
> getStack(String name) to return a custom JavaScriptStack implementation.
>
> The custom JavaScriptStack will provide wrappers for:
> List<Asset> getJavaScriptLibraries();
> List<StylesheetLink> getStylesheets();
>
> You'll need to delegate to AssetPathConverter  in Asset.toClientURL() and
> StylesheetLink.getURL()
>

Was thinking about this and as far as I can see with this approach I would
then get 'cdn' urls for the different scripts that make up the stack, and
not the stack url itself - but could be wrong.

I did try to implement my own proposed solution with Advice - quite simple
and it seems to be working fine. Although there could be side-effects I'm
not aware of yet ...

*@Advise(serviceInterface = JavaScriptStackPathConstructor.class)*
*public static void adviseJavaScriptStackPathConstructor(*
* MethodAdviceReceiver receiver,*
* @Local final AssetPathConverter assetPathConverter) {*
*try {*
*  MethodAdvice ma = new MethodAdvice(){*
*  @Override*
*  public void advise(MethodInvocation invocation) {*
*  invocation.proceed();*
*  List<String> paths = (List<String>) invocation.getReturnValue();*
*  if(paths==null) return;*
*  *
*  List<String> newList = new ArrayList<>(paths.size());*
*  for (String path : paths) {*
*  newList.add(assetPathConverter.convertAssetPath(path));*
*  }*
*  invocation.setReturnValue(newList);*
*  }*
*  };**   *
*  Class<?> serviceInterface = receiver.getInterface();*
*  receiver.adviseMethod(serviceInterface.getMethod("constructPathsForJavaScriptStack",
String.class), ma);**   *
*  } catch (Exception e) {*
*  throw new RuntimeException("Can't find methods. Changed API?", e);*
*  }*
*}*

Let me know if you have further suggestions/ideas.

thanks
Magnus

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Lance Java <la...@googlemail.com>.
I think the easiest way would be to decorate the JavaScriptStackSource
service. Wrap the default implementation with a version which decorates
getStack(String name) to return a custom JavaScriptStack implementation.

The custom JavaScriptStack will provide wrappers for:
List<Asset> getJavaScriptLibraries();
List<StylesheetLink> getStylesheets();

You'll need to delegate to AssetPathConverter  in Asset.toClientURL() and
StylesheetLink.getURL()

Lots of wrapping but it looks like it's doable.

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
Hi guys.

Sorry for keep asking for this, but I've still got no good solution for it.
Would like to serve stack javascript assets from cdn.

I think I'll try to patch tapestry internals, but would like to know if you
have pointers to where the best place would be.

I'm looking at JavaScriptStackPathConstructorImpl#combinedStackURL as
possible place to call AssetPathConverter.
Could possibly advice it and modify it's return value?

Or possibly higher up in JavaScriptSupportImpl#addAssetsFromStack


Let me know if you have thoughts.

Thanks
Magnus


On Wed, Nov 7, 2012 at 4:48 PM, Bård Magnus Kvalheim <ma...@kvalheim.eu>wrote:

> I'm still searching for a way to resolve this - now in 5.3.6.
>
> Anyone have ideas on what potentially could be done? Creative ideas
> welcome :)
>
> cheers
> Magnus
>
>
> On Thu, Oct 25, 2012 at 2:13 PM, Bård Magnus Kvalheim <ma...@kvalheim.eu>wrote:
>
>>
>> Regarding AssetPathConverter - should I open a JIRA for stack assets?
>>>
>>> I just created Jira.
>> https://issues.apache.org/jira/browse/TAP5-2019
>>
>> Let me know if you know of a workaround in tap 5.3.4.
>>
>> thanks
>> Magnus
>>
>
>

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
I'm still searching for a way to resolve this - now in 5.3.6.

Anyone have ideas on what potentially could be done? Creative ideas welcome
:)

cheers
Magnus


On Thu, Oct 25, 2012 at 2:13 PM, Bård Magnus Kvalheim <ma...@kvalheim.eu>wrote:

>
> Regarding AssetPathConverter - should I open a JIRA for stack assets?
>>
>> I just created Jira.
> https://issues.apache.org/jira/browse/TAP5-2019
>
> Let me know if you know of a workaround in tap 5.3.4.
>
> thanks
> Magnus
>

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
> Regarding AssetPathConverter - should I open a JIRA for stack assets?
>
> I just created Jira.
https://issues.apache.org/jira/browse/TAP5-2019

Let me know if you know of a workaround in tap 5.3.4.

thanks
Magnus

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
On Fri, Oct 5, 2012 at 6:28 PM, Howard Lewis Ship <hl...@gmail.com> wrote:

Sounds nice; that's how I've always assumed CDNs worked (lazily)
> though I'm told other require an explicit load of assets into the CDN,
> which is tricky in the Tapestry world where many of those assets are
> dynamically generated (or compiled, or aggregated).
>

Yes, it works great with dynamic content - although we have to disable cdn
during releases as we currently don't do an atomic update in cluster. If we
didn't then users will be missing assets as we use a cookieless domain for
that. (Expect to do atomic updates soon though.)

Regarding AssetPathConverter - should I open a JIRA for stack assets?


On Fri, Oct 5, 2012 at 10:37 PM, trsvax <tr...@gmail.com> wrote:

> I wrote a CloudFront CDN while ago and also ran into a few problems. Is
> loading content other than from S3 a new feature?


It's not new - think they started beta back in 2008. However they launch
new features all of the time.


> I wrote a CDNManger
> service that Lazily loaded the assets onto S3. The problem I ran into is
> Tapestry uses the same URL to deliver compressed and uncompressed content
> depending on the client request. I suspect if you just point ClouldFront
> back to your Tapestry app you will have strange problems with old browsers
>

No, compressed files is supported with cloudfront so it should be a non
issue. It respects the Accept-Encoding header.
http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html

As a cdn, cloudfront is superior to s3. They serve different purposes, but
work well together.
s3 can easily be configured as origin to cloudfront and you pay no
additional cost for this. I'm a satisfied user of both.

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Magnus Kvalheim <ma...@movellas.com>.
On Fri, Oct 5, 2012 at 6:28 PM, Howard Lewis Ship <hl...@gmail.com> wrote:

> Sounds nice; that's how I've always assumed CDNs worked (lazily)
> though I'm told other require an explicit load of assets into the CDN,
> which is tricky in the Tapestry world where many of those assets are
> dynamically generated (or compiled, or aggregated).
>

Yes, it works great with dynamic content - although we have to disable cdn
during releases as we currently don't do an atomic update in cluster. If we
didn't then users will be missing assets as we use a cookieless domain for
that. (Expect to do atomic updates soon though.)

Regarding AssetPathConverter - should I open a JIRA for stack assets?


On Fri, Oct 5, 2012 at 10:37 PM, trsvax <tr...@gmail.com> wrote:

> I wrote a CloudFront CDN while ago and also ran into a few problems. Is
> loading content other than from S3 a new feature?


It's not new - think they started beta back in 2008. However they launch
new features all of the time.


> I wrote a CDNManger
> service that Lazily loaded the assets onto S3. The problem I ran into is
> Tapestry uses the same URL to deliver compressed and uncompressed content
> depending on the client request. I suspect if you just point ClouldFront
> back to your Tapestry app you will have strange problems with old browsers
>

No, compressed files is supported with cloudfront so it should be a non
issue. It respects the Accept-Encoding header.
http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html

As a cdn, cloudfront is superior to s3. They serve different purposes, but
work well together.
s3 can easily be configured as origin to cloudfront and you pay no
additional cost for this. I'm a satisfied user of both.

Re: Why is AssetPathConverter not called for javascript stacks

Posted by trsvax <tr...@gmail.com>.
I wrote a CloudFront CDN while ago and also ran into a few problems. Is
loading content other than from S3 a new feature? I wrote a CDNManger
service that Lazily loaded the assets onto S3. The problem I ran into is
Tapestry uses the same URL to deliver compressed and uncompressed content
depending on the client request. I suspect if you just point ClouldFront
back to your Tapestry app you will have strange problems with old browsers
that do not accept gziped content. 



--
View this message in context: http://tapestry.1045711.n5.nabble.com/Why-is-AssetPathConverter-not-called-for-javascript-stacks-tp5716629p5716687.html
Sent from the Tapestry - User mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Why is AssetPathConverter not called for javascript stacks

Posted by Bård Magnus Kvalheim <ma...@kvalheim.eu>.
Hi Howard - thanks for your reply.

Looks like an oversight.  I'm not familiar with CloudFront; can you
> give me a thumbnail overview of how your CDN hooks work?
>
> Sure.

Well Cloudfront is at heart a CDN.
It has many features, but how it works is that it delivers content from
edges that are close to end users.
If it don't have the content (or it is expired) it will proxy back to an
'origin' (there can be several) get the content, store it at the edge and
deliver to user.

It is a lazy CDN approach that works well as there is no need to first
upload content to a CDN - like S3.
http://aws.amazon.com/cloudfront/


How it works in the tapestry application is that we have configured a
cookieless domain against the CloudFront with the tapestry app as origin.
It all works great - apart from the stack assets where the
AssetPathConverter#convertAssetPath is never called.

*public class CDNAssetPathConverter implements AssetPathConverter {*
* private IParameter ip;*
* private String applicationVersion;*
*
*
*    public CDNAssetPathConverter(@Inject
@Symbol(SymbolConstants.APPLICATION_VERSION) String applicationVersion,*
*                    @Inject IParameter ip){*
*        this.applicationVersion = applicationVersion;*
*        this.ip = ip;*
*    }    *
*    String getCDNDomain() {*
*    return ip.getString(PKey.DOMAIN_CDN_VERSIONED, null);*
*    }    *
*    @Override*
*    public String convertAssetPath(String assetPath) {*
*    String domain = getCDNDomain();*
*    if(domain==null) return assetPath;*
*    *
*    String result = convertToCDN(assetPath, domain);*
*    return result;*
*    }*
*    private String convertToCDN(String path, String domain) {*
*        String _path = path.replaceFirst("^/+", "");*
*        return String.format("http://%s/%s", domain, _path);*
*    }*
*    @Override*
*    public boolean isInvariant() {*
*        return false;*
*    }*
*} *

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Magnus Kvalheim <ma...@movellas.com>.
Hi Howard - thanks for your reply.

Looks like an oversight.  I'm not familiar with CloudFront; can you
> give me a thumbnail overview of how your CDN hooks work?
>
> Sure.

Well Cloudfront is at heart a CDN.
It has many features, but how it works is that it delivers content from
edges that are close to end users.
If it don't have the content (or it is expired) it will proxy back to an
'origin' (there can be several) get the content, store it at the edge and
deliver to user.

It is a lazy CDN approach that works well as there is no need to first
upload content to a CDN - like S3.
http://aws.amazon.com/cloudfront/


How it works in the tapestry application is that we have configured a
cookieless domain against the CloudFront with the tapestry app as origin.
It all works great - apart from the stack assets where the
AssetPathConverter#convertAssetPath is never called.

*public class CDNAssetPathConverter implements AssetPathConverter {*
* private IParameter ip;*
* private String applicationVersion;*
*
*
*    public CDNAssetPathConverter(@Inject
@Symbol(SymbolConstants.APPLICATION_VERSION) String applicationVersion,*
*                    @Inject IParameter ip){*
*        this.applicationVersion = applicationVersion;*
*        this.ip = ip;*
*    }    *
*    String getCDNDomain() {*
*    return ip.getString(PKey.DOMAIN_CDN_VERSIONED, null);*
*    }    *
*    @Override*
*    public String convertAssetPath(String assetPath) {*
*    String domain = getCDNDomain();*
*    if(domain==null) return assetPath;*
*    *
*    String result = convertToCDN(assetPath, domain);*
*    return result;*
*    }*
*    private String convertToCDN(String path, String domain) {*
*        String _path = path.replaceFirst("^/+", "");*
*        return String.format("http://%s/%s", domain, _path);*
*    }*
*    @Override*
*    public boolean isInvariant() {*
*        return false;*
*    }*
*} *

Re: Why is AssetPathConverter not called for javascript stacks

Posted by Howard Lewis Ship <hl...@gmail.com>.
Looks like an oversight.  I'm not familiar with CloudFront; can you
give me a thumbnail overview of how your CDN hooks work?

On Thu, Oct 4, 2012 at 3:54 AM, Bård Magnus Kvalheim <ma...@kvalheim.eu> wrote:
> Hi good people.
>
> We were looking into serving assets from aws cloudfront and could quite
> easily make a AssetPathConverter to support that thanks to previous
> mailinglist discussions and examples.
>
> The only issue now is that stacks (js) don't seem to go through the
> AssetPathConverter. Applies to both custom and core stacks.
>
> Tapestry 5.3.4
> I've done this in module:
> *binder.bind(AssetPathConverter.class,
> CDNAssetPathConverter.class).withId("CDNAssetPathConverter");*
> *
> *
> *public static void
> contributeServiceOverride(MappedConfiguration<Class,Object> configuration,*
> * @Local AssetPathConverter assetPathConverter) { *
> * configuration.add(AssetPathConverter.class, assetPathConverter);*
> *}*
> *
> *
> Any idea how to convert paths for javascript stacks?
>
> Many thanks in advance
> Magnus Kvalheim



-- 
Howard M. Lewis Ship

Creator of Apache Tapestry

The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!

(971) 678-5210
http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org