Skip to content

Commit

Permalink
Merge branch 'release-1.0.0' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
DominicWatson committed Jul 18, 2023
2 parents 0747ee5 + 7b9b41a commit 38b86ec
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 90 deletions.
22 changes: 18 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
branch=${GITHUB_REF##*/}
publish=false
if [[ "{{ env.event.name }}" != "pull_request" ]] ; then
if [[ $branch == v* ]] ; then
if [[ $branch == release-* ]] || [[ $branch == v* ]] ; then
publish=true
fi
fi
Expand All @@ -24,12 +24,26 @@ jobs:
fetch-depth: 0

- name: Build jars
run: cd java-src && mvn package && mkdir ../lib && cp artifacts/*.jar ../lib/
run: cd java-src && mvn package

- name: Convert to bundle
run: |
cd java-src/artifacts && \
unzip cbjgroups-1.0.0.jar && \
echo "Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: CBJGroups Java Services
Bundle-SymbolicName: org.pixl8.cbjgroups
Bundle-Version: 1.0.0
" > META-INF/MANIFEST.MF && \
rm cbjgroups-1.0.0.jar && \
zip -rq cbjgroups-1.0.0.jar * && \
cp cbjgroups-1.0.0.jar ../../lib/
- name: Generate release version number
if: "env.PUBLISH == 'true'"
id: versiongen
uses: pixl8/github-action-twgit-release-version-generator@v1
uses: pixl8/github-action-twgit-release-version-generator@v2

- name: Inject version into box json
if: "env.PUBLISH == 'true'"
Expand All @@ -55,7 +69,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
tag_name: ${{ steps.versiongen.outputs.semver_release_string }}
release_name: Release ${{ steps.versiongen.outputs.semver_release_string }}
draft: false
prerelease: ${{ steps.versiongen.outputs.semver_release_is_snapshot }}
Expand Down
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.0.0

* Rewrite of service layer to use a proxy java object with OSGi bundle. Eliminates issues such as [#15](https://github.com/pixl8/cbjgroups/issues/15) + should perform slightly better (already performs well)

## 0.3.3

* [#14](https://github.com/pixl8/cbjgroups/issues/14) Fix issue with try/catch logic using Preside helper function that is unavailable to this non-Preside-specific service
Expand Down
16 changes: 16 additions & 0 deletions java-src/localBuild.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

rm -rf artifacts/*
mvn package || exit 1
cd artifacts
unzip cbjgroups-1.0.0.jar
echo "Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: CBJgroups Java Services
Bundle-SymbolicName: org.pixl8.cbjgroups
Bundle-Version: 1.0.0
" > META-INF/MANIFEST.MF
rm cbjgroups-1.0.0.jar
zip -rq cbjgroups-1.0.0.jar *

cp cbjgroups-1.0.0.jar ../../lib/
4 changes: 2 additions & 2 deletions java-src/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.8</source>
<target>1.8</target>
<includes>
<include>org/pixl8/cbjgroups/*.java</include>
</includes>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.pixl8.cbjgroups;

import java.io.File;
import java.io.FileInputStream;
import java.util.Map;
import java.io.FileNotFoundException;

import org.jgroups.*;
import lucee.runtime.Component;
import lucee.runtime.exp.PageException;
import lucee.loader.engine.CFMLEngineFactory;
import lucee.runtime.type.Struct;
import lucee.runtime.type.Array;


public class CbJGroupsClusterWrapper {

private JChannel _channel;

// CONSTRUCTOR
public CbJGroupsClusterWrapper( String configFilePath, Boolean discardOwnMessages, Component listenerCfc, Component loggerCfc, String contextRoot ) throws PageException, FileNotFoundException, Exception {
if ( configFilePath.length() > 0 ) {
_channel = new JChannel( new FileInputStream( new File( configFilePath ) ) );
} else {
_channel = new JChannel();
}

_channel.setDiscardOwnMessages( discardOwnMessages );
_channel.setReceiver( new CbJGroupsMessageReceiver( listenerCfc, loggerCfc, contextRoot ) );
}

// PUBLIC API
public Boolean connect( String clusterName ) throws Exception {
if ( !isConnected() ) {
_channel.connect( clusterName );
return isConnected();
}
return true;
}

public void close() {
_channel.disconnect();
_channel.close();
}

public Boolean isConnected() {
return _channel.isConnected();
}

public void sendMessage( String msg ) throws Exception {
_channel.send( new Message( null, msg.getBytes() ) );
}

public Struct getStats() throws PageException {
Struct stats = CFMLEngineFactory.getInstance().getCreationUtil().createStruct();
Array memberAddresses = CFMLEngineFactory.getInstance().getCreationUtil().createArray();
Address[] members = _channel.getView().getMembersRaw();
Map<String, Object> dumpStats = (Map<String, Object>)_channel.dumpStats().get( "channel" );

for (String key : dumpStats.keySet()) {
stats.put( key, dumpStats.get( key ) );
}
for( int i=0; i<members.length; i++ ) {
memberAddresses.append( members[i].toString() );
}

stats.put( "members", memberAddresses );
stats.put( "self", _channel.getAddress().toString() );
stats.put( "is_coordinator", members.length <= 1 || members[0].equals( _channel.getAddress() ) );

if ( _channel.isConnected() ) {
stats.put( "connection", "CONNECTED" );
} else if ( _channel.isConnecting() ) {
stats.put( "connection", "CONNECTING" );
} else if ( _channel.isOpen() ) {
stats.put( "connection", "DISCONNECTED" );
} else {
stats.put( "connection", "CLOSED" );
}

return stats;
}

public Boolean isCoordinator() {
Address[] members = _channel.getView().getMembersRaw();

return members.length <= 1 || members[0].equals( _channel.getAddress() );
}
}
2 changes: 2 additions & 0 deletions lib/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
115 changes: 33 additions & 82 deletions models/CbJGroupsCluster.cfc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Object to represent a cluster. Once instantiated,
* this object takes provides an API to run ColdBox
* this object provides an API to run ColdBox
* events across your cluster and takes care of
* receiving and processing requests from other
* members of your cluster.
Expand Down Expand Up @@ -37,14 +37,11 @@ component {
lock type="exclusive" name=_getLockname() timeout=0 {
if ( !_isConnected() ) {
_getLogger().info( "Connecting to jGroups cluster: [#_getClusterName()#]..." );
if ( !_isJChannelInitialized() ) {
_setupJChannel();
if ( !_isClusterInitialised() ) {
_setupCluster();
}

var channel = _getChannel();

channel.setReceiver( _setupReceiver() );
channel.connect( _getClusterName() );
_getClusterWrapper().connect( _getClusterName() );

_getLogger().info( "Connected to jGroups cluster: [#_getClusterName()#]" );
}
Expand All @@ -60,7 +57,7 @@ component {
public void function shutdown() {
try {
_getLogger().info( "Disconnecting from jGroups cluster [#_getClusterName()#]..." );
_getChannel().close();
_getClusterWrapper().close();
_getLogger().info( "Completed disconnecting from jGroups cluster [#_getClusterName()#]." );
} catch( any e ) {
_getLogger().error( e );
Expand All @@ -81,12 +78,12 @@ component {
, boolean prePostExempt = true
, boolean private = true
) {
_getChannel().send( _getMessage( SerializeJson( {
_getClusterWrapper().sendMessage( SerializeJson( {
event = arguments.event
, eventArguments = arguments.eventArguments
, prePostExempt = arguments.prePostExempt
, private = arguments.private
} ) ) );
} ) );
}

/**
Expand Down Expand Up @@ -120,30 +117,7 @@ component {
*
*/
public any function getStats() {
var stats = {};
var channel = _getChannel();
var members = channel.getView().getMembers();

stats.append( channel.dumpStats().channel );
stats.members = [];
stats.self = channel.getAddress().toString();

for( var i=1; i<=ArrayLen( members ); i++ ) {
stats.members.append( members[ i ].toString() );
}
stats.is_coordinator = ArrayLen( stats.members ) <= 1 || stats.members[ 1 ] == stats.self;

if ( channel.isConnected() ) {
stats.connection = "CONNECTED";
} else if ( channel.isConnecting() ) {
stats.connection = "CONNECTING";
} else if ( channel.isOpen() ) {
stats.connection = "DISCONNECTED";
} else {
stats.connection = "CLOSED";
}

return stats;
return _getClusterWrapper().getStats();
}

/**
Expand All @@ -152,11 +126,7 @@ component {
*
*/
public boolean function isCoordinator() {
var channel = _getChannel();
var members = channel.getView().getMembers();
var self = channel.getAddress().toString();

return ArrayLen( members ) <= 1 || members[ 1 ].toString() == self;
return _getClusterWrapper().isCoordinator();
}

/**
Expand All @@ -169,54 +139,41 @@ component {
}

// PRIVATE HELPERS
private void function _setupJChannel() {
var configXmlPath = _getJGroupsConfigXmlPath();
var channel = "";

// user specified config
if ( Len( Trim( configXmlPath ) ) ) {
if ( !FileExists( configXmlPath ) ) {
throw( type="cbjgroups.bad.config", message="The configured XML config file, [#configXmlPath#], could not be found." );
}
var configFile = CreateObject( "java", "java.io.File" ).init( configXmlPath );
channel = CreateObject( "java", "org.jgroups.JChannel", _getLib() ).init( configFile );

// default jgroups config
} else {
channel = CreateObject( "java", "org.jgroups.JChannel", _getLib() ).init();
}

channel.setDiscardOwnMessages( JavaCast( "Boolean", _getDiscardOwnMessages() ) );
private void function _setupCluster() {
_registerOsgiBundle();

_setChannel( channel );
_setClusterWrapper( CreateObject( "java", "org.pixl8.cbjgroups.CbJGroupsClusterWrapper", "org.pixl8.cbjgroups" ).init(
_getJGroupsConfigXmlPath() // configFilePath
, _getDiscardOwnMessages() // discardOwnMessages
, this // listenerCfc
, _getLogger() // loggerCfc
, ExpandPath( "/" ) // contextRoot
) );
}

private any function _setupReceiver(){
return CreateObject( "java", "org.pixl8.cbjgroups.CbJGroupsMessageReceiver", _getLib() ).init(
this // ListenerCFC
, _getLogger() // LoggerCFC
, ExpandPath( "/" ) // Context path
);
}
private function _registerOsgiBundle() {
if ( !StructKeyExists( application, "_cbjgroupsBundleRegistered" ) ) {
var cfmlEngine = CreateObject( "java", "lucee.loader.engine.CFMLEngineFactory" ).getInstance();
var osgiUtil = CreateObject( "java", "lucee.runtime.osgi.OSGiUtil" );
var lib = ExpandPath( GetDirectoryFromPath(GetCurrentTemplatePath()) & "../lib/cbjgroups-1.0.0.jar" );
var resource = cfmlEngine.getResourceUtil().toResourceExisting( getPageContext(), lib );

private array function _getLib() {
return DirectoryList( ExpandPath( GetDirectoryFromPath(GetCurrentTemplatePath()) & "../lib" ), false, "path" );
osgiUtil.installBundle( cfmlEngine.getBundleContext(), resource, true );

application._cbjgroupsBundleRegistered = true;
}
}

private any function _setupApplicationContext() {
getPageContext().setApplicationContext( _getApplicationContext() );
}

private any function _getMessage( required string message ) {
return CreateObject( "java", "org.jgroups.Message", _getLib() ).init( NullValue(), _stringToBinary( arguments.message ) );
}

private boolean function _isConnected() {
return _isJChannelInitialized() && _getChannel().isConnected();
return _isClusterInitialised() && _getClusterWrapper().isConnected();
}

private boolean function _isJChannelInitialized() {
var channel = _getChannel();
private boolean function _isClusterInitialised() {
var channel = _getClusterWrapper();

return !IsNull( local.channel );
}
Expand All @@ -225,12 +182,6 @@ component {
return _getColdbox().getInterceptorService().processState( argumentCollection=arguments );
}

private any function _stringToBinary( required string stringValue ){
var base64Value = ToBase64( stringValue );
var binaryValue = ToBinary( base64Value );

return binaryValue ;
}
private any function _binaryToString( required any binaryValue ){
return ToString( arguments.binaryValue );
}
Expand All @@ -250,10 +201,10 @@ component {
_applicationContext = arguments.applicationContext;
}

private any function _getChannel() {
private any function _getClusterWrapper() {
return _channel ?: NullValue();
}
private void function _setChannel( required any channel ) {
private void function _setClusterWrapper( required any channel ) {
_channel = arguments.channel;
}

Expand Down
1 change: 0 additions & 1 deletion models/CbJGroupsClusterFactory.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ component {
}
}


// PRIVATE HELPERS
private struct function _getClusterSettings( required string clusterName ) {
return {
Expand Down

0 comments on commit 38b86ec

Please sign in to comment.