/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.naming;
import org.jboss.as.naming.deployment.JndiNamingDependencyProcessor;
import org.jboss.as.naming.deployment.RuntimeBindReleaseService;
import org.jboss.as.naming.logging.NamingLogger;
import org.jboss.as.naming.service.BinderService;
import org.jboss.as.naming.service.SharedBinderService;
import org.jboss.as.naming.util.ThreadLocalStack;
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.service.StabilityMonitor;
import org.jboss.msc.value.ImmediateValue;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import java.util.Hashtable;
import static org.jboss.as.naming.util.NamingUtils.isLastComponentEmpty;
import static org.jboss.as.naming.util.NamingUtils.namingException;
/**
* @author John Bailey
* @author Eduardo Martins
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
public class WritableServiceBasedNamingStore extends ServiceBasedNamingStore implements WritableNamingStore {
private static final ThreadLocalStack WRITE_OWNER = new ThreadLocalStack();
private final ServiceTarget serviceTarget;
public WritableServiceBasedNamingStore(ServiceRegistry serviceRegistry, ServiceName serviceNameBase, ServiceTarget serviceTarget) {
super(serviceRegistry, serviceNameBase);
this.serviceTarget = serviceTarget;
}
public void bind(final Name name, final Object object, final Class<?> bindType) throws NamingException {
bind(name, object);
}
public void bind(final Name name, final Object object) throws NamingException {
final Object owner = requireOwner();
final ServiceName bindName = buildServiceName(name);
bind(name, object, owner, bindName);
}
private void bind(Name name, Object object, Object owner, ServiceName bindName) throws NamingException {
ServiceTarget serviceTarget = this.serviceTarget;
ServiceName deploymentUnitServiceName = null;
if (owner instanceof ServiceName) {
deploymentUnitServiceName = (ServiceName) owner;
} else {
serviceTarget = (ServiceTarget) owner;
}
try {
// unlike on deployment processors, we may assume here it's a shareable bind if the owner is a deployment, because deployment unshareable namespaces are readonly stores
final BinderService binderService = deploymentUnitServiceName != null ? new SharedBinderService(name.toString(), null) : new BinderService(name.toString(), null);
final ServiceBuilder<?> builder = serviceTarget.addService(bindName, binderService)
.addDependency(getServiceNameBase(), ServiceBasedNamingStore.class, binderService.getNamingStoreInjector())
.addInjection(binderService.getManagedObjectInjector(), new ImmediateManagedReferenceFactory(object))
.setInitialMode(ServiceController.Mode.ACTIVE);
final ServiceController<?> binderServiceController = builder.install();
final StabilityMonitor monitor = new StabilityMonitor();
monitor.addController(binderServiceController);
try {
monitor.awaitStability();
} finally {
monitor.removeController(binderServiceController);
}
final Exception startException = binderServiceController.getStartException();
if (startException != null) {
throw startException;
}
if (deploymentUnitServiceName != null) {
final RuntimeBindReleaseService.References duBindingReferences = (RuntimeBindReleaseService.References) binderServiceController.getServiceContainer().getService(JndiNamingDependencyProcessor.serviceName(deploymentUnitServiceName)).getValue();
duBindingReferences.acquire(((SharedBinderService) binderService));
}
} catch (Exception e) {
throw namingException("Failed to bind [" + object + "] at location [" + bindName + "]", e);
}
}
public void rebind(Name name, Object object) throws NamingException {
final Object owner = requireOwner();
// re-set the existent binder service injected value
final ServiceName bindName = buildServiceName(name);
final ServiceController<?> controller = getServiceRegistry().getService(bindName);
if (controller == null) {
bind(name, object, owner, bindName);
} else {
final BinderService binderService = (BinderService) controller.getService();
if (owner instanceof ServiceName && binderService instanceof SharedBinderService) {
final ServiceName deploymentUnitServiceName = (ServiceName) owner;
final RuntimeBindReleaseService.References duBindingReferences = (RuntimeBindReleaseService.References) controller.getServiceContainer().getService(JndiNamingDependencyProcessor.serviceName(deploymentUnitServiceName)).getValue();
duBindingReferences.acquire(((SharedBinderService) binderService));
}
binderService.getManagedObjectInjector().setValue(new ImmediateValue(new ImmediateManagedReferenceFactory(object)));
}
}
public void rebind(final Name name, final Object object, final Class<?> bindType) throws NamingException {
rebind(name, object);
}
public void unbind(final Name name) throws NamingException {
requireOwner();
final ServiceName bindName = buildServiceName(name);
final ServiceController<?> controller = getServiceRegistry().getService(bindName);
if (controller == null) {
throw NamingLogger.ROOT_LOGGER.cannotResolveService(bindName);
}
((BinderService) controller.getService()).stopNow();
final StabilityMonitor monitor = new StabilityMonitor();
monitor.addController(controller);
try {
monitor.awaitStability();
} catch (Exception e) {
throw namingException("Failed to unbind [" + bindName + "]", e);
} finally {
monitor.removeController(controller);
}
}
public Context createSubcontext(final Name name) throws NamingException {
requireOwner();
if (isLastComponentEmpty(name)) {
throw NamingLogger.ROOT_LOGGER.emptyNameNotAllowed();
}
return new NamingContext(name, WritableServiceBasedNamingStore.this, new Hashtable<String, Object>());
}
private Object requireOwner() {
final Object owner = WRITE_OWNER.peek();
if (owner == null) {
throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
}
return owner;
}
public static void pushOwner(final ServiceName deploymentUnitServiceName) {
WRITE_OWNER.push(deploymentUnitServiceName);
}
public static void pushOwner(final ServiceTarget serviceTarget) {
WRITE_OWNER.push(serviceTarget);
}
public static void popOwner() {
WRITE_OWNER.pop();
}
}