001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.plugin;
021:
022: import java.io.IOException;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.Iterator;
026: import java.util.Map;
027:
028: import org.apache.commons.lang.StringUtils;
029: import org.apache.log4j.Logger;
030: import org.apache.oro.text.GlobCompiler;
031: import org.apache.oro.text.regex.*;
032:
033: import com.ecyrd.jspwiki.*;
034: import com.ecyrd.jspwiki.parser.MarkupParser;
035: import com.ecyrd.jspwiki.parser.WikiDocument;
036: import com.ecyrd.jspwiki.render.RenderingManager;
037:
038: /**
039: * This is a base class for all plugins using referral things.
040: *
041: * <p>Parameters:<br>
042: * maxwidth: maximum width of generated links<br>
043: * separator: separator between generated links (wikitext)<br>
044: * after: output after the link
045: * before: output before the link
046: * @author Janne Jalkanen
047: */
048: public abstract class AbstractReferralPlugin implements WikiPlugin {
049: private static Logger log = Logger
050: .getLogger(AbstractReferralPlugin.class);
051:
052: public static final int ALL_ITEMS = -1;
053: public static final String PARAM_MAXWIDTH = "maxwidth";
054: public static final String PARAM_SEPARATOR = "separator";
055: public static final String PARAM_AFTER = "after";
056: public static final String PARAM_BEFORE = "before";
057:
058: public static final String PARAM_EXCLUDE = "exclude";
059: public static final String PARAM_INCLUDE = "include";
060:
061: protected int m_maxwidth = Integer.MAX_VALUE;
062: protected String m_before = ""; // null not blank
063: protected String m_separator = ""; // null not blank
064: protected String m_after = "\\\\";
065:
066: protected Pattern[] m_exclude;
067: protected Pattern[] m_include;
068:
069: protected WikiEngine m_engine;
070:
071: /**
072: * Used to initialize some things. All plugins must call this first.
073: *
074: * @since 1.6.4
075: */
076:
077: // FIXME: The compiled pattern strings should really be cached somehow.
078: public void initialize(WikiContext context, Map params)
079: throws PluginException {
080: m_engine = context.getEngine();
081: m_maxwidth = TextUtil.parseIntParameter((String) params
082: .get(PARAM_MAXWIDTH), Integer.MAX_VALUE);
083: if (m_maxwidth < 0)
084: m_maxwidth = 0;
085:
086: String s = (String) params.get(PARAM_SEPARATOR);
087:
088: if (s != null) {
089: m_separator = s;
090: // pre-2.1.145 there was a separator at the end of the list
091: // if they set the parameters, we use the new format of
092: // before Item1 after separator before Item2 after separator before Item3 after
093: m_after = "";
094: }
095:
096: s = (String) params.get(PARAM_BEFORE);
097:
098: if (s != null) {
099: m_before = s;
100: }
101:
102: s = (String) params.get(PARAM_AFTER);
103:
104: if (s != null) {
105: m_after = s;
106: }
107:
108: s = (String) params.get(PARAM_EXCLUDE);
109:
110: if (s != null) {
111: try {
112: PatternCompiler pc = new GlobCompiler();
113:
114: String[] ptrns = StringUtils.split(s, ",");
115:
116: m_exclude = new Pattern[ptrns.length];
117:
118: for (int i = 0; i < ptrns.length; i++) {
119: m_exclude[i] = pc.compile(ptrns[i]);
120: }
121: } catch (MalformedPatternException e) {
122: throw new PluginException(
123: "Exclude-parameter has a malformed pattern: "
124: + e.getMessage());
125: }
126: }
127:
128: // TODO: Cut-n-paste, refactor
129: s = (String) params.get(PARAM_INCLUDE);
130:
131: if (s != null) {
132: try {
133: PatternCompiler pc = new GlobCompiler();
134:
135: String[] ptrns = StringUtils.split(s, ",");
136:
137: m_include = new Pattern[ptrns.length];
138:
139: for (int i = 0; i < ptrns.length; i++) {
140: m_include[i] = pc.compile(ptrns[i]);
141: }
142: } catch (MalformedPatternException e) {
143: throw new PluginException(
144: "Include-parameter has a malformed pattern: "
145: + e.getMessage());
146: }
147: }
148:
149: // log.debug( "Requested maximum width is "+m_maxwidth );
150: }
151:
152: protected Collection filterCollection(Collection c) {
153: ArrayList result = new ArrayList();
154:
155: PatternMatcher pm = new Perl5Matcher();
156:
157: for (Iterator i = c.iterator(); i.hasNext();) {
158: String pageName = (String) i.next();
159:
160: //
161: // If include parameter exists, then by default we include only those
162: // pages in it (excluding the ones in the exclude pattern list).
163: //
164: // include='*' means the same as no include.
165: //
166: boolean includeThis = m_include == null;
167:
168: if (m_include != null) {
169: for (int j = 0; j < m_include.length; j++) {
170: if (pm.matches(pageName, m_include[j])) {
171: includeThis = true;
172: break;
173: }
174: }
175: }
176:
177: if (m_exclude != null) {
178: for (int j = 0; j < m_exclude.length; j++) {
179: if (pm.matches(pageName, m_exclude[j])) {
180: includeThis = false;
181: break; // The inner loop, continue on the next item
182: }
183: }
184: }
185:
186: if (includeThis) {
187: result.add(pageName);
188: }
189: }
190:
191: return result;
192: }
193:
194: /**
195: * Makes WikiText from a Collection.
196: *
197: * @param links Collection to make into WikiText.
198: * @param separator Separator string to use.
199: * @param numItems How many items to show.
200: */
201: protected String wikitizeCollection(Collection links,
202: String separator, int numItems) {
203: if (links == null || links.isEmpty())
204: return "";
205:
206: StringBuffer output = new StringBuffer();
207:
208: Iterator it = links.iterator();
209: int count = 0;
210:
211: //
212: // The output will be B Item[1] A S B Item[2] A S B Item[3] A
213: //
214: while (it.hasNext()
215: && ((count < numItems) || (numItems == ALL_ITEMS))) {
216: String value = (String) it.next();
217:
218: if (count > 0) {
219: output.append(m_after);
220: output.append(m_separator);
221: }
222:
223: output.append(m_before);
224:
225: // Make a Wiki markup link. See TranslatorReader.
226: output.append("[" + m_engine.beautifyTitle(value) + "|"
227: + value + "]");
228: count++;
229: }
230:
231: //
232: // Output final item - if there have been none, no "after" is printed
233: //
234: if (count > 0)
235: output.append(m_after);
236:
237: return output.toString();
238: }
239:
240: /**
241: * Makes HTML with common parameters.
242: *
243: * @since 1.6.4
244: */
245: protected String makeHTML(WikiContext context, String wikitext) {
246: String result = "";
247:
248: RenderingManager mgr = m_engine.getRenderingManager();
249:
250: try {
251: MarkupParser parser = mgr.getParser(context, wikitext);
252:
253: parser.addLinkTransmutator(new CutMutator(m_maxwidth));
254: parser.enableImageInlining(false);
255:
256: WikiDocument doc = parser.parse();
257:
258: result = mgr.getHTML(context, doc);
259: } catch (IOException e) {
260: log.error("Failed to convert page data to HTML", e);
261: }
262:
263: return result;
264: }
265:
266: /**
267: * A simple class that just cuts a String to a maximum
268: * length, adding three dots after the cutpoint.
269: */
270: private static class CutMutator implements StringTransmutator {
271: private int m_length;
272:
273: public CutMutator(int length) {
274: m_length = length;
275: }
276:
277: public String mutate(WikiContext context, String text) {
278: if (text.length() > m_length) {
279: return text.substring(0, m_length) + "...";
280: }
281:
282: return text;
283: }
284: }
285: }
|