blob: a7fb69bd7db46d9c6ead189eabb62147f36ce455 [file] [log] [blame]
// Copyright May 8, 2006 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.tapestry.util;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.hivemind.ApplicationRuntimeException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Various scripting utility methods.
*/
public final class ScriptUtils
{
/**
* XML cdata start.
*/
public static final String BEGIN_COMMENT = "\n<script>\n//<![CDATA[\n";
/**
* XML character data end.
*/
public static final String END_COMMENT = "\n//]]>\n</script>\n";
/**
* Regexp represenging javascript matches.
*/
public static final String SCRIPT_PATTERN = "(?:<script.*?>)(.*?)(?:<\\/script>)";
private static final KeyedPoolableObjectFactory _factory = new RegexpPoolObjectFactory();
private static final GenericKeyedObjectPool _pool;
private static final int MAX_ACTIVE = 100;
private static final long SLEEP_TIME = 1000 * 60 * 4;
static {
_pool = new GenericKeyedObjectPool(_factory, MAX_ACTIVE, GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK, -1);
_pool.setMaxIdle(MAX_ACTIVE / 2);
_pool.setMinEvictableIdleTimeMillis(MAX_ACTIVE);
_pool.setTimeBetweenEvictionRunsMillis(SLEEP_TIME);
}
/* defeat instantiation */
private ScriptUtils() { }
/**
* Takes any <script>contents..</script> tags found in the specified
* input string and replaces their contents into one large <script></script>
* block (meaning if multiple script blocks are found, they will be turned into one),
* with the addition of {@link #BEGIN_COMMENT} inserted before the logic block and
* {@link #END_COMMENT} inserted after the logic block.
*
* @param input
* The string to replace tags on
* @return The properly formatted string, if any formatting needed to occur.
*/
public static String ensureValidScriptTags(String input) {
if (input == null)
return null;
Pattern compiled = null;
try {
compiled = (Pattern)_pool.borrowObject(SCRIPT_PATTERN);
Matcher matcher = compiled.matcher(input);
StringBuffer buffer = new StringBuffer(input.length());
boolean matched = false;
int end = 0;
while (matcher.find()) {
matched = true;
String str = matcher.group(1);
int pos = matcher.start() - end;
end = matcher.end();
if (str == null || str.trim().equals(""))
matcher.appendReplacement(buffer, "");
else {
// gather the text from the beggining to the match into a new buffer
StringBuffer matchLocal = new StringBuffer();
matcher.appendReplacement(matchLocal, BEGIN_COMMENT + "$1" + END_COMMENT);
// the first part is always script-less, no need to remove comments from it.
String curr = matchLocal.toString();
String prefix = curr.substring(0, pos);
String suffix = curr.substring(pos);
// the second part is in a script, so remove comments.
suffix = StringUtils.replace(suffix, "<!--", "");
suffix = StringUtils.replace(suffix, "// -->", "");
buffer.append(prefix).append(suffix);
}
}
if (!matched)
buffer.append(input);
else {
//copies non matched character input, ie content after the last script.
matcher.appendTail(buffer);
}
return buffer.toString();
} catch (Exception e) {
throw new ApplicationRuntimeException(e);
} finally {
try { _pool.returnObject(SCRIPT_PATTERN, compiled); } catch (Throwable t) { }
}
}
/**
* Utility that will attempt to generate a unique hash string
* that is javascript client in a function name based on the inomcing
* object's {@link Object#hashCode()} return value.
*
* @param target The object to hash a string for.
* @return A string hash value, not necessarily exactly the same thing that would
* be returned by {@link Object#hashCode()}.
*/
public static String functionHash(Object target)
{
int hash = target.hashCode();
if (hash < 0) // flip exponent if negative
hash = hash*-1;
return String.valueOf(hash);
}
}