roller-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject svn commit: r398715 [2/2] - in /incubator/roller/trunk/contrib/plugins/src/org/apache: ./ roller/ roller/presentation/ roller/presentation/velocity/ roller/presentation/velocity/plugins/ roller/presentation/velocity/plugins/acronyms/ roller/presentatio...
Date Mon, 01 May 2006 22:29:25 GMT
Added: incubator/roller/trunk/contrib/plugins/src/org/apache/roller/presentation/velocity/plugins/topictag/TopicTagPlugin.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/contrib/plugins/src/org/apache/roller/presentation/velocity/plugins/topictag/TopicTagPlugin.java?rev=398715&view=auto
==============================================================================
--- incubator/roller/trunk/contrib/plugins/src/org/apache/roller/presentation/velocity/plugins/topictag/TopicTagPlugin.java
(added)
+++ incubator/roller/trunk/contrib/plugins/src/org/apache/roller/presentation/velocity/plugins/topictag/TopicTagPlugin.java
Mon May  1 15:29:19 2006
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.presentation.velocity.plugins.topictag;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.velocity.context.Context;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.RollerConfig;
+import org.apache.roller.model.BookmarkManager;
+import org.apache.roller.model.RollerFactory;
+import org.apache.roller.pojos.BookmarkData;
+import org.apache.roller.pojos.WeblogEntryData;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.model.PagePlugin;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.FieldPosition;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.servlet.ServletConfig;
+
+/**
+ * Provides an easy way to write topic tag links for Technorati (or similar services).
+ * <p/>
+ * Looks for occurrences of topic tag specifiers of the form
+ * <pre>
+ * <code>topic:{topicbookmark}[tag]</code>  OR    <code>topic:[tag]</code>
+ * </pre>
+ * and replaces them with a topic tag link of the form:
+ * <pre>
+ * <code>&lt;a rel="tag" href="site/tag"&gt;tag&lt;/a&gt;</code>
+ * </pre>
+ * <p/>
+ * More information on topic tag links can be found at <a href="http://www.technorati.com">Technorati</a>.
+ * <p/>
+ * <p/>
+ * In the first form, the <code>topicbookmark</code> is used as the name of a
bookmark, and the URL from that bookmark
+ * entry is used as the <code>site</code> portion in the <code>href</code>
of the link.
+ * <p/>
+ * All folders are searched to find a bookmark with the name specified by <code>topicbookmark</code>.
A name must match
+ * exactly, ignoring case.  The first matching bookmark is used, and folders may be searched
in any order.  The
+ * bookmark's URL value can end in a "/" or not; either will work.
+ * <p/>
+ * The second form is equivalent to using the string "Default Topic Site" as the value of
<code>topicbookmark</code>.
+ * <p/>
+ * If the bookmark lookup fails, then "http://www.technorati.com/tag" is used as the site
name in the topic tag link.
+ * <p/>
+ * You can specify some Roller site-wide properties in the roller.properties or roller-custom.properties
to override
+ * some of the defaults of this plugin. All of these are optional.
+ * <p/>
+ * <dl> <dt><code>org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.defaultTopicBookmarkName</code></dt>
+ * <dd>Specify the name of the default topic bookmark instead of "Default Topic Site"</dd>
+ * <p/>
+ * <dt><code>org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.defaultTopicSite</code></dt>
<dd>Specify
+ * the default site name to be used instead of "http://www.technorati.com" for the case in
which all of the lookups
+ * fail.</dd>
+ * <p/>
+ * <dt><code>org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.tagPatternWithBookmark</code></dt>
<dd>Can
+ * be used to redefine the regular expression used to find a long-form topic tag specifiers
in the input.  This pattern
+ * corresponds to the "long form" and must have two matching groups.  Group 1 must correspond
to the bookmark name.
+ * Group 2 must correspond to the tag.</dd>
+ * <p/>
+ * <dt><code>org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.tagPatternDefaultBookmark</code></dt>
+ * <dd>Can be used to redefine the regular expression used to find short-form topic
tag specifiers in the input. This
+ * pattern must have one matching group, which corresponds to the tag.</dd>
+ * <p/>
+ * <dt><code>org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.linkFormatString</code></dt>
<dd>Can be
+ * used to redefine the format of the generated link.  This string is a message format string
with three positional
+ * parameters.  Parameter <code>{0}</code> represents the site including a trailing
"/",  parameter <code>{1}</code>
+ * represents the url-encoded tag and parameter <code>{2}</code> represents the
original unencoded tag text.</dd>
+ * <p/>
+ * </dl>
+ *
+ * @author <a href="mailto:anil@busybuddha.org">Anil Gangolli</a>
+ * @version 0.3
+ */
+public class TopicTagPlugin implements PagePlugin
+{
+    private static final String version = "0.3";
+    private static final Log mLogger = LogFactory.getFactory().getInstance(TopicTagPlugin.class);
+
+
+    // Default values of properties that can be set from the web.xml configuration.
+    private String defaultTopicBookmarkName = "Default Topic Site";
+    private String defaultTopicSite = "http://www.technorati.com/tag";
+    private String tagRegexWithBookmark = "topic:\\{(.*?)\\}\\[(.*?)\\]";
+    private String tagRegexWithoutBookmark = "topic:\\[(.*?)\\]";
+    private String linkFormatString = "<a rel=\"tag\" href=\"{0}{1}\">{2}</a>";
+
+    // Compiled form of the regular expressions above.  Compiled during the init()
+    private Pattern tagPatternWithBookmark;
+    private Pattern tagPatternWithoutBookmark;
+    private MessageFormat linkFormat;
+
+    // A map of the user's bookmarks (values of type BookmarkData) keyed by name (String).
  If the user has multiple
+    // bookmarks with the same name in different folders, only one gets used (the last encountered).
+    private Map userBookmarks;
+
+
+    public TopicTagPlugin()
+    {
+    }
+
+    /**
+     * Initialize the plugin instance.   This sets up the configurable properties and default
topic site.
+     *
+     * @param rreq Plugins may need to access RollerRequest.
+     * @param ctx  Plugins may place objects into the Velocity Context.
+     * @see PagePlugin#init(org.apache.roller.presentation.RollerRequest, org.apache.velocity.context.Context)
+     */
+    public void init(
+            WebsiteData website,
+            Object config,
+            String baseURL,
+            Context ctx) throws RollerException
+    {
+        if (mLogger.isDebugEnabled())
+        {
+            mLogger.debug("TopicTagPlugin v. " + version);
+        }
+
+        // Initialize property settings
+        initializeProperties();
+
+        // Build map of the user's bookmarks
+        userBookmarks = buildBookmarkMap(website);
+
+        // Determine default topic site from bookmark if present
+        BookmarkData defaultTopicBookmark = (BookmarkData) userBookmarks.get(defaultTopicBookmarkName);
+        if (defaultTopicBookmark != null) defaultTopicSite = defaultTopicBookmark.getUrl();
+
+        // Append / to defaultTopicSite if it doesn't have it
+        if (!defaultTopicSite.endsWith("/"))
+        {
+            defaultTopicSite += "/";
+        }
+
+        // Compile patterns and make sure they have the correct number of matching groups
in them.
+        try
+        {
+            tagPatternWithBookmark = Pattern.compile(tagRegexWithBookmark);
+        }
+        catch (PatternSyntaxException e)
+        {
+            throw new RollerException("Invalid regular expression for topic tags with bookmark
'" +
+                tagRegexWithBookmark + "': " + e.getMessage());
+        }
+        int groupCount = tagPatternWithBookmark.matcher("").groupCount();
+        if (groupCount != 2)
+        {
+            throw new RollerException("Regular expression for topic tags with bookmark '"
+ tagRegexWithBookmark +
+                "' contains wrong number of capture groups.  Must have exactly 2.  Contains
" + groupCount);
+        }
+
+        try
+        {
+            tagPatternWithoutBookmark = Pattern.compile(tagRegexWithoutBookmark);
+        }
+        catch (PatternSyntaxException e)
+        {
+            throw new RollerException("Invalid regular expression for topic tags without
bookmark '" +
+                tagRegexWithoutBookmark + "': " + e.getMessage());
+        }
+        groupCount = tagPatternWithoutBookmark.matcher("").groupCount();
+        if (groupCount != 1)
+        {
+            throw new RollerException("Regular expression for topic tags without bookmark
'" + tagRegexWithoutBookmark +
+                "' contains wrong number of capture groups.  Must have exactly 1.  Contains
" + groupCount);
+        }
+
+        // Create link format from format string
+        setLinkFormat(new MessageFormat(linkFormatString));
+    }
+
+    /**
+     * Apply the plugin to the given entry.  Returns the entry text with topic tags expanded.
+     *
+     * @param entry           WeblogEntry to which plugin should be applied.
+     * @param singleEntry     Ignored.
+     * @return Results of applying plugin to entry.
+     */
+    public String render(WeblogEntryData entry, String str)
+    {
+        String entryText = str;
+        StringBuffer result = new StringBuffer(entryText.length());
+        MessageFormat fmt = getLinkFormat();
+
+        // Replace all of the instances matching the pattern with bookmark specified.
+        Matcher m = tagPatternWithBookmark.matcher(entryText);
+        while (m.find())
+        {
+            String bookmark = m.group(1);
+            String tag = m.group(2);
+            String site = getBookmarkSite(bookmark);
+            if (site == null)
+            {
+                site = getDefaultTopicSite();
+            }
+            if (!site.endsWith("/"))
+            {
+                site += "/";
+            }
+            String link = generateLink(fmt, site, tag);
+            m.appendReplacement(result, link);
+        }
+        m.appendTail(result);
+
+        // Now, in a second phase replace all of the instances matching the pattern without
bookmark specified.
+        entryText = result.toString();
+        result = new StringBuffer(entryText.length());
+        m = tagPatternWithoutBookmark.matcher(entryText);
+        while (m.find())
+        {
+            String tag = m.group(1);
+            String site = getDefaultTopicSite();
+            String link = generateLink(fmt, site, tag);
+            m.appendReplacement(result, link);
+        }
+        m.appendTail(result);
+
+        return result.toString();
+    }
+
+    /**
+     * Render from a string without entry data context. Because we require the context of
the website in order to do the
+     * bookmark searches.  This implementation can only return the input string.
+     *
+     * @param str String to which plugin should be applied.
+     * @return the input value.
+     * @see PagePlugin#render(String)
+     */
+    public String render(String str)
+    {
+        return str;
+    }
+
+    /**
+     * Returns the human-friendly name of this Plugin. This is what users will see.
+     *
+     * @return The human-friendly name of this Plugin.
+     */
+    public String getName()
+    {
+        // TODO: i18n
+        return "Topic Tags";
+    }
+
+    /**
+     * Briefly describes the function of the Plugin. May contain HTML.
+     *
+     * @return A brief description of the Plugin.
+     */
+    public String getDescription()
+    {
+        // TODO: i18n
+        return "Expands topic tags for <a href=\\'http://www.technorati.com\\'>Technorati</a>
and similar sites. " +
+            "Topic tags are of the form <code>topic:{topicbookmark}[tag]</code>,
where <code>topicbookmark</code> " +
+            "is the name of a bookmark whose URL will be used for the site name in the topic
tag. " +
+            "If <code>{topicbookmark}</code> is omitted the plugin will use the
URL of the <code>Default Topic Site</code> " +
+            "bookmark, if that is defined, otherwise http://www.technorati.com.";
+    }
+
+    /**
+     * Helper to generate the link from the link format and values of the site and tag.
+     *
+     * @param fmt  link format.  This should have positional parameters {0} representing
site with terminal /,  {1} for
+     *             url-encoded-tag, and {2} for visible tag text.
+     * @param site base portion of the URL
+     * @param tag  tag value
+     * @return the generated link as a string
+     */
+    protected String generateLink(MessageFormat fmt, String site, String tag)
+    {
+        // Allocate initial capacity of buffer of approximately the right length.
+        StringBuffer sb = new StringBuffer(site.length() + tag.length() + getLinkFormatString().length());
+        fmt.format(new Object[]{site, urlEncode(tag), tag}, sb, new FieldPosition(0));
+        return sb.toString();
+    }
+
+    /**
+     * Resolve the bookmark name and return the URL from it.  If the bookmark can't be found,
return null
+     *
+     * @param bookmarkName name of the bookmark
+     * @return String form of the URL from the bookmark by that name from any of the user's
folders, or null if not
+     *         found.
+     */
+    protected String getBookmarkSite(String bookmarkName)
+    {
+        BookmarkData bookmark = (BookmarkData) getUserBookmarks().get(bookmarkName);
+        return bookmark == null ? null : bookmark.getUrl();
+    }
+
+
+    /**
+     * Build the bookmark map.
+     * If ignoreBookmarks property is set, an empty map is returned.
+     * @return map of the user's bookmarks (type BookmarkData), keyed by name (type String).
+     */
+    protected Map buildBookmarkMap(WebsiteData website) throws RollerException
+    {
+        Map bookmarkMap = new HashMap();
+        if (RollerConfig.getBooleanProperty(
+            "org.apache.roller.presentation.velocity.plugins.topictag.TopicTagPlugin.ignoreBookmarks"))
{
+            return bookmarkMap;
+        }
+        if (website == null)
+        {
+            mLogger.debug("Init called without website.  Skipping bookmark initialization.");
+        }
+        else
+        {
+            BookmarkManager bMgr = RollerFactory.getRoller().getBookmarkManager();
+            List bookmarks = bMgr.getBookmarks(bMgr.getRootFolder(website), true);
+
+            for (Iterator i = bookmarks.iterator(); i.hasNext();)
+            {
+                BookmarkData b = (BookmarkData) i.next();
+                bookmarkMap.put(b.getName(), b);
+            }
+        }
+        return bookmarkMap;
+    }
+
+
+    // Sets up properties.  For better and worse, doesn't use reflection
+    private void initializeProperties()
+    {
+        setDefaultTopicBookmarkName(getSetting("defaultTopicBookmarkName", getDefaultTopicBookmarkName()));
+        setDefaultTopicSite(getSetting("defaultTopicSite", getDefaultTopicSite()));
+        setTagRegexWithBookmark(getSetting("tagRegexWithBookmark", getTagRegexWithBookmark()));
+        setTagRegexWithoutBookmark(getSetting("tagRegexWithoutBookmark", getTagRegexWithoutBookmark()));
+        setLinkFormatString(getSetting("linkFormatString", getLinkFormatString()));
+    }
+
+    private static final String thisClassnameDot = TopicTagPlugin.class.getName() + ".";
+
+    private String getSetting(String propName, String defaultValue)
+    {
+        String fullPropName = thisClassnameDot + propName;
+        String val = (String) RollerConfig.getProperty(fullPropName);
+        return (val != null) ? val : defaultValue;
+    }
+
+
+    // Private helper to URL encode the tag text.
+    private String urlEncode(String text)
+    {
+        // URL encode the searchtext
+        try
+        {
+            return URLEncoder.encode(text, "UTF-8");
+        }
+        catch (UnsupportedEncodingException uex)
+        {
+            // Should never actually occur for UTF-8.  If it does, we barf bitterly.
+            throw new RuntimeException(uex);
+        }
+    }
+
+
+    // Property getters and setters
+
+
+    public String getDefaultTopicSite()
+    {
+        return defaultTopicSite;
+    }
+
+    public void setDefaultTopicSite(String defaultTopicSite)
+    {
+        this.defaultTopicSite = defaultTopicSite;
+    }
+
+    public String getTagRegexWithBookmark()
+    {
+        return tagRegexWithBookmark;
+    }
+
+    public void setTagRegexWithBookmark(String tagRegexWithBookmark)
+    {
+        this.tagRegexWithBookmark = tagRegexWithBookmark;
+    }
+
+    public String getTagRegexWithoutBookmark()
+    {
+        return tagRegexWithoutBookmark;
+    }
+
+    public void setTagRegexWithoutBookmark(String tagRegexWithoutBookmark)
+    {
+        this.tagRegexWithoutBookmark = tagRegexWithoutBookmark;
+    }
+
+    public String getLinkFormatString()
+    {
+        return linkFormatString;
+    }
+
+    public void setLinkFormatString(String linkFormatString)
+    {
+        this.linkFormatString = linkFormatString;
+    }
+
+    public MessageFormat getLinkFormat()
+    {
+        return linkFormat;
+    }
+
+    public void setLinkFormat(MessageFormat linkFormat)
+    {
+        this.linkFormat = linkFormat;
+    }
+
+    public Pattern getTagPatternWithBookmark()
+    {
+        return tagPatternWithBookmark;
+    }
+
+    public void setTagPatternWithBookmark(Pattern tagPatternWithBookmark)
+    {
+        this.tagPatternWithBookmark = tagPatternWithBookmark;
+    }
+
+    public Pattern getTagPatternWithoutBookmark()
+    {
+        return tagPatternWithoutBookmark;
+    }
+
+    public void setTagPatternWithoutBookmark(Pattern tagPatternWithoutBookmark)
+    {
+        this.tagPatternWithoutBookmark = tagPatternWithoutBookmark;
+    }
+
+    public String getDefaultTopicBookmarkName()
+    {
+        return defaultTopicBookmarkName;
+    }
+
+    public void setDefaultTopicBookmarkName(String defaultTopicBookmarkName)
+    {
+        this.defaultTopicBookmarkName = defaultTopicBookmarkName;
+    }
+
+    public Map getUserBookmarks()
+    {
+        return userBookmarks;
+    }
+
+    public void setUserBookmarks(Map userBookmarks)
+    {
+        this.userBookmarks = userBookmarks;
+    }
+
+    public boolean getSkipOnSingleEntry() {return false;}
+}



Mime
View raw message