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 }