package org.opendaylight.controller.sal.dom.broker;
import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
-
+import java.util.List;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.util.ListenerRegistry;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
-import org.opendaylight.yangtools.yang.parser.impl.util.URLSchemaContextResolver;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
-
-public class GlobalBundleScanningSchemaServiceImpl implements //
- SchemaContextProvider, //
- SchemaService, //
- ServiceTrackerCustomizer<SchemaServiceListener, SchemaServiceListener>, //
- AutoCloseable {
- private static final Logger logger = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
+public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvider, SchemaService, ServiceTrackerCustomizer<SchemaContextListener, SchemaContextListener>, AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(GlobalBundleScanningSchemaServiceImpl.class);
- private ListenerRegistry<SchemaServiceListener> listeners;
+ private final ListenerRegistry<SchemaContextListener> listeners = new ListenerRegistry<>();
+ private final URLSchemaContextResolver contextResolver = URLSchemaContextResolver.create("global-bundle");
+ private final BundleScanner scanner = new BundleScanner();
+ private final BundleContext context;
- private BundleContext context;
- private BundleScanner scanner = new BundleScanner();
-
- private BundleTracker<ImmutableSet<Registration<URL>>> bundleTracker;
-
- private final URLSchemaContextResolver contextResolver = new URLSchemaContextResolver();
+ private ServiceTracker<SchemaContextListener, SchemaContextListener> listenerTracker;
+ private BundleTracker<Iterable<Registration>> bundleTracker;
+ private boolean starting = true;
+ private static GlobalBundleScanningSchemaServiceImpl instance;
- private ServiceTracker<SchemaServiceListener, SchemaServiceListener> listenerTracker;
+ private GlobalBundleScanningSchemaServiceImpl(final BundleContext context) {
+ this.context = Preconditions.checkNotNull(context);
+ }
- private boolean starting = true;
+ public synchronized static GlobalBundleScanningSchemaServiceImpl createInstance(final BundleContext ctx) {
+ Preconditions.checkState(instance == null);
+ instance = new GlobalBundleScanningSchemaServiceImpl(ctx);
+ instance.start();
+ return instance;
+ }
- public ListenerRegistry<SchemaServiceListener> getListeners() {
- return listeners;
+ public synchronized static GlobalBundleScanningSchemaServiceImpl getInstance() {
+ Preconditions.checkState(instance != null, "Global Instance was not instantiated");
+ return instance;
}
- public void setListeners(ListenerRegistry<SchemaServiceListener> listeners) {
- this.listeners = listeners;
+ @VisibleForTesting
+ public static synchronized void destroyInstance() {
+ try {
+ instance.close();
+ } finally {
+ instance = null;
+ }
}
public BundleContext getContext() {
return context;
}
- public void setContext(BundleContext context) {
- this.context = context;
- }
-
public void start() {
checkState(context != null);
- if (listeners == null) {
- listeners = new ListenerRegistry<>();
- }
- listenerTracker = new ServiceTracker<>(context, SchemaServiceListener.class, GlobalBundleScanningSchemaServiceImpl.this);
- bundleTracker = new BundleTracker<ImmutableSet<Registration<URL>>>(context, BundleEvent.RESOLVED
- | BundleEvent.UNRESOLVED, scanner);
+ listenerTracker = new ServiceTracker<>(context, SchemaContextListener.class, GlobalBundleScanningSchemaServiceImpl.this);
+ bundleTracker = new BundleTracker<>(context, BundleEvent.RESOLVED | BundleEvent.UNRESOLVED, scanner);
bundleTracker.open();
listenerTracker.open();
starting = false;
return getGlobalContext();
}
+ @Override
public SchemaContext getGlobalContext() {
return contextResolver.getSchemaContext().orNull();
}
@Override
- public void addModule(Module module) {
+ public void addModule(final Module module) {
throw new UnsupportedOperationException();
}
}
@Override
- public void removeModule(Module module) {
+ public void removeModule(final Module module) {
throw new UnsupportedOperationException();
}
@Override
- public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(SchemaServiceListener listener) {
+ public synchronized ListenerRegistration<SchemaContextListener> registerSchemaContextListener(final SchemaContextListener listener) {
+ Optional<SchemaContext> potentialCtx = contextResolver.getSchemaContext();
+ if(potentialCtx.isPresent()) {
+ listener.onGlobalContextUpdated(potentialCtx.get());
+ }
return listeners.register(listener);
}
@Override
- public void close() throws Exception {
+ public void close() {
if (bundleTracker != null) {
bundleTracker.close();
}
if (listenerTracker != null) {
listenerTracker.close();
}
- // FIXME: Add listeners.close();
- }
+ for (ListenerRegistration<SchemaContextListener> l : listeners.getListeners()) {
+ l.close();
+ }
+ }
- private void updateContext(SchemaContext snapshot) {
+ private synchronized void updateContext(final SchemaContext snapshot) {
Object[] services = listenerTracker.getServices();
+ for (ListenerRegistration<SchemaContextListener> listener : listeners) {
+ try {
+ listener.getInstance().onGlobalContextUpdated(snapshot);
+ } catch (Exception e) {
+ LOG.error("Exception occured during invoking listener", e);
+ }
+ }
if (services != null) {
for (Object rawListener : services) {
- SchemaServiceListener listener = (SchemaServiceListener) rawListener;
+ final SchemaContextListener listener = (SchemaContextListener) rawListener;
try {
listener.onGlobalContextUpdated(snapshot);
} catch (Exception e) {
- logger.error("Exception occured during invoking listener", e);
+ LOG.error("Exception occured during invoking listener {}", listener, e);
}
}
}
- for (ListenerRegistration<SchemaServiceListener> listener : listeners) {
- try {
- listener.getInstance().onGlobalContextUpdated(snapshot);
- } catch (Exception e) {
- logger.error("Exception occured during invoking listener", e);
- }
- }
}
- private class BundleScanner implements BundleTrackerCustomizer<ImmutableSet<Registration<URL>>> {
+ private class BundleScanner implements BundleTrackerCustomizer<Iterable<Registration>> {
@Override
- public ImmutableSet<Registration<URL>> addingBundle(Bundle bundle, BundleEvent event) {
+ public Iterable<Registration> addingBundle(final Bundle bundle, final BundleEvent event) {
if (bundle.getBundleId() == 0) {
- return ImmutableSet.of();
+ return Collections.emptyList();
}
- Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
- Builder<Registration<URL>> builder = ImmutableSet.<Registration<URL>> builder();
- while (enumeration != null && enumeration.hasMoreElements()) {
- Registration<URL> reg = contextResolver.registerSource(enumeration.nextElement());
- builder.add(reg);
+ final Enumeration<URL> enumeration = bundle.findEntries("META-INF/yang", "*.yang", false);
+ if (enumeration == null) {
+ return Collections.emptyList();
}
- ImmutableSet<Registration<URL>> urls = builder.build();
- if(urls.isEmpty()) {
- return urls;
+
+ final List<Registration> urls = new ArrayList<>();
+ while (enumeration.hasMoreElements()) {
+ final URL u = enumeration.nextElement();
+ try {
+ urls.add(contextResolver.registerSource(u));
+ LOG.debug("Registered {}", u);
+ } catch (Exception e) {
+ LOG.warn("Failed to register {}, ignoring it", e);
+ }
}
- tryToUpdateSchemaContext();
- return urls;
+
+ if (!urls.isEmpty()) {
+ LOG.debug("Loaded {} new URLs, rebuilding schema context", urls.size());
+ tryToUpdateSchemaContext();
+ }
+
+ return ImmutableList.copyOf(urls);
}
@Override
- public void modifiedBundle(Bundle bundle, BundleEvent event, ImmutableSet<Registration<URL>> object) {
- logger.debug("Modified bundle {} {} {}", bundle, event, object);
+ public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration> object) {
+ LOG.debug("Modified bundle {} {} {}", bundle, event, object);
}
/**
*/
@Override
- public synchronized void removedBundle(Bundle bundle, BundleEvent event, ImmutableSet<Registration<URL>> urls) {
- for (Registration<URL> url : urls) {
+ public synchronized void removedBundle(final Bundle bundle, final BundleEvent event, final Iterable<Registration> urls) {
+ for (Registration url : urls) {
try {
url.close();
} catch (Exception e) {
- e.printStackTrace();
+ LOG.warn("Failed do unregister URL {}, proceeding", url, e);
}
}
tryToUpdateSchemaContext();
}
@Override
- public SchemaServiceListener addingService(ServiceReference<SchemaServiceListener> reference) {
+ public synchronized SchemaContextListener addingService(final ServiceReference<SchemaContextListener> reference) {
- SchemaServiceListener listener = context.getService(reference);
+ SchemaContextListener listener = context.getService(reference);
SchemaContext _ctxContext = getGlobalContext();
if (getContext() != null && _ctxContext != null) {
listener.onGlobalContextUpdated(_ctxContext);
}
public synchronized void tryToUpdateSchemaContext() {
- if(starting ) {
+ if (starting) {
return;
}
- Optional<SchemaContext> schema = contextResolver.tryToUpdateSchemaContext();
+ Optional<SchemaContext> schema = contextResolver.getSchemaContext();
if(schema.isPresent()) {
updateContext(schema.get());
}
}
@Override
- public void modifiedService(ServiceReference<SchemaServiceListener> reference, SchemaServiceListener service) {
+ public void modifiedService(final ServiceReference<SchemaContextListener> reference, final SchemaContextListener service) {
// NOOP
}
@Override
- public void removedService(ServiceReference<SchemaServiceListener> reference, SchemaServiceListener service) {
+ public void removedService(final ServiceReference<SchemaContextListener> reference, final SchemaContextListener service) {
context.ungetService(reference);
}
}