diff --git a/sar/src/main/java/org/jboss/as/service/AbstractService.java b/sar/src/main/java/org/jboss/as/service/AbstractService.java index 1139aeabff03..f7732646122f 100644 --- a/sar/src/main/java/org/jboss/as/service/AbstractService.java +++ b/sar/src/main/java/org/jboss/as/service/AbstractService.java @@ -28,11 +28,14 @@ import java.util.List; import java.util.ListIterator; import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import java.util.function.Supplier; import org.jboss.as.server.deployment.SetupAction; import org.jboss.msc.service.LifecycleContext; -import org.jboss.msc.service.Service; -import org.jboss.msc.value.InjectedValue; +import org.jboss.msc.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StopContext; import org.wildfly.security.manager.WildFlySecurityManager; /** @@ -40,29 +43,35 @@ * * @author Richard Opalka */ -abstract class AbstractService implements Service { +abstract class AbstractService implements Service { - private final Object mBeanInstance; + protected final Object mBeanInstance; private final List setupActions; private final ClassLoader mbeanContextClassLoader; - protected final InjectedValue executor = new InjectedValue(); + private final Consumer mBeanInstanceConsumer; + protected final Supplier executorSupplier; /** * @param mBeanInstance * @param setupActions actions to setup the thread local context */ - protected AbstractService(final Object mBeanInstance, final List setupActions, final ClassLoader mbeanContextClassLoader) { + protected AbstractService(final Object mBeanInstance, final List setupActions, final ClassLoader mbeanContextClassLoader, final Consumer mBeanInstanceConsumer, final Supplier executorSupplier) { this.mBeanInstance = mBeanInstance; this.setupActions = setupActions; this.mbeanContextClassLoader = mbeanContextClassLoader; + this.mBeanInstanceConsumer = mBeanInstanceConsumer; + this.executorSupplier = executorSupplier; } - /** - * {@inheritDoc} - */ - public final Object getValue() { - return mBeanInstance; + @Override + public void start(final StartContext context) { + mBeanInstanceConsumer.accept(mBeanInstance); + } + + @Override + public void stop(final StopContext context) { + mBeanInstanceConsumer.accept(null); } protected void invokeLifecycleMethod(final Method method, final LifecycleContext context) throws InvocationTargetException, IllegalAccessException { @@ -86,9 +95,4 @@ protected void invokeLifecycleMethod(final Method method, final LifecycleContext } } } - - public InjectedValue getExecutorInjector() { - return executor; - } - } diff --git a/sar/src/main/java/org/jboss/as/service/CreateDestroyService.java b/sar/src/main/java/org/jboss/as/service/CreateDestroyService.java index edd94ab95ff2..ff6bf7e7493e 100644 --- a/sar/src/main/java/org/jboss/as/service/CreateDestroyService.java +++ b/sar/src/main/java/org/jboss/as/service/CreateDestroyService.java @@ -22,9 +22,16 @@ package org.jboss.as.service; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; +import java.util.function.Consumer; +import java.util.function.Supplier; import org.jboss.as.naming.ManagedReference; import org.jboss.as.server.deployment.SetupAction; @@ -47,18 +54,20 @@ final class CreateDestroyService extends AbstractService { private final Method destroyMethod; private final ServiceComponentInstantiator componentInstantiator; + private final Map> injections = new HashMap<>(); private ManagedReference managedReference; CreateDestroyService(final Object mBeanInstance, final Method createMethod, final Method destroyMethod, ServiceComponentInstantiator componentInstantiator, - List setupActions, final ClassLoader mbeanContextClassLoader) { - super(mBeanInstance, setupActions, mbeanContextClassLoader); + List setupActions, final ClassLoader mbeanContextClassLoader, final Consumer mBeanInstanceConsumer, final Supplier executorSupplier) { + super(mBeanInstance, setupActions, mbeanContextClassLoader, mBeanInstanceConsumer, executorSupplier); this.createMethod = createMethod; this.destroyMethod = destroyMethod; this.componentInstantiator = componentInstantiator; } /** {@inheritDoc} */ - public void start(final StartContext context) throws StartException { + public void start(final StartContext context) { + super.start(context); if (SarLogger.ROOT_LOGGER.isTraceEnabled()) { SarLogger.ROOT_LOGGER.tracef("Creating Service: %s", context.getController().getName()); } @@ -66,18 +75,20 @@ public void start(final StartContext context) throws StartException { @Override public void run() { try { + injectDependencies(); invokeLifecycleMethod(createMethod, context); if (componentInstantiator != null) { - managedReference = componentInstantiator.initializeInstance(getValue()); + managedReference = componentInstantiator.initializeInstance(mBeanInstance); } context.complete(); } catch (Throwable e) { + uninjectDependencies(); context.failed(new StartException(SarLogger.ROOT_LOGGER.failedExecutingLegacyMethod("create()"), e)); } } }; try { - executor.getValue().submit(task); + executorSupplier.get().submit(task); } catch (RejectedExecutionException e) { task.run(); } finally { @@ -87,6 +98,7 @@ public void run() { /** {@inheritDoc} */ public void stop(final StopContext context) { + super.stop(context); if (SarLogger.ROOT_LOGGER.isTraceEnabled()) { SarLogger.ROOT_LOGGER.tracef("Destroying Service: %s", context.getController().getName()); } @@ -101,12 +113,13 @@ public void run() { } catch (Exception e) { SarLogger.ROOT_LOGGER.error(SarLogger.ROOT_LOGGER.failedExecutingLegacyMethod("destroy()"), e); } finally { + uninjectDependencies(); context.complete(); } } }; try { - executor.getValue().submit(task); + executorSupplier.get().submit(task); } catch (RejectedExecutionException e) { task.run(); } finally { @@ -114,4 +127,28 @@ public void run() { } } + void inject(final Method setter, final Supplier injectionSupplier) { + injections.put(setter, injectionSupplier); + } + + private void injectDependencies() throws IllegalAccessException, InvocationTargetException { + Method setter; + Object arg; + for (final Entry> injection : injections.entrySet()) { + setter = injection.getKey(); + arg = injection.getValue().get(); + setter.invoke(mBeanInstance, arg); + } + } + + private void uninjectDependencies() { + Method setter; + for (final Entry> injection : injections.entrySet()) { + try { + setter = injection.getKey(); + setter.invoke(mBeanInstance, (Object[]) null); + } catch (final Throwable ignored) {} + } + } + } diff --git a/sar/src/main/java/org/jboss/as/service/DelegatingSupplier.java b/sar/src/main/java/org/jboss/as/service/DelegatingSupplier.java new file mode 100644 index 000000000000..10eb65e5d137 --- /dev/null +++ b/sar/src/main/java/org/jboss/as/service/DelegatingSupplier.java @@ -0,0 +1,38 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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.service; + +import java.util.function.Supplier; + +/** + * @author Richard Opalka + */ +abstract class DelegatingSupplier implements Supplier { + + protected volatile Supplier objectSupplier; + + void setObjectSupplier(final Supplier objectSupplier) { + this.objectSupplier = objectSupplier; + } + +} diff --git a/sar/src/main/java/org/jboss/as/service/InjectedBeanMethodValue.java b/sar/src/main/java/org/jboss/as/service/InjectedBeanMethodValue.java deleted file mode 100644 index 58a19a6c4e1b..000000000000 --- a/sar/src/main/java/org/jboss/as/service/InjectedBeanMethodValue.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2016 Red Hat, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - */ - -package org.jboss.as.service; - -import org.jboss.msc.value.Value; - -import java.lang.reflect.Method; - -/** - * Resolves the method on an injected bean using {@code MethodFinder}. - */ -public class InjectedBeanMethodValue implements Value { - private final Value targetBeanValue; - private final MethodFinder methodFinder; - - interface MethodFinder { - Method find(final Class clazz); - } - - public InjectedBeanMethodValue(Value targetBeanValue, MethodFinder methodFinder) { - this.methodFinder = methodFinder; - this.targetBeanValue = targetBeanValue; - } - - @Override - public Method getValue() throws IllegalStateException, IllegalArgumentException { - return methodFinder.find(targetBeanValue.getValue().getClass()); - } - -} diff --git a/sar/src/main/java/org/jboss/as/service/MBeanRegistrationService.java b/sar/src/main/java/org/jboss/as/service/MBeanRegistrationService.java new file mode 100644 index 000000000000..810eb8a3a88d --- /dev/null +++ b/sar/src/main/java/org/jboss/as/service/MBeanRegistrationService.java @@ -0,0 +1,124 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2010, 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.service; + +import static org.jboss.as.service.logging.SarLogger.ROOT_LOGGER; + +import java.lang.management.ManagementFactory; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.function.Supplier; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.jboss.as.server.deployment.SetupAction; +import org.jboss.msc.Service; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; + +/** + * Service used to register and unregister an mbean with an mbean server. + * + * @author John Bailey + * @author Richard Opalka + */ +final class MBeanRegistrationService implements Service { + static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("mbean", "registration"); + private final Supplier mBeanServerSupplier; + private final Supplier objectSupplier; + private final String name; + private ObjectName objectName; + private final List setupActions; + + public MBeanRegistrationService(final String name, final List setupActions, + final Supplier mBeanServerSupplier, + final Supplier objectSupplier) { + this.name = name; + this.setupActions = setupActions; + this.mBeanServerSupplier = mBeanServerSupplier; + this.objectSupplier = objectSupplier; + } + + public synchronized void start(final StartContext context) throws StartException { + final MBeanServer mBeanServer = getMBeanServer(); + final Object value = objectSupplier.get(); + try { + objectName = new ObjectName(name); + } catch (MalformedObjectNameException e) { + throw ROOT_LOGGER.mbeanRegistrationFailed(e, name); + } + try { + for (SetupAction action : setupActions) { + action.setup(Collections.emptyMap()); + } + try { + ROOT_LOGGER.debugf("Registering [%s] with name [%s]", value, objectName); + mBeanServer.registerMBean(value, objectName); + } catch (Exception e) { + throw ROOT_LOGGER.mbeanRegistrationFailed(e, name); + } + } finally { + ListIterator it = setupActions.listIterator(setupActions.size()); + while (it.hasPrevious()) { + SetupAction action = it.previous(); + action.teardown(Collections.emptyMap()); + } + } + } + + public synchronized void stop(final StopContext context) { + if (objectName == null) { + ROOT_LOGGER.cannotUnregisterObject(); + } + final MBeanServer mBeanServer = getMBeanServer(); + try { + for (SetupAction action : setupActions) { + action.setup(Collections.emptyMap()); + } + try { + mBeanServer.unregisterMBean(objectName); + } catch (Exception e) { + ROOT_LOGGER.unregistrationFailure(e, objectName); + } + } finally { + ListIterator it = setupActions.listIterator(setupActions.size()); + while (it.hasPrevious()) { + SetupAction action = it.previous(); + action.teardown(Collections.emptyMap()); + } + } + } + + private MBeanServer getMBeanServer() { + MBeanServer mBeanServer = mBeanServerSupplier.get(); + if (mBeanServer == null) { + mBeanServer = ManagementFactory.getPlatformMBeanServer(); + } + return mBeanServer; + } + +} diff --git a/sar/src/main/java/org/jboss/as/service/MBeanServices.java b/sar/src/main/java/org/jboss/as/service/MBeanServices.java index 70731bbfbf64..4c8a9903f42f 100644 --- a/sar/src/main/java/org/jboss/as/service/MBeanServices.java +++ b/sar/src/main/java/org/jboss/as/service/MBeanServices.java @@ -24,21 +24,20 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import java.util.function.Supplier; import javax.management.MBeanServer; -import org.jboss.as.jmx.MBeanRegistrationService; -import org.jboss.as.server.Services; +import org.jboss.as.controller.AbstractControllerService; import org.jboss.as.server.deployment.SetupAction; import org.jboss.as.server.deployment.reflect.ClassReflectionIndex; import org.jboss.as.service.component.ServiceComponentInstantiator; import org.jboss.as.service.logging.SarLogger; -import org.jboss.msc.inject.Injector; -import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceTarget; -import org.jboss.msc.value.Value; /** * Services associated with MBean responsible for dependencies & injection management. @@ -55,8 +54,8 @@ final class MBeanServices { private final String mBeanName; private final ServiceName createDestroyServiceName; private final ServiceName startStopServiceName; - private final Service createDestroyService; - private final Service startStopService; + private final CreateDestroyService createDestroyService; + private final StartStopService startStopService; private final ServiceBuilder createDestroyServiceBuilder; private final ServiceBuilder startStopServiceBuilder; private final ServiceTarget target; @@ -65,20 +64,11 @@ final class MBeanServices { private final List setupActions; - /** - * @param mBeanName - * @param mBeanInstance - * @param mBeanClassHierarchy - * @param target - * @param componentInstantiator - * @param setupActions the deployment unit's service name - * @param mbeanServerServiceName - */ MBeanServices(final String mBeanName, final Object mBeanInstance, final List mBeanClassHierarchy, final ServiceTarget target, final ServiceComponentInstantiator componentInstantiator, final List setupActions, final ClassLoader mbeanContextClassLoader, final ServiceName mbeanServerServiceName) { if (mBeanClassHierarchy == null) { - throw SarLogger.ROOT_LOGGER.nullVar("mBeanName"); + throw SarLogger.ROOT_LOGGER.nullVar("mBeanClassHierarchy"); } if (mBeanInstance == null) { throw SarLogger.ROOT_LOGGER.nullVar("mBeanInstance"); @@ -92,65 +82,61 @@ final class MBeanServices { final Method createMethod = ReflectionUtils.getMethod(mBeanClassHierarchy, CREATE_METHOD_NAME, NO_ARGS, false); final Method destroyMethod = ReflectionUtils.getMethod(mBeanClassHierarchy, DESTROY_METHOD_NAME, NO_ARGS, false); - createDestroyService = new CreateDestroyService(mBeanInstance, createMethod, destroyMethod,componentInstantiator, setupActions, mbeanContextClassLoader); createDestroyServiceName = ServiceNameFactory.newCreateDestroy(mBeanName); - createDestroyServiceBuilder = target.addService(createDestroyServiceName, createDestroyService); - Services.addServerExecutorDependency(createDestroyServiceBuilder, ((CreateDestroyService) createDestroyService).getExecutorInjector()); + createDestroyServiceBuilder = target.addService(createDestroyServiceName); + Consumer mBeanInstanceConsumer = createDestroyServiceBuilder.provides(createDestroyServiceName); + Supplier executorSupplier = createDestroyServiceBuilder.requires(AbstractControllerService.EXECUTOR_CAPABILITY.getCapabilityServiceName()); + createDestroyService = new CreateDestroyService(mBeanInstance, createMethod, destroyMethod, componentInstantiator, setupActions, mbeanContextClassLoader, mBeanInstanceConsumer, executorSupplier); + createDestroyServiceBuilder.setInstance(createDestroyService); if(componentInstantiator != null) { // the service that starts the EE component needs to start first - createDestroyServiceBuilder.addDependency(componentInstantiator.getComponentStartServiceName()); + createDestroyServiceBuilder.requires(componentInstantiator.getComponentStartServiceName()); } final Method startMethod = ReflectionUtils.getMethod(mBeanClassHierarchy, START_METHOD_NAME, NO_ARGS, false); final Method stopMethod = ReflectionUtils.getMethod(mBeanClassHierarchy, STOP_METHOD_NAME, NO_ARGS, false); - startStopService = new StartStopService(mBeanInstance, startMethod, stopMethod, setupActions, mbeanContextClassLoader); startStopServiceName = ServiceNameFactory.newStartStop(mBeanName); - startStopServiceBuilder = target.addService(startStopServiceName, startStopService); - startStopServiceBuilder.addDependency(createDestroyServiceName); - - for(SetupAction action : setupActions) { - startStopServiceBuilder.addDependencies(action.dependencies()); - createDestroyServiceBuilder.addDependencies(action.dependencies()); + startStopServiceBuilder = target.addService(startStopServiceName); + mBeanInstanceConsumer = startStopServiceBuilder.provides(startStopServiceName); + executorSupplier = startStopServiceBuilder.requires(AbstractControllerService.EXECUTOR_CAPABILITY.getCapabilityServiceName()); + startStopService = new StartStopService(mBeanInstance, startMethod, stopMethod, setupActions, mbeanContextClassLoader, mBeanInstanceConsumer, executorSupplier); + startStopServiceBuilder.setInstance(startStopService); + startStopServiceBuilder.requires(createDestroyServiceName); + + for (SetupAction action : setupActions) { + for (ServiceName dependency : action.dependencies()) { + startStopServiceBuilder.requires(dependency); + createDestroyServiceBuilder.requires(dependency); + } } - Services.addServerExecutorDependency(startStopServiceBuilder, ((StartStopService) startStopService).getExecutorInjector()); - this.mBeanName = mBeanName; this.target = target; this.setupActions = setupActions; this.mbeanServerServiceName = mbeanServerServiceName; } - Service getCreateDestroyService() { - assertState(); - return createDestroyService; - } - - Service getStartStopService() { - assertState(); - return startStopService; - } - void addDependency(final String dependencyMBeanName) { assertState(); final ServiceName injectedMBeanCreateDestroyServiceName = ServiceNameFactory.newCreateDestroy(dependencyMBeanName); - createDestroyServiceBuilder.addDependency(injectedMBeanCreateDestroyServiceName); + createDestroyServiceBuilder.requires(injectedMBeanCreateDestroyServiceName); final ServiceName injectedMBeanStartStopServiceName = ServiceNameFactory.newStartStop(dependencyMBeanName); - startStopServiceBuilder.addDependency(injectedMBeanStartStopServiceName); + startStopServiceBuilder.requires(injectedMBeanStartStopServiceName); } - void addAttribute(final String attributeMBeanName, final Injector injector) { - assertState(); - final ServiceName injectedMBeanCreateDestroyServiceName = ServiceNameFactory.newCreateDestroy(attributeMBeanName); - createDestroyServiceBuilder.addDependency(injectedMBeanCreateDestroyServiceName, injector); - final ServiceName injectedMBeanStartStopServiceName = ServiceNameFactory.newStartStop(attributeMBeanName); - startStopServiceBuilder.addDependency(injectedMBeanStartStopServiceName); - } - + void addAttribute(final String attributeMBeanName, final Method setter, final DelegatingSupplier propertySupplier) { + assertState(); + final ServiceName injectedMBeanCreateDestroyServiceName = ServiceNameFactory.newCreateDestroy(attributeMBeanName); + final Supplier injectedMBeanSupplier = createDestroyServiceBuilder.requires(injectedMBeanCreateDestroyServiceName); + propertySupplier.setObjectSupplier(injectedMBeanSupplier); + createDestroyService.inject(setter, propertySupplier); + final ServiceName injectedMBeanStartStopServiceName = ServiceNameFactory.newStartStop(attributeMBeanName); + startStopServiceBuilder.requires(injectedMBeanStartStopServiceName); + } - void addInjectionValue(final Injector injector, final Value value) { + void addValue(final Method setter, final Supplier objectSupplier) { assertState(); - createDestroyServiceBuilder.addInjectionValue(injector, value); + createDestroyService.inject(setter, objectSupplier); } void install() { @@ -159,11 +145,11 @@ void install() { startStopServiceBuilder.install(); // Add service to register the mbean in the mbean server - final MBeanRegistrationService mbeanRegistrationService = new MBeanRegistrationService(mBeanName, setupActions); - target.addService(MBeanRegistrationService.SERVICE_NAME.append(mBeanName), mbeanRegistrationService) - .addDependency(mbeanServerServiceName, MBeanServer.class, mbeanRegistrationService.getMBeanServerInjector()) - .addDependency(startStopServiceName, Object.class, mbeanRegistrationService.getValueInjector()) - .install(); + final ServiceBuilder sb = target.addService(MBeanRegistrationService.SERVICE_NAME.append(mBeanName)); + final Supplier mBeanServerSupplier = sb.requires(mbeanServerServiceName); + final Supplier objectSupplier = sb.requires(startStopServiceName); + sb.setInstance(new MBeanRegistrationService(mBeanName, setupActions, mBeanServerSupplier, objectSupplier)); + sb.install(); installed = true; } diff --git a/sar/src/main/java/org/jboss/as/service/NullInjector.java b/sar/src/main/java/org/jboss/as/service/ObjectSupplier.java similarity index 62% rename from sar/src/main/java/org/jboss/as/service/NullInjector.java rename to sar/src/main/java/org/jboss/as/service/ObjectSupplier.java index 7d4898ef8554..43aabd42045f 100644 --- a/sar/src/main/java/org/jboss/as/service/NullInjector.java +++ b/sar/src/main/java/org/jboss/as/service/ObjectSupplier.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2011, Red Hat, Inc., and individual contributors + * Copyright 2018, 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. * @@ -22,34 +22,22 @@ package org.jboss.as.service; -import org.jboss.msc.inject.InjectionException; -import org.jboss.msc.inject.Injector; +import java.util.function.Supplier; /** - * Implements Null Object pattern with defined neutral ("null") behavior. - * * @author Richard Opalka */ -final class NullInjector implements Injector { - - private static final Injector SINGLETON = new NullInjector(); - - private NullInjector() { - // forbidden instantiation - } +final class ObjectSupplier implements Supplier { - static Injector getInstance() { - return SINGLETON; - } + private final Object object; - @Override - public void inject(final Object value) throws InjectionException { - // does nothing + ObjectSupplier(final Object object) { + this.object = object; } @Override - public void uninject() { - // does nothing + public Object get() { + return object; } } diff --git a/sar/src/main/java/org/jboss/as/service/ParsedServiceDeploymentProcessor.java b/sar/src/main/java/org/jboss/as/service/ParsedServiceDeploymentProcessor.java index a397eeb80890..396f0fa7cd7d 100644 --- a/sar/src/main/java/org/jboss/as/service/ParsedServiceDeploymentProcessor.java +++ b/sar/src/main/java/org/jboss/as/service/ParsedServiceDeploymentProcessor.java @@ -22,13 +22,11 @@ package org.jboss.as.service; -import static org.jboss.msc.value.Values.cached; - import java.beans.PropertyEditor; +import java.util.function.Supplier; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -56,15 +54,8 @@ import org.jboss.as.service.logging.SarLogger; import org.jboss.common.beans.property.finder.PropertyEditorFinder; import org.jboss.modules.Module; -import org.jboss.msc.inject.Injector; -import org.jboss.msc.inject.MethodInjector; -import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceTarget; -import org.jboss.msc.value.ImmediateValue; -import org.jboss.msc.value.MethodValue; -import org.jboss.msc.value.Value; -import org.jboss.msc.value.Values; import org.wildfly.security.manager.WildFlySecurityManager; /** @@ -133,38 +124,36 @@ private void addServices(final ServiceTarget target, final JBossServiceConfig mB final MBeanServices mBeanServices = new MBeanServices(mBeanName, mBeanInstance, mBeanClassHierarchy, target, componentInstantiator, deploymentUnit.getAttachmentList(org.jboss.as.ee.component.Attachments.WEB_SETUP_ACTIONS), classLoader, mbeanServerServiceName); final JBossServiceDependencyConfig[] dependencyConfigs = mBeanConfig.getDependencyConfigs(); - addDependencies(dependencyConfigs, mBeanClassHierarchy, mBeanServices); + addDependencies(dependencyConfigs, mBeanClassHierarchy, mBeanServices, mBeanInstance); final JBossServiceDependencyListConfig[] dependencyListConfigs = mBeanConfig.getDependencyConfigLists(); - addDependencyLists(dependencyListConfigs, mBeanClassHierarchy, mBeanServices); + addDependencyLists(dependencyListConfigs, mBeanClassHierarchy, mBeanServices, mBeanInstance); final JBossServiceAttributeConfig[] attributeConfigs = mBeanConfig.getAttributeConfigs(); - addAttributes(attributeConfigs, mBeanClassHierarchy, mBeanServices, classLoader); + addAttributes(attributeConfigs, mBeanClassHierarchy, mBeanServices, classLoader, mBeanInstance); // register all mBean related services mBeanServices.install(); } - private void addDependencies(final JBossServiceDependencyConfig[] dependencyConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices) throws DeploymentUnitProcessingException { + private void addDependencies(final JBossServiceDependencyConfig[] dependencyConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices, final Object mBeanInstance) throws DeploymentUnitProcessingException { if (dependencyConfigs != null) { - final Service createDestroyService = mBeanServices.getCreateDestroyService(); for (final JBossServiceDependencyConfig dependencyConfig : dependencyConfigs) { final String optionalAttributeName = dependencyConfig.getOptionalAttributeName(); if(optionalAttributeName != null){ - final Injector injector = getOptionalAttributeInjector(optionalAttributeName, mBeanClassHierarchy, createDestroyService); + final Method setter = ReflectionUtils.getSetter(mBeanClassHierarchy, optionalAttributeName); final ObjectName dependencyObjectName = createDependencyObjectName(dependencyConfig.getDependencyName()); - final ImmediateValue dependencyNameValue = new ImmediateValue(dependencyObjectName); - mBeanServices.addInjectionValue(injector, dependencyNameValue); + final Supplier objectSupplier = new ObjectSupplier(dependencyObjectName); + mBeanServices.addValue(setter, objectSupplier); } mBeanServices.addDependency(dependencyConfig.getDependencyName()); } } } - private void addDependencyLists(final JBossServiceDependencyListConfig[] dependencyListConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices) throws DeploymentUnitProcessingException { + private void addDependencyLists(final JBossServiceDependencyListConfig[] dependencyListConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices, final Object mBeanInstance) throws DeploymentUnitProcessingException { if(dependencyListConfigs != null){ - final Service createDestroyService = mBeanServices.getCreateDestroyService(); for(final JBossServiceDependencyListConfig dependencyListConfig: dependencyListConfigs) { final List dependencyObjectNames = new ArrayList(dependencyListConfig.getDependencyConfigs().length); for(final JBossServiceDependencyConfig dependencyConfig: dependencyListConfig.getDependencyConfigs()){ @@ -175,34 +164,31 @@ private void addDependencyLists(final JBossServiceDependencyListConfig[] depende } final String optionalAttributeName = dependencyListConfig.getOptionalAttributeName(); if(optionalAttributeName != null){ - final Injector injector = getOptionalAttributeInjector(optionalAttributeName, mBeanClassHierarchy, createDestroyService); - final ImmediateValue> dependencyNamesValue = new ImmediateValue>(dependencyObjectNames); - mBeanServices.addInjectionValue(injector, dependencyNamesValue); + final Method setter = ReflectionUtils.getSetter(mBeanClassHierarchy, optionalAttributeName); + final ObjectSupplier objectSupplier = new ObjectSupplier(dependencyObjectNames); + mBeanServices.addValue(setter, objectSupplier); } } } } - private void addAttributes(final JBossServiceAttributeConfig[] attributeConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices, final ClassLoader classLoader) throws DeploymentUnitProcessingException { + private void addAttributes(final JBossServiceAttributeConfig[] attributeConfigs, final List mBeanClassHierarchy, final MBeanServices mBeanServices, final ClassLoader classLoader, final Object mBeanInstance) throws DeploymentUnitProcessingException { if (attributeConfigs != null) { - final Service createDestroyService = mBeanServices.getCreateDestroyService(); for (final JBossServiceAttributeConfig attributeConfig : attributeConfigs) { final String propertyName = attributeConfig.getName(); final Inject injectConfig = attributeConfig.getInject(); final ValueFactory valueFactoryConfig = attributeConfig.getValueFactory(); + final Method setter = ReflectionUtils.getSetter(mBeanClassHierarchy, propertyName); if (injectConfig != null) { - final Value value = getValue(injectConfig); - final Injector injector = getPropertyInjector(propertyName, mBeanClassHierarchy, createDestroyService, value); - mBeanServices.addAttribute(injectConfig.getBeanName(), injector); + final DelegatingSupplier propertySupplier = getObjectSupplier(injectConfig); + mBeanServices.addAttribute(injectConfig.getBeanName(), setter, propertySupplier); } else if (valueFactoryConfig != null) { - final Value value = getValue(valueFactoryConfig, classLoader); - final Injector injector = getPropertyInjector(propertyName, mBeanClassHierarchy, createDestroyService, value); - mBeanServices.addAttribute(valueFactoryConfig.getBeanName(), injector); + final DelegatingSupplier valueFactorySupplier = getObjectSupplier(valueFactoryConfig, classLoader); + mBeanServices.addAttribute(valueFactoryConfig.getBeanName(), setter, valueFactorySupplier); } else { - final Value value = getValue(attributeConfig, mBeanClassHierarchy); - final Injector injector = getPropertyInjector(propertyName, mBeanClassHierarchy, createDestroyService, Values.injectedValue()); - mBeanServices.addInjectionValue(injector, value); + final Supplier value = getObjectSupplier(attributeConfig, mBeanClassHierarchy); + mBeanServices.addValue(setter, value); } } } @@ -216,50 +202,30 @@ private ObjectName createDependencyObjectName(final String dependencyName) throw } } - private static Injector getOptionalAttributeInjector(final String attributeName, final List mBeanClassHierarchy, final Service service) { - return getPropertyInjector(attributeName, mBeanClassHierarchy, service, Values.injectedValue()); - } - - private static Value getValue(final Inject injectConfig) { - final String propertyName = injectConfig.getPropertyName(); - Value valueToInject = Values.injectedValue(); - if (propertyName != null) { - final Value methodValue = new InjectedBeanMethodValue(Values.injectedValue(), new InjectedBeanMethodValue.MethodFinder() { - @Override - public Method find(Class clazz) { - return ReflectionUtils.getGetter(clazz, propertyName); - } - }); - valueToInject = cached(new MethodValue(methodValue, valueToInject, Values.emptyList())); - } - return valueToInject; + private static DelegatingSupplier getObjectSupplier(final Inject injectConfig) { + return new PropertySupplier(injectConfig.getPropertyName()); } - private static Value getValue(final ValueFactory valueFactory, final ClassLoader classLoader) throws DeploymentUnitProcessingException { + private static DelegatingSupplier getObjectSupplier(final ValueFactory valueFactory, final ClassLoader classLoader) { final String methodName = valueFactory.getMethodName(); final ValueFactoryParameter[] parameters = valueFactory.getParameters(); - final List> paramTypes = new ArrayList>(parameters.length); - final List> paramValues = new ArrayList>(parameters.length); + final Class[] paramTypes = new Class[parameters.length]; + final Object[] args = new Object[parameters.length]; + int index = 0; for (ValueFactoryParameter parameter : parameters) { - final Class attributeTypeValue = ReflectionUtils.getClass(parameter.getType(), classLoader); - paramTypes.add(attributeTypeValue); - paramValues.add(new ImmediateValue(newValue(attributeTypeValue, parameter.getValue()))); + final Class attributeType = ReflectionUtils.getClass(parameter.getType(), classLoader); + paramTypes[index] = attributeType; + args[index] = newValue(attributeType, parameter.getValue()); + index++; } - final Value methodValue = new InjectedBeanMethodValue(Values.injectedValue(), new InjectedBeanMethodValue.MethodFinder() { - @Override - public Method find(Class clazz) { - return ReflectionUtils.getMethod(clazz, methodName, paramTypes.toArray(new Class[0])); - } - }); - return cached(new MethodValue(methodValue, Values.injectedValue(), paramValues)); + return new ValueFactorySupplier(methodName, paramTypes, args); } - private static Value getValue(final JBossServiceAttributeConfig attributeConfig, final List mBeanClassHierarchy) { + private static Supplier getObjectSupplier(final JBossServiceAttributeConfig attributeConfig, final List mBeanClassHierarchy) { final String attributeName = attributeConfig.getName(); final Method setterMethod = ReflectionUtils.getSetter(mBeanClassHierarchy, attributeName); final Class setterType = setterMethod.getParameterTypes()[0]; - - return new ImmediateValue(newValue(setterType, attributeConfig.getValue())); + return new ObjectSupplier(newValue(setterType, attributeConfig.getValue())); } private static Object newInstance(final JBossServiceConfig serviceConfig, final List mBeanClassHierarchy, final ClassLoader deploymentClassLoader) throws DeploymentUnitProcessingException { @@ -292,11 +258,6 @@ private static Object newInstance(final JBossServiceConfig serviceConfig, final } } - private static Injector getPropertyInjector(final String propertyName, final List mBeanClassHierarchy, final Service service, final Value value) { - final Method setterMethod = ReflectionUtils.getSetter(mBeanClassHierarchy, propertyName); - return new MethodInjector(setterMethod, service, Values.nullValue(), Collections.singletonList(value)); - } - private static Object newValue(final Class type, final String value) { final PropertyEditor editor = PropertyEditorFinder.getInstance().find(type); if (editor == null) { diff --git a/sar/src/main/java/org/jboss/as/service/PropertySupplier.java b/sar/src/main/java/org/jboss/as/service/PropertySupplier.java new file mode 100644 index 000000000000..c04429dcb588 --- /dev/null +++ b/sar/src/main/java/org/jboss/as/service/PropertySupplier.java @@ -0,0 +1,63 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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.service; + +import java.lang.reflect.InvocationTargetException; +import java.util.function.Supplier; + +/** + * @author Richard Opalka + */ +final class PropertySupplier extends DelegatingSupplier { + + private final String propertyName; + + PropertySupplier(final String propertyName) { + this.propertyName = propertyName; + } + + @Override + public Object get() { + final Supplier objectSupplier = this.objectSupplier; + if (objectSupplier == null) { + throw new IllegalStateException("Object supplier not available"); + } + final Object o = objectSupplier.get(); + if (o == null) { + throw new IllegalStateException("Object not available"); + } + if (propertyName != null) { + try { + return ReflectionUtils.getGetter(o.getClass(), propertyName).invoke(o, (Object[]) null); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Method is not accessible", e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("Failed to invoke method", e); + } + + } else { + return o; + } + } + +} diff --git a/sar/src/main/java/org/jboss/as/service/StartStopService.java b/sar/src/main/java/org/jboss/as/service/StartStopService.java index ac89b2371054..415f59d8742d 100644 --- a/sar/src/main/java/org/jboss/as/service/StartStopService.java +++ b/sar/src/main/java/org/jboss/as/service/StartStopService.java @@ -24,7 +24,10 @@ import java.lang.reflect.Method; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionException; +import java.util.function.Supplier; +import java.util.function.Consumer; import org.jboss.as.server.deployment.SetupAction; import org.jboss.as.service.logging.SarLogger; @@ -43,14 +46,15 @@ final class StartStopService extends AbstractService { private final Method startMethod; private final Method stopMethod; - StartStopService(final Object mBeanInstance, final Method startMethod, final Method stopMethod, final List setupActions, final ClassLoader mbeanContextClassLoader) { - super(mBeanInstance, setupActions, mbeanContextClassLoader); + StartStopService(final Object mBeanInstance, final Method startMethod, final Method stopMethod, final List setupActions, final ClassLoader mbeanContextClassLoader, final Consumer mBeanInstanceConsumer, final Supplier executorSupplier) { + super(mBeanInstance, setupActions, mbeanContextClassLoader, mBeanInstanceConsumer, executorSupplier); this.startMethod = startMethod; this.stopMethod = stopMethod; } /** {@inheritDoc} */ - public void start(final StartContext context) throws StartException { + public void start(final StartContext context) { + super.start(context); if (SarLogger.ROOT_LOGGER.isTraceEnabled()) { SarLogger.ROOT_LOGGER.tracef("Starting Service: %s", context.getController().getName()); } @@ -66,7 +70,7 @@ public void run() { } }; try { - executor.getValue().submit(task); + executorSupplier.get().submit(task); } catch (RejectedExecutionException e) { task.run(); } finally { @@ -76,6 +80,7 @@ public void run() { /** {@inheritDoc} */ public void stop(final StopContext context) { + super.stop(context); if (SarLogger.ROOT_LOGGER.isTraceEnabled()) { SarLogger.ROOT_LOGGER.tracef("Stopping Service: %s", context.getController().getName()); } @@ -92,7 +97,7 @@ public void run() { } }; try { - executor.getValue().submit(task); + executorSupplier.get().submit(task); } catch (RejectedExecutionException e) { task.run(); } finally { diff --git a/sar/src/main/java/org/jboss/as/service/ValueFactorySupplier.java b/sar/src/main/java/org/jboss/as/service/ValueFactorySupplier.java new file mode 100644 index 000000000000..43d84dcac2c5 --- /dev/null +++ b/sar/src/main/java/org/jboss/as/service/ValueFactorySupplier.java @@ -0,0 +1,62 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2018, 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.service; + +import java.lang.reflect.InvocationTargetException; +import java.util.function.Supplier; + +/** + * @author Richard Opalka + */ +final class ValueFactorySupplier extends DelegatingSupplier { + + private final String methodName; + private final Class[] paramTypes; + private final Object[] args; + + ValueFactorySupplier(final String methodName, final Class[] paramTypes, final Object[] args) { + this.methodName = methodName; + this.paramTypes = paramTypes; + this.args = args; + } + + @Override + public Object get() { + final Supplier objectSupplier = this.objectSupplier; + if (objectSupplier == null) { + throw new IllegalStateException("Object supplier not available"); + } + final Object o = objectSupplier.get(); + if (o == null) { + throw new IllegalStateException("Object not available"); + } + try { + return ReflectionUtils.getMethod(o.getClass(), methodName, paramTypes).invoke(o, args); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Method is not accessible", e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("Failed to invoke method", e); + } + } + +} diff --git a/sar/src/main/java/org/jboss/as/service/logging/SarLogger.java b/sar/src/main/java/org/jboss/as/service/logging/SarLogger.java index ffabd823c72d..cefd72f7a56d 100644 --- a/sar/src/main/java/org/jboss/as/service/logging/SarLogger.java +++ b/sar/src/main/java/org/jboss/as/service/logging/SarLogger.java @@ -22,9 +22,11 @@ package org.jboss.as.service.logging; +import static org.jboss.logging.Logger.Level.ERROR; import static org.jboss.logging.Logger.Level.WARN; import javax.xml.namespace.QName; +import javax.management.ObjectName; import org.jboss.as.server.deployment.DeploymentUnit; import org.jboss.as.server.deployment.DeploymentUnitProcessingException; @@ -35,9 +37,11 @@ import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.MessageLogger; import org.jboss.vfs.VirtualFile; +import org.jboss.msc.service.StartException; /** * @author James R. Perkins + * @author Richard Opalka */ @MessageLogger(projectCode = "WFLYSAR", length = 4) public interface SarLogger extends BasicLogger { @@ -205,4 +209,33 @@ public interface SarLogger extends BasicLogger { */ @Message(id = 14, value = "Could not find default constructor for %s") DeploymentUnitProcessingException defaultConstructorNotFound(Class clazz); + + /** + * Creates an exception indicating a failure to register the MBean. + * + * @param cause the cause of the error. + * @param name the name of the MBean. + * + * @return a {@link StartException} for the error. + */ + @Message(id = 15, value = "Failed to register mbean [%s]") + StartException mbeanRegistrationFailed(@Cause Throwable cause, String name); + + /** + * Logs a warning message indicating no {@link javax.management.ObjectName} is available to unregister. + */ + @LogMessage(level = WARN) + @Message(id = 16, value = "No ObjectName available to unregister") + void cannotUnregisterObject(); + + /** + * Logs an error message indicating a failure to unregister the object name. + * + * @param cause the cause of the error. + * @param name the name of the object name. + */ + @LogMessage(level = ERROR) + @Message(id = 17, value = "Failed to unregister [%s]") + void unregistrationFailure(@Cause Throwable cause, ObjectName name); + }