001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util.transformers;
011:
012: import java.util.regex.Pattern;
013: import java.util.regex.Matcher;
014:
015: import org.mmbase.util.functions.Parameter;
016: import org.mmbase.util.functions.Parameters;
017: import org.mmbase.util.logging.Logger;
018: import org.mmbase.util.logging.Logging;
019:
020: /**
021: * This TransformerFactory enables the use of two different escapers in one piece
022: * of text. I started it to simplify the inclusion of a code snippet in html.
023: * You can specify the tags between which you wish to escape your text, the
024: * escaper to use and you can set an escaper for the rest of the text.<br />
025: * The tags default to <pre> and </pre>, the first escaper defaults to
026: * 'text/html' (which escapes &, <, >, " and leaves the linebreakes
027: * untouched). The last escaper does by default nothing. But of course you can set
028: * your own with the parameters 'starttag', 'closetag', 'escapecode' and 'escaperest'.
029: *
030: * @author André van Toly
031: * @since MMBase 1.8.0
032: * @version $Id: CodeSampleFactory.java,v 1.6 2008/02/03 17:33:56 nklasens Exp $
033: */
034:
035: public class CodeSampleFactory implements
036: ParameterizedTransformerFactory<CharTransformer> {
037:
038: private final static Logger log = Logging
039: .getLoggerInstance(CodeSampleFactory.class);
040:
041: private final static Parameter[] PARAMS = new Parameter[] {
042: new Parameter<String>("starttag", String.class, "<pre>"),
043: new Parameter<String>("closetag", String.class, ""),
044: new Parameter<String>("escapecode", String.class,
045: "text/html"), // like attr. escaper of mm:content
046: new Parameter<String>("escaperest", String.class, ""), // do nothing by default
047:
048: };
049:
050: public Parameters createParameters() {
051: return new Parameters(PARAMS);
052: }
053:
054: public CharTransformer createTransformer(Parameters parameters) {
055: parameters.checkRequiredParameters();
056:
057: return new CodeSample((String) parameters.get("starttag"),
058: (String) parameters.get("closetag"),
059: (String) parameters.get("escapecode"),
060: (String) parameters.get("escaperest"));
061: }
062:
063: protected class CodeSample extends StringTransformer {
064: private String starttag = "<pre>"; // default?
065: private String closetag = "";
066: private String escapecode = "text/html";
067: private String escaperest = ""; // do nothing
068:
069: /**
070: * Constructor
071: *
072: */
073: public CodeSample(String st, String ct, String ec, String er) {
074: starttag = st;
075: closetag = ct;
076: escapecode = ec;
077: escaperest = er;
078: }
079:
080: /**
081: * Default transform method with no (other) parameters then the string
082: * to transform while using <pre> as the tag between which to escape
083: * the text while using the default escaper 'text/html'.
084: *
085: * @param str The original string
086: * @return The transformed string
087: */
088: public String transform(String str) {
089: return transform(str, starttag, closetag, escapecode,
090: escaperest);
091: }
092:
093: /**
094: * Transforms the characters of a code example between two tags,
095: * <pre>-tags and </pre> f.e., within a string and can use a
096: * different escaper for the rest of the text.
097: *
098: * @param str The original string
099: * @param starttag The opentag of the pair of tags between which code needs to be escaped
100: * @param closetag The closetag of the pair of tags between which code needs to be escaped
101: * @param escapecode The escaper to use on the piece of text between the tags
102: * @param escaperest The escaper to use on the rest of the text
103: * @return The transformed string
104: */
105: public String transform(String str, String starttag,
106: String closetag, String escapecode, String escaperest) {
107: StringBuilder result = new StringBuilder();
108:
109: String stag = starttag;
110: String ctag = closetag;
111: if (ctag.equals("")) { // create closetag based on starttag, only usefull on an html tag
112: ctag = "</" + starttag.substring(1, starttag.length());
113: }
114:
115: Pattern sp = Pattern.compile("\\Q" + stag + "\\E",
116: Pattern.DOTALL);
117: Pattern cp = Pattern.compile("\\Q" + ctag + "\\E",
118: Pattern.DOTALL);
119: Matcher stm = sp.matcher(str); // starttag Matcher
120: Matcher ctm = cp.matcher(str); // closetag Matcher
121:
122: int s = 0; // startposition 'rest' of the text
123: while (stm.find() && ctm.find()) {
124: // stm.start(0) = position of starttag
125: // stm.end(0) = where starttag ends
126: // ctm.start(0) = position of closetag
127: // etc.
128: String normalStr = ""; // for the 'normal' text (not between the tags)
129: normalStr = str.substring(s, stm.start(0));
130: if (log.isDebugEnabled())
131: log.debug("Found rest str: " + normalStr);
132: normalStr = transformPart(normalStr, escaperest);
133: result.append(normalStr).append(stag); // the transformed str and the tag
134:
135: s = ctm.end(0); // here starts the rest of the text to be worked on
136:
137: String codeStr = str
138: .substring(stm.end(0), ctm.start(0)); // the 'code'
139: if (log.isDebugEnabled())
140: log.debug("Found code str: " + codeStr);
141: codeStr = transformPart(codeStr, escapecode);
142:
143: result.append(codeStr).append(ctag);
144: }
145:
146: // use escaperest upond the remaining piece of text and append it
147: // plus we always use escaperest, even when there is not match
148: String rest = str.substring(s, str.length());
149: result.append(transformPart(rest, escaperest));
150: if (s == 0) {
151: if (log.isDebugEnabled())
152: log.debug("No match with the tags '" + stag
153: + "' and '" + ctag + "'");
154: }
155: return result.toString();
156: }
157:
158: /**
159: * Transforms parts of the string. Calls the transform methods in
160: * {@link org.mmbase.util.transformers.XmlField} and {@link org.mmbase.util.transformers.Xml}.
161: * This method needs to be rewritten to support all escapers/transformers. It only
162: * supports p, pp, p-ommit-surrounding, pp-ommit-surrounding, inline, text/html and text/xml.
163: *
164: * @param str String to transform
165: * @param escaper The transformer or escaper to use (see escaper attr of <mm:content />)
166: * @return The transformed string
167: */
168: public String transformPart(String str, String escaper) {
169: if (escaper.equals("p")) {
170: str = XmlField.richToHTMLBlock(str, true, true);
171: } else if (escaper.equals("pp")) {
172: str = XmlField.richToHTMLBlock(str);
173: } else if (escaper.equals("p-ommit-surrounding")) {
174: str = XmlField.richToHTMLBlock(str, true, false);
175: } else if (escaper.equals("pp-ommit-surrounding")) {
176: str = XmlField.richToHTMLBlock(str, false, false);
177: } else if (escaper.equals("inline")) {
178: str = XmlField.poorToHTMLInline(str);
179: } else if (escaper.equals("text/html")
180: || escaper.equals("text/xml")) {
181: str = Xml.XMLEscape(str);
182: } else { // at least return something
183: //throw new UnsupportedOperationException("Cannot transform");
184: }
185: if (log.isDebugEnabled())
186: log.debug("Returning: " + str);
187: return str;
188: }
189:
190: }
191: }
|