PageRenderTime 54ms CodeModel.GetById 26ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/jboss-as-7.1.1.Final/ee/src/main/java/org/jboss/as/ee/component/deployers/ModuleJndiBindingProcessor.java

#
Java | 305 lines | 215 code | 40 blank | 50 comment | 45 complexity | b683d1d12273f88c0a57e354eb0d34cd MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1/*
  2 * JBoss, Home of Professional Open Source.
  3 * Copyright 2011, Red Hat, Inc., and individual contributors
  4 * as indicated by the @author tags. See the copyright.txt file in the
  5 * distribution for a full listing of individual contributors.
  6 *
  7 * This is free software; you can redistribute it and/or modify it
  8 * under the terms of the GNU Lesser General Public License as
  9 * published by the Free Software Foundation; either version 2.1 of
 10 * the License, or (at your option) any later version.
 11 *
 12 * This software is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15 * Lesser General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU Lesser General Public
 18 * License along with this software; if not, write to the Free
 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 21 */
 22package org.jboss.as.ee.component.deployers;
 23
 24import java.util.HashMap;
 25import java.util.HashSet;
 26import java.util.List;
 27import java.util.Map;
 28import java.util.Set;
 29
 30import org.jboss.as.controller.ServiceVerificationHandler;
 31import org.jboss.as.ee.component.Attachments;
 32import org.jboss.as.ee.component.BindingConfiguration;
 33import org.jboss.as.ee.component.ClassDescriptionTraversal;
 34import org.jboss.as.ee.component.ComponentConfiguration;
 35import org.jboss.as.ee.component.ComponentNamingMode;
 36import org.jboss.as.ee.component.EEApplicationClasses;
 37import org.jboss.as.ee.component.EEModuleClassDescription;
 38import org.jboss.as.ee.component.EEModuleConfiguration;
 39import org.jboss.as.ee.component.EEModuleDescription;
 40import org.jboss.as.ee.component.InjectionSource;
 41import org.jboss.as.ee.component.InterceptorDescription;
 42import org.jboss.as.ee.metadata.MetadataCompleteMarker;
 43import org.jboss.as.ee.naming.ContextInjectionSource;
 44import org.jboss.as.ee.structure.DeploymentType;
 45import org.jboss.as.ee.structure.DeploymentTypeMarker;
 46import org.jboss.as.naming.ManagedReferenceFactory;
 47import org.jboss.as.naming.ServiceBasedNamingStore;
 48import org.jboss.as.naming.deployment.ContextNames;
 49import org.jboss.as.naming.service.BinderService;
 50import org.jboss.as.server.CurrentServiceContainer;
 51import org.jboss.as.server.deployment.DeploymentPhaseContext;
 52import org.jboss.as.server.deployment.DeploymentUnit;
 53import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
 54import org.jboss.as.server.deployment.DeploymentUnitProcessor;
 55import org.jboss.as.server.deployment.reflect.ClassIndex;
 56import org.jboss.as.server.deployment.reflect.DeploymentClassIndex;
 57import org.jboss.msc.service.AbstractServiceListener;
 58import org.jboss.msc.service.CircularDependencyException;
 59import org.jboss.msc.service.DuplicateServiceException;
 60import org.jboss.msc.service.ServiceBuilder;
 61import org.jboss.msc.service.ServiceController;
 62import org.jboss.msc.service.ServiceName;
 63
 64import static org.jboss.as.ee.EeLogger.ROOT_LOGGER;
 65import static org.jboss.as.ee.EeMessages.MESSAGES;
 66
 67/**
 68 * Processor that sets up JNDI bindings that are owned by the module. It also handles class level jndi bindings
 69 * that belong to components that do not have their own java:comp namespace, and class level bindings declared in
 70 * namespaces above java:comp.
 71 * <p/>
 72 * This processor is also responsible for throwing an exception if any ee component classes have been marked as invalid.
 73 *
 74 * @author Stuart Douglas
 75 */
 76public class
 77        ModuleJndiBindingProcessor implements DeploymentUnitProcessor {
 78
 79    private static class IntHolder {
 80        private int value = 0;
 81    }
 82
 83    public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
 84        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 85        final EEApplicationClasses applicationClasses = deploymentUnit.getAttachment(Attachments.EE_APPLICATION_CLASSES_DESCRIPTION);
 86        final EEModuleConfiguration moduleConfiguration = deploymentUnit.getAttachment(Attachments.EE_MODULE_CONFIGURATION);
 87        final EEModuleDescription eeModuleDescription = deploymentUnit.getAttachment(Attachments.EE_MODULE_DESCRIPTION);
 88        final DeploymentClassIndex classIndex = deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.CLASS_INDEX);
 89        if (moduleConfiguration == null) {
 90            return;
 91        }
 92        final Set<ServiceName> dependencies = deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.JNDI_DEPENDENCIES);
 93
 94        final Map<ServiceName, BindingConfiguration> deploymentDescriptorBindings = new HashMap<ServiceName, BindingConfiguration>();
 95
 96        // bindings
 97        // Handle duplicates binding from the same source
 98        // TODO: Should the view configuration just return a Set instead of a List? Or is there a better way to
 99        // handle these duplicates?
100        IntHolder moduleCount = new IntHolder();
101        final List<BindingConfiguration> bindingConfigurations = eeModuleDescription.getBindingConfigurations();
102
103        //we need to make sure that java:module/env and java:comp/env are always available
104        if (!DeploymentTypeMarker.isType(DeploymentType.EAR, deploymentUnit)) {
105            bindingConfigurations.add(new BindingConfiguration("java:module/env", new ContextInjectionSource("env", "java:module/env")));
106        }
107        if (deploymentUnit.getParent() == null) {
108            bindingConfigurations.add(new BindingConfiguration("java:app/env", new ContextInjectionSource("env", "java:app/env")));
109        }
110
111
112        final ServiceName moduleOwnerName = deploymentUnit.getServiceName().append("module").append(moduleConfiguration.getApplicationName()).append(moduleConfiguration.getModuleName());
113        for (BindingConfiguration binding : bindingConfigurations) {
114
115            final ContextNames.BindInfo bindInfo = ContextNames.bindInfoForEnvEntry(moduleConfiguration.getApplicationName(), moduleConfiguration.getModuleName(), null, false, binding.getName());
116
117            deploymentDescriptorBindings.put(bindInfo.getBinderServiceName(), binding);
118            addJndiBinding(moduleConfiguration, binding, phaseContext, bindInfo.getBinderServiceName(), moduleOwnerName, moduleCount, dependencies);
119        }
120
121        //now we process all component level bindings, for components that do not have their own java:comp namespace.
122        // these are bindings that have been added via a deployment descriptor
123        for (final ComponentConfiguration componentConfiguration : moduleConfiguration.getComponentConfigurations()) {
124            // TODO: Should the view configuration just return a Set instead of a List? Or is there a better way to
125            // handle these duplicates?
126            for (BindingConfiguration binding : componentConfiguration.getComponentDescription().getBindingConfigurations()) {
127                final String bindingName = binding.getName();
128                final boolean compBinding = bindingName.startsWith("java:comp") || !bindingName.startsWith("java:");
129                if (componentConfiguration.getComponentDescription().getNamingMode() == ComponentNamingMode.CREATE && compBinding) {
130                    //components with there own comp context do their own binding
131                    continue;
132                }
133
134                final ContextNames.BindInfo bindInfo = ContextNames.bindInfoForEnvEntry(moduleConfiguration.getApplicationName(), moduleConfiguration.getModuleName(), null, false, binding.getName());
135                deploymentDescriptorBindings.put(bindInfo.getBinderServiceName(), binding);
136                addJndiBinding(moduleConfiguration, binding, phaseContext, bindInfo.getBinderServiceName(), moduleOwnerName, moduleCount, dependencies);
137            }
138        }
139
140        //now add all class level bindings
141        final Set<String> handledClasses = new HashSet<String>();
142
143        for (final ComponentConfiguration componentConfiguration : moduleConfiguration.getComponentConfigurations()) {
144            final Set<Class<?>> classConfigurations = new HashSet<Class<?>>();
145            classConfigurations.add(componentConfiguration.getComponentClass());
146
147            for (final InterceptorDescription interceptor : componentConfiguration.getComponentDescription().getAllInterceptors()) {
148                try {
149                    final ClassIndex interceptorClass = classIndex.classIndex(interceptor.getInterceptorClassName());
150                    classConfigurations.add(interceptorClass.getModuleClass());
151                } catch (ClassNotFoundException e) {
152                    throw MESSAGES.cannotLoadInterceptor(e, interceptor.getInterceptorClassName(), componentConfiguration.getComponentClass());
153                }
154            }
155            processClassConfigurations(phaseContext, applicationClasses, moduleConfiguration, deploymentDescriptorBindings, handledClasses, componentConfiguration.getComponentDescription().getNamingMode(), classConfigurations, componentConfiguration.getComponentName(), moduleOwnerName, moduleCount, dependencies);
156        }
157
158    }
159
160    private void processClassConfigurations(final DeploymentPhaseContext phaseContext, final EEApplicationClasses applicationClasses, final EEModuleConfiguration moduleConfiguration, final Map<ServiceName, BindingConfiguration> deploymentDescriptorBindings, final Set<String> handledClasses, final ComponentNamingMode namingMode, final Set<Class<?>> classes, final String componentName, final ServiceName ownerName, final IntHolder handleCount, final Set<ServiceName> dependencies) throws DeploymentUnitProcessingException {
161        for (final Class<?> clazz : classes) {
162            new ClassDescriptionTraversal(clazz, applicationClasses) {
163                @Override
164                protected void handle(final Class<?> currentClass, final EEModuleClassDescription classDescription) throws DeploymentUnitProcessingException {
165                    if (classDescription == null) {
166                        return;
167                    }
168                    if (classDescription.isInvalid()) {
169                        throw MESSAGES.componentClassHasErrors(classDescription.getClassName(), componentName, classDescription.getInvalidMessage());
170                    }
171                    //only process classes once
172                    if (handledClasses.contains(classDescription.getClassName())) {
173                        return;
174                    }
175                    handledClasses.add(classDescription.getClassName());
176                    // TODO: Should the view configuration just return a Set instead of a List? Or is there a better way to
177                    // handle these duplicates?
178                    if (!MetadataCompleteMarker.isMetadataComplete(phaseContext.getDeploymentUnit())) {
179                        final Set<BindingConfiguration> classLevelBindings = new HashSet<BindingConfiguration>(classDescription.getBindingConfigurations());
180                        for (BindingConfiguration binding : classLevelBindings) {
181                            final String bindingName = binding.getName();
182                            final boolean compBinding = bindingName.startsWith("java:comp") || !bindingName.startsWith("java:");
183                            if (namingMode == ComponentNamingMode.CREATE && compBinding) {
184                                //components with their own comp context do their own binding
185                                continue;
186                            }
187                            final ContextNames.BindInfo bindInfo = ContextNames.bindInfoForEnvEntry(moduleConfiguration.getApplicationName(), moduleConfiguration.getModuleName(), null, false, binding.getName());
188
189                            ROOT_LOGGER.tracef("Binding %s using service %s", binding.getName(), bindInfo.getBinderServiceName());
190
191                            if (deploymentDescriptorBindings.containsKey(bindInfo.getBinderServiceName())) {
192                                continue; //this has been overridden by a DD binding
193                            }
194                            addJndiBinding(moduleConfiguration, binding, phaseContext, bindInfo.getBinderServiceName(), ownerName, handleCount, dependencies);
195                        }
196                    }
197                }
198            }.run();
199        }
200    }
201
202
203    protected void addJndiBinding(final EEModuleConfiguration module, final BindingConfiguration bindingConfiguration, final DeploymentPhaseContext phaseContext, ServiceName serviceName, ServiceName ownerName, IntHolder handleCount, final Set<ServiceName> dependencies) throws DeploymentUnitProcessingException {
204        // Gather information about the dependency
205        final String bindingName = bindingConfiguration.getName().startsWith("java:") ? bindingConfiguration.getName() : "java:module/env/" + bindingConfiguration.getName();
206
207        final ServiceVerificationHandler serviceVerificationHandler = phaseContext.getDeploymentUnit().getAttachment(org.jboss.as.server.deployment.Attachments.SERVICE_VERIFICATION_HANDLER);
208
209        InjectionSource.ResolutionContext resolutionContext = new InjectionSource.ResolutionContext(
210                true,
211                module.getModuleName(),
212                module.getModuleName(),
213                module.getApplicationName()
214        );
215
216        // Check to see if this entry should actually be bound into JNDI.
217        if (bindingName != null) {
218            final ContextNames.BindInfo bindInfo = ContextNames.bindInfoForEnvEntry(module.getApplicationName(), module.getModuleName(), module.getModuleName(), false, bindingName);
219
220            if (bindingName.startsWith("java:comp") || bindingName.startsWith("java:module") || bindingName.startsWith("java:app")) {
221                //this is a binding that does not need to be shared.
222
223                try {
224                    final BinderService service = new BinderService(bindInfo.getBindName(), bindingConfiguration.getSource());
225                    dependencies.add(bindInfo.getBinderServiceName());
226                    ServiceBuilder<ManagedReferenceFactory> serviceBuilder = phaseContext.getServiceTarget().addService(bindInfo.getBinderServiceName(), service);
227                    bindingConfiguration.getSource().getResourceValue(resolutionContext, serviceBuilder, phaseContext, service.getManagedObjectInjector());
228                    serviceBuilder.addDependency(bindInfo.getParentContextServiceName(), ServiceBasedNamingStore.class, service.getNamingStoreInjector());
229                    serviceBuilder.install();
230                } catch (DuplicateServiceException e) {
231                    ServiceController<ManagedReferenceFactory> registered = (ServiceController<ManagedReferenceFactory>) CurrentServiceContainer.getServiceContainer().getService(bindInfo.getBinderServiceName());
232                    if (registered == null)
233                        throw e;
234
235                    BinderService service = (BinderService) registered.getService();
236                    if (!service.getSource().equals(bindingConfiguration.getSource()))
237                        throw MESSAGES.conflictingBinding(bindingName, bindingConfiguration.getSource());
238                } catch (CircularDependencyException e) {
239                    throw MESSAGES.circularDependency(bindingName);
240                }
241
242            } else {
243                ServiceController<ManagedReferenceFactory> controller = null;
244                BinderService service;
245                try {
246                    service = new BinderService(bindInfo.getBindName(), bindingConfiguration.getSource());
247                    dependencies.add(bindInfo.getBinderServiceName());
248                    ServiceBuilder<ManagedReferenceFactory> serviceBuilder = CurrentServiceContainer.getServiceContainer().addService(bindInfo.getBinderServiceName(), service);
249                    bindingConfiguration.getSource().getResourceValue(resolutionContext, serviceBuilder, phaseContext, service.getManagedObjectInjector());
250                    serviceBuilder.addDependency(bindInfo.getParentContextServiceName(), ServiceBasedNamingStore.class, service.getNamingStoreInjector());
251                    serviceBuilder.addListener(serviceVerificationHandler);
252                    controller = serviceBuilder.install();
253
254                    service.acquire();
255                } catch (DuplicateServiceException e) {
256                    controller = (ServiceController<ManagedReferenceFactory>) CurrentServiceContainer.getServiceContainer().getService(bindInfo.getBinderServiceName());
257                    if (controller == null)
258                        throw e;
259
260                    service = (BinderService) controller.getService();
261                    if (!service.getSource().equals(bindingConfiguration.getSource())) {
262                        throw MESSAGES.conflictingBinding(bindingName, bindingConfiguration.getSource());
263                    }
264                    service.acquire();
265                }
266                //as these bindings are not child services
267                //we need to add a listener that released the service when the deployment stops
268                ServiceController<?> unitService = CurrentServiceContainer.getServiceContainer().getService(phaseContext.getDeploymentUnit().getServiceName());
269                final BinderService binderService = service;
270                unitService.addListener(new BinderReleaseListener(binderService));
271            }
272
273        } else {
274            throw MESSAGES.nullBindingName(bindingConfiguration);
275        }
276    }
277
278    public void undeploy(DeploymentUnit context) {
279    }
280
281    private static class BinderReleaseListener<T> extends AbstractServiceListener<T> {
282
283        private final BinderService binderService;
284
285        public BinderReleaseListener(final BinderService binderService) {
286            this.binderService = binderService;
287        }
288
289        @Override
290        public void listenerAdded(final ServiceController<? extends T> serviceController) {
291            if (serviceController.getState() == ServiceController.State.DOWN || serviceController.getState() == ServiceController.State.STOPPING) {
292                binderService.release();
293                serviceController.removeListener(this);
294            }
295        }
296
297        @Override
298        public void transition(final ServiceController<? extends T> serviceController, final ServiceController.Transition transition) {
299            if (transition.getAfter() == ServiceController.Substate.STOPPING) {
300                binderService.release();
301                serviceController.removeListener(this);
302            }
303        }
304    }
305}