001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.internal.webresources; 014 015import org.apache.commons.io.IOUtils; 016import org.apache.tapestry5.ContentType; 017import org.apache.tapestry5.annotations.Path; 018import org.apache.tapestry5.internal.InternalConstants; 019import org.apache.tapestry5.ioc.OperationTracker; 020import org.apache.tapestry5.ioc.Resource; 021import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 022import org.apache.tapestry5.ioc.internal.util.InternalUtils; 023import org.apache.tapestry5.services.assets.ResourceDependencies; 024import org.apache.tapestry5.services.assets.ResourceTransformer; 025import org.mozilla.javascript.NativeObject; 026 027import java.io.IOException; 028import java.io.InputStream; 029import java.nio.charset.Charset; 030import java.util.List; 031 032public class CoffeeScriptCompiler implements ResourceTransformer 033{ 034 private final static Charset UTF8 = Charset.forName("utf-8"); 035 036 private final RhinoExecutorPool executorPool; 037 038 @Override 039 public ContentType getTransformedContentType() 040 { 041 return InternalConstants.JAVASCRIPT_CONTENT_TYPE; 042 } 043 044 public CoffeeScriptCompiler(@Path("classpath:org/apache/tapestry5/webresources/internal/coffee-script.js") 045 Resource mainCompiler, 046 @Path("classpath:org/apache/tapestry5/webresources/internal/invoke-coffeescript.js") 047 Resource shim, 048 OperationTracker tracker) 049 { 050 051 executorPool = new RhinoExecutorPool(tracker, toList(mainCompiler, shim)); 052 } 053 054 private List<Resource> toList(Resource... resources) 055 { 056 List<Resource> list = CollectionFactory.newList(); 057 058 for (Resource r : resources) 059 { 060 list.add(r); 061 } 062 063 return list; 064 } 065 066 067 private static String getString(NativeObject object, String key) 068 { 069 return object.get(key).toString(); 070 } 071 072 073 @Override 074 public InputStream transform(Resource source, ResourceDependencies dependencies) throws IOException 075 { 076 InputStream is = null; 077 String content; 078 079 try 080 { 081 is = source.openStream(); 082 content = IOUtils.toString(is, UTF8); 083 } finally 084 { 085 InternalUtils.close(is); 086 } 087 088 RhinoExecutor executor = executorPool.get(); 089 090 try 091 { 092 093 NativeObject result = (NativeObject) executor.invokeFunction("compileCoffeeScriptSource", content, source.toString()); 094 095 if (result.containsKey("exception")) 096 { 097 throw new RuntimeException(getString(result, "exception")); 098 } 099 100 return IOUtils.toInputStream(getString(result, "output"), UTF8); 101 102 } finally 103 { 104 executor.discard(); 105 } 106 107 108 } 109}