I started creating an OSGI project with Spring DM. I Created two bundles, the first one (bundle1) provides a service that changes the order of a recieved string. The seconde one (bundle2) consumes that service and prints the result in the console.
service implementation:
public final class Bundle1ServiceImpl implements Bundle1Service {
public Bundle1ServiceImpl() {
System.out.println("Bundle1ServiceImpl contructor...");
}
public String scramble(String text) {
List charList = new ArrayList();
char[] textChars = text.toCharArray();
for (int i = 0; i < textChars.length; i++) {
charList.add(new Character(textChars[i]));
}
Collections.shuffle(charList);
char[] mixedChars = new char[text.length()];
for (int i = 0; i < mixedChars.length; i++) {
mixedChars[i] = ((Character) charList.get(i)).charValue();
}
return new String(mixedChars);
}}
spring file for service provider :
bundle1-osgi.xml
<service ref="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
bundle1-context.xml
<bean id="bundle1Service" class="fr.thispro.bundle1.internal.Bundle1ServiceImpl">
</bean>
consumer :
public class Bundle2Consumer {
private final Bundle1Service service;
public Bundle2Consumer(Bundle1Service service) {
this.service = service;
}
public void start() {
System.out.println(service.scramble("Text"));
System.out.println("im started");
}
public void stop() {
System.out.println("im stopped");
}}
spring files for consumer:
bundle2-context.xml
<beans:bean id="consumer" class="fr.thispro.bundle2.Bundle2Consumer" init-method="start" destroy-method="stop" lazy-init="false" ><beans:constructor-arg ref="bundle1Service"/>
bundle2-osgi.xml
<reference id="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
The service is well registred referenced and discovered. But the consumer doesn't print anything even when i start it explicitly by start command.
Thanks in adanvance,
I found the problem. You bundle2 incldues an Activtor but you did not define the activator in the Manifest. So the bundle never actually starts up.
If you intended to start the bundle2 using spring dm then the problem is that the jar does not contain the spring xml files.
Related
I can't get this working, I've googled and probably found every page on how to do this, all two of them!
Basically I'm just trying to get SF Remoting V2 working from a stateless .NET Core 2 MVC App' to a Statefull service.
Here's what I have done:
Client Code in Controller: (Simplified as much as Possible):
public class ValuesController : Controller
{
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
// Provide certificate details.
var serviceProxyFactory = new ServiceProxyFactory((c) => new FabricTransportServiceRemotingClientFactory());
var proxy = serviceProxyFactory.CreateServiceProxy<ICallMe>(new Uri("fabric:/SFExperiment/Stateful1"));
var value3 = await proxy.GetGreeeting("Bob");
return new[] { "value1", "value2", value3 };
}
Service Code Interface:
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Remoting;
using Microsoft.ServiceFabric.Services.Remoting.FabricTransport;
[assembly: FabricTransportServiceRemotingProvider(RemotingListener =
RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
namespace Stateful1.Abstractions
{
public interface ICallMe : IService
{
Task<string> GetGreeeting(string name);
}
}
Service Code:
Public sealed class Stateful1 : StatefulService, ICallMe
{
public Stateful1(StatefulServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
public Task<string> GetGreeeting(string name)
{
return Task.FromResult(#"Congratulations, you have remoting working. :-) ");
}
I have added below to ServiceManifest.xml
<Resources>
<Endpoints>
<!-- To enable Service remonting for remoting services V2-->
<Endpoint Name="ServiceEndpointV2" />
<Endpoint Name="ReplicatorEndpoint" />
</Endpoints>
</Resources>
And it doesn't work.. I get the following Exception:
Invalid partition key/ID '{0}' for selector {1}
What am I doing wrong?
In the call to create a service proxy, you must specify a partition key because you are connecting to a stateful service.
long partitionKey = 0L; //TODO: Determine partition key
var proxy = serviceProxyFactory.CreateServiceProxy<ICallMe>(new Uri("fabric:/SFExperiment/Stateful1"), new ServicePartitionKey(partitionKey), TargetReplicaSelector.PrimaryReplica);
Also, make sure you reuse your service proxy factory, instead of creating a new one.
Have a look at this code for example.
So I am wrapping the Spring Integration TCP client to provide APIs for my application. Previous questions regarding this can be found here and here. The problem with this is that the gateway.send() doesn't end at all and the API response never comes back.
Here is my ServerConnection.java file:
package com.abc.xyz.serverconnection;
import org.springframework.context.support.GenericXmlApplicationContext;
public class ServerConnections {
private SimpleGateway gateway;
public ServerConnections() {
final GenericXmlApplicationContext context = setupContext();
this.setGateway(context.getBean(SimpleGateway.class));
}
public static GenericXmlApplicationContext setupContext() {
final GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/integration/tcpClientServerDemo-context.xml");
context.registerShutdownHook();
context.refresh();
return context;
}
public SimpleGateway getGateway() {
return gateway;
}
public void setGateway(SimpleGateway gateway) {
this.gateway = gateway;
}
public boolean sendData(String input) {
this.gateway.send(input);
return true;
}
public void recieveData(String output) {
System.out.println("Data from server:" + output);
}
}
In my controller, I do something like this:
#RequestMapping(value = "/logon", method = RequestMethod.GET)
#ResponseBody
public String logon() {
// logics go here and the result is stored like below and sent
String message = "0000005401F40000C1E3E304010000000020000000000000000000000000000000000000000000004040404040404040C1E3E300C1C2C3C4C5C6C7C8E8C5E2C8E6C1D540F1F7F24BF0F1F64BF0F0F34BF0F5F200";
if (serverConnections.sendData(message)) {
return "Data sent successfully!";
} else {
return "Data not sent!";
}
}
Here is how my config looks like:
<context:property-placeholder />
<int:channel id="input" />
<int:channel id="toSA" />
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
<bean id="echoService" class="com.abc.xyz.serverconnection.ServerConnection" />
<bean id="CustomSerializerDeserializer" class="com.abc.xyz.serverconnection.CustomSerializerDeserializer" />
<int:object-to-string-transformer id="serverBytes2String"
input-channel="serverBytes2StringChannel"
output-channel="toSA"/>
<int:gateway id="gw"
service-interface="com.abc.xyz.serverconnection.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="<ip>"
serializer="CustomSerializerDeserializer"
deserializer="CustomSerializerDeserializer"
port="6100"
single-use="false" />
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="serverBytes2StringChannel"
connection-factory="client" />
EDIT: Not able to get the DEBUG log of the application since I am using the TCP client implementation as a Maven Module inside a Maven Project. Another module uses this as a dependency and that is where the REST API end-points reside at.
I think your
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
Doesn't return any result to be sent to the replyChannel header, meanwhile your gateway.send() isn't a void method. That's how it waits for the reply which never comes back.
Is there a work-around to get Spring to handle incoming messages from XMPP? I have tried many different configurations to get an inbound-channel-adapter to respond to incoming XMPP messages and nothing happens. I know that they show up at the Spring Integration layer (I can see that in the logs) but they are ignored. Is there any way to get them into my application layer? I hope to avoid needing to make changes to Spring Integration itself if I can.
Here is my integration configuration:
<int-xmpp:inbound-channel-adapter id="gcmIn"
channel="gcmInChannel"
xmpp-connection="gcmConnection"
auto-startup="true"
/>
<bean id="inboundBean" class="example.integration.GcmInputHandler"/>
<int:service-activator input-channel="gcmInChannel" output-channel="nullChannel" ref="inboundBean" method="handle"/>
Using the outbound-channel-adapter works fine. I can send messages over GCM 100% easily. But inbound does nothing, even though I know the messages are coming in.
Thanks
Not a very clean one, you would need to overwrite the ChatMessageListeningEndpoint, which drops all empty body messages.
This one needs then to be used as inbound-channel adapter in your config.
In addition you need to register the GCM package extension on the Smack Provider Manager, otherwise you lose the JSON message.
Working on a sample project -- so if you need more help let me know and I will post a link as soon it works somehow in a understandable way.
Here a sample GCM Input Adapter
public class GcmMessageListeningEndpoint extends ChatMessageListeningEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(GcmMessageListeningEndpoint.class);
#Setter
protected PacketListener packetListener = new GcmPacketListener();
protected XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
public GcmMessageListeningEndpoint(XMPPConnection connection) {
super(connection);
ProviderManager.addExtensionProvider(GcmPacketExtension.GCM_ELEMENT_NAME, GcmPacketExtension.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
#Override
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
super.setHeaderMapper(headerMapper);
this.headerMapper = headerMapper;
if (this.headerMapper == null) throw new IllegalArgumentException("Null XmppHeaderMapper isn't supported!");
}
public String getComponentType() {
return "xmpp:inbound-channel-adapter-gcm";
}
#Override
protected void doStart() {
Assert.isTrue(this.initialized, this.getComponentName() + " [" + this.getComponentType() + "] must be initialized");
this.xmppConnection.addPacketListener(this.packetListener, null);
}
#Override
protected void doStop() {
if (this.xmppConnection != null) {
this.xmppConnection.removePacketListener(this.packetListener);
}
}
class GcmPacketListener implements PacketListener {
#Override
public void processPacket(Packet packet) throws NotConnectedException {
if (packet instanceof org.jivesoftware.smack.packet.Message) {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) packet;
Map<String, ?> mappedHeaders = headerMapper.toHeadersFromRequest(xmppMessage);
sendMessage(MessageBuilder.withPayload(xmppMessage).copyHeaders(mappedHeaders).build());
} else {
LOG.warn("Unsuported Packet {}", packet);
}
}
}
}
And here the new configuration for the inbound-channel-adapter remove the one in XML:
#Bean
public GcmMessageListeningEndpoint inboundAdpater(XMPPConnection connection, MessageChannel gcmInChannel) {
GcmMessageListeningEndpoint endpoint = new GcmMessageListeningEndpoint(connection);
endpoint.setOutputChannel(gcmInChannel);
return endpoint;
}
I'm trying to configure JMX with JBoss EAP 6.1, for this I've added jmx-console.war in my JBoss and put jboss-service.xml in my application. I'm trying to load a properties file and want to get it registered with JMX. JMX is showing all system beans but not loading my application's bean. This thing was working in AS version of JBoss. Is there some other way of configuring JMX with JBoss EAP? I've googled with all the combination but not finding any suitable answer. My jboss-service.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- ===================================================================== -->
<!-- JBoss Server Configuration -->
<!-- ===================================================================== -->
<server>
<mbean code="com.asd.store.util.mbean.SystemConfig"
name="com.asd.store.util.mbean:service=jmx-common">
<constructor>
<arg type="java.lang.String" value="store-properties.xml"/>
<arg type="java.lang.String" value="${jboss.server.home.dir}/conf"/>
</constructor>
</mbean>
</server>
JBoss AS 7.x does that slightly differently.
Here's a nice article on 'How to create SAR on JBoss AS7':
http://middlewaremagic.com/jboss/?p=366
You can see JBoss and your MBeans by using jconsole, e.g. JBOSS_HOME/bin/jconsole.sh and see MBeans tab. I guess your jmx-console.war would work too.
It seems your MBeans did not get instantiated and registered properly by your application.
There are few ways to register your MBeans, see the article above for one possible way.
Here is another way that you can create and register your MBean using #Singleton, #Startup EJB bean:
- make your MBean #Singleton, #Startup EJB
- register your MBean in #PostConstruct lifecycle method
- unregister you MBean in your #PreDestroy lifecycle method
Here's an example MBean that tracks current number of users, maximum number of users, performance, etc...
MBean interface, e.g. MonitoringResourceMXBean.java:
package examples.mymonitoring;
public interface MonitoringResourceMXBean {
// current user count
long getCurrentUsers();
void countUserUp();
void countUserDown();
// maximum user count
long getMaximumUsers();
void setMaximumUsers(long max);
// request count
long getRequests();
long countRequest();
// maximum duration of request
long getMaximumWait();
void reportWait(long wait);
}
MBean implementation, e.g.
package examples.mymonitoring;
import java.lang.management.ManagementFactory;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.management.MBeanServer;
import javax.management.ObjectName;
#Singleton
#Startup
public class MonitoringResource implements MonitoringResourceMXBean {
private MBeanServer platformMBeanServer;
private ObjectName objectName = null;
private long maximumUsers = 100;
private AtomicLong requestCount = new AtomicLong(0);
private AtomicLong currentUsers = new AtomicLong(0);
private long maximumWait = 0;
#PostConstruct
public void registerInJMX() {
try {
objectName = new ObjectName("MyMonitoring:type=" + this.getClass().getName());
platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
platformMBeanServer.registerMBean(this, objectName);
} catch (Exception e) {
throw new IllegalStateException("Problem during registration of Monitoring into JMX:" + e);
}
}
#PreDestroy
public void unregisterFromJMX() {
try {
platformMBeanServer.unregisterMBean(this.objectName);
} catch (Exception e) {
throw new IllegalStateException("Problem during unregistration of Monitoring into JMX:" + e);
}
}
#Override
public long getCurrentUsers() {
return this.currentUsers.get();
}
#Override
public void countUserUp() {
this.currentUsers.incrementAndGet();
}
#Override
public void countUserDown() {
this.currentUsers.decrementAndGet();
}
#Override
public long getMaximumWait() {
return this.maximumWait;
}
#Override
public long getMaximumUsers() {
return this.maximumUsers;
}
#Override
public void setMaximumUsers(long max) {
this.maximumUsers = max;
}
#Override
public void reportWait(long wait) {
if ( wait > maximumWait ) maximumWait = wait;
}
#Override
public long getRequests() {
return this.requestCount.get();
}
#Override
public long countRequest() {
return this.requestCount.incrementAndGet();
}
}
Hope the example helps.
Cheers!
We are using NLog to send email messages whenever a 'serious' error occurs. It might be happening very often in some cases generating too many messages.
Is there a way to make NLog limit the number of messages it sends on one particular or any error within a set period?
Is there an analogous mechanism in log4net or any other popular logging library?
Config file changes:
<target name="SystemErrorLog" xsi:type="TokenTimeThrottler" EntryExpirationPeriodSec="300">
<target xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard">
<target xsi:type="Mail" ... />
</target> </target>
Target Class:
[Target("TokenTimeThrottler", IsCompound = true)]
public class ThrottlingLogTarget : CompoundTargetBase
{
private ITokenTimeThrottler _tokenTimeThrottler;
public ThrottlingLogTarget()
: this(new Target[0])
{
}
public ThrottlingLogTarget(params Target[] targets)
: base(targets)
{
}
[Required]
public int EntryExpirationPeriodSec { get; set; }
protected override void InitializeTarget()
{
base.InitializeTarget();
_tokenTimeThrottler = new TokenTimeThrottler(EntryExpirationPeriodSec > 0 ? EntryExpirationPeriodSec : 0);
}
protected override void Write(AsyncLogEventInfo logEvent)
{
if (this.Targets.Count == 0)
{
logEvent.Continuation(null);
return;
}
var token = string.Format("{0},{1},{2}", logEvent.LogEvent.LoggerName, logEvent.LogEvent.Level, logEvent.LogEvent.FormattedMessage);
if (_tokenTimeThrottler.CheckAllow(token))
{
foreach (var target in Targets)
{
target.WriteAsyncLogEvent(logEvent);
}
}
}
}
public class TokenTimeThrottler : ITokenTimeThrottler
{
private readonly ConcurrentDictionary<string, DateTime> _entriesLastTimes;
private readonly int _expirationPeriodSec;
public TokenTimeThrottler(int entryExpirationPeriodSec)
{
_entriesLastTimes = new ConcurrentDictionary<string, DateTime>();
_expirationPeriodSec = entryExpirationPeriodSec;
}
public bool CheckAllow(string token)
{
DateTime lastLoggedTime;
if (_entriesLastTimes.TryGetValue(token, out lastLoggedTime))
{
DateTime? updatedTime = null;
if (lastLoggedTime.AddSeconds(_expirationPeriodSec) < DateTime.Now)
{
updatedTime = DateTime.Now;
}
_entriesLastTimes.AddOrUpdate(token, k => updatedTime ?? lastLoggedTime,
(k, v) => updatedTime ?? v);
return updatedTime.HasValue;
}
_entriesLastTimes.AddOrUpdate(token, k => DateTime.Now, (k, v) => v);
return true;
}
}
You can see my answer to a similar log4net question here:
log4net - any filter for logging only the Nth message?
In that answer I proposed a custom log4net Filter implementation that allows repeated messages within a configurable time period to be throttled.
For NLog, the easiest way might be to write a custom Wrapper target. The custom Wrapper target implemenation would examine the incoming logging messages, forwarding if the current message is different than the most recent message (or maybe if a certain amount of time has passed). You could then wrap any existing Target with this custom Wrapper.
Note that I have not actually written a Wrapper target, or I would try to provide more info.