smartrics.rest.fitnesse.fixture.ext.SvgImage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smartrics-RestFixtureExtensions Show documentation
Show all versions of smartrics-RestFixtureExtensions Show documentation
Extensions of the RestFixture.
An extension is a RestFixture with some specific/bespoke behaviour not generic enough to make it to the RestFixture itself.
/* Copyright 2012 Fabrizio Cannizzo
*
* This file is part of RestFixture.
*
* RestFixture (http://code.google.com/p/rest-fixture/) is free software:
* you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* RestFixture is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with RestFixture. If not, see .
*
* If you want to contact the author please leave a comment here
* http://smartrics.blogspot.com/2008/08/get-fitnesse-with-some-rest.html
*/
package smartrics.rest.fitnesse.fixture.ext;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import util.Maybe;
import fitnesse.html.HtmlTag;
import fitnesse.wikitext.parser.Matcher;
import fitnesse.wikitext.parser.Parser;
import fitnesse.wikitext.parser.Rule;
import fitnesse.wikitext.parser.Symbol;
import fitnesse.wikitext.parser.SymbolProvider;
import fitnesse.wikitext.parser.SymbolType;
import fitnesse.wikitext.parser.Translation;
import fitnesse.wikitext.parser.Translator;
/**
* Allows inclusion of an SVG file in a FitNesse page. For the file to be
* reachable over HTTP in FitNesse, it needs to be store under (a directory in)
* FitNesseRoot/files
.
*
* For the symbol to be deployed, put the RestFixture.jar in the FitNesse start
* command (eg:
* java -classpath path_to/RestFixture.jar -jar fitnesse.jar
* ) and add to the plugins.properties file the following property:
* SymbolTypes=smartrics.rest.fitnesse.fixture.SvgImage
. See this for more
* details.
*
* To use the symbol, is sufficient to specify in a line in the test page the
* following:
*
* !svg /files/path/to/image.svg rendering_mode
*
* The rendering_mode
is one of the following:
*
*
*
* inline
* the image is included as is, hence using the <svg> tag
*
*
* embed
* the image is rendered using the <embed> tag
*
*
* object
* the image is rendered using the <object> tag
*
*
* img
* the image is rendered using the <img> tag
*
*
* iframe
* the image is rendered using the <iframe> tag
*
*
* anchor
* the image is rendered using the <a> tag
*
*
* Each mode (except inline
) will point to the file in the fitnesse
* server.
*
* Basically this means that when embed is used, the conent of the SVG file is
* read at that point in time and substituted as the page is rendering. With the
* others, an HTML tag is rendered that has a src that points to the remote
* file, hence the image is rendered when the browser decides to.
*
* Also note that rendering SVG files embedded in HTML pages is one of the
* least supported features across all browsers. So the end result of embedding
* an SVG is highly dependant on the browser and unluckely to be portable.
*
* @author smartrics
*
*/
public class SvgImage extends SymbolType implements Rule, Translation {
static final Log LOG = LogFactory.getLog(SvgImage.class);
/**
* The selected rendering mode.
*/
private enum Mode {
inline, embed("embed", "src", "type=\"image/svg+xml\""), object("object", "data", "type=\"image/svg+xml\""), iframe("iframe", "src"), img("img", "src"), anchor("a", "href");
public String toString(String stuff) {
if (this.equals(inline)) {
return stuff;
}
String s = "";
if (otherAttr != null) {
s = otherAttr;
}
return "<" + tag + " " + srcAttr + "=\"" + stuff + "\" " + s + " />";
}
private Mode() {
this(null, null, null);
}
private Mode(String tag, String srcAttr) {
this(tag, srcAttr, null);
}
private Mode(String tag, String srcAttr, String otherAttr) {
this.tag = tag;
this.srcAttr = srcAttr;
this.otherAttr = otherAttr;
}
private String tag;
private String srcAttr;
private String otherAttr;
}
private Mode defaultMode = Mode.inline;
public SvgImage() {
super("SVG-Image");
wikiMatcher(new Matcher().string("!svg"));
htmlTranslation(this);
wikiRule(this);
}
public Maybe parse(Symbol current, Parser parser) {
Symbol targetList = parser.parseToEnds(-1,
SymbolProvider.pathRuleProvider,
new SymbolType[] { SymbolType.Newline });
return new Maybe(current.add(targetList));
}
public String toTarget(Translator translator, Symbol symbol) {
String symContent = symbol.getContent();
String target = symContent + translator.translate(symbol.childAt(0));
return toTarget(translator, target, symbol);
}
public String toTarget(Translator translator, String body, Symbol args) {
Symbol symbol = getPathSymbol(args);
if (symbol == null) {
return error("Missing image path");
}
String line = translator.translate(symbol);
line = line.replaceAll("\\s+", " ").trim();
String[] parts = line.split(" ");
String location = null;
Mode mode = defaultMode;
if (parts.length > 0) {
location = parts[0];
}
if (parts.length > 1) {
for (String part : parts) {
if (part.contains("mode=")) {
mode = parseMode(part);
}
}
}
return inlineSvg(mode, location);
}
private Mode parseMode(String s) {
String mString = null;
Mode mode = defaultMode;
try {
mString = s.trim();
String[] subParts = mString.split("=");
mode = Enum.valueOf(Mode.class, subParts[1].trim());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Mode not supported: " + mString);
}
return mode;
}
private Symbol getPathSymbol(Symbol args) {
if (args.getChildren().size() > 0) {
return args.childAt(0);
}
return null;
}
private String inlineSvg(Mode tag, String location) {
if (location == null) {
return error("Invalid file path: null");
}
if (tag.equals(Mode.inline)) {
String content = read(location);
return tag.toString(content);
} else {
return tag.toString(location);
}
}
private String read(String path) {
String loc = path.trim();
if (loc.startsWith("/files")) {
loc = "FitNesseRoot" + path.trim();
}
String content = null;
File f = new File(loc);
try {
if (f.exists()) {
content = readFile(f);
} else {
content = error("File not found: " + f.getAbsolutePath() + ", path=" + path);
}
} catch (FileNotFoundException e) {
content = error("File not found: " + loc + ", path=" + path + ", err=" + e.getMessage());
} catch (RuntimeException e) {
content = error("Unable to read: " + loc + ", path=" + path);
}
return content;
}
private String readFile(File f) throws FileNotFoundException {
FileReader reader = new FileReader(f);
BufferedReader r = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String line;
LOG.debug("Reading file " + f.getAbsolutePath());
try {
while ((line = r.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
throw new IllegalArgumentException("Unable to read from stream", e);
} finally {
try {
r.close();
} catch (IOException e) {
LOG.debug("Exception closing file reader for file " + f.getAbsolutePath());
}
}
return sb.toString();
}
private String error(String string) {
HtmlTag tag = new HtmlTag("p");
tag.addAttribute("style", "color:red");
tag.add(string);
return tag.htmlInline();
}
}