Created
September 29, 2011 20:53
-
-
Save lfryc/1251921 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.richfaces.demo; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.io.PrintWriter; | |
import java.io.Writer; | |
import java.util.LinkedHashSet; | |
import java.util.Set; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
import org.jboss.weld.exceptions.UnsupportedOperationException; | |
public class MultipleScriptTagPrintWriter extends PrintWriter { | |
private final static String HEAD_START = "<head"; | |
private final static String HEAD_STOP = "</head"; | |
private final static Pattern SCRIPT_PATTERN1 = Pattern.compile("<script ([^>]*)/>"); | |
private final static Pattern SCRIPT_PATTERN2 = Pattern.compile("<script ([^>]*)></script>"); | |
private final static Pattern SRC_PATTERN = Pattern.compile("src=\"([^\"]+)\""); | |
private TokenMatcher headStart = new TokenMatcher(HEAD_START); | |
private TokenMatcher headStop = new TokenMatcher(HEAD_STOP); | |
private TokenPairMatcher headPair = new TokenPairMatcher(headStart, headStop); | |
private boolean headProcessed = false; | |
private StringBuffer cache = new StringBuffer(); | |
public MultipleScriptTagPrintWriter(Writer out, boolean autoFlush) { | |
super(out, autoFlush); | |
} | |
@Override | |
public void write(int b) { | |
try { | |
processHead(b); | |
} catch (IOException e) { | |
throw new IllegalStateException("Unexpected exception when processing " + this.getClass().getName(), e); | |
} | |
} | |
@Override | |
public void write(char[] buf) { | |
for (char c : buf) { | |
this.write(c); | |
} | |
} | |
@Override | |
public void write(char[] buf, int off, int len) { | |
for (int i = 0; i < len; i++) { | |
char c = buf[off + i]; | |
this.write(c); | |
} | |
} | |
@Override | |
public void write(String s) { | |
for (char c : s.toCharArray()) { | |
this.write(c); | |
} | |
} | |
@Override | |
public void write(String s, int off, int len) { | |
this.write(s.toCharArray(), off, len); | |
} | |
private void processHead(int b) throws IOException { | |
if (headStop.matches()) { | |
if (!headProcessed) { | |
processScripts(); | |
headProcessed = true; | |
} | |
out.write(b); | |
} else { | |
boolean matched = headPair.write(b); | |
if (headStart.matches()) { | |
cache.append((char) b); | |
} else { | |
if (matched) { | |
cache.append((char) b); | |
} else { | |
flushCacheToOut(); | |
out.write(b); | |
} | |
} | |
} | |
} | |
private void processScripts() throws IOException { | |
int firstScriptPosition = getFirstScriptPosition(); | |
if (firstScriptPosition >= 0) { | |
CharSequence scriptsSubstitution = getScriptsSubstitution(); | |
cache = new StringBuffer(SCRIPT_PATTERN1.matcher(cache).replaceAll("")); | |
cache = new StringBuffer(SCRIPT_PATTERN2.matcher(cache).replaceAll("")); | |
cache.insert(firstScriptPosition, scriptsSubstitution); | |
} | |
flushCacheToOut(); | |
} | |
private CharSequence getScriptsSubstitution() { | |
StringBuffer newScripts = new StringBuffer(); | |
Set<String> sources = lookForScriptsSources(); | |
for (String source : sources) { | |
newScripts.append("<script type=\"text/javascript\" src=\""); | |
newScripts.append(source); | |
newScripts.append("\"></script>"); | |
} | |
return newScripts; | |
} | |
private int getFirstScriptPosition() { | |
int result = -1; | |
Matcher matcherScript = SCRIPT_PATTERN1.matcher(cache); | |
if (matcherScript.find()) { | |
result = matcherScript.start(); | |
} | |
matcherScript = SCRIPT_PATTERN2.matcher(cache); | |
if (matcherScript.find()) { | |
if (result >= 0) { | |
result = Math.min(result, matcherScript.start()); | |
} else { | |
result = matcherScript.start(); | |
} | |
} | |
return result; | |
} | |
private Set<String> lookForScriptsSources() { | |
Set<String> scripts = new LinkedHashSet<String>(); | |
Matcher matcherScript = SCRIPT_PATTERN1.matcher(cache); | |
while (matcherScript.find()) { | |
String script = matcherScript.group(1); | |
Matcher matcherSrc = SRC_PATTERN.matcher(script); | |
if (matcherSrc.find()) { | |
String src = matcherSrc.group(1); | |
scripts.add(src); | |
} | |
} | |
matcherScript = SCRIPT_PATTERN2.matcher(cache); | |
while (matcherScript.find()) { | |
String script = matcherScript.group(1); | |
Matcher matcherSrc = SRC_PATTERN.matcher(script); | |
if (matcherSrc.find()) { | |
String src = matcherSrc.group(1); | |
scripts.add(src); | |
} | |
} | |
return scripts; | |
} | |
private void flushCacheToOut() throws IOException { | |
if (cache.length() > 0) { | |
for (char c : cache.toString().toCharArray()) { | |
out.write(c); | |
} | |
resetCache(); | |
} | |
} | |
private void resetCache() { | |
cache = new StringBuffer(); | |
} | |
private class TokenPairMatcher { | |
TokenMatcher opening; | |
TokenMatcher closing; | |
public TokenPairMatcher(TokenMatcher open, TokenMatcher close) { | |
this.opening = open; | |
this.closing = close; | |
} | |
private boolean write(int b) { | |
boolean openingWritten = false; | |
if (!opening.matches()) { | |
openingWritten = opening.write(b); | |
} else { | |
if (!closing.matches()) { | |
closing.write(b); | |
} | |
} | |
return openingWritten; | |
} | |
private boolean matches() { | |
return opening.matches() && closing.matches(); | |
} | |
private void reset() { | |
opening.reset(); | |
closing.reset(); | |
} | |
} | |
private class TokenMatcher { | |
private String pattern; | |
private StringBuffer buffer; | |
private boolean match; | |
public TokenMatcher(String pattern) { | |
this.pattern = pattern; | |
this.buffer = new StringBuffer(pattern.length()); | |
} | |
private boolean write(int b) { | |
if (b == pattern.codePointAt(buffer.length())) { | |
char c = (char) b; | |
buffer.append(c); | |
if (buffer.length() == pattern.length()) { | |
match = true; | |
} | |
return true; | |
} else { | |
this.reset(); | |
return false; | |
} | |
} | |
private boolean matches() { | |
return match; | |
} | |
private void reset() { | |
buffer = new StringBuffer(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment