001 // Copyright May 8, 2006 The Apache Software Foundation. 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 package org.apache.tapestry.util; 015 016 import org.apache.commons.lang.StringUtils; 017 import org.apache.commons.pool.KeyedPoolableObjectFactory; 018 import org.apache.commons.pool.impl.GenericKeyedObjectPool; 019 import org.apache.hivemind.ApplicationRuntimeException; 020 021 import java.util.regex.Matcher; 022 import java.util.regex.Pattern; 023 024 025 /** 026 * Various scripting utility methods. 027 */ 028 public final class ScriptUtils 029 { 030 /** 031 * XML cdata start. 032 */ 033 public static final String BEGIN_COMMENT = "\n<script>\n//<![CDATA[\n"; 034 /** 035 * XML character data end. 036 */ 037 public static final String END_COMMENT = "\n//]]>\n</script>\n"; 038 039 /** 040 * Regexp represenging javascript matches. 041 */ 042 public static final String SCRIPT_PATTERN = "(?:<script.*?>)(.*?)(?:<\\/script>)"; 043 044 private static final KeyedPoolableObjectFactory _factory = new RegexpPoolObjectFactory(); 045 046 private static final GenericKeyedObjectPool _pool; 047 048 private static final int MAX_ACTIVE = 100; 049 050 private static final long SLEEP_TIME = 1000 * 60 * 4; 051 052 static { 053 _pool = new GenericKeyedObjectPool(_factory, MAX_ACTIVE, GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK, -1); 054 055 _pool.setMaxIdle(MAX_ACTIVE / 2); 056 _pool.setMinEvictableIdleTimeMillis(MAX_ACTIVE); 057 _pool.setTimeBetweenEvictionRunsMillis(SLEEP_TIME); 058 } 059 060 /* defeat instantiation */ 061 private ScriptUtils() { } 062 063 /** 064 * Takes any <script>contents..</script> tags found in the specified 065 * input string and replaces their contents into one large <script></script> 066 * block (meaning if multiple script blocks are found, they will be turned into one), 067 * with the addition of {@link #BEGIN_COMMENT} inserted before the logic block and 068 * {@link #END_COMMENT} inserted after the logic block. 069 * 070 * @param input 071 * The string to replace tags on 072 * @return The properly formatted string, if any formatting needed to occur. 073 */ 074 public static String ensureValidScriptTags(String input) { 075 076 if (input == null) 077 return null; 078 079 080 Pattern compiled = null; 081 082 try { 083 084 compiled = (Pattern)_pool.borrowObject(SCRIPT_PATTERN); 085 086 Matcher matcher = compiled.matcher(input); 087 StringBuffer buffer = new StringBuffer(input.length()); 088 089 boolean matched = false; 090 int end = 0; 091 while (matcher.find()) { 092 093 matched = true; 094 String str = matcher.group(1); 095 int pos = matcher.start() - end; 096 end = matcher.end(); 097 098 if (str == null || str.trim().equals("")) 099 matcher.appendReplacement(buffer, ""); 100 else { 101 // gather the text from the beggining to the match into a new buffer 102 StringBuffer matchLocal = new StringBuffer(); 103 matcher.appendReplacement(matchLocal, BEGIN_COMMENT + "$1" + END_COMMENT); 104 105 // the first part is always script-less, no need to remove comments from it. 106 String curr = matchLocal.toString(); 107 String prefix = curr.substring(0, pos); 108 String suffix = curr.substring(pos); 109 110 // the second part is in a script, so remove comments. 111 suffix = StringUtils.replace(suffix, "<!--", ""); 112 suffix = StringUtils.replace(suffix, "// -->", ""); 113 buffer.append(prefix).append(suffix); 114 } 115 } 116 117 if (!matched) 118 buffer.append(input); 119 else { 120 //copies non matched character input, ie content after the last script. 121 matcher.appendTail(buffer); 122 } 123 124 return buffer.toString(); 125 126 } catch (Exception e) { 127 128 throw new ApplicationRuntimeException(e); 129 } finally { 130 131 try { _pool.returnObject(SCRIPT_PATTERN, compiled); } catch (Throwable t) { } 132 } 133 } 134 135 /** 136 * Utility that will attempt to generate a unique hash string 137 * that is javascript client in a function name based on the inomcing 138 * object's {@link Object#hashCode()} return value. 139 * 140 * @param target The object to hash a string for. 141 * @return A string hash value, not necessarily exactly the same thing that would 142 * be returned by {@link Object#hashCode()}. 143 */ 144 public static String functionHash(Object target) 145 { 146 int hash = target.hashCode(); 147 if (hash < 0) // flip exponent if negative 148 hash = hash*-1; 149 150 return String.valueOf(hash); 151 } 152 }