Many thanks, I shall reimplement tomorrow and potentially seek further specific advice if I've still got any questions. Best, Dan.
> On 19 Sep 2013, at 18:57, BJ Hargrave <[email protected]> wrote: > > Some comments. > > You should not put the tracked service in the instance variable channel of > the outer class. When you need the service in your Handler, get it from the > tracker in a local var. > > You should not be using the tracker object for your own wait/notify needs. > ServiceTracker is not really designed for that. You should use your own > objects for that. > > You probably should not block the handler's publish method indefinitely. Who > knows what kind of deadlocks that will result in. Instead, you should buffer > the info yourself until a tracked service reappears at which time you can > flush your buffer into the tracked service. You should probably implement > yourself as a queue where the handler publish implementation enqueues items. > If there is a tracked channel, it can be immediately dequeued to the channel. > Otherwise, then the tracker customizer later adds a channel, all queued items > can be dequeued to the channel. > -- > BJ Hargrave > Senior Technical Staff Member, IBM > OSGi Fellow and CTO of the OSGi Alliance > [email protected] > > office: +1 386 848 1781 > mobile: +1 386 848 3788 > > > > > From: Daniel McGreal <[email protected]> > To: [email protected] > Date: 2013/09/19 12:03 > Subject: [osgi-dev] ServiceTrackers and blocking during refresh > Sent by: [email protected] > > > > 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 > _______________________________________________ > OSGi Developer Mail List > [email protected] > https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________ OSGi Developer Mail List [email protected] https://mail.osgi.org/mailman/listinfo/osgi-dev
