Hi OSGi-devs,

I have a question about utilising ServiceTracker to manage a class's 
dependencies and blocking during the call, which I confess is probably well 
trodden ground but for which I can't apparently find the right Google 
terminology. Perhaps because I've been, until now, coddled by higher-level 
service dynamism, like Blueprint.

I have a java.util.logging.Handler whose publish method needs a couple of OSGi 
services to operate. Any LogRecords that are published during a refresh of 
either of the dependencies should not be lost and should be reattempted when 
services resume (which in practice might be a long time, the device this 
application targets is incredibly primitive).

Currently I have the Activator and Handler in the same implementation (which 
seems like it might be bad practice, if it is, I'd love to know why). Here's a 
trimmed down version, with just one dependency:

public class RemoteLoggingHandler extends Handler implements BundleActivator {
        private volatile Channel channel;
        
        private ServiceTracker<IAmqpChannelProvider, IAmqpChannelProvider> 
channelProviderTracker;
        
        @Override public void start(BundleContext context) throws Exception {   
        
                channelProviderTracker = new 
ServiceTracker<IAmqpChannelProvider, IAmqpChannelProvider>(context, 
IAmqpChannelProvider.class, null){
                        @Override public IAmqpChannelProvider 
addingService(ServiceReference<IAmqpChannelProvider> reference) {
                                IAmqpChannelProvider channelProvider = 
super.addingService(reference);
                                try {
                                        channel = 
channelProvider.createChannel();
                                        //Some initialisation, can happen once 
or multiple times, no problem.
                                        
channel.exchangeDeclare(LoggingConstants.LOGGING_EXG_NAME, "topic", true);
                                        notifyAll();
                                } catch (IOException e) {
                                        e.printStackTrace();
                                }
                                return channelProvider;
                        }
                        
                        @Override public synchronized void 
modifiedService(ServiceReference<IAmqpChannelProvider> reference, 
IAmqpChannelProvider service) {
                                removedService(reference, service);
                                addingService(reference);
                        }
                        
                        @Override public void 
removedService(ServiceReference<IAmqpChannelProvider> reference, 
IAmqpChannelProvider service) {
                                super.removedService(reference, service);
                                channel = null;
                        }
                };
                channelProviderTracker.open();
                                
                LogManager.getLogManager().getLogger("").addHandler(this);
        }

        @Override public void stop(BundleContext context) throws Exception {
                LogManager.getLogManager().getLogger("").removeHandler(this);
        }

        @Override
        public void publish(LogRecord record) {
                try {
                        synchronized (channelProviderTracker) {
                                while(channel == null) 
channelProviderTracker.wait();
                                
                                
channel.basicPublish(LoggingConstants.LOGGING_EXG_NAME, record.getLoggerName(),
                                                null, 
record.getMessage().getBytes());
                        }
                } catch (Exception e) {
                    reportError(null, e, ErrorManager.WRITE_FAILURE);
                    return;
                }
        }
        
        //Some boilerplate....
        
        @Override public void flush() {} //Unnecessary.

        @Override
        public void close() throws SecurityException {
                flush();
                try {
                        channel.close();
                } catch (IOException e) {
                        reportError("Amqp channel could not be closed", e, 
ErrorManager.CLOSE_FAILURE);                 
                }
        }
        
}

I don't feel that I've been successful. The channel member field can still go 
to null while it's being used in publish, and probably many other problems I've 
missed! Can anyone point out to me either the standard procedure for this, or 
any comments on my above attempt?

Many thanks,
Dan.


_______________________________________________
OSGi Developer Mail List
[email protected]
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to