/* * JBoss, Home of Professional Open Source. * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.controller.capability; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.jboss.as.controller.logging.ControllerLogger; import org.jboss.msc.service.ServiceName; /** * A capability exposed in a running WildFly process. * * @param <T> the type of the runtime API object exposed by the capability * * @author Brian Stansberry (c) 2014 Red Hat Inc. */ public class RuntimeCapability<T> extends AbstractCapability { /** * Constructs a full capability name from a static base name and a dynamic element. * * @param baseName the base name. Cannot be {@code null} * @param dynamicNameElement the dynamic portion of the name. Cannot be {@code null} * @return the full capability name. Will not return {@code null} */ public static String buildDynamicCapabilityName(String baseName, String dynamicNameElement) { assert baseName != null; assert dynamicNameElement != null; return baseName + "." + dynamicNameElement; } /** * Creates a fully named capability from a {@link #isDynamicallyNamed() dynamically named} base * capability. Capability providers should use this method to generate fully named capabilities in logic * that handles dynamically named resources. * * @param base the base capability. Cannot be {@code null}, and {@link #isDynamicallyNamed()} must return {@code true} * @param dynamicElement the dynamic portion of the full capability name. Cannot be {@code null} or empty * @param <T> the type of the runtime API object exposed by the capability * @return the fully name capability. * * @deprecated use {@link #fromBaseCapability(String)} on {@code base} */ @Deprecated public static <T> RuntimeCapability<T> fromBaseCapability(RuntimeCapability<T> base, String dynamicElement) { return base.fromBaseCapability(dynamicElement); } private final Class<?> serviceValueType; private final ServiceName serviceName; private final T runtimeAPI; /** * Creates a new capability * @param name the name of the capability. Cannot be {@code null} * @param runtimeAPI implementation of the API exposed by this capability to other capabilities. May be {@code null} * @param requirements names of other capabilities upon which this capability has a hard requirement. May be {@code null} * @param optionalRequirements names of other capabilities upon which this capability has an optional requirement. May be {@code null} * * @deprecated use a {@link org.jboss.as.controller.capability.RuntimeCapability.Builder} */ @Deprecated public RuntimeCapability(String name, T runtimeAPI, Set<String> requirements, Set<String> optionalRequirements) { super(name, false, requirements, optionalRequirements, null, null, null); this.runtimeAPI = runtimeAPI; this.serviceValueType = null; this.serviceName = null; } /** * Creates a new capability * @param name the name of the capability. Cannot be {@code null} * @param runtimeAPI implementation of the API exposed by this capability to other capabilities. May be {@code null} * @param requirements names of other capabilities upon which this capability has a hard requirement. May be {@code null} * * @deprecated use a {@link org.jboss.as.controller.capability.RuntimeCapability.Builder} */ @Deprecated @SuppressWarnings("deprecation") public RuntimeCapability(String name, T runtimeAPI, Set<String> requirements) { this(name, runtimeAPI, requirements, null); } /** * Creates a new capability * @param name the name of the capability. Cannot be {@code null} * @param runtimeAPI implementation of the API exposed by this capability to other capabilities. May be {@code null} * @param requirements names of other capabilities upon which this capability has a hard requirement. May be {@code null} * * @deprecated use a {@link org.jboss.as.controller.capability.RuntimeCapability.Builder} */ @Deprecated public RuntimeCapability(String name, T runtimeAPI, String... requirements) { super(name, false, new HashSet<>(Arrays.asList(requirements)), null, null, null, null); this.runtimeAPI = runtimeAPI; this.serviceValueType = null; this.serviceName = null; } /** * Constructor for use by the builder. */ private RuntimeCapability(Builder<T> builder) { super(builder.baseName, builder.dynamic, builder.requirements, builder.optionalRequirements, builder.runtimeOnlyRequirements, builder.dynamicRequirements, builder.dynamicOptionalRequirements); this.runtimeAPI = builder.runtimeAPI; this.serviceValueType = builder.serviceValueType; this.serviceName = ServiceName.parse(builder.baseName); } /** * Constructor for use by {@link #fromBaseCapability(String)} */ private RuntimeCapability(String baseName, String dynamicElement, Class<?> serviceValueType, T runtimeAPI, Set<String> requirements, Set<String> optionalRequirements, Set<String> runtimeOnlyRequirements, Set<String> dynamicRequirements, Set<String> dynamicOptionalRequirements) { super(buildDynamicCapabilityName(baseName, dynamicElement), false, requirements, optionalRequirements, runtimeOnlyRequirements, dynamicRequirements, dynamicOptionalRequirements); this.runtimeAPI = runtimeAPI; this.serviceValueType = serviceValueType; this.serviceName = dynamicElement == null ? ServiceName.parse(baseName) : ServiceName.parse(baseName).append(dynamicElement); } /** * Gets the name of the service provided by this capability, if there is one. * * @return the name of the service. Will not be {@code null} * * @throws IllegalArgumentException if the capability does not provide a service */ public ServiceName getCapabilityServiceName() { return getCapabilityServiceName((Class<?>) null); } /** * Gets the name of service provided by this capability. * * @param serviceValueType the expected type of the service's value. Only used to provide validate that * the service value type provided by the capability matches the caller's * expectation. May be {@code null} in which case no validation is performed * * @return the name of the service. Will not be {@code null} * * @throws IllegalArgumentException if the capability does not provide a service or if its value type * is not assignable to {@code serviceValueType} */ public ServiceName getCapabilityServiceName(Class<?> serviceValueType) { if (this.serviceValueType == null || (serviceValueType != null && !serviceValueType.isAssignableFrom(this.serviceValueType))) { throw ControllerLogger.MGMT_OP_LOGGER.invalidCapabilityServiceType(getName(), serviceValueType); } return serviceName; } /** * Gets the name of the service provided by this capability, if there is one. Only usable with * {@link #isDynamicallyNamed() dynamically named} capabilities. * * @param dynamicNameElement the dynamic portion of the capability name. Cannot be {@code null} * * @return the name of the service. Will not be {@code null} * * @throws IllegalArgumentException if the capability does not provide a service * @throws AssertionError if {@link #isDynamicallyNamed()} does not return {@code true} */ public ServiceName getCapabilityServiceName(String dynamicNameElement) { return getCapabilityServiceName(dynamicNameElement, null); } /** * Gets the name of service provided by this capability. * * @param dynamicNameElement the dynamic portion of the capability name. Cannot be {@code null} * @param serviceValueType the expected type of the service's value. Only used to provide validate that * the service value type provided by the capability matches the caller's * expectation. May be {@code null} in which case no validation is performed * * @return the name of the service. Will not be {@code null} * * @throws IllegalArgumentException if the capability does not provide a service or if its value type * is not assignable to {@code serviceValueType} * @throws IllegalStateException if {@link #isDynamicallyNamed()} does not return {@code true} */ public ServiceName getCapabilityServiceName(String dynamicNameElement, Class<?> serviceValueType) { return fromBaseCapability(dynamicNameElement).getCapabilityServiceName(serviceValueType); } /** * Gets the valid type to pass to {@link #getCapabilityServiceName(Class)}. * * @return the valid type. May be {@code null} if this capability does not provide a * service */ public Class<?> getCapabilityServiceValueType() { return serviceValueType; } /** * Object encapsulating the API exposed by this capability to other capabilities that require it, if it does * expose such an API. * * @return the API object, or {@code null} if the capability exposes no API to other capabilities */ public T getRuntimeAPI() { return runtimeAPI; } /** * Creates a fully named capability from a {@link #isDynamicallyNamed() dynamically named} base * capability. Capability providers should use this method to generate fully named capabilities in logic * that handles dynamically named resources. * * @param dynamicElement the dynamic portion of the full capability name. Cannot be {@code null} or empty * @return the fully named capability. * * @throws AssertionError if {@link #isDynamicallyNamed()} returns {@code false} */ public RuntimeCapability<T> fromBaseCapability(String dynamicElement) { assert isDynamicallyNamed(); assert dynamicElement != null; assert dynamicElement.length() > 0; return new RuntimeCapability<T>(getName(), dynamicElement, serviceValueType, runtimeAPI, getRequirements(), getOptionalRequirements(), getRuntimeOnlyRequirements(), getDynamicRequirements(), getDynamicOptionalRequirements()); } /** * Builder for a {@link RuntimeCapability}. * * @param <T> the type of the runtime API object exposed by the capability */ public static class Builder<T> { private final String baseName; private final T runtimeAPI; private final boolean dynamic; private Class<?> serviceValueType; private Set<String> requirements; private Set<String> optionalRequirements; private Set<String> runtimeOnlyRequirements; private Set<String> dynamicRequirements; private Set<String> dynamicOptionalRequirements; /** * Create a builder for a non-dynamic capability with no custom runtime API. * @param name the name of the capability. Cannot be {@code null} or empty. * @return the builder */ public static Builder<Void> of(String name) { return new Builder<Void>(name, false, null); } /** * Create a builder for a possibly dynamic capability with no custom runtime API. * @param name the name of the capability. Cannot be {@code null} or empty. * @param dynamic {@code true} if the capability is a base capability for dynamically named capabilities * @return the builder */ public static Builder<Void> of(String name, boolean dynamic) { return new Builder<Void>(name, dynamic, null); } /** * Create a builder for a non-dynamic capability that installs a service with the given value type. * * @param name the name of the capability. Cannot be {@code null} or empty. * @param serviceValueType the value type of the service installed by the capability * @return the builder */ public static Builder<Void> of(String name, Class<?> serviceValueType) { return new Builder<Void>(name, false, null).setServiceType(serviceValueType); } /** * Create a builder for a possibly dynamic capability that installs a service with the given value type. * * @param name the name of the capability. Cannot be {@code null} or empty. * @param dynamic {@code true} if the capability is a base capability for dynamically named capabilities * @param serviceValueType the value type of the service installed by the capability * @return the builder */ public static Builder<Void> of(String name, boolean dynamic, Class<?> serviceValueType) { return new Builder<Void>(name, dynamic, null).setServiceType(serviceValueType); } /** * Create a builder for a non-dynamic capability that provides the given custom runtime API. * @param name the name of the capability. Cannot be {@code null} or empty. * @param runtimeAPI the custom API implementation exposed by the capability * @param <T> the type of the runtime API object exposed by the capability * @return the builder */ public static <T> Builder<T> of(String name, T runtimeAPI) { return new Builder<T>(name, false, runtimeAPI); } /** * Create a builder for a possibly dynamic capability that provides the given custom runtime API. * @param name the name of the capability. Cannot be {@code null} or empty. * @param dynamic {@code true} if the capability is a base capability for dynamically named capabilities * @param runtimeAPI the custom API implementation exposed by the capability * @param <T> the type of the runtime API object exposed by the capability * @return the builder */ public static <T> Builder<T> of(String name, boolean dynamic, T runtimeAPI) { return new Builder<T>(name, dynamic, runtimeAPI); } private Builder(String baseName, boolean dynamic, T runtimeAPI) { assert baseName != null; assert baseName.length() > 0; this.baseName = baseName; this.runtimeAPI = runtimeAPI; this.dynamic = dynamic; } /** * Sets that the capability installs a service with the given value type. * @param type the value type of the service installed by the capability. May be {@code null} * @return the builder */ public Builder<T> setServiceType(Class<?> type) { this.serviceValueType = type; return this; } /** * Adds the names of other capabilities that this capability requires. The requirement * for these capabilities will automatically be registered when this capability is registered. * * @param requirements the capability names * @return the builder */ public Builder<T> addRequirements(String... requirements) { assert requirements != null; if (this.requirements == null) { this.requirements = new HashSet<>(requirements.length); } Collections.addAll(this.requirements, requirements); return this; } /** * Adds the names of other capabilities that this capability optionally requires. * @param requirements the capability names * @return the builder * * @deprecated nothing is currently done with this data and unless a true use is implemented this method may be removed */ @Deprecated public Builder<T> addOptionalRequirements(String... requirements) { assert requirements != null; if (this.optionalRequirements == null) { this.optionalRequirements = new HashSet<>(requirements.length); } Collections.addAll(this.optionalRequirements, requirements); return this; } /** * Adds the names of other capabilities that this capability optionally uses, * but only if they are present in the runtime. The persistent configuration of * the capability being built will never mandate the presence of these capabilities. * * @param requirements the capability names * @return the builder * * @deprecated nothing is currently done with this data and unless a true use is implemented this method may be removed */ @Deprecated public Builder<T> addRuntimeOnlyRequirements(String... requirements) { assert requirements != null; if (this.runtimeOnlyRequirements == null) { this.runtimeOnlyRequirements = new HashSet<>(requirements.length); } Collections.addAll(this.runtimeOnlyRequirements, requirements); return this; } /** * Adds the the names of other dynamically named capabilities upon a concrete instance of which this * capability will have a hard requirement once the full name is known * * @param requirements the capability names * @return the builder * * @deprecated nothing is currently done with this data and unless a true use is implemented this method may be removed */ @Deprecated public Builder<T> addDynamicRequirements(String... requirements) { assert requirements != null; if (this.dynamicRequirements == null) { this.dynamicRequirements = new HashSet<>(requirements.length); } Collections.addAll(this.dynamicRequirements, requirements); return this; } /** * Adds the the names of other dynamically named capabilities upon a concrete instance of which this * capability will have an optional requirement once the full name is known * * @param requirements the capability names * @return the builder * * @deprecated nothing is currently done with this data and unless a true use is implemented this method may be removed */ @Deprecated public Builder<T> addDynamicOptionalRequirements(String... requirements) { assert requirements != null; if (this.dynamicOptionalRequirements == null) { this.dynamicOptionalRequirements = new HashSet<>(requirements.length); } Collections.addAll(this.dynamicOptionalRequirements, requirements); return this; } /** * Builds the capability. * * @return the capability. Will not return {@code null} */ public RuntimeCapability<T> build() { return new RuntimeCapability<>(this); } } }