Skip to content

Commit

Permalink
Replaced ignoreDuplicates parameter with allowDuplicates flag in config
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkmc committed Nov 30, 2010
1 parent d4dc23c commit ddb18f2
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 78 deletions.
63 changes: 45 additions & 18 deletions app/press/Compressor.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public abstract class Compressor extends PlayPlugin {
String requestKey = null;

// The list of files compressed as part of this request
Map<String, FileInfo> fileInfos;
Map<String, List<FileInfo>> fileInfos;

protected interface FileCompressor {
public void compress(String fileName, Reader in, Writer out) throws Exception;
Expand All @@ -76,7 +76,7 @@ public Compressor(String fileType, String extension, String getCompressedFileAct
String tagName, String compressedTagName, String pressRequestStart,
String pressRequestEnd, String srcDir, String compressedDir) {

this.fileInfos = new HashMap<String, FileInfo>();
this.fileInfos = new HashMap<String, List<FileInfo>>();

this.fileType = fileType;
this.extension = extension;
Expand All @@ -94,25 +94,25 @@ public Compressor(String fileType, String extension, String getCompressedFileAct
*
* @return the file request signature to be output in the HTML
*/
public String add(String fileName, boolean compress, boolean ignoreDuplicates) {
if (compress && !ignoreDuplicates) {
public String add(String fileName, boolean compress) {
if (compress) {
PressLogger.trace("Adding %s to output", fileName);
} else {
PressLogger.trace("Adding %s to output (compress: %b, ignore duplicates: %b)",
fileName, compress, ignoreDuplicates);
PressLogger.trace("Adding uncompressed file %s to output", fileName);
}

if (fileInfos.containsKey(fileName)) {
if(ignoreDuplicates) {
return "";
}

if (fileInfos.containsKey(fileName) && !PluginConfig.allowDuplicates()) {
throw new DuplicateFileException(fileType, fileName, tagName);
}

fileInfos.put(fileName, new FileInfo(fileName, compress, null));
List<FileInfo> fileInfoList = fileInfos.get(fileName);
if (fileInfoList == null) {
fileInfoList = new ArrayList<FileInfo>();
fileInfos.put(fileName, fileInfoList);
}
fileInfoList.add(new FileInfo(fileName, compress, null));

return getFileRequestSignature(fileName);
return getFileRequestSignature(getFileNameWithIndex(fileName, (fileInfoList.size() - 1)));
}

/**
Expand Down Expand Up @@ -167,7 +167,7 @@ public String compressedUrl() {
params.put("key", requestKey);
ActionDefinition route = Router.reverse(getCompressedFileAction, params);

int numFiles = fileInfos.size();
int numFiles = getTotalFileCount();
PressLogger.trace("Adding key %s for compression of %d files", requestKey, numFiles);

return route.url;
Expand All @@ -182,7 +182,7 @@ public void saveFileList() {
// to compression but they will not be output. So throw an
// exception telling the user he needs to add some files.
if (fileInfos.size() > 0) {
String msg = fileInfos.size() + " files added to compression with ";
String msg = getTotalFileCount() + " files added to compression with ";
msg += tagName + " tag but no " + compressedTagName + " tag was found. ";
msg += "You must include a " + compressedTagName + " tag in the template ";
msg += "to output the compressed content of these files: ";
Expand Down Expand Up @@ -216,7 +216,7 @@ public List<FileInfo> getFileListOrder() {
List<FileInfo> filesInOrder = new ArrayList<FileInfo>(namesInOrder.size());

// Do some sanity checking
if (namesInOrder.size() != fileInfos.size()) {
if (namesInOrder.size() != getTotalFileCount()) {
String msg = "Number of file compress requests found in response ";
msg += "(" + namesInOrder.size() + ") ";
msg += "not equal to number of files added to compression ";
Expand All @@ -226,15 +226,17 @@ public List<FileInfo> getFileListOrder() {
}

// Copy the FileInfo from the map into an array, in order
for (String fileName : namesInOrder) {
for (String fileNameWithIndex : namesInOrder) {
String fileName = getFileName(fileNameWithIndex);
int fileIndex = getFileIndex(fileNameWithIndex);
if (!fileInfos.containsKey(fileName)) {
String msg = "File compress request for '" + fileName + "' ";
msg += "found in response but file was never added to file list. ";
msg += "Please report a bug.";
throw new PressException(msg);
}

filesInOrder.add(fileInfos.get(fileName));
filesInOrder.add(fileInfos.get(fileName).get(fileIndex));
}

return filesInOrder;
Expand Down Expand Up @@ -652,6 +654,31 @@ protected List<String> getFilesInResponse(String content) {
return filesInOrder;
}

private String getFileNameWithIndex(String fileName, int index) {
return fileName + "[" + index + "]";
}

private String getFileName(String fileNameWithIndex) {
int indexPart = fileNameWithIndex.lastIndexOf('[');
return fileNameWithIndex.substring(0, indexPart);
}

private int getFileIndex(String fileNameWithIndex) {
int indexPartBegin = fileNameWithIndex.lastIndexOf('[');
String indexPart = fileNameWithIndex.substring(indexPartBegin + 1, fileNameWithIndex
.length() - 1);
return Integer.parseInt(indexPart);
}

private int getTotalFileCount() {
int i = 0;
for (String fileName : fileInfos.keySet()) {
i += fileInfos.get(fileName).size();
}

return i;
}

/**
* Gets the file at the given path, relative to the application root, even
* if the file doesn't exist
Expand Down
2 changes: 1 addition & 1 deletion app/press/DuplicateFileException.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private static String buildMessage(String fileType, String fileName, String tagN
msg += "Check that you're not including the same file in two different ";
msg += tagName + " tags.\n";
msg += "If you need to include the same file multiple times, set ";
msg += "ignoreDuplicates to true in the tag.\n";
msg += "the allowDuplicates configuration key to true.\n";

return msg;
}
Expand Down
44 changes: 22 additions & 22 deletions app/press/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.HashMap;
import java.util.Map;

import play.Logger;
import play.PlayPlugin;

public class Plugin extends PlayPlugin {
Expand Down Expand Up @@ -49,31 +48,32 @@ public static String compressedSingleCSSUrl(String fileName) {
return cssCompressor.get().compressedSingleFileUrl(fileName);
}

public static boolean outputJSTag(String fileName, boolean compress, boolean ignoreDuplicates) {
return outputTag(jsFiles.get(), fileName, compress, ignoreDuplicates,
JSCompressor.FILE_TYPE, JSCompressor.TAG_NAME);
}

public static boolean outputCSSTag(String fileName, boolean compress, boolean ignoreDuplicates) {
return outputTag(cssFiles.get(), fileName, compress, ignoreDuplicates,
CSSCompressor.FILE_TYPE, CSSCompressor.TAG_NAME);
/**
* Check if the given JS file has already been included.
*/
public static void checkForJSDuplicates(String fileName, boolean compress) {
checkForDuplicates(jsFiles.get(), fileName, JSCompressor.FILE_TYPE, JSCompressor.TAG_NAME);
}

/**
* If the file is included multiple times, and ignoreDuplicates is true, we
* only want to output the <script> or <link rel="css"> tag the first time.
* Check if the given CSS file has already been included.
*/
private static boolean outputTag(Map<String, Boolean> files, String fileName, boolean compress,
boolean ignoreDuplicates, String fileType, String tagName) {

public static void checkForCSSDuplicates(String fileName, boolean compress) {
checkForDuplicates(cssFiles.get(), fileName, CSSCompressor.FILE_TYPE,
CSSCompressor.TAG_NAME);
}

private static void checkForDuplicates(Map<String, Boolean> files, String fileName,
String fileType, String tagName) {

if (!files.containsKey(fileName)) {
files.put(fileName, true);
return true;
return;
}

if (ignoreDuplicates) {
PressLogger.trace("Ignoring duplicate file %s", fileName);
return false;
if (PluginConfig.allowDuplicates()) {
PressLogger.trace("Allowing duplicate file %s", fileName);
return;
}

throw new DuplicateFileException(fileType, fileName, tagName);
Expand All @@ -83,16 +83,16 @@ private static boolean outputTag(Map<String, Boolean> files, String fileName, bo
* Adds the given file to the JS compressor, returning the file signature to
* be output in HTML
*/
public static String addJS(String fileName, boolean compress, boolean ignoreDuplicates) {
return jsCompressor.get().add(fileName, compress, ignoreDuplicates);
public static String addJS(String fileName, boolean compress) {
return jsCompressor.get().add(fileName, compress);
}

/**
* Adds the given file to the CSS compressor, returning the file signature
* to be output in HTML
*/
public static String addCSS(String fileName, boolean compress, boolean ignoreDuplicates) {
return cssCompressor.get().add(fileName, compress, ignoreDuplicates);
public static String addCSS(String fileName, boolean compress) {
return cssCompressor.get().add(fileName, compress);
}

/**
Expand Down
14 changes: 13 additions & 1 deletion app/press/PluginConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ public static class DefaultConfig {
// to occur before a timeout exception is thrown.
public static final int maxCompressionTimeMillis = 60000;

// Whether to allow the same file to be added to compression multiple
// times
public static final boolean allowDuplicates = false;

public static class js {
// The directory where source javascript files are read from
public static final String srcDir = "/public/javascripts/";
Expand Down Expand Up @@ -61,6 +65,7 @@ public static class css {
public static boolean cacheClearEnabled;
public static String compressionKeyStorageTime;
public static int maxCompressionTimeMillis;
public static boolean allowDuplicates;

public static class js {
public static String srcDir = DefaultConfig.js.srcDir;
Expand All @@ -80,6 +85,10 @@ public static class css {
public static int lineBreak = DefaultConfig.css.lineBreak;
}

public static boolean allowDuplicates() {
return allowDuplicates;
}

/**
* Reads from the config file into memory. If the config file doesn't exist
* or is deleted, uses the default values.
Expand All @@ -97,6 +106,8 @@ public static void readConfig() {
DefaultConfig.compressionKeyStorageTime);
maxCompressionTimeMillis = ConfigHelper.getInt("press.compression.maxTimeMillis",
DefaultConfig.maxCompressionTimeMillis);
allowDuplicates = ConfigHelper.getBoolean("press.allowDuplicates",
DefaultConfig.allowDuplicates);

css.srcDir = ConfigHelper.getString("press.css.sourceDir", DefaultConfig.css.srcDir);
css.compressedDir = ConfigHelper.getString("press.css.outputDir",
Expand Down Expand Up @@ -127,10 +138,11 @@ public static void readConfig() {
}

private static void logConfig() {
PressLogger.trace("enabled: %s", enabled);
PressLogger.trace("enabled: %b", enabled);
PressLogger.trace("caching strategy: %s", cache);
PressLogger.trace("cache publicly clearable: %s", cacheClearEnabled);
PressLogger.trace("compression key storage time: %s", compressionKeyStorageTime);
PressLogger.trace("allow duplicates: %b", allowDuplicates);
PressLogger.trace("css source directory: %s", css.srcDir);
PressLogger.trace("css compressed output directory: %s", css.compressedDir);
PressLogger.trace("js source directory: %s", js.srcDir);
Expand Down
18 changes: 5 additions & 13 deletions app/views/tags/press/script.tag
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
* - media (optional) media : screen, print, aural, projection ...
* - compress (optional) if set to false, file is added to compressed output,
* but is not itself compressed
* - ignoreDuplicates (optional)
* if set to true, the file can be included multiple
* times and press will not throw an error. Only the
* first ocurrence of the file will be output.
*
* When the plugin is enabled, outputs a comment and adds the script to the
* list of files to be compressed.
Expand All @@ -34,19 +30,15 @@
_compress = true;
}

// ignoreDuplicates defaults to false
if(_ignoreDuplicates == null) {
_ignoreDuplicates = false;
}

if(! _src) {
throw new play.exceptions.TagInternalException("src attribute cannot be empty for press.script tag");
}

}%
#{if press.Plugin.performCompression() }
${ press.Plugin.addJS(_src, _compress, _ignoreDuplicates) }
${ press.Plugin.addJS(_src, _compress) }
#{/if}
#{elseif press.Plugin.outputJSTag(_src, _compress, _ignoreDuplicates) }
<script src="/public/javascripts/${_src}" type="text/javascript" language="javascript" charset="utf-8"></script>
#{/elseif}
#{else}
%{ press.Plugin.checkForJSDuplicates(_src, _compress)
}% <script src="/public/javascripts/${_src}" type="text/javascript" language="javascript" charset="utf-8"></script>
#{/else}
18 changes: 5 additions & 13 deletions app/views/tags/press/stylesheet.tag
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
* - media (optional) media : screen, print, aural, projection ...
* - compress (optional) if set to false, file is added to compressed output,
* but is not itself compressed
* - ignoreDuplicates (optional)
* if set to true, the file can be included multiple
* times and press will not throw an error. Only the
* first occurrence of the file will be output.
*
* When the plugin is enabled, outputs a comment and adds the css file to the
* list of files to be compressed.
Expand All @@ -33,19 +29,15 @@
_compress = true;
}

// ignoreDuplicates defaults to false
if(_ignoreDuplicates == null) {
_ignoreDuplicates = false;
}

if(! _src) {
throw new play.exceptions.TagInternalException("src attribute cannot be empty for stylesheet tag");
}

}%
#{if press.Plugin.performCompression() }
${ press.Plugin.addCSS(_src, _compress, _ignoreDuplicates) }
${ press.Plugin.addCSS(_src, _compress) }
#{/if}
#{elseif press.Plugin.outputCSSTag(_src, _compress, _ignoreDuplicates) }
<link href="/public/stylesheets/${_src}" rel="stylesheet" type="text/css" charset="utf-8" #{if _media} media="${_media}"#{/if}></link>
#{/elseif}
#{else}
%{ press.Plugin.checkForCSSDuplicates(_src, _compress)
}% <link href="/public/stylesheets/${_src}" rel="stylesheet" type="text/css" charset="utf-8" #{if _media} media="${_media}"#{/if}></link>
#{/else}
19 changes: 9 additions & 10 deletions documentation/manual/home.textile
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ h2. <a>Tips</a>
* The source files will be output in compressed format in the same order as they appear in HTML when compression is disabled.
* It doesn't matter where the **#{press.compressed-script}** and **#{press.compressed-stylesheet}** tags are declared. Even if there are **#{press.script}** or **#{press.stylesheet}** tags after them in the template, they will still be included in compression.
* In dev mode, changes to the JS and CSS files are detected real time. Simply save and refresh the page. See "Caching":#caching for options related to caching and the defaults for each mode.
* If a file is included twice an exception will be thrown. If it's absolutely necessary, you can include a file twice by passing a flag to the tag. See "Duplicate Files":#duplicate_files
* If a file is included twice an exception will be thrown. If it's absolutely necessary, you can include a file twice by setting a config key. See "Configuration":#configuration


h2. <a name="caching">Caching</a>
Expand Down Expand Up @@ -168,6 +168,14 @@ The maximum amount of time in milli-seconds that compression is allowed to take
**press.compression.maxTimeMillis=60000**


h3. __press.allowDuplicates__

Indicates whether to allow files to be added to compression more than once.

__press__ will throw an exception if you add the same file to compression twice, because usually it's a mistake. In some cases it may be necessary, however, so for those specific cases you can set the allowDuplicates flag to true.
**press.allowDuplicates=false**


h3. __press.js.sourceDir__

The source directory for javascript files, relative to the application root
Expand Down Expand Up @@ -219,15 +227,6 @@ When the browser makes a request for **/press/js/sNJSWMCDDFAekXYWryWgigJJ.js**,
The process is the same for CSS files.


h2. <a name="duplicate_files">Duplicate files</a>

__press__ will throw an exception if you add the same file to compression twice, because usually it's a mistake. In some cases it may be necessary, however, so for those specific cases you can pass the ignoreDuplicates flag to the tag:

bc. #{press.script 'mywidget.js', ignoreDuplicates: true /}
#{press.stylesheet 'map.css', ignoreDuplicates: true /}

When __press__ is disabled, the first time the tag is called the corresponding file will be output. Subsequent calls to the tag will output nothing. When __press__ is enabled, the file will be included in compression as if it had only been called the first time.


h2. <a>Gotchas</a>

Expand Down

0 comments on commit ddb18f2

Please sign in to comment.