/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}