/* * Copyright 2014-2016 Red Hat, Inc, and individual contributors. * * 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.projectodd.wunderboss.as.singletons; import org.jboss.as.server.ServerEnvironment; import org.jboss.as.server.ServerEnvironmentService; import org.jboss.msc.service.DelegatingServiceContainer; import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.ServiceTarget; import org.jboss.msc.value.InjectedValue; import org.projectodd.wunderboss.WunderBoss; import org.projectodd.wunderboss.as.ASUtils; import org.projectodd.wunderboss.as.ModuleUtils; import org.wildfly.clustering.singleton.SingletonElectionPolicy; import org.wildfly.clustering.singleton.SingletonServiceBuilderFactory; import java.lang.reflect.InvocationTargetException; public class SingletonHelper { private static final ServiceName[] SINGLETON_FACTORY_NAMES = { ServiceName.parse("jboss.clustering.singleton.builder.server.default"), // WF8,9 ServiceName.parse("jboss.clustering.singleton.server.default") }; // WF10 private static final ServiceName SINGLETON_NAME = ServiceName.of("wunderboss", "singleton"); //TODO: expose election policy, quorum? public static void installSingleton(final ServiceRegistry registry, final ServiceTarget target, final Service service, final String name) { final String deploymentName = (String)WunderBoss.options().get("deployment-name"); final ServiceName serviceName = SINGLETON_NAME.append(deploymentName).append(name); if (ASUtils.containerIsEAP6()) { installEAPSingleton(registry, target, service, serviceName); } else { installWildFlySingleton(registry, target, service, serviceName); } } private static void installEAPSingleton(final ServiceRegistry registry, final ServiceTarget target, final Service service, final ServiceName name) { try { Class clazz = SingletonHelper.class.getClassLoader() .loadClass("org.jboss.as.clustering.singleton.SingletonService"); Object singletonService = clazz.getDeclaredConstructor(Service.class, ServiceName.class) .newInstance(service, name); ModuleUtils.lookupMethodByName(clazz, "setElectionPolicy").invoke(singletonService, electionPolicy()); ServiceBuilder builder = (ServiceBuilder)ModuleUtils.lookupMethod(clazz, "build", ServiceTarget.class) .invoke(singletonService, new DelegatingServiceContainer(target, registry)); builder.setInitialMode(ServiceController.Mode.ACTIVE).install(); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("Failed to install singleton service", e); } } private static void installWildFlySingleton(final ServiceRegistry registry, final ServiceTarget target, final Service service, final ServiceName name) { SingletonServiceBuilderFactory factory = null; for(ServiceName each : SINGLETON_FACTORY_NAMES) { ServiceController factoryService = registry.getService(each); if (factoryService != null) { factory = (SingletonServiceBuilderFactory)factoryService.getValue(); } } if (factory == null) { throw new RuntimeException("Failed to locate singleton builder"); } final InjectedValue<ServerEnvironment> env = new InjectedValue<>(); factory.createSingletonServiceBuilder(name, service) .electionPolicy((SingletonElectionPolicy)electionPolicy()) .requireQuorum(1) .build(target) .addDependency(ServerEnvironmentService.SERVICE_NAME, ServerEnvironment.class, env) .setInitialMode(ServiceController.Mode.ACTIVE) .install(); } private static Object electionPolicy() { String className; if (ASUtils.containerIsEAP6()) { className = "org.jboss.as.clustering.singleton.election.SimpleSingletonElectionPolicy"; } else if (ASUtils.containerIsWildFly10()) { className = "org.wildfly.clustering.singleton.election.RandomSingletonElectionPolicy"; } else { // non-deterministic election policies (in WF versions < 10) can cause multiple or no // singletons to start in the cluster, since each node determines the master individually // so we use the simple policy (which is deterministic) if we're not in WF10. // see https://issues.jboss.org/browse/WFLY-5108 className = "org.wildfly.clustering.singleton.election.SimpleSingletonElectionPolicy"; } try { Class clazz = SingletonHelper.class.getClassLoader().loadClass(className); return clazz.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { throw new RuntimeException("Failed to load election policy", e); } } }