Plug-ins Developer Guide
From BlogBridge Wiki
Please check the Plug-ins User Guide for general information about BlogBridge plug-ins and their types.
Contents |
Plug-in Architecture
BlogBridge plug-in architecture is very simple. Every BlogBridge plug-in is placed into a package. The package can contain one or more plug-ins simultaneously. When a user enables such package, all BlogBridge plug-ins in it are enabled at the same time.
The package is a simple .ZIP file with an XML descriptor. XML descriptor is the heart of the package and contains the list of all plug-ins with their properties included in the package.
WARNING: The BlogBridge plug-in architecture is very young at the moment and will grow and change. Every change bringing incompatibility with previous versions will be highlighted in the main BlogBridge product blog.
Package Descriptor
The sample descriptor:
<package name="Sample Package"
description="The set of plug-ins."
version="1.0"
author="John Doe"
email="john@doe.com">
<theme file="themes/custom1.theme" />
<theme file="themes/custom2.theme" />
<actions bundle="keys" type="Key bindings" />
<resources bundle="sounds" />
<strings bundle="messages" />
<smartfeed name="Sample del.icio.us"
type="text"
mode="brief"
id="1001"
icon="delicious.gif"
url="http://del.icio.us/rss/tag/{query}"
parameter="Keys"
description="My custom del.icio.us Query Feed." />
<code class="com.my_site.plugins.CustomPlugin2" />
</package>
Every package descriptor has the mandatory section and optional list of BlogBridge plug-ins included. The mandatory section declares the name of the package, its short description, version and author coordinates:
<package name="Sample Package"
description="The set of plug-ins."
version="1.0"
author="John Doe"
email="john@doe.com">
The name of the package is used to display in the list of installed BlogBridge plug-ins in the Plug-in Manager dialog. It should be more or less unique, because the packages with the same name aren't allowed for installation simply to protect the user from a mess.
Note (Markus Merz): The CMS Textpattern is using a three letter prefix plus underscore for every Textpattern plug-in. Example: mma_plugin-name, where "mma_" is the prefix for the single developer. Maybe BlogBridge plug-in developers should use the same syntax? (To be discussed in the forum! Plug-Ins: Naming convention - three letter prefix for developer)
The description is a plain text message to be shown in the details box of the BlogBridge Plug-in Manager dialog when the plug-in row is selected in the list. It's a very good idea to shed the light on what the user should expect from the package: what are the key bindings you modify, what's the name of the theme or the smart feed, whatever necessary to spot the extensions you provide.
The version field is currently not used, but added for the forward compatibility and ease of reference. When a user reports the problem it's always convenient to know what version of your extension causes troubles.
The author and email fields are self-explanatory. You put your name and address there to be contacted in case of any troubles, comments and suggestions.
As you can see, the sample package descriptor declares:
- 2 new themes
- Key bindings bundle
- Resources bundle
- Strings bundle
- 1 new SmartFeed
- 2 code plug-ins
In the following sections we will discuss every one of these types in details.
Types
BlogBridge extension or plug-in can be of several types. As you can see from above, types are diverse and cover most of the application areas. BlogBridge plug-ins of some types can only be declared once per package as it doesn't make sense to include many of them, whereas other types allow multiple instances.
Themes
BlogBridge plug-ins of this type simply add another theme to the list on the General page of the Preferences dialog. A BlogBridge theme is a set of properties describing fonts and colors to be used in the application for rendering guide, feeds and articles panels. Every theme overrides the properties of the default theme (see sources: src/resources/themes/default.theme), which in turn overrides the properties taken from the native look.
To create a BlogBridge theme plug-in you need to create a text file with whatever overrides you have in mind. If you don't like the font of the text only, you create a theme file with the only line below to change select another font:
font=Verdana-11
To change, for example, the color of the background of an undiscovered blog link you add another line:
bloglink.undiscovered.background=#884455
You finish your custom BlogBridge theme by adding two more properties:
name=my-custom title=My Custom Theme
- name is unique name of your BlogBridge theme that will be used to refer to your theme internally.
- title is the name of your BlogBridge theme to show in the picker drop-down list.
After the theme file is ready, you add the line to the package descriptor:
<theme file="your_filename.theme" />
... and finally compress both files in the package (.ZIP).
Actions
An "Action" in BlogBridge is a command in all its variations. On the menus, on the toolbars, on the context menus.
An Action plug-in allows you to change the title, helptext, icon, keyboard shortcut, and other properties of each and every command. An Action plug-in doesn't require any programming, just two text files, the common package.xml descriptor file which all plug-ins have, and then the properties file containing the actual settings.
All commands have Action Codes, for example, sync.full or article.font.smaller. You use these codes in the properties file to indicate which commands should be overridden with what new properties. Take a look at the following samples:
article.show.unread.toolbar.label=&Unread Articles article.show.pinned.toolbar.tooltip=Flagged articles only
Here are all the suffixes that are available:
| Suffix | Meaning | Example |
| .label | Text label | article.show.unread.toolbar.label=&Unread Articles |
| .label.mac | Mac specific label | com.jgoodies.help.close.label.mac=Close Window |
| .tooltip | Tooltip | article.show.unread.toolbar.tooltip=Show only the articles that are still unread |
| .icon | icon | article.viewmode.mini.toolbar.icon=resources/viewmode/mini.png |
| .accelerator | keyboard shortcut | article.tags.accelerator=T |
| .accelerator.mac | Mac specific shortcut | feed.browse.accelerator.mac=meta shift B |
Analogically to the theme type, you create a file with all overrides for the keys and put it in the same package with the descriptor. Don't forget to add the line to the descriptor file to let the application know of your customization.
Take the sample line of the descriptor:
<actions bundle="keys" type="Key Bindings" />
and compare it to this:
<actions bundle="actions" />
There are two differences here:
- The name of the bundle. The name of the bundle is the name of your custom definitions file without the .properties extension. It's important that your files have this extension as it's required by the underlying framework. The name of the file however is your choice.
- The type of a plug-in of this sort is Actions by default. The type is shown in the description field of the Plug-in Manager along with the descriptor and author information. If you want, you can specify an alternative type (anything you like), as in the first example. Here's the list of allowed types:
- Actions - general actions type if you override many aspects
- Keys - use this if you change key bindings only
- Icons - use this if you assign new icons to actions
- Messages - use this if you change textual part (labels, tooltips, help strings etc)
Note: You can NOT have more than one plug-in of this type enabled at a time. The last enabled plug-in is used.
FYI: In case you are interested, BlogBridge has all its commands names, icons and key bindings declared in the Action.properties file which is included in the main BlogBridge distribution. If you are curious, you can find this file by simply examining the blogbridge.jar file or looking in the src folder of the source tree.
Resources
Just like with actions, BlogBridge holds links to almost every resource used in the application in its Resource.properties file: icons, external links, sound files, default theme and many more. You are free to change the values of these keys to provide your content instead of the defaults provided by us.
A "resource" type plug-in does not require any programming, just the creation of a few text files plus of course the resources you want to replace.
Again, you simply create a file, add whatever keys with alternative values you like and package it along with the descriptor. Please have a look at the descriptor below:
sound.no.unread=no-unread.wav sound.new.articles=new-articles.wav
Again the pattern repeats. Click here to see a list of all the kinds of resources, grouped by function.
In the descriptor XML file, just like for Actions, you specify the bundle file name without the .properties extension and the type of services your plug-in provides. Here's the list of types allowed for the resource plug-ins:
- Resources - general type if you change lots of things
- Icons - if you change icons
- Sounds - sounds if you change sounds
Using only Resources and Actions types of plug-ins you can redesign the look and feel of the application to your taste almost entirely. Keys, graphics, messages... everything is under control.
Note: You can NOT have more than one plug-in of this type enabled at a time. The last enabled plug-in is used.
Strings
Note: This type of plug-in became available only in BlogBridge 5.8
Strings are the sub-type of resources. The plug-ins of this type let you change / translate any messages used within the application (dialog boxes, tool-tips and many more).
A "strings" type plug-in does not require any programming, just the creation of a few text files plus of course the resources you want to replace.
You create a file, add whatever keys with alternative values you like and package it along with the descriptor. Please have a look at the descriptor below:
deletefeed.delete=&Удалить deletefeed.disable=&Выключить
In the descriptor XML file, just like for Actions, you specify the bundle file name without the .properties extension and the type of services your plug-in provides. Here's the list of types allowed for the strings plug-ins:
- Strings - default general
- Messages - simple alias to "Strings"
Using this type of plug-ins in conjunction with Resources and Actions, you can create a complete translation of BlogBridge.
Preferences
There are some hidden and uber-advanced preferences in BlogBridge. Normally, no one needs them, but sometimes the finest configuration may be necessary. It's possible to configure them through the properties section of the package descriptor. Please see the example below and the list of all possible keys at the moment.
<preferences> <property name="feeds.selectionDelay" value="1000" /> <property name="articles.showGroups" value="false" /> </preferences>
The above plug-in will disable the groups in the articles list panel and set the feed selection delay (the time in milliseconds between your click over the feed cell in the list and the moment the feed is actually selected) to 1 second.
| Property Name | Value Format | Description |
|---|---|---|
| discovery.skipExtensions | Example: "mp3, avi" | The list of file extensions not to try to discover when found in the link. |
| articles.showGroups | true / false | Enable / disable showing date groups in the articles list. |
| articles.showEmptyGroups | true / false | Enable / disable showing empty date groups. |
| feeds.selectionDelay | time in ms | The time between your clicking over the feed cell and the moment when the feed is selected and its contents are shown. |
| starz.topActivity | integer | The number of updates of a feed per day to count as the highest update rate (for BlogStarz computation) |
| starz.maxHightlights | integer | The number of keywords found in the article to consider as the highest rate (for BlogStarz computation) |
Smart Feeds
This is the first functional extension so far. As it comes from the name, you can add new types of Smart Feeds easily without a line of code. Take a look at this declaration:
<smartfeed name="Sample del.icio.us"
type="text"
mode="brief"
id="1001"
icon="delicious.gif"
url="http://del.icio.us/rss/tag/{query}?max={max}"
parameter="Keys"
description="My custom del.icio.us Query Feed." />
Even though del.icio.us Smart Feed is already included, it's a good example of how you could add another Smart Feed type.
The name is what the user sees in the Smart Feed picker drop-down. Try to make it descriptive, but not too long. It's a good idea to include the name of the service here too.
The type attribute is used to give a hint about what the content of the feed is going to be. There are several understood values:
- text - general text feed
- link - a feed with links instead of articles
- image - a photo-feed, like Flickr and other similar services provide
The mode attribute is clearly the default view mode of the feed. Possible values here are: full, brief and mini.
The id attribute is unique identifier of the SmartFeed. It is important that no one except for you uses this identifier. Currently there's no way to learn if some identifier is used by someone else or can be picked up, but when the centralized repository is started, this will become possible. For now just remember that the ID can't be less that 1000 as the first thousand of identities are reserved.
The icon attribute is used to specify the name of the icon file. Icons have 16x16 dimensions and are displayed in the Smart Feed selector drop-down along with the name. Supported formats are GIF, JPEG and PNG. Don't forget to package the image file.
In addition to everything above you need to specify the label for the field the user will be entering his query keys to in the Smart Feed properties dialog. This label is specified in the co-named attribute -- parameter. You can have only one parameter.
One of the last steps is to specify the description of your Smart Feed. Please examine the descriptions of standard feeds to see how we reflect the essence of a service provided. Try to follow the established scheme to make your Smart Feed look consistent.
Finally, the most important part of the declaration is the URL of the query. Have a close look at how we defined the query URL in our example above:
http://del.icio.us/rss/tag/{query}?max={max}
The markup of the URL should be clear to you from the first glance. When the application is required to query the service, it substitutes the {query} with encoded version of the keys the user entered in the Smart Feed properties. Optionally, if {max} is present in the URL template, it is replaced by the maximum number of articles limit. Not all services support the limit in their feed URLs (and del.icio.us one of them; it's just an example URL).
One thing to notice here is that it's possible to have multiple {query} and {max} in the URL, however, it's rarely needed.
Code
Code plug-ins can do almost anything. Period.
The only real requirement is to create a class implementing the com.salas.bb.plugins.domain.ICodePlugin interface. Enabled plug-ins are loaded during startup at the very beginning right after all the major components are initialized, but before the data is loaded and the main frame is displayed.
It's important to understand that there are two main phases in plug-in life cycle:
- Loading - when the plug-in is created and loaded into memory (the call of the constructor).
- Initialization - when it's asked to start working (the call of the initialize() method).
You see the distinction? Every plug-in installed in the system goes through the loading phase, but only enabled plug-ins through initialization. It's polite when you create the plug-in to simply store the preferences and other stuff you need during loading without actually touching any resources or making other CPU-, network-, user-expensive operations. It isn't the right time.
All you need to do to deliver the plug-in is to package it along with the descriptor preserving all the directories reflecting your full class name. The descriptor must contain the line, like below:
<code class="com.my_site.plugins.CustomPlugin1" />
You can have as many code plug-ins as you like and they will be loaded and initialized in the order of appearance.
Below is the source code of IPlugin and ICodePlugin interfaces. As it was said before, you need to implement ICodePlugin interface in your plug-in class.
/**
* Code plug-in interface.
*/
public interface ICodePlugin extends IPlugin
{
/**
* Sets the package loader to use for resources access.
*
* @param loader loader
*/
void setPackageLoader(ClassLoader loader);
/**
* Sets the parameters before the initialization.
*
* @param params parameters.
*/
void setParameters(Map<String, String> params);
}
/**
* Plug-in interface. The typical sequence of calls is.
*
* <ul>
* <li>Creation</li>
* <li>setParameters() - called to let the plug-in
* know of the parameters even between the initialization.</li>
* <li>initialize() - initialization of plug-in.
* Only enabled plug-ins are initialized during lading.</li>
* </ul>
*/
public interface IPlugin
{
/**
* Returns the name of plug-in type (Theme, Actions ...).
*
* @return the name of plug-in type.
*/
String getTypeName();
/** Initializes plug-in. */
void initialize();
}
- setPackageLoader provides your plug-in with the class loader to access any resources within your plug-in package
- setParameters passes the configuration parameters from the XML descriptor provided as property sub-elements (with name and value attributes) of the code element
- getTypeName is your opportunity to give the name of the type to show in the Plug-in Manager dialog.
- initialize is called once after the packageLoader and setParameters calls if and only if the plug-in is enabled.
If you have any questions, you can try looking for the answers in our Plug-ins Cookbook.
Toolbar
This type of plug-ins helps to redefine the look of the application tool bar. You can select either from actions that are already defined in the application, or from your own actions added to BlogBridge with Code plug-ins.
Here's an simple example:
<package name="Sample Toolbar"
description="Customizes the toolbar."
version="1.0"
author="Aleksey Gureiev"
email="spyromus@noizeramp.com">
<toolbar>
<action name="sync.full"
icon="resources/small-up.gif" />
<separator />
<action name="article.goto.next.unread.toolbar"
label="Next"
tooltip="Next unread article"
helptext="Goes to the next unread article"
icon="systray.icon" />
</toolbar>
</package>
What you can see is the redefinition of the tool bar. It states that there should be two action icons shown in it: "full synchronization" and "go to next unread article". There's a separator between them which is simply a gap. Even though you could specify only the name of the action, I added some other attributes (icon, label etc) to show what's possible to customize.
When you specify the icon, you can use either the path to the image file (gif, png, jpg) or the key from the Resources (either standard or added through the Resources plug-in). The engine will figure out what you have in mind automatically.
The label attribute changes the label of the action defined in the standard files.
The tooltip and helptext are self-explanatory. They provide additional text for the tooltip and the help line (in the status bar).
Debugging
There's one handy feature of plug-in framework. It "understands" folders when scans for installed plug-ins in the "plugins" folder inside your BlogBridge working folder. To quickly create and test your new extension, you can create a folder there, put package.xml descriptor there and all supplementary files, and work with all this as if it was packaged into .ZIP archive. Of course, you will need to restart the application to grab all the changes every time you make them, but still it's way simpler than making package archives every time.
Sample Plug-ins
Below is the list of sample plug-ins:
- themes.zip -- Themes plug-in sample: two simple themes as an example of packaging and overriding some basic properties
- actions-keys.zip -- Actions plug-in sample: an example of how to redefine keys of existing commands
- code-kayak-sf.zip -- Code plug-in sample: Kayak Travel SmartFeed (source code)
- resources-sounds.zip -- Resources plug-in sample: Illustrates how to override sounds.
- smartfeed-tailrank.zip -- SmartFeed plug-in sample: TailRank engine support.
- toolbar.zip -- Simple toolbar redefinition plug-in.
