001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.impl;
017:
018: import java.io.IOException;
019: import java.io.StringReader;
020: import java.io.StringWriter;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import org.directwebremoting.extend.Compressor;
025: import org.directwebremoting.util.Logger;
026: import org.mozilla.javascript.ErrorReporter;
027: import org.mozilla.javascript.EvaluatorException;
028:
029: import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
030:
031: /**
032: * JavaScript Compression Implementation using the YUI Compressor.
033: *
034: * @author David Marginian [david at butterdev dot com]
035: */
036: public class YahooJSCompressor implements Compressor {
037: /**
038: * Constructor: YahooJSCompressor using default property values.
039: */
040: public YahooJSCompressor() {
041: setCompressorParameters(null);
042: }
043:
044: /**
045: * Constructor: YahooJSCompressor using the property map passed in.
046: *
047: * @param specifiedCompressorParameters
048: */
049: public YahooJSCompressor(
050: Map<String, Object> specifiedCompressorParameters) {
051: setCompressorParameters(specifiedCompressorParameters);
052: }
053:
054: /* (non-Javadoc)
055: * @see org.directwebremoting.extend.Compressor#compressJavaScript(java.lang.String)
056: */
057: public String compressJavaScript(String script) throws IOException {
058: StringReader stringReader = new StringReader(script);
059: JavaScriptCompressor yuiJavaScriptCompressor = new JavaScriptCompressor(
060: stringReader, new YahooJSErrorReporter());
061: StringWriter stringWriter = new StringWriter();
062: yuiJavaScriptCompressor.compress(stringWriter,
063: ((Integer) compressorParameters
064: .get(PARAMETER_LINEBREAK)).intValue(),
065: ((Boolean) compressorParameters.get(PARAMETER_MUNGE))
066: .booleanValue(),
067: ((Boolean) compressorParameters.get(PARAMETER_VERBOSE))
068: .booleanValue(),
069: ((Boolean) compressorParameters
070: .get(PARAMETER_PRESERVE_ALL_SEMICOLONS))
071: .booleanValue(),
072: ((Boolean) compressorParameters
073: .get(PARAMETER_DISABLE_OPTIMIZATIONS))
074: .booleanValue());
075: String compressedScript = stringWriter.toString();
076: return compressedScript;
077: }
078:
079: /**
080: * Builds the compressor parameter map using the parameters specified or
081: * the default parameters.
082: *
083: * @param configuredCompressorParameters -
084: * Parameters specified by the applications configuration. We still need
085: * to validate these parameters and use defaults if all of the parameters
086: * were not specified.
087: */
088: private void setCompressorParameters(
089: Map<String, Object> configuredCompressorParameters) {
090: String mungeString = null;
091: String disableOptString = null;
092: String preserveSemiString = null;
093: String verboseString = null;
094: String linebreakString = null;
095: if (null != configuredCompressorParameters) {
096: mungeString = (String) configuredCompressorParameters
097: .get(PARAMETER_MUNGE);
098: disableOptString = (String) configuredCompressorParameters
099: .get(PARAMETER_DISABLE_OPTIMIZATIONS);
100: preserveSemiString = (String) configuredCompressorParameters
101: .get(PARAMETER_PRESERVE_ALL_SEMICOLONS);
102: verboseString = (String) configuredCompressorParameters
103: .get(PARAMETER_VERBOSE);
104: linebreakString = (String) configuredCompressorParameters
105: .get(PARAMETER_LINEBREAK);
106: }
107: // Place either the configured parameters or the default parameters into the compressorParameters Map
108: compressorParameters.put(PARAMETER_MUNGE,
109: (null != mungeString) ? Boolean.valueOf(mungeString)
110: : DEFAULT_MUNGE);
111: compressorParameters.put(PARAMETER_DISABLE_OPTIMIZATIONS,
112: (null != disableOptString) ? Boolean
113: .valueOf(disableOptString)
114: : DEFAULT_DISABLE_OPTIMIZATIONS);
115: compressorParameters.put(PARAMETER_PRESERVE_ALL_SEMICOLONS,
116: (null != preserveSemiString) ? Boolean
117: .valueOf(preserveSemiString)
118: : DEFAULT_PRESERVE_ALL_SEMICOLONS);
119: compressorParameters.put(PARAMETER_VERBOSE,
120: (null != verboseString) ? Boolean
121: .valueOf(verboseString) : DEFAULT_VERBOSE);
122: compressorParameters.put(PARAMETER_LINEBREAK,
123: (null != linebreakString) ? Integer
124: .valueOf(linebreakString) : DEFAULT_LINEBREAK);
125: }
126:
127: /**
128: * ErrorReporter implementation required by the YUI Compressor compress.
129: */
130: protected class YahooJSErrorReporter implements ErrorReporter {
131: public void warning(String message, String sourceName,
132: int line, String lineSource, int lineOffset) {
133: if (line < 0) {
134: log.warn(message);
135: } else {
136: log.error("\n" + line + ':' + lineOffset + ':'
137: + message);
138: }
139: }
140:
141: public void error(String message, String sourceName, int line,
142: String lineSource, int lineOffset) {
143: if (line < 0) {
144: log.error(message);
145: } else {
146: log.error(line + ':' + lineOffset + ':' + message);
147: }
148: }
149:
150: public EvaluatorException runtimeError(String message,
151: String sourceName, int line, String lineSource,
152: int lineOffset) {
153: error(message, sourceName, line, lineSource, lineOffset);
154: return new EvaluatorException(message);
155: }
156: }
157:
158: protected static final Logger log = Logger
159: .getLogger(YahooJSCompressor.class);
160:
161: private Map<String, Object> compressorParameters = new HashMap<String, Object>();
162:
163: // Fields representing the parameters that can be configured for this Compressor.
164: // Obfuscates the script
165: private static final String PARAMETER_MUNGE = "munge";
166:
167: // Display informational messages and warnings.
168: private static final String PARAMETER_VERBOSE = "verbose";
169:
170: // Some source control tools don't like it when files containing lines longer
171: // than, say 8000 characters, are checked in. The linebreak option is used in
172: // that case to split long lines after a specific column.
173: private static final String PARAMETER_LINEBREAK = "linebreak";
174:
175: // Append a semi-colon at the end, even if unnecessary semi-colons are
176: // supposed to be removed. This is especially useful when concatenating
177: // several minified files (the absence of an ending semi-colon at the
178: // end of one file may very likely cause a syntax error)
179: private static final String PARAMETER_PRESERVE_ALL_SEMICOLONS = "preserveAllSemiColons";
180:
181: // Disable all the built-in micro optimizations.
182: private static final String PARAMETER_DISABLE_OPTIMIZATIONS = "disableOptimizations";
183:
184: // Default values for the parameters that can be configured for this Compressor in case they
185: // are not specified.
186: private static final Boolean DEFAULT_MUNGE = new Boolean(false);
187:
188: private static final Boolean DEFAULT_VERBOSE = new Boolean(false);
189:
190: private static final Integer DEFAULT_LINEBREAK = new Integer(20000);
191:
192: private static final Boolean DEFAULT_PRESERVE_ALL_SEMICOLONS = new Boolean(
193: false);
194:
195: private static final Boolean DEFAULT_DISABLE_OPTIMIZATIONS = new Boolean(
196: false);
197: }
|