Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
Maintaining ReadyMarkers in a dedicated service
Browse files Browse the repository at this point in the history
...instead of using the SCR for it.

Signed-off-by: Simon Kaufmann <[email protected]>
  • Loading branch information
Simon Kaufmann committed Sep 11, 2017
1 parent cf3bda6 commit 2245c1d
Show file tree
Hide file tree
Showing 19 changed files with 654 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
package org.eclipse.smarthome.config.xml;

import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;

import org.eclipse.smarthome.config.core.ConfigDescription;
import org.eclipse.smarthome.config.core.ConfigDescriptionProvider;
Expand All @@ -18,6 +20,8 @@
import org.eclipse.smarthome.config.xml.osgi.XmlDocumentProvider;
import org.eclipse.smarthome.config.xml.osgi.XmlDocumentProviderFactory;
import org.eclipse.smarthome.config.xml.util.XmlDocumentReader;
import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.eclipse.smarthome.core.service.ReadyService;
import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
Expand All @@ -41,19 +45,31 @@ public class ConfigXmlConfigDescriptionProvider extends AbstractXmlConfigDescrip
private XmlDocumentBundleTracker<List<ConfigDescription>> configDescriptionTracker;

private ConfigI18nLocalizationService configI18nLocalizerService;
private ReadyService readyService;

private ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(XmlDocumentBundleTracker.THREAD_POOL_NAME);
private Future<?> trackerJob;

@Activate
public void activate(ComponentContext componentContext) {
XmlDocumentReader<List<ConfigDescription>> configDescriptionReader = new ConfigDescriptionReader();

configDescriptionTracker = new XmlDocumentBundleTracker<>(componentContext.getBundleContext(), XML_DIRECTORY,
configDescriptionReader, this, READY_MARKER);
configDescriptionTracker.open();
configDescriptionReader, this, READY_MARKER, readyService);
trackerJob = scheduler.submit(() -> {
configDescriptionTracker.open();
});
}

@Deactivate
public void deactivate() {
if (trackerJob != null && !trackerJob.isDone()) {
trackerJob.cancel(true);
trackerJob = null;
}
configDescriptionTracker.close();
configDescriptionTracker = null;
}

@Reference
Expand All @@ -65,6 +81,15 @@ public void unsetConfigI18nLocalizerService(ConfigI18nLocalizationService config
this.configI18nLocalizerService = null;
}

@Reference
public void setReadyService(ReadyService readyService) {
this.readyService = readyService;
}

public void unsetReadyService(ReadyService readyService) {
this.readyService = null;
}

@Override
protected ConfigI18nLocalizationService getConfigI18nLocalizerService() {
return configI18nLocalizerService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,18 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.eclipse.smarthome.config.xml.util.XmlDocumentReader;
import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.eclipse.smarthome.core.service.ReadyMarker;
import org.eclipse.smarthome.core.service.ReadyUtil;
import org.eclipse.smarthome.core.service.ReadyService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.BundleTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -55,20 +53,22 @@
*/
public class XmlDocumentBundleTracker<T> extends BundleTracker<Bundle> {

public static final String THREAD_POOL_NAME = "xml-processing";

private final Logger logger = LoggerFactory.getLogger(XmlDocumentBundleTracker.class);
private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool("xml-processing");
private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(THREAD_POOL_NAME);
private final String xmlDirectory;
private final XmlDocumentReader<T> xmlDocumentTypeReader;
private final XmlDocumentProviderFactory<T> xmlDocumentProviderFactory;
private final Map<Bundle, XmlDocumentProvider<T>> bundleDocumentProviderMap = new ConcurrentHashMap<>();
private final Map<Bundle, ScheduledFuture<?>> queue = new ConcurrentHashMap<>();
private final Map<Bundle, Future<?>> queue = new ConcurrentHashMap<>();
private final Set<Bundle> finishedBundles = new CopyOnWriteArraySet<>();
@SuppressWarnings("rawtypes")
private final Map<String, ServiceRegistration> bundleReadyMarkerRegistrations = new ConcurrentHashMap<>();
private final Map<String, ReadyMarker> bundleReadyMarkerRegistrations = new ConcurrentHashMap<>();
private final String readyMarkerKey;

@SuppressWarnings("rawtypes")
private BundleTracker relevantBundlesTracker;
private ReadyService readyService;

/**
* Creates a new instance of this class with the specified parameters.
Expand All @@ -91,7 +91,7 @@ public class XmlDocumentBundleTracker<T> extends BundleTracker<Bundle> {
*/
public XmlDocumentBundleTracker(BundleContext bundleContext, String xmlDirectory,
XmlDocumentReader<T> xmlDocumentTypeReader, XmlDocumentProviderFactory<T> xmlDocumentProviderFactory,
String readyMarkerKey) throws IllegalArgumentException {
String readyMarkerKey, ReadyService readyService) throws IllegalArgumentException {
super(bundleContext, Bundle.ACTIVE, null);

if (bundleContext == null) {
Expand All @@ -106,15 +106,23 @@ public XmlDocumentBundleTracker(BundleContext bundleContext, String xmlDirectory
if (xmlDocumentProviderFactory == null) {
throw new IllegalArgumentException("The XmlDocumentProviderFactory must not be null!");
}
if (readyService == null) {
throw new IllegalArgumentException("The ReadyService must not be null!");
}

this.readyMarkerKey = readyMarkerKey;
this.xmlDirectory = xmlDirectory;
this.xmlDocumentTypeReader = xmlDocumentTypeReader;
this.xmlDocumentProviderFactory = xmlDocumentProviderFactory;
this.readyService = readyService;
}

private boolean isBundleRelevant(Bundle bundle) {
return bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null && isResourcePresent(bundle, xmlDirectory);
return isNotFragment(bundle) && isResourcePresent(bundle, xmlDirectory);
}

private boolean isNotFragment(Bundle bundle) {
return bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null;
}

private Set<Bundle> getRelevantBundles() {
Expand Down Expand Up @@ -144,13 +152,15 @@ public final synchronized void close() {
super.close();
unregisterReadyMarkers();
bundleDocumentProviderMap.clear();
relevantBundlesTracker.close();
if (relevantBundlesTracker != null) {
relevantBundlesTracker.close();
}
clearQueue();
finishedBundles.clear();
}

private void clearQueue() {
for (ScheduledFuture<?> future : queue.values()) {
for (Future<?> future : queue.values()) {
future.cancel(true);
}
queue.clear();
Expand Down Expand Up @@ -214,9 +224,9 @@ public final synchronized Bundle addingBundle(Bundle bundle, BundleEvent event)

@Override
public final synchronized void removedBundle(Bundle bundle, BundleEvent event, Bundle object) {
logger.debug("Removing the XML related objects from module '{}'...", bundle.getSymbolicName());
logger.trace("Removing the XML related objects from module '{}'...", bundle.getSymbolicName());
finishedBundles.remove(bundle);
ScheduledFuture<?> future = queue.remove(bundle);
Future<?> future = queue.remove(bundle);
if (future != null) {
future.cancel(true);
}
Expand Down Expand Up @@ -284,13 +294,14 @@ private final boolean isResourcePresent(Bundle bundle, String path) {
* @param bundle
*/
private void addingBundle(Bundle bundle) {
if (!isBundleRelevant(bundle)) {
finishBundle(bundle);
return;
}
ScheduledFuture<?> future = scheduler.schedule(() -> {
processBundle(bundle);
}, 0, TimeUnit.SECONDS);
Future<?> future = scheduler.submit(new Runnable() {
// this should remain an anonymous class and not be converted to a lambda because of
// http://bugs.java.com/view_bug.do?bug_id=8073755
@Override
public void run() {
processBundle(bundle);
}
});
queue.put(bundle, future);
}

Expand All @@ -313,10 +324,12 @@ private Set<Bundle> getRemainingBundles() {
}

private void processBundle(Bundle bundle) {
Enumeration<URL> xmlDocumentPaths = bundle.findEntries(xmlDirectory, "*.xml", true);
if (xmlDocumentPaths != null) {
Collection<URL> filteredPaths = filterPatches(xmlDocumentPaths, bundle);
parseDocuments(bundle, filteredPaths);
if (isNotFragment(bundle)) {
Enumeration<URL> xmlDocumentPaths = bundle.findEntries(xmlDirectory, "*.xml", true);
if (xmlDocumentPaths != null) {
Collection<URL> filteredPaths = filterPatches(xmlDocumentPaths, bundle);
parseDocuments(bundle, filteredPaths);
}
}
finishBundle(bundle);
}
Expand Down Expand Up @@ -344,25 +357,23 @@ private void parseDocuments(Bundle bundle, Collection<URL> filteredPaths) {
private void registerReadyMarker(Bundle bundle) {
String bsn = bundle.getSymbolicName();
if (!bundleReadyMarkerRegistrations.containsKey(bsn)) {
@SuppressWarnings("rawtypes")
ServiceRegistration reg = ReadyUtil.markAsReady(context, readyMarkerKey, bsn);
bundleReadyMarkerRegistrations.put(bsn, reg);
ReadyMarker readyMarker = new ReadyMarker(readyMarkerKey, bsn);
readyService.markReady(readyMarker);
bundleReadyMarkerRegistrations.put(bsn, readyMarker);
}
}

private void unregisterReadyMarker(Bundle bundle) {
String bsn = bundle.getSymbolicName();
@SuppressWarnings("rawtypes")
ServiceRegistration reg = bundleReadyMarkerRegistrations.remove(bsn);
if (reg != null) {
reg.unregister();
ReadyMarker readyMarker = bundleReadyMarkerRegistrations.remove(bsn);
if (readyMarker != null) {
readyService.unmarkReady(readyMarker);
}
}

private void unregisterReadyMarkers() {
for (@SuppressWarnings("rawtypes")
ServiceRegistration reg : bundleReadyMarkerRegistrations.values()) {
reg.unregister();
for (ReadyMarker readyMarker : bundleReadyMarkerRegistrations.values()) {
readyService.unmarkReady(readyMarker);
}
bundleReadyMarkerRegistrations.clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Import-Package: com.thoughtworks.xstream,
org.eclipse.smarthome.config.xml.osgi,
org.eclipse.smarthome.config.xml.util,
org.eclipse.smarthome.core.binding,
org.eclipse.smarthome.core.common,
org.eclipse.smarthome.core.common.osgi,
org.eclipse.smarthome.core.common.registry,
org.eclipse.smarthome.core.i18n,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;

import org.eclipse.smarthome.config.core.ConfigDescriptionProvider;
import org.eclipse.smarthome.config.xml.AbstractXmlBasedProvider;
Expand All @@ -20,8 +22,10 @@
import org.eclipse.smarthome.config.xml.util.XmlDocumentReader;
import org.eclipse.smarthome.core.binding.BindingInfo;
import org.eclipse.smarthome.core.binding.BindingInfoProvider;
import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.eclipse.smarthome.core.i18n.BindingI18nUtil;
import org.eclipse.smarthome.core.i18n.TranslationProvider;
import org.eclipse.smarthome.core.service.ReadyService;
import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
Expand Down Expand Up @@ -49,18 +53,29 @@ public class XmlBindingInfoProvider extends AbstractXmlBasedProvider<String, Bin
private BindingI18nUtil bindingI18nUtil;
private AbstractXmlConfigDescriptionProvider configDescriptionProvider;
private XmlDocumentBundleTracker<BindingInfoXmlResult> bindingInfoTracker;
private ReadyService readyService;

private ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(XmlDocumentBundleTracker.THREAD_POOL_NAME);
private Future<?> trackerJob;

@Activate
public void activate(ComponentContext componentContext) {
XmlDocumentReader<BindingInfoXmlResult> bindingInfoReader = new BindingInfoReader();

bindingInfoTracker = new XmlDocumentBundleTracker<>(componentContext.getBundleContext(), XML_DIRECTORY,
bindingInfoReader, this, READY_MARKER);
bindingInfoTracker.open();
bindingInfoReader, this, READY_MARKER, readyService);
trackerJob = scheduler.submit(() -> {
bindingInfoTracker.open();
});
}

@Deactivate
public void deactivate(ComponentContext componentContext) {
if (trackerJob != null && !trackerJob.isDone()) {
trackerJob.cancel(true);
trackerJob = null;
}
bindingInfoTracker.close();
bindingInfoTracker = null;
}
Expand Down Expand Up @@ -93,6 +108,15 @@ public void unsetConfigDescriptionProvider(ConfigDescriptionProvider configDescr
this.configDescriptionProvider = null;
}

@Reference
public void setReadyService(ReadyService readyService) {
this.readyService = readyService;
}

public void unsetReadyService(ReadyService readyService) {
this.readyService = null;
}

@Override
protected BindingInfo localize(Bundle bundle, BindingInfo bindingInfo, Locale locale) {
if (this.bindingI18nUtil == null) {
Expand Down
Loading

0 comments on commit 2245c1d

Please sign in to comment.