-
1. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 15, 2013 8:52 AM (in response to janssk77)The best way to do this involves creating a custom MSC service in combination with a ServiceActivator.
e.g.
First create an MSC service that creates the counter service:
{code}
public class MyCounterService implements org.jboss.msc.service.Service<CounterService> {
private final Value<Channel> channel;
private volatile CounterService service;
public MyCounterService(Value<Channel> channel) {
this.channel = channel;
}
@Override
public CounterService getValue() {
return this.service;
}
@Override
public void start(StartContext context) {
this.service = new CounterService((JChannel) this.channel.getValue());
}
@Override
public void stop(StopContext context) {
this.service = null;
}
}
{code}
Next, create a service activator that installs your counter service injecting the desired channel:
{code}
public class MyCounterServiceActivator implements org.jboss.msc.service.ServiceActivator {
private static final ServiceName SERVICE_NAME = ...; // The service name of the counter service
private static final String CHANNEL_NAME = ...; // The name of the channel used by the counter service
@Override
public void activate(ServiceActivatorContext context) {
InjectedValue<Channel> channel = new InjectedValue<Channel>();
context.getServiceTarget().addService(SERVICE_NAME, new MyCounterService(channel))
.addDependency(ServiceName.JBOSS.append("jgroups", "channel", CHANNEL_NAME), Channel.class, channel)
.setInitialMode(ServiceController.Mode.ACTIVE)
.install()
;
}
}
{code}
Finally, add a META-INF/services/org.jboss.msc.service.ServiceActivator file to your deployment that specifies the fully qualified class name of your MyCounterServiceActivator class. When you deploy your application, the AS will locate and activate any service activators defined by your deployment. Your service activator will then create the CounterService using a given channel.
-
2. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 29, 2013 6:00 PM (in response to pferraro)I want to do something similar with the LockService. Will this code work for that service as well? If so, can you tell me what the values should be for "SERVICE_NAME" and "CHANNEL_NAME"? I'm not sure where these should come from.
Thanks,
Dave. -
3. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 30, 2013 11:00 AM (in response to drathnow)Yes - this code should work for LockService as well.
The code above assumes that the channel with the given service name exists.
If you want to create a new channel for use with these services, you'll need to install a separate channel service, and make sure the MyCounterService starts/stops the channel.
Here's the above example modified to create a LockService, complete with functional channel/service names.
e.g.
{code}public class MyLockService implements org.jboss.msc.service.Service<LockService> {
private final Value<Channel> channel;
private final String cluster;
private volatile LockService service;
public MyLockService(Value<Channel> channel, String cluster) {
this.channel = channel;
this.cluster = cluster;
}
@Override
public LockService getValue() {
return this.service;
}
@Override
public void start(StartContext context) throws StartException {
JChannel channel = (JChannel) this.channel.getValue();
this.service = new LockService(channel);
try {
channel.connect(this.cluster);
} catch (Exception e) {
throw new StartException(e);
}
}
@Override
public void stop(StopContext context) {
this.channel.getValue().close();
this.service = null;
}
}{code}
{code}public class MyLockServiceActivator implements org.jboss.msc.service.ServiceActivator {
@Override
public void activate(ServiceActivatorContext context) {
String cluster = "lock"; // Any name to uniquely identify the cluster
ServiceName channelName = ChannelService.getServiceName(cluster); // Generates the appropriate service name for a channel
ServiceName lockName = channelName.append("service"); // Any service name to unique identify the lock service
ServiceTarget target = context.getServiceTarget();
// Creates the lock service
InjectedValue<Channel> channel = new InjectedValue<Channel>();
target.addService(counterName, new MyLockService(channel, cluster))
.addDependency(channelName, Channel.class, channel)
.setInitialMode(ServiceController.Mode.ACTIVE)
.install()
;
// Creates the requisite channel service used by the counter service
InjectedValue<ChannelFactory> factory = new InjectedValue<ChannelFactory>();
target.addService(channelName, new ChannelService(cluster, factory))
.addDependency(ChannelFactoryService.getServiceName(null), ChannelFactory.class, factory) // Use the default-stack
.setInitialMode(ServiceController.Mode.ON_DEMAND)
.install()
;
}
}{code}
-
4. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 30, 2013 1:10 PM (in response to pferraro)Thanks for taking the time to answer this. However, I have to admit, I'm unsure how to use ServiceActivator.
Could you provide a brief description or point me to some documentation where I can read about it myself. I've been searching the JBoss web site but haven't found where it's documented.
Thanks.
-
5. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 30, 2013 2:30 PM (in response to drathnow)Upon deployment, the AS will load any ServiceActivator classes via ServiceLoader and call their activate(...) method.
To do this, you need to add a META-INF/services/org.jboss.msc.service.ServiceActivator file to your application archive containing the fully qualified class name of your MyLockServiceActivator class.
-
6. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 30, 2013 2:35 PM (in response to pferraro)That much if figured out but how do I find my service at runtime?
-
7. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 30, 2013 5:10 PM (in response to drathnow)I can think of 2 ways off the top of my head...
The quick and dirty way:
{code}ServiceController<?> controller = org.jboss.as.clustering.msc.ServiceContainerHelper.getService(lockName);
LockService service = org.jboss.as.clustering.msc.ServiceContainerHelper.getValue(controller, LockService.class);{code}
The more elegant way:
Bind the LockService to JNDI in your service activator.
e.g.
{code}String jndiName = "java:jboss/my-lock-service"; // Pick any jndi name
ContextNames.BindInfo bindInfo = ContextNames.bindInfoFor(jndiName);
BinderService binder = new BinderService(bindInfo.getBindName());
target.addService(bindInfo.getBinderServiceName(), binder)
.addAliases(ContextNames.JAVA_CONTEXT_SERVICE_NAME.append(jndiName))
.addDependency(lockName, LockService.class, new ManagedReferenceInjector<LockService>(binder.getManagedObjectInjector()))
.addDependency(bindInfo.getParentContextServiceName(), ServiceBasedNamingStore.class, binder.getNamingStoreInjector())
.setInitialMode(ServiceController.Mode.PASSIVE)
.install()
;{code}
Now you can inject the LockService wherever needed:
e.g.
{code}@Resource(lookup = "java:jboss/my-lock-service")
private LockService service;{code}
-
8. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 30, 2013 10:45 PM (in response to pferraro)Well, I decided to try the elegant approach but I've hit a snag. I put the code in place but when I attempt to start my app, I'm getting the exceptions below:
20:04:47,409 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-7) MSC00001: Failed to start service jboss.deployment.subunit."myapp.ear"."myapp-ejb-6.0.0.jar".INSTALL: org.jboss.msc.service.StartException in service jboss.deployment.subunit."myapp.ear"."myapp-ejb-6.0.0.jar".INSTALL: Failed to process phase INSTALL of subdeployment "myapp-ejb-6.0.0.jar" of deployment "myapp.ear"
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:119) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [rt.jar:1.7.0_06]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [rt.jar:1.7.0_06]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_06]
Caused by: java.lang.NoClassDefFoundError: org/jboss/as/clustering/jgroups/subsystem/ChannelService
at zedi.myapp.app.msc.MyLockServiceActivator.activate(MyLockServiceActivator.java:23)
at org.jboss.as.server.deployment.service.ServiceActivatorProcessor.deploy(ServiceActivatorProcessor.java:62) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:113) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
... 5 more
Caused by: java.lang.ClassNotFoundException: org.jboss.as.clustering.jgroups.subsystem.ChannelService from [Module "deployment.myapp.ear.myapp-ejb-6.0.0.jar:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) [jboss-modules.jar:1.1.1.GA]
... 8 more
For some reason, ChannelService can't be found, yet it is in one of the provided jboss jar files. My ear looks like this:
myapp.ear
|-- myapp.jar <---ejb
|-- myapp.ejb <---ejb
|-- myapp.war <---war
|--- \lib <-- lib with jars
Any ideas why ChannelService isn't being found?
Here is what my code looks like:
public class MyLockServiceActivator implements org.jboss.msc.service.ServiceActivator {
@Override
public void activate(ServiceActivatorContext context) {
String cluster = "cluster";
ServiceName channelName = ChannelService.getServiceName(cluster);
ServiceName lockName = channelName.append("lock-service");
ServiceTarget target = context.getServiceTarget();
InjectedValue<Channel> channel = new InjectedValue<Channel>();
target.addService(lockName, new MyLockService(channel, cluster))
.addDependency(channelName, Channel.class, channel)
.setInitialMode(ServiceController.Mode.ACTIVE)
.install();
InjectedValue<ChannelFactory> factory = new InjectedValue<ChannelFactory>();
target.addService(channelName, new ChannelService(cluster, factory))
.addDependency(ChannelFactoryService.getServiceName(null), ChannelFactory.class, factory)
.setInitialMode(ServiceController.Mode.ON_DEMAND)
.install();
String jndiName = "java:jboss/myapp/cluster-lock-service";
ContextNames.BindInfo bindInfo = ContextNames.bindInfoFor(jndiName);
BinderService binder = new BinderService(bindInfo.getBindName());
target.addService(bindInfo.getBinderServiceName(), binder)
.addAliases(ContextNames.JAVA_CONTEXT_SERVICE_NAME.append(jndiName))
.addDependency(lockName, LockService.class, new ManagedReferenceInjector<LockService>(binder.getManagedObjectInjector()))
.addDependency(bindInfo.getParentContextServiceName(), ServiceBasedNamingStore.class, binder.getNamingStoreInjector())
.setInitialMode(ServiceController.Mode.PASSIVE)
.install();
}
}
public class MyLockService implements org.jboss.msc.service.Service<LockService> {
private final Value<Channel> channel;
private final String cluster;
private volatile LockService service;
public MyLockService(Value<Channel> channel, String cluster) {
this.channel = channel;
this.cluster = cluster;
}
@Override
public LockService getValue() {
return this.service;
}
@Override
public void start(StartContext context) throws StartException {
JChannel channel = (JChannel) this.channel.getValue();
this.service = new LockService(channel);
try {
channel.connect(this.cluster);
} catch (Exception e) {
throw new StartException(e);
}
}
@Override
public void stop(StopContext context) {
this.channel.getValue().close();
this.service = null;
}
}
-
9. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 30, 2013 11:02 PM (in response to drathnow)And BTW: where is
org.jboss.as.clustering.msc.ServiceContainerHelper?
It doesn't seem to exist in JBossAS 7.1.1 -
10. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 31, 2013 2:45 PM (in response to drathnow)After plugging away at this for a couple of hours, I was able to solve the ClassNotFound issues. I had to add the necessary incantations to my MANIFEST.MF file:
Dependencies: org.jboss.as.clustering.jgroups services export, org.jboss.as.naming
But now I'm stuck on this error:
JBAS014775: New missing/unsatisfied dependencies:
service jboss.jgroups.stack (missing) dependents: [service jboss.jgroups.channel.cluster]
Thoughts?
-
11. Re: Using jgroups CounterService with jboss's cluster channel
drathnow Jan 31, 2013 3:27 PM (in response to drathnow)Finally!
Getting this to work was an effort but, in doing so, I cleaned up a few things in my app that would've ultimiately come back to haunt me. The issue with the "missing/unsatisfied dependencies" was simply that I was using a profile from the domain.xml file that did not have a jgroups subsystem defined.(Oops! ) Once I added that, I ended up with other errors that exposed other problems. The worst being that I had an extra copy of the jgroups jar under my lib folder of my ear. I thought it needed to be there because of the ClassNotFoundExceptions I was getting but it ended up causing ClassCastExceptions when it was there....and on it went...
The code that Paul provided works fine but in order to get it working, I had to make sure that the appropriate dependencies were in the MANIFEST.MF files (i.e. the jar or ejb file that contains the MyLockServiceActivator class). The ones that eventually did it for me were:
Dependencies: org.jboss.as.clustering.jgroups,
org.jgroups,
org.jboss.as.naming
As Paul pointed out, the other thing that needs to be done is to create a folder under you META-INF directory calleed "services" and create a file called "org.jboss.msc.service.ServiceActivator" that contains the fully qualified name of the ServiceActivator implemenation (in my case my MyLockServiceActivator).
Thanks Paul for all your help!
-
12. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 31, 2013 3:28 PM (in response to drathnow)IIRC, ServiceContainerHelper is new to 7.1.3.Final.
-
13. Re: Using jgroups CounterService with jboss's cluster channel
pferraro Jan 31, 2013 3:29 PM (in response to drathnow)Congrats!