The concepts underlying what we are doing here are gone from MD-SAL.
Update the version of the XML namespace and remove support for
- action-implementation
- action-instance
- notification-listener
- rpc-implementation
- rpc-service
- specific-reference-list
- static-reference
JIRA: CONTROLLER-2090
Change-Id: I7d9c992108378283a83ce80d6612794ccac1730e
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-dom-api</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-dom-spi</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-api</artifactId>
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.Set;
-import java.util.function.Predicate;
-import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
-import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
-import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
-import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-
-abstract class AbstractInvokableServiceMetadata extends AbstractDependentComponentFactoryMetadata {
- private final String interfaceName;
-
- private ListenerRegistration<DOMRpcAvailabilityListener> rpcListenerReg;
- private RpcConsumerRegistry rpcRegistry;
- private Class<RpcService> rpcInterface;
- private Set<QName> rpcSchemaPaths;
-
- AbstractInvokableServiceMetadata(final String id, final String interfaceName) {
- super(id);
- this.interfaceName = requireNonNull(interfaceName);
- }
-
- Class<RpcService> rpcInterface() {
- return rpcInterface;
- }
-
- @SuppressWarnings({ "checkstyle:IllegalCatch", "unchecked" })
- @Override
- public final void init(final ExtendedBlueprintContainer container) {
- super.init(container);
-
- final Class<?> interfaceClass;
- try {
- interfaceClass = container().getBundleContext().getBundle().loadClass(interfaceName);
- } catch (final Exception e) {
- throw new ComponentDefinitionException(String.format("%s: Error obtaining interface class %s",
- logName(), interfaceName), e);
- }
-
- if (!RpcService.class.isAssignableFrom(interfaceClass)) {
- throw new ComponentDefinitionException(String.format(
- "%s: The specified interface %s is not an RpcService", logName(), interfaceName));
- }
-
- rpcInterface = (Class<RpcService>)interfaceClass;
- }
-
- @Override
- protected final void startTracking() {
- // Request RpcProviderRegistry first ...
- retrieveService("RpcConsumerRegistry", RpcConsumerRegistry.class, this::onRpcRegistry);
- }
-
- private void onRpcRegistry(final Object service) {
- log.debug("{}: Retrieved RpcProviderRegistry {}", logName(), service);
- rpcRegistry = (RpcConsumerRegistry)service;
-
- // Now acquire SchemaService...
- retrieveService("SchemaService", DOMSchemaService.class, this::onSchemaService);
- }
-
- private void onSchemaService(final Object service) {
- log.debug("{}: Retrieved SchemaService {}", logName(), service);
-
- // Now get the SchemaContext and trigger RPC resolution
- retrievedSchemaContext(((DOMSchemaService)service).getGlobalContext());
- }
-
- private void retrievedSchemaContext(final EffectiveModelContext schemaContext) {
- log.debug("{}: retrievedSchemaContext", logName());
-
- final Collection<QName> schemaPaths = RpcUtil.decomposeRpcService(rpcInterface, schemaContext,
- rpcFilter());
- if (schemaPaths.isEmpty()) {
- log.debug("{}: interface {} has no acceptable entries, assuming it is satisfied", logName(), rpcInterface);
- setSatisfied();
- return;
- }
-
- rpcSchemaPaths = ImmutableSet.copyOf(schemaPaths);
- log.debug("{}: Got SchemaPaths: {}", logName(), rpcSchemaPaths);
-
- // First get the DOMRpcService OSGi service. This will be used to register a listener to be notified
- // when the underlying DOM RPC service is available.
- retrieveService("DOMRpcService", DOMRpcService.class, this::retrievedDOMRpcService);
- }
-
- private void retrievedDOMRpcService(final Object service) {
- log.debug("{}: retrievedDOMRpcService {}", logName(), service);
- final DOMRpcService domRpcService = (DOMRpcService)service;
-
- setDependencyDesc("Available DOM RPC for binding RPC: " + rpcInterface);
- rpcListenerReg = domRpcService.registerRpcListener(new DOMRpcAvailabilityListener() {
- @Override
- public void onRpcAvailable(final Collection<DOMRpcIdentifier> rpcs) {
- onRpcsAvailable(rpcs);
- }
-
- @Override
- public void onRpcUnavailable(final Collection<DOMRpcIdentifier> rpcs) {
- }
- });
- }
-
- abstract Predicate<ContentRoutedRpcContext> rpcFilter();
-
- @SuppressWarnings("checkstyle:IllegalCatch")
- @Override
- public final Object create() throws ComponentDefinitionException {
- log.debug("{}: In create: interfaceName: {}", logName(), interfaceName);
-
- super.onCreate();
-
- try {
- RpcService rpcService = rpcRegistry.getRpcService(rpcInterface);
-
- log.debug("{}: create returning service {}", logName(), rpcService);
-
- return rpcService;
- } catch (final RuntimeException e) {
- throw new ComponentDefinitionException("Error getting RPC service for " + interfaceName, e);
- }
- }
-
- protected final void onRpcsAvailable(final Collection<DOMRpcIdentifier> rpcs) {
- for (DOMRpcIdentifier identifier : rpcs) {
- if (rpcSchemaPaths.contains(identifier.getType())) {
- log.debug("{}: onRpcsAvailable - found SchemaPath {}", logName(), identifier.getType());
- setSatisfied();
- break;
- }
- }
- }
-
- @Override
- public final void stopTracking() {
- super.stopTracking();
- closeRpcListenerReg();
- }
-
- private void closeRpcListenerReg() {
- if (rpcListenerReg != null) {
- rpcListenerReg.close();
- rpcListenerReg = null;
- }
- }
-
- @Override
- public final void destroy(final Object instance) {
- super.destroy(instance);
- closeRpcListenerReg();
- }
-
- @Override
- public final String toString() {
- return MoreObjects.toStringHelper(this).add("id", getId()).add("interfaceName", interfaceName).toString();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
-import java.util.Objects;
-import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
-import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
-import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.util.concurrent.FluentFutures;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.osgi.framework.Bundle;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Blueprint bean corresponding to the "action-provider" element that registers the promise to instantiate action
- * instances with RpcProviderRegistry.
- *
- * <p>
- * This bean has two distinct facets:
- * - if a reference bean is provided, it registers it with {@link RpcProviderService}
- * - if a reference bean is not provided, it registers the corresponding no-op implementation with
- * {@link DOMRpcProviderService} for all action (Routed RPC) elements in the provided interface
- */
-public class ActionProviderBean {
- static final String ACTION_PROVIDER = "action-provider";
-
- private static final Logger LOG = LoggerFactory.getLogger(ActionProviderBean.class);
-
- private DOMRpcProviderService domRpcProvider = null;
- private RpcProviderService bindingRpcProvider = null;
- private DOMSchemaService schemaService = null;
- private RpcService implementation = null;
- private String interfaceName = null;
- private Registration reg;
- private Bundle bundle = null;
-
- public void setBundle(final Bundle bundle) {
- this.bundle = bundle;
- }
-
- public void setInterfaceName(final String interfaceName) {
- this.interfaceName = interfaceName;
- }
-
- public void setImplementation(final RpcService implementation) {
- this.implementation = implementation;
- }
-
- public void setDomRpcProvider(final DOMRpcProviderService rpcProviderService) {
- domRpcProvider = rpcProviderService;
- }
-
- public void setBindingRpcProvider(final RpcProviderService rpcProvider) {
- bindingRpcProvider = rpcProvider;
- }
-
- public void setSchemaService(final DOMSchemaService schemaService) {
- this.schemaService = schemaService;
- }
-
- public void init() {
- // First resolve the interface class
- final Class<RpcService> interfaceClass = getRpcClass();
-
- LOG.debug("{}: resolved interface {} to {}", ACTION_PROVIDER, interfaceName, interfaceClass);
-
- if (implementation != null) {
- registerImplementation(interfaceClass);
- } else {
- registerFallback(interfaceClass);
- }
- }
-
- @SuppressWarnings("checkstyle:IllegalCatch")
- public void destroy() {
- if (reg != null) {
- try {
- reg.close();
- } catch (final Exception e) {
- LOG.warn("{}: error while unregistering", ACTION_PROVIDER, e);
- } finally {
- reg = null;
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private Class<RpcService> getRpcClass() {
- final Class<?> iface;
-
- try {
- iface = bundle.loadClass(interfaceName);
- } catch (final ClassNotFoundException e) {
- throw new ComponentDefinitionException(String.format(
- "The specified \"interface\" for %s \"%s\" does not refer to an available class", interfaceName,
- ACTION_PROVIDER), e);
- }
- if (!RpcService.class.isAssignableFrom(iface)) {
- throw new ComponentDefinitionException(String.format(
- "The specified \"interface\" %s for \"%s\" is not an RpcService", interfaceName, ACTION_PROVIDER));
- }
-
- return (Class<RpcService>) iface;
- }
-
- private void registerFallback(final Class<RpcService> interfaceClass) {
- final var paths = RpcUtil.decomposeRpcService(interfaceClass, schemaService.getGlobalContext(),
- Objects::nonNull);
- if (paths.isEmpty()) {
- LOG.warn("{}: interface {} has no actions defined", ACTION_PROVIDER, interfaceClass);
- return;
- }
-
- final var rpcs = ImmutableSet.copyOf(Collections2.transform(paths, DOMRpcIdentifier::create));
- reg = domRpcProvider.registerRpcImplementation(
- (rpc, input) -> FluentFutures.immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException(
- "Action %s has no instance matching %s", rpc, input)), rpcs);
- LOG.debug("Registered provider for {}", interfaceName);
- }
-
- private void registerImplementation(final Class<RpcService> interfaceClass) {
- if (!interfaceClass.isInstance(implementation)) {
- throw new ComponentDefinitionException(String.format(
- "The specified \"interface\" %s for \"%s\" is not implemented by RpcService \"ref\" %s",
- interfaceName, ACTION_PROVIDER, implementation.getClass()));
- }
-
- reg = bindingRpcProvider.registerRpcImplementation(interfaceClass, implementation);
- LOG.debug("Registered implementation {} for {}", implementation, interfaceName);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import java.util.Objects;
-import java.util.function.Predicate;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
-import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
-
-/**
- * Factory metadata corresponding to the "action-service" element. It waits for a DOM promise of registration
- * to appear in the {@link DOMRpcService} and then acquires a dynamic proxy via RpcProviderRegistry.
- */
-final class ActionServiceMetadata extends AbstractInvokableServiceMetadata {
- /*
- * Implementation note:
- *
- * This implementation assumes Binding V1 semantics for actions, which means actions are packaged along with RPCs
- * into a single interface. This has interesting implications on working with RpcServiceMetadata, which only
- * handles the RPC side of the contract.
- *
- * Further interesting interactions stem from the fact that in DOM world each action is a separate entity, so the
- * interface contract can let some actions to be invoked, while failing for others. This is a shortcoming of the
- * Binding Specification and will be addressed in Binding V2 -- where each action is its own interface.
- */
- ActionServiceMetadata(final String id, final String interfaceName) {
- super(id, interfaceName);
- }
-
- @Override
- Predicate<ContentRoutedRpcContext> rpcFilter() {
- return Objects::nonNull;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import org.opendaylight.mdsal.binding.api.NotificationService;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.NotificationListener;
-import org.osgi.framework.Bundle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Blueprint bean corresponding to the "notification-listener" element that registers a NotificationListener
- * with the NotificationService.
- *
- * @author Thomas Pantelis
- */
-public class NotificationListenerBean {
- private static final Logger LOG = LoggerFactory.getLogger(NotificationListenerBean.class);
- static final String NOTIFICATION_LISTENER = "notification-listener";
-
- private Bundle bundle = null;
- private NotificationService notificationService = null;
- private NotificationListener notificationListener = null;
- private ListenerRegistration<?> registration = null;
-
- public void setNotificationService(final NotificationService notificationService) {
- this.notificationService = notificationService;
- }
-
- public void setNotificationListener(final NotificationListener notificationListener) {
- this.notificationListener = notificationListener;
- }
-
- public void setBundle(final Bundle bundle) {
- this.bundle = bundle;
- }
-
- public void init() {
- LOG.debug("{}: init - registering NotificationListener {}", bundle.getSymbolicName(), notificationListener);
-
- registration = notificationService.registerNotificationListener(notificationListener);
- }
-
- public void destroy() {
- if (registration != null) {
- LOG.debug("{}: destroy - closing ListenerRegistration {}", bundle.getSymbolicName(), notificationListener);
- registration.close();
- } else {
- LOG.debug("{}: destroy - listener was not registered", bundle.getSymbolicName());
- }
- }
-}
import org.apache.aries.blueprint.ComponentDefinitionRegistry;
import org.apache.aries.blueprint.NamespaceHandler;
import org.apache.aries.blueprint.ParserContext;
-import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
import org.apache.aries.blueprint.mutable.MutableRefMetadata;
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
import org.apache.aries.blueprint.mutable.MutableValueMetadata;
import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
-import org.opendaylight.mdsal.binding.api.NotificationService;
-import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
-import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.reflect.BeanMetadata;
private static final String USE_DEFAULT_FOR_REFERENCE_TYPES = "use-default-for-reference-types";
private static final String CLUSTERED_APP_CONFIG = "clustered-app-config";
private static final String INTERFACE = "interface";
- private static final String REF_ATTR = "ref";
private static final String ID_ATTR = "id";
- private static final String RPC_SERVICE = "rpc-service";
- private static final String ACTION_SERVICE = "action-service";
- private static final String SPECIFIC_SERVICE_REF_LIST = "specific-reference-list";
- private static final String STATIC_REFERENCE = "static-reference";
@SuppressWarnings("rawtypes")
@Override
public Metadata parse(final Element element, final ParserContext context) {
LOG.debug("In parse for {}", element);
- if (nodeNameEquals(element, RpcImplementationBean.RPC_IMPLEMENTATION)) {
- return parseRpcImplementation(element, context);
- } else if (nodeNameEquals(element, RPC_SERVICE)) {
- return parseRpcService(element, context);
- } else if (nodeNameEquals(element, NotificationListenerBean.NOTIFICATION_LISTENER)) {
- return parseNotificationListener(element, context);
- } else if (nodeNameEquals(element, CLUSTERED_APP_CONFIG)) {
+ if (nodeNameEquals(element, CLUSTERED_APP_CONFIG)) {
return parseClusteredAppConfig(element, context);
- } else if (nodeNameEquals(element, SPECIFIC_SERVICE_REF_LIST)) {
- return parseSpecificReferenceList(element, context);
- } else if (nodeNameEquals(element, STATIC_REFERENCE)) {
- return parseStaticReference(element, context);
- } else if (nodeNameEquals(element, ACTION_SERVICE)) {
- return parseActionService(element, context);
- } else if (nodeNameEquals(element, ActionProviderBean.ACTION_PROVIDER)) {
- return parseActionProvider(element, context);
}
throw new ComponentDefinitionException("Unsupported standalone element: " + element.getNodeName());
private static ComponentMetadata decorateServiceType(final Attr attr, final ComponentMetadata component,
final ParserContext context) {
- if (!(component instanceof MutableServiceMetadata)) {
+ if (!(component instanceof MutableServiceMetadata service)) {
throw new ComponentDefinitionException("Expected an instanceof MutableServiceMetadata");
}
- MutableServiceMetadata service = (MutableServiceMetadata)component;
-
LOG.debug("decorateServiceType for {} - adding type property {}", service.getId(), attr.getValue());
service.addServiceProperty(createValue(context, TYPE_ATTR), createValue(context, attr.getValue()));
return metadata;
}
- private static Metadata parseActionProvider(final Element element, final ParserContext context) {
- registerDomRpcProviderServiceRefBean(context);
- registerBindingRpcProviderServiceRefBean(context);
- registerSchemaServiceRefBean(context);
-
- MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), ActionProviderBean.class,
- true, true);
- addBlueprintBundleRefProperty(context, metadata);
- metadata.addProperty("domRpcProvider", createRef(context, DOM_RPC_PROVIDER_SERVICE_NAME));
- metadata.addProperty("bindingRpcProvider", createRef(context, BINDING_RPC_PROVIDER_SERVICE_NAME));
- metadata.addProperty("schemaService", createRef(context, SCHEMA_SERVICE_NAME));
- metadata.addProperty("interfaceName", createValue(context, element.getAttribute(INTERFACE)));
-
- if (element.hasAttribute(REF_ATTR)) {
- metadata.addProperty("implementation", createRef(context, element.getAttribute(REF_ATTR)));
- }
-
- LOG.debug("parseActionProvider returning {}", metadata);
- return metadata;
- }
-
-
- private static Metadata parseRpcImplementation(final Element element, final ParserContext context) {
- registerBindingRpcProviderServiceRefBean(context);
-
- MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), RpcImplementationBean.class,
- true, true);
- addBlueprintBundleRefProperty(context, metadata);
- metadata.addProperty("rpcProvider", createRef(context, BINDING_RPC_PROVIDER_SERVICE_NAME));
- metadata.addProperty("implementation", createRef(context, element.getAttribute(REF_ATTR)));
-
- if (element.hasAttribute(INTERFACE)) {
- metadata.addProperty("interfaceName", createValue(context, element.getAttribute(INTERFACE)));
- }
-
- LOG.debug("parseRpcImplementation returning {}", metadata);
- return metadata;
- }
-
- private static Metadata parseActionService(final Element element, final ParserContext context) {
- ComponentFactoryMetadata metadata = new ActionServiceMetadata(getId(context, element),
- element.getAttribute(INTERFACE));
-
- LOG.debug("parseActionService returning {}", metadata);
-
- return metadata;
- }
-
- private static Metadata parseRpcService(final Element element, final ParserContext context) {
- ComponentFactoryMetadata metadata = new RpcServiceMetadata(getId(context, element),
- element.getAttribute(INTERFACE));
-
- LOG.debug("parseRpcService returning {}", metadata);
-
- return metadata;
- }
-
- private static void registerDomRpcProviderServiceRefBean(final ParserContext context) {
- registerRefBean(context, DOM_RPC_PROVIDER_SERVICE_NAME, DOMRpcProviderService.class);
- }
-
- private static void registerBindingRpcProviderServiceRefBean(final ParserContext context) {
- registerRefBean(context, BINDING_RPC_PROVIDER_SERVICE_NAME, RpcProviderService.class);
- }
-
- private static void registerSchemaServiceRefBean(final ParserContext context) {
- registerRefBean(context, SCHEMA_SERVICE_NAME, DOMSchemaService.class);
- }
-
- private static void registerRefBean(final ParserContext context, final String name, final Class<?> clazz) {
- ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry();
- if (registry.getComponentDefinition(name) == null) {
- MutableReferenceMetadata metadata = createServiceRef(context, clazz, null);
- metadata.setId(name);
- registry.registerComponentDefinition(metadata);
- }
- }
-
- private static Metadata parseNotificationListener(final Element element, final ParserContext context) {
- registerNotificationServiceRefBean(context);
-
- MutableBeanMetadata metadata = createBeanMetadata(context, context.generateId(), NotificationListenerBean.class,
- true, true);
- addBlueprintBundleRefProperty(context, metadata);
- metadata.addProperty("notificationService", createRef(context, NOTIFICATION_SERVICE_NAME));
- metadata.addProperty("notificationListener", createRef(context, element.getAttribute(REF_ATTR)));
-
- LOG.debug("parseNotificationListener returning {}", metadata);
-
- return metadata;
- }
-
- private static void registerNotificationServiceRefBean(final ParserContext context) {
- ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry();
- if (registry.getComponentDefinition(NOTIFICATION_SERVICE_NAME) == null) {
- MutableReferenceMetadata metadata = createServiceRef(context, NotificationService.class, null);
- metadata.setId(NOTIFICATION_SERVICE_NAME);
- registry.registerComponentDefinition(metadata);
- }
- }
-
private static Metadata parseClusteredAppConfig(final Element element, final ParserContext context) {
LOG.debug("parseClusteredAppConfig");
}
}
- private static Metadata parseSpecificReferenceList(final Element element, final ParserContext context) {
- ComponentFactoryMetadata metadata = new SpecificReferenceListMetadata(getId(context, element),
- element.getAttribute(INTERFACE));
-
- LOG.debug("parseSpecificReferenceList returning {}", metadata);
-
- return metadata;
- }
-
- private static Metadata parseStaticReference(final Element element, final ParserContext context) {
- ComponentFactoryMetadata metadata = new StaticReferenceMetadata(getId(context, element),
- element.getAttribute(INTERFACE));
-
- LOG.debug("parseStaticReference returning {}", metadata);
-
- return metadata;
- }
-
private static Element parseXML(final String name, final String xml) {
try {
return UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(xml))).getDocumentElement();
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import com.google.common.base.Strings;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.osgi.framework.Bundle;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Blueprint bean corresponding to the "rpc-implementation" element that registers an RPC implementation with
- * the RpcProviderRegistry.
- *
- * @author Thomas Pantelis
- */
-public class RpcImplementationBean {
- private static final Logger LOG = LoggerFactory.getLogger(RpcImplementationBean.class);
- static final String RPC_IMPLEMENTATION = "rpc-implementation";
-
- private final List<ObjectRegistration<RpcService>> rpcRegistrations = new ArrayList<>();
- private RpcProviderService rpcProvider = null;
- private Bundle bundle = null;
- private String interfaceName = null;
- private RpcService implementation = null;
-
- public void setRpcProvider(final RpcProviderService rpcProvider) {
- this.rpcProvider = rpcProvider;
- }
-
- public void setBundle(final Bundle bundle) {
- this.bundle = bundle;
- }
-
- public void setInterfaceName(final String interfaceName) {
- this.interfaceName = interfaceName;
- }
-
- public void setImplementation(final RpcService implementation) {
- this.implementation = implementation;
- }
-
- @SuppressWarnings("checkstyle:IllegalCatch")
- public void init() {
- try {
- final var rpcInterfaces = getImplementedRpcServiceInterfaces(interfaceName,
- implementation.getClass(), bundle, RPC_IMPLEMENTATION);
-
- LOG.debug("{}: init - adding implementation {} for RpcService interface(s) {}", bundle.getSymbolicName(),
- implementation, rpcInterfaces);
-
- for (var rpcInterface : rpcInterfaces) {
- rpcRegistrations.add(rpcProvider.registerRpcImplementation(rpcInterface, implementation));
- }
- } catch (final ComponentDefinitionException e) {
- throw e;
- } catch (final Exception e) {
- throw new ComponentDefinitionException(String.format(
- "Error processing \"%s\" for %s", RPC_IMPLEMENTATION, implementation.getClass()), e);
- }
- }
-
- public void destroy() {
- for (ObjectRegistration<RpcService> reg: rpcRegistrations) {
- reg.close();
- }
- }
-
- @SuppressWarnings("unchecked")
- static List<Class<RpcService>> getImplementedRpcServiceInterfaces(final String interfaceName,
- final Class<?> implementationClass, final Bundle bundle, final String logName)
- throws ClassNotFoundException {
- if (!Strings.isNullOrEmpty(interfaceName)) {
- Class<?> rpcInterface = bundle.loadClass(interfaceName);
-
- if (!rpcInterface.isAssignableFrom(implementationClass)) {
- throw new ComponentDefinitionException(String.format(
- "The specified \"interface\" %s for \"%s\" is not implemented by RpcService \"ref\" %s",
- interfaceName, logName, implementationClass));
- }
-
- return Collections.singletonList((Class<RpcService>)rpcInterface);
- }
-
- final var rpcInterfaces = new ArrayList<Class<RpcService>>();
- for (var intface : implementationClass.getInterfaces()) {
- if (RpcService.class.isAssignableFrom(intface)) {
- rpcInterfaces.add((Class<RpcService>) intface);
- }
- }
-
- if (rpcInterfaces.isEmpty()) {
- throw new ComponentDefinitionException(String.format(
- "The \"ref\" instance %s for \"%s\" does not implemented any RpcService interfaces",
- implementationClass, logName));
- }
-
- return rpcInterfaces;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import java.util.Objects;
-import java.util.function.Predicate;
-import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
-
-/**
- * Factory metadata corresponding to the "rpc-service" element that gets an RPC service implementation from
- * the RpcProviderRegistry and provides it to the Blueprint container.
- *
- * @author Thomas Pantelis
- */
-final class RpcServiceMetadata extends AbstractInvokableServiceMetadata {
- RpcServiceMetadata(final String id, final String interfaceName) {
- super(id, interfaceName);
- }
-
- @Override
- Predicate<ContentRoutedRpcContext> rpcFilter() {
- return Objects::isNull;
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility methods for dealing with various aspects of RPCs and actions.
- */
-final class RpcUtil {
- private static final Logger LOG = LoggerFactory.getLogger(RpcUtil.class);
-
- private RpcUtil() {
- // Hidden on purpose
- }
-
- static List<QName> decomposeRpcService(final Class<RpcService> service,
- final EffectiveModelContext schemaContext, final Predicate<ContentRoutedRpcContext> filter) {
- final var moduleName = BindingReflections.getQNameModule(service);
- final var module = schemaContext.findModuleStatement(moduleName)
- .orElseThrow(() -> new IllegalArgumentException("Module not found in SchemaContext: " + moduleName
- + "; service: " + service));
- LOG.debug("Resolved service {} to module {}", service, module);
-
- return module.streamEffectiveSubstatements(RpcEffectiveStatement.class)
- .filter(rpc -> filter.test(ContentRoutedRpcContext.forRpc(rpc)))
- .map(RpcEffectiveStatement::argument)
- .collect(Collectors.toList());
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import com.google.common.io.Resources;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentSkipListSet;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.osgi.util.tracker.BundleTracker;
-import org.osgi.util.tracker.BundleTrackerCustomizer;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Factory metadata corresponding to the "specific-reference-list" element that obtains a specific list
- * of service instances from the OSGi registry for a given interface. The specific list is learned by first
- * extracting the list of expected service types by inspecting RESOLVED bundles for a resource file under
- * META-INF/services with the same name as the given interface. The type(s) listed in the resource file
- * must match the "type" property of the advertised service(s). In this manner, an app bundle announces the
- * service type(s) that it will advertise so that this class knows which services to expect up front. Once
- * all the expected services are obtained, the container is notified that all dependencies of this component
- * factory are satisfied.
- *
- * @author Thomas Pantelis
- */
-class SpecificReferenceListMetadata extends AbstractDependentComponentFactoryMetadata {
- private static final Logger LOG = LoggerFactory.getLogger(SpecificReferenceListMetadata.class);
-
- private final String interfaceName;
- private final String serviceResourcePath;
- private final Collection<String> expectedServiceTypes = new ConcurrentSkipListSet<>();
- private final Collection<String> retrievedServiceTypes = new ConcurrentSkipListSet<>();
- private final Collection<Object> retrievedServices = Collections.synchronizedList(new ArrayList<>());
- private volatile BundleTracker<Bundle> bundleTracker;
- private volatile ServiceTracker<Object, Object> serviceTracker;
-
- SpecificReferenceListMetadata(final String id, final String interfaceName) {
- super(id);
- this.interfaceName = interfaceName;
- serviceResourcePath = "META-INF/services/" + interfaceName;
- }
-
- @Override
- protected void startTracking() {
- BundleTrackerCustomizer<Bundle> bundleListener = new BundleTrackerCustomizer<>() {
- @Override
- public Bundle addingBundle(final Bundle bundle, final BundleEvent event) {
- bundleAdded(bundle);
- return bundle;
- }
-
- @Override
- public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) {
- }
-
- @Override
- public void removedBundle(final Bundle bundle, final BundleEvent event, final Bundle object) {
- }
- };
-
- bundleTracker = new BundleTracker<>(container().getBundleContext(), Bundle.RESOLVED | Bundle.STARTING
- | Bundle.STOPPING | Bundle.ACTIVE, bundleListener);
-
- // This will get the list of all current RESOLVED+ bundles.
- bundleTracker.open();
-
- if (expectedServiceTypes.isEmpty()) {
- setSatisfied();
- return;
- }
-
- ServiceTrackerCustomizer<Object, Object> serviceListener = new ServiceTrackerCustomizer<>() {
- @Override
- public Object addingService(final ServiceReference<Object> reference) {
- return serviceAdded(reference);
- }
-
- @Override
- public void modifiedService(final ServiceReference<Object> reference, final Object service) {
- }
-
- @Override
- public void removedService(final ServiceReference<Object> reference, final Object service) {
- container().getBundleContext().ungetService(reference);
- }
- };
-
- setDependencyDesc(interfaceName + " services with types " + expectedServiceTypes);
-
- serviceTracker = new ServiceTracker<>(container().getBundleContext(), interfaceName, serviceListener);
- serviceTracker.open();
- }
-
- private void bundleAdded(final Bundle bundle) {
- URL resource = bundle.getEntry(serviceResourcePath);
- if (resource == null) {
- return;
- }
-
- LOG.debug("{}: Found {} resource in bundle {}", logName(), resource, bundle.getSymbolicName());
-
- try {
- for (String line : Resources.readLines(resource, StandardCharsets.UTF_8)) {
- int ci = line.indexOf('#');
- if (ci >= 0) {
- line = line.substring(0, ci);
- }
-
- line = line.trim();
- if (line.isEmpty()) {
- continue;
- }
-
- String serviceType = line;
- LOG.debug("{}: Retrieved service type {}", logName(), serviceType);
- expectedServiceTypes.add(serviceType);
- }
- } catch (final IOException e) {
- setFailure(String.format("%s: Error reading resource %s from bundle %s", logName(), resource,
- bundle.getSymbolicName()), e);
- }
- }
-
- private Object serviceAdded(final ServiceReference<Object> reference) {
- Object service = container().getBundleContext().getService(reference);
- String serviceType = (String) reference.getProperty(OpendaylightNamespaceHandler.TYPE_ATTR);
-
- LOG.debug("{}: Service type {} added from bundle {}", logName(), serviceType,
- reference.getBundle().getSymbolicName());
-
- if (serviceType == null) {
- LOG.error("{}: Missing OSGi service property '{}' for service interface {} in bundle {}", logName(),
- OpendaylightNamespaceHandler.TYPE_ATTR, interfaceName, reference.getBundle().getSymbolicName());
- return service;
- }
-
- if (!expectedServiceTypes.contains(serviceType)) {
- LOG.error("{}: OSGi service property '{}' for service interface {} in bundle {} was not found in the "
- + "expected service types {} obtained via {} bundle resources. Is the bundle resource missing or "
- + "the service type misspelled?", logName(), OpendaylightNamespaceHandler.TYPE_ATTR, interfaceName,
- reference.getBundle().getSymbolicName(), expectedServiceTypes, serviceResourcePath);
- return service;
- }
-
- // If already satisfied, meaning we got all initial services, then a new bundle must've been
- // dynamically installed or a prior service's blueprint container was restarted, in which case we
- // restart our container.
- if (isSatisfied()) {
- restartContainer();
- } else {
- retrievedServiceTypes.add(serviceType);
- retrievedServices.add(service);
-
- if (retrievedServiceTypes.equals(expectedServiceTypes)) {
- LOG.debug("{}: Got all expected service types", logName());
- setSatisfied();
- } else {
- Set<String> remaining = new HashSet<>(expectedServiceTypes);
- remaining.removeAll(retrievedServiceTypes);
- setDependencyDesc(interfaceName + " services with types " + remaining);
- }
- }
-
- return service;
- }
-
- @Override
- public Object create() throws ComponentDefinitionException {
- LOG.debug("{}: In create: interfaceName: {}", logName(), interfaceName);
-
- super.onCreate();
-
- LOG.debug("{}: create returning service list {}", logName(), retrievedServices);
-
- synchronized (retrievedServices) {
- return List.copyOf(retrievedServices);
- }
- }
-
- @Override
- public void destroy(final Object instance) {
- super.destroy(instance);
-
- if (bundleTracker != null) {
- bundleTracker.close();
- bundleTracker = null;
- }
-
- if (serviceTracker != null) {
- serviceTracker.close();
- serviceTracker = null;
- }
- }
-
- @Override
- public String toString() {
- return new StringBuilder()
- .append("SpecificReferenceListMetadata [interfaceName=").append(interfaceName)
- .append(", serviceResourcePath=").append(serviceResourcePath).append("]")
- .toString();
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 Brocade Communications Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.blueprint.ext;
-
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Factory metadata corresponding to the "static-reference" element that obtains an OSGi service and
- * returns the actual instance. This differs from the standard "reference" element that returns a dynamic
- * proxy whose underlying service instance can come and go.
- *
- * @author Thomas Pantelis
- */
-class StaticReferenceMetadata extends AbstractDependentComponentFactoryMetadata {
- private static final Logger LOG = LoggerFactory.getLogger(StaticReferenceMetadata.class);
-
- private final String interfaceName;
- private volatile Object retrievedService;
-
- StaticReferenceMetadata(final String id, final String interfaceName) {
- super(id);
- this.interfaceName = interfaceName;
- }
-
- @Override
- protected void startTracking() {
- retrieveService(interfaceName, interfaceName, service -> {
- retrievedService = service;
- setSatisfied();
- });
- }
-
- @Override
- public Object create() throws ComponentDefinitionException {
- super.onCreate();
-
- LOG.debug("{}: create returning service {}", logName(), retrievedService);
-
- return retrievedService;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("StaticReferenceMetadata [interfaceName=").append(interfaceName).append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-<xsd:schema xmlns="http://opendaylight.org/xmlns/blueprint/v1.0.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- targetNamespace="http://opendaylight.org/xmlns/blueprint/v1.0.0" elementFormDefault="qualified"
- attributeFormDefault="unqualified" version="1.0.0">
-
- <!--
- Copyright © 2016, 2018 Brocade Communications Systems, Inc. and others.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v1.0 which accompanies this distribution,
- and is available at http://www.eclipse.org/legal/epl-v10.html
- -->
-
- <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
-
- <xsd:attribute name="restart-dependents-on-updates" type="xsd:boolean"/>
- <xsd:attribute name="use-default-for-reference-types" type="xsd:boolean"/>
- <xsd:attribute name="type" type="xsd:string"/>
-
- <!--
- String representation of an instance identifier. Precise string format
- is undefined just now.
- -->
- <xsd:simpleType name="Tpath">
- <xsd:restriction base="xsd:string"/>
- </xsd:simpleType>
-
- <!--
- A promise to instantiate actions of specified binding interface.
- Specified interface must define at least one action. In case a bean
- is specified, it will be used as the implementation of last resort
- for actions not otherwise bound. If a bean is not specified, a blank
- implementation will be substituted.
- -->
- <xsd:complexType name="TactionProvider">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="optional"/>
- </xsd:complexType>
- <xsd:element name="action-provider" type="TactionProvider"/>
-
- <!--
- A reference to an action-provider providing specified interface.
- Specified interface must define at least one action.
- -->
- <xsd:complexType name="TactionService">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-service" type="TactionService"/>
-
- <!--
- Implementation of an action at specific instance. This is used
- to provide binding to actions on specific context, rather than
- to a more general contract of action-provider.
- <xsd:complexType name="TactionImplementation">
- <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- <xsd:attribute name="path" type="Tpath" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-implementation" type="TactionImplementation"/ -->
-
- <!--
- A reference to a specific action-implementation.
- <xsd:complexType name="TactionInstance">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="path" type="Tpath" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="action-instance" type="TactionInstance"/ -->
-
- <xsd:complexType name="TrpcImplementation">
- <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- </xsd:complexType>
- <xsd:element name="rpc-implementation" type="TrpcImplementation"/>
-
- <xsd:complexType name="TrpcService">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="rpc-service" type="TrpcService"/>
-
- <xsd:complexType name="TnotificationListener">
- <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
- </xsd:complexType>
- <xsd:element name="notification-listener" type="TnotificationListener"/>
-
- <xsd:complexType name="TclusteredAppConfig">
- <xsd:sequence>
- <xsd:element name="default-config" type="xsd:string" minOccurs="0" maxOccurs="1"/>
- </xsd:sequence>
- <xsd:attribute name="binding-class" type="bp:Tclass" use="required"/>
- <xsd:attribute name="list-key-value" type="xsd:string" use="optional"/>
- <xsd:attribute name="default-config-file-name" type="xsd:string" use="optional"/>
- <xsd:attribute name="id" type="xsd:ID" use="required"/>
- <xsd:attribute name="update-strategy" type="TupdateStrategy" use="optional" default="reload"/>
- </xsd:complexType>
- <xsd:element name="clustered-app-config" type="TclusteredAppConfig"/>
- <xsd:simpleType name="TupdateStrategy">
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="none"/>
- <xsd:enumeration value="reload"/>
- </xsd:restriction>
- </xsd:simpleType>
- <xsd:complexType name="TspecificReferenceList">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="specific-reference-list" type="TspecificReferenceList"/>
-
- <xsd:complexType name="TstaticReference">
- <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
- <xsd:attribute name="id" type="xsd:ID"/>
- </xsd:complexType>
- <xsd:element name="static-reference" type="TstaticReference"/>
-</xsd:schema>
--- /dev/null
+<xsd:schema xmlns="http://opendaylight.org/xmlns/blueprint/v2.0.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ targetNamespace="http://opendaylight.org/xmlns/blueprint/v2.0.0" elementFormDefault="qualified"
+ attributeFormDefault="unqualified" version="2.0.0">
+
+ <!--
+ Copyright © 2016, 2018 Brocade Communications Systems, Inc. and others.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+ -->
+
+ <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
+
+ <xsd:attribute name="restart-dependents-on-updates" type="xsd:boolean"/>
+ <xsd:attribute name="use-default-for-reference-types" type="xsd:boolean"/>
+ <xsd:attribute name="type" type="xsd:string"/>
+
+ <xsd:complexType name="TclusteredAppConfig">
+ <xsd:sequence>
+ <xsd:element name="default-config" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ <xsd:attribute name="binding-class" type="bp:Tclass" use="required"/>
+ <xsd:attribute name="list-key-value" type="xsd:string" use="optional"/>
+ <xsd:attribute name="default-config-file-name" type="xsd:string" use="optional"/>
+ <xsd:attribute name="id" type="xsd:ID" use="required"/>
+ <xsd:attribute name="update-strategy" type="TupdateStrategy" use="optional" default="reload"/>
+ </xsd:complexType>
+ <xsd:element name="clustered-app-config" type="TclusteredAppConfig"/>
+ <xsd:simpleType name="TupdateStrategy">
+ <xsd:restriction base="xsd:NMTOKEN">
+ <xsd:enumeration value="none"/>
+ <xsd:enumeration value="reload"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+</xsd:schema>