Skip to content

Instantly share code, notes, and snippets.

@fabiomontefuscolo
Last active August 18, 2023 22:01
Show Gist options
  • Save fabiomontefuscolo/42b144cc5803051281fc9a1be3286bf7 to your computer and use it in GitHub Desktop.
Save fabiomontefuscolo/42b144cc5803051281fc9a1be3286bf7 to your computer and use it in GitHub Desktop.
Starting plugin development in Openfire

New Openfire Plugin

Install requirements

$ sudo pacman -S \
	intellij-idea-community-edition \
	jre8-openjdk \
	maven

Environment

$ export WORKSPACE_FOLDER=/home/fabio/Work/avantech

Openfire

Getting the code

$ git clone --depth=1 https://github.com/igniterealtime/Openfire.git openfire

Building the project

$ cd openfire
$ mvn verify
$ cd ..

A dumb plugin

Creating folders

$ mkdir -p example-plugin/src/web
$ mkdir -p example-plugin/src/java/br/com/example

Creating the pom.xml

$ cat > example-plugin/pom.xml <<'EOF'
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>plugins</artifactId>
        <groupId>org.igniterealtime.openfire</groupId>
        <version>4.3.0-beta</version>
    </parent>
    <groupId>org.igniterealtime.openfire.plugins</groupId>

    <artifactId>exampleplugin</artifactId>
    <version>0.1</version>
    <name>Example Plugin</name>
    <description>A start point to create a new plugin</description>

    <organization>
        <name>Example Organization</name>
        <url>https://example-url.com.br/</url>
    </organization>

    <developers>
        <developer>
            <id>exampleuserid</id>
            <name>Example Author</name>
            <email>example@email.com</email>
            <organization>Example Organization</organization>
        </developer>
    </developers>

    <build>
        <sourceDirectory>src/java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <!-- FIXME: This temporarily overrides the provided plugin, to set appendAssemblyId and attach to true.
                     This change should be pushed down to the parent project, after the development to distribute plugins via Maven has settled. -->
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.6</version>
                <dependencies>
                    <dependency>
                        <groupId>org.igniterealtime.openfire.plugins</groupId>
                        <artifactId>openfire-plugin-assembly-descriptor</artifactId>
                        <version>${openfire.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <appendAssemblyId>true</appendAssemblyId>
                            <finalName>${plugin.name}</finalName>
                            <attach>true</attach>
                            <!-- This is where we use our shared assembly descriptor -->
                            <descriptorRefs>
                                <descriptorRef>openfire-plugin-assembly</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
                <!-- End of override -->
            </plugin>
            <!-- Compiles the Openfire Admin Console JSP pages. -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-jspc-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <dependencies>
    </dependencies>

    <distributionManagement>
        <!-- Repository in which we deploy this project, when desired. -->
        <repository>
            <id>igniterealtime</id>
            <name>Ignite Realtime Repository</name>
            <url>https://www.igniterealtime.org/archiva/repository/maven/</url>
        </repository>
    </distributionManagement>

    <repositories>
        <!-- Where we obtain dependencies. -->
        <repository>
            <id>igniterealtime</id>
            <name>Ignite Realtime Repository</name>
            <url>https://igniterealtime.org/archiva/repository/maven/</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <!-- Typically used to retrieve Maven plugins used by this project from. This
             apparently is also used to obtain the dependencies _used by_ plugins
             (eg: openfire-plugin-assembly-descriptor) -->
        <pluginRepository>
            <id>igniterealtime</id>
            <name>Ignite Realtime Repository</name>
            <url>https://igniterealtime.org/archiva/repository/maven/</url>
        </pluginRepository>
    </pluginRepositories>
</project>
EOF

Creating the plugin.xml

$ cat > example-plugin/plugin.xml <<'EOF' 
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <class>br.com.example.ExamplePlugin</class>
    <name>Example Plugin</name>
    <description>A start point to create a new plugin</description>
    <author>Example author</author>
    <version>${project.version}</version>
    <date>1/2/2019</date>
    <minServerVersion>4.3.2</minServerVersion>
</plugin>
EOF

Creating the plugin main class

$ cat > example-plugin/src/java/br/com/example/ExamplePlugin.java <<'EOF' 
package br.com.example;

import java.io.File;
import java.security.Security;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
  * This class initialize the ExamplePlugin
  */
public class ExamplePlugin implements Plugin
{
    private static final Logger Log = LoggerFactory.getLogger( ExamplePlugin.class );

    @Override
    public void initializePlugin( PluginManager manager, File pluginDirectory )
    {
        Log.info("Initializing Example Plugin");
    }

    @Override
    public void destroyPlugin()
    {
        Log.info("Destroying Example Plugin");
    }
}
EOF

Verify if dumb plugin compile

$ cd example-plugin
$ mvn verify 

Development

Setting up IDEA

  1. Execute idea
  2. Click on Import Project
  3. Select the Openfire directory
  4. Select Maven option and clik on Next
  5. Click on Next
  6. Click on Next
  7. Click on Next
  8. Check if JRE is select and click on Next
  9. Give Project name the value openfire and click on Finish
  10. Click on File > Project Structure
  11. Got to modules section
  12. Click on + sign in the top of second column
  13. Click on Import module
  14. Select example-plugin
  15. Select Maven option and clik on Next
  16. Click on Next
  17. Click on Next
  18. Click on Finish
  19. Click on Ok
  20. Click on Run > Edit Configurations
  21. Click on + sign and select Remote
  22. Change the Name from Unamed to Attach on Openfire
  23. Copy the content of Command line arguments for remote JVM, it will be something like -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

Running Openfire

The only I could have breakpoints during development was adding manually the options -DpluginDirs, -Dexample-plugin.classes, -Dexample-plugin.webRoot. Even passing these options, depending the type of change made in source code, it will be necessary to restart Openfire.

$ cd openfire
$ java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
	-Dlog4j.configurationFile=${WORKSPACE_FOLDER}/openfire/distribution/target/distribution-base/lib/log4j2.xml \
	-server \
	-DopenfireHome="${WORKSPACE_FOLDER}/openfire/distribution/target/distribution-base" \
	-DpluginDirs="${WORKSPACE_FOLDER}/example-plugin" \
	-Dexample-plugin.classes="target/classes" \
	-Dexample-plugin.webRoot="src/web" \
	-Dopenfire.lib.dir="${WORKSPACE_FOLDER}/openfire/distribution/target/distribution-base/lib" \
	-classpath "${WORKSPACE_FOLDER}/openfire/distribution/target/distribution-base/lib/startup.jar" \
	-jar "${WORKSPACE_FOLDER}/openfire/distribution/target/distribution-base/lib/startup.jar"

You should see an output like

Listening for transport dt_socket at address: 5005
Openfire 4.4.0 Alpha [Feb 21, 2019 5:05:11 PM]
Admin console listening at:
  http://localhost:9090
  https://localhost:9091
Successfully loaded plugin 'admin'.
Plugin 'example-plugin' is running in development mode.
Successfully loaded plugin 'example-plugin'.
Successfully loaded plugin 'search'.
Finished processing all plugins.

That is it. Have fun

@abdurrahmanekr
Copy link

And in the meantime, I used the plugin in the /plugins directory instead of running it in the main (/) directory.

@fabiomontefuscolo
Copy link
Author

@abdurrahmanekr it was very dirty, but I took all deps maven downloaded and uncompressed that in the classes folder.

@parcool
Copy link

parcool commented Apr 21, 2020

why my jar has only two folder that com.xxx and META-INF?

@fabiomontefuscolo
Copy link
Author

Hi @parcool. I think you should have two jars. One will have the word assembly in the name. You should use this one.

@CoalDev
Copy link

CoalDev commented Aug 18, 2023

Hey, how do I run system commands (ie: getRuntime().exec()) in a plugin? I'm new to this and like a bit of help :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment