1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.description;
21
22 import org.apache.axiom.om.OMAbstractFactory;
23 import org.apache.axiom.om.OMElement;
24 import org.apache.axiom.om.OMFactory;
25 import org.apache.axiom.om.OMNode;
26 import org.apache.axiom.om.OMText;
27 import org.apache.axis2.AxisFault;
28 import org.apache.axis2.engine.AxisConfiguration;
29 import org.apache.axis2.i18n.Messages;
30 import org.apache.axis2.modules.Module;
31 import org.apache.axis2.util.JavaUtils;
32 import org.apache.axis2.util.Utils;
33 import org.apache.axis2.wsdl.WSDLConstants;
34 import org.apache.axis2.wsdl.WSDLUtil;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.neethi.Assertion;
38 import org.apache.neethi.Policy;
39
40 import javax.xml.stream.XMLStreamException;
41 import java.io.StringWriter;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.concurrent.ConcurrentHashMap;
48
49 public abstract class AxisDescription implements ParameterInclude, DescriptionConstants {
50
51 protected AxisDescription parent = null;
52
53 private ParameterInclude parameterInclude;
54
55 private PolicyInclude policyInclude = null;
56
57 private PolicySubject policySubject = null;
58
59 private Map<Object, AxisDescription> children;
60
61 protected Map<String, AxisModule> engagedModules;
62
63 /** List of ParameterObservers who want to be notified of changes */
64 protected List<ParameterObserver> parameterObservers = null;
65
66 private OMFactory omFactory = OMAbstractFactory.getOMFactory();
67
68 // Holds the documentation details for each element
69 private OMNode documentation;
70
71 // creating a logger instance
72 private static Log log = LogFactory.getLog(AxisDescription.class);
73
74 public AxisDescription() {
75 parameterInclude = new ParameterIncludeImpl();
76 children = new ConcurrentHashMap<Object, AxisDescription>();
77 policySubject = new PolicySubject();
78 }
79
80 public void addParameterObserver(ParameterObserver observer) {
81 if (parameterObservers == null)
82 parameterObservers = new ArrayList<ParameterObserver>();
83 parameterObservers.add(observer);
84 }
85
86 public void removeParameterObserver(ParameterObserver observer) {
87 if (parameterObservers != null) {
88 parameterObservers.remove(observer);
89 }
90 }
91
92 public void addParameter(Parameter param) throws AxisFault {
93 if (param == null) {
94 return;
95 }
96
97 if (isParameterLocked(param.getName())) {
98 throw new AxisFault(Messages.getMessage("paramterlockedbyparent",
99 param.getName()));
100 }
101
102 parameterInclude.addParameter(param);
103
104 // Tell anyone who wants to know
105 if (parameterObservers != null) {
106 for (Object parameterObserver : parameterObservers) {
107 ParameterObserver observer = (ParameterObserver)parameterObserver;
108 observer.parameterChanged(param.getName(), param.getValue());
109 }
110 }
111 }
112
113 public void addParameter(String name, Object value) throws AxisFault {
114 addParameter(new Parameter(name, value));
115 }
116
117 public void removeParameter(Parameter param) throws AxisFault {
118 parameterInclude.removeParameter(param);
119 }
120
121 public void deserializeParameters(OMElement parameterElement)
122 throws AxisFault {
123
124 parameterInclude.deserializeParameters(parameterElement);
125
126 }
127
128 /**
129 * If the parameter is found in the current description then the Parameter will be writable else
130 * it will be read only
131 *
132 * @param name name of Parameter to retrieve
133 * @return the Parameter, if found anywhere in the stack, or null if not
134 */
135 public Parameter getParameter(String name) {
136 Parameter parameter = parameterInclude.getParameter(name);
137 if (parameter != null) {
138 parameter.setEditable(true);
139 return parameter;
140 }
141 if (parent != null) {
142 parameter = parent.getParameter(name);
143 if (parameter != null) {
144 parameter.setEditable(false);
145 }
146 return parameter;
147 }
148 return null;
149 }
150
151 public Object getParameterValue(String name) {
152 Parameter param = getParameter(name);
153 if (param == null) {
154 return null;
155 }
156 return param.getValue();
157 }
158
159 public boolean isParameterTrue(String name) {
160 Parameter param = getParameter(name);
161 return param != null && JavaUtils.isTrue(param.getValue());
162 }
163
164 public ArrayList<Parameter> getParameters() {
165 return parameterInclude.getParameters();
166 }
167
168 public boolean isParameterLocked(String parameterName) {
169
170 if (this.parent != null && this.parent.isParameterLocked(parameterName)) {
171 return true;
172 }
173
174 Parameter parameter = getParameter(parameterName);
175 return parameter != null && parameter.isLocked();
176 }
177
178 public String getDocumentation() {
179 if (documentation != null) {
180 if (documentation.getType() == OMNode.TEXT_NODE) {
181 return ((OMText)documentation).getText();
182 } else {
183 StringWriter writer = new StringWriter();
184 documentation.build();
185 try {
186 documentation.serialize(writer);
187 } catch (XMLStreamException e) {
188 log.error(e);
189 }
190 writer.flush();
191 return writer.toString();
192 }
193 }
194 return null;
195 }
196
197 public OMNode getDocumentationNode() {
198 return documentation;
199 }
200
201 public void setDocumentation(OMNode documentation) {
202 this.documentation = documentation;
203 }
204
205 public void setDocumentation(String documentation) {
206 if (!"".equals(documentation)) {
207 this.documentation = omFactory.createOMText(documentation);
208 }
209 }
210
211 public void setParent(AxisDescription parent) {
212 this.parent = parent;
213 }
214
215 public AxisDescription getParent() {
216 return parent;
217 }
218
219 /**
220 * @param policyInclude PolicyInclude value
221 * @see org.apache.axis2.description.AxisDescription#setPolicyInclude(PolicyInclude)
222 * @deprecated As of release 1.4, if you want to access the policy cache of a particular
223 * AxisDescription object use {@link #getPolicySubject()} instead.
224 */
225 public void setPolicyInclude(PolicyInclude policyInclude) {
226 this.policyInclude = policyInclude;
227 }
228
229
230 /**
231 * @return the active PolicyInclue
232 * @see org.apache.axis2.description.AxisDescription#getPolicySubject()
233 * @deprecated As of release 1.4, replaced by {@link #getPolicySubject()}
234 */
235 public PolicyInclude getPolicyInclude() {
236 if (policyInclude == null) {
237 policyInclude = new PolicyInclude(this);
238 }
239 return policyInclude;
240 }
241
242
243 // NOTE - These are NOT typesafe!
244 public void addChild(AxisDescription child) {
245 if (child.getKey() == null) {
246 // FIXME: Several classes that extend AxisDescription pass null in their getKey method.
247 // throw new IllegalArgumentException("Please specify a key in the child");
248 } else {
249 children.put(child.getKey(), child);
250 }
251 }
252
253
254 public void addChild(Object key, AxisDescription child) {
255 children.put(key, child);
256 }
257
258 public Iterator<? extends AxisDescription> getChildren() {
259 return children.values().iterator();
260 }
261
262 public AxisDescription getChild(Object key) {
263 if (key == null) {
264 // FIXME: Why are folks sending in null?
265 return null;
266 }
267 return (AxisDescription)children.get(key);
268 }
269
270 public void removeChild(Object key) {
271 children.remove(key);
272 }
273
274 /**
275 * This method sets the policy as the default of this AxisDescription instance. Further more
276 * this method does the followings. <p/> (1) Engage whatever modules necessary to execute new
277 * the effective policy of this AxisDescription instance. (2) Disengage whatever modules that
278 * are not necessary to execute the new effective policy of this AxisDescription instance. (3)
279 * Check whether each module can execute the new effective policy of this AxisDescription
280 * instance. (4) If not throw an AxisFault to notify the user. (5) Else notify each module about
281 * the new effective policy.
282 *
283 * @param policy the new policy of this AxisDescription instance. The effective policy is the
284 * merge of this argument with effective policy of parent of this
285 * AxisDescription.
286 * @throws AxisFault if any module is unable to execute the effective policy of this
287 * AxisDescription instance successfully or no module to execute some portion
288 * (one or more PrimtiveAssertions ) of that effective policy.
289 */
290 public void applyPolicy(Policy policy) throws AxisFault {
291 // sets AxisDescription policy
292 getPolicySubject().clear();
293 getPolicySubject().attachPolicy(policy);
294
295 /*
296 * now we try to engage appropriate modules based on the merged policy
297 * of axis description object and the corresponding axis binding
298 * description object.
299 */
300 applyPolicy();
301 }
302
303 /**
304 * Applies the policies on the Description Hierarchy recursively.
305 *
306 * @throws AxisFault an error occurred applying the policy
307 */
308 public void applyPolicy() throws AxisFault {
309 AxisConfiguration configuration = getAxisConfiguration();
310 if (configuration == null) {
311 return;
312 }
313
314 Policy applicablePolicy = getApplicablePolicy(this);
315 if (applicablePolicy != null) {
316 engageModulesForPolicy(applicablePolicy, configuration);
317 }
318
319 for (Iterator<? extends AxisDescription> children = getChildren(); children.hasNext();) {
320 AxisDescription child = children.next();
321 child.applyPolicy();
322 }
323 }
324
325 private boolean canSupportAssertion(Assertion assertion, List<AxisModule> moduleList) {
326
327 Module module;
328
329 for (AxisModule axisModule : moduleList) {
330 // FIXME is this step really needed ??
331 // Shouldn't axisMoudle.getModule always return not-null value ??
332 module = axisModule.getModule();
333
334 if (!(module == null || module.canSupportAssertion(assertion))) {
335 log.debug(axisModule.getName() + " says it can't support " + assertion.getName());
336 return false;
337 }
338 }
339
340 return true;
341 }
342
343 private void engageModulesForPolicy(Policy policy, AxisConfiguration axisConfiguration)
344 throws AxisFault {
345 /*
346 * for the moment we consider policies with only one alternative. If the
347 * policy contains multiple alternatives only the first alternative will
348 * be considered.
349 */
350 Iterator iterator = policy.getAlternatives();
351 if (!iterator.hasNext()) {
352 throw new AxisFault("Policy doesn't contain any policy alternatives");
353 }
354
355 List assertionList = (List)iterator.next();
356
357 Assertion assertion;
358 String namespaceURI;
359
360 List moduleList;
361
362 List namespaceList = new ArrayList();
363 List modulesToEngage = new ArrayList();
364
365 for (Object anAssertionList : assertionList) {
366 assertion = (Assertion)anAssertionList;
367 namespaceURI = assertion.getName().getNamespaceURI();
368
369 moduleList = axisConfiguration.getModulesForPolicyNamesapce(namespaceURI);
370
371 if (moduleList == null) {
372 log.debug("can't find any module to process " + assertion.getName() +
373 " type assertions");
374 continue;
375 }
376
377 if (!canSupportAssertion(assertion, moduleList)) {
378 throw new AxisFault("atleast one module can't support " + assertion.getName());
379 }
380
381 if (!namespaceList.contains(namespaceURI)) {
382 namespaceList.add(namespaceURI);
383 modulesToEngage.addAll(moduleList);
384 }
385 }
386 engageModulesToAxisDescription(modulesToEngage, this);
387 }
388
389 private void engageModulesToAxisDescription(List<AxisModule> moduleList, AxisDescription description)
390 throws AxisFault {
391
392 AxisModule axisModule;
393 Module module;
394
395 for (Object aModuleList : moduleList) {
396 axisModule = (AxisModule)aModuleList;
397 // FIXME is this step really needed ??
398 // Shouldn't axisMoudle.getModule always return not-null value ??
399 module = axisModule.getModule();
400
401 if (!(module == null || description.isEngaged(axisModule.getName()))) {
402 // engages the module to AxisDescription
403 description.engageModule(axisModule);
404 // notifies the module about the engagement
405 axisModule.getModule().engageNotify(description);
406 }
407 }
408 }
409
410 public AxisConfiguration getAxisConfiguration() {
411
412 if (this instanceof AxisConfiguration) {
413 return (AxisConfiguration)this;
414 }
415
416 if (this.parent != null) {
417 return this.parent.getAxisConfiguration();
418 }
419
420 return null;
421 }
422
423 public abstract Object getKey();
424
425
426 /**
427 * Engage a Module at this level
428 *
429 * @param axisModule the Module to engage
430 * @throws AxisFault if there's a problem engaging
431 */
432 public void engageModule(AxisModule axisModule) throws AxisFault {
433 engageModule(axisModule, this);
434 }
435
436 /**
437 * Engage a Module at this level, keeping track of which level the engage was originally called
438 * from. This is meant for internal use only.
439 *
440 * @param axisModule module to engage
441 * @param source the AxisDescription which originally called engageModule()
442 * @throws AxisFault if there's a problem engaging
443 */
444 public void engageModule(AxisModule axisModule, AxisDescription source) throws AxisFault {
445 if (engagedModules == null) engagedModules = new ConcurrentHashMap<String, AxisModule>();
446 String moduleName = axisModule.getName();
447 for (Object o : engagedModules.values()) {
448 AxisModule tempAxisModule = ((AxisModule)o);
449 String tempModuleName = tempAxisModule.getName();
450
451 if (moduleName.equals(tempModuleName)) {
452 String existing = tempAxisModule.getVersion();
453 if (!Utils.checkVersion(axisModule.getVersion(), existing)) {
454 throw new AxisFault(Messages.getMessage("mismatchedModuleVersions",
455 getClass().getName(),
456 moduleName,
457 existing));
458 }
459 }
460
461 }
462
463 // Let the Module know it's being engaged. If it's not happy about it, it can throw.
464 Module module = axisModule.getModule();
465 if (module != null) {
466 module.engageNotify(this);
467 }
468
469 // If we have anything specific to do, let that happen
470 onEngage(axisModule, source);
471
472 engagedModules.put(Utils.getModuleName(axisModule.getName(), axisModule.getVersion()),
473 axisModule);
474 }
475
476 protected void onEngage(AxisModule module, AxisDescription engager)
477 throws AxisFault {
478 // Default version does nothing, feel free to override
479 }
480
481 static Collection<AxisModule> NULL_MODULES = new ArrayList<AxisModule>(0);
482
483 public Collection<AxisModule> getEngagedModules() {
484 return engagedModules == null ? NULL_MODULES : engagedModules.values();
485 }
486
487 /**
488 * Check if a given module is engaged at this level.
489 *
490 * @param moduleName module to investigate.
491 * @return true if engaged, false if not. TODO: Handle versions? isEngaged("addressing") should
492 * be true even for versioned modulename...
493 */
494 public boolean isEngaged(String moduleName) {
495 return engagedModules != null
496 && engagedModules.keySet().contains(moduleName);
497 }
498
499 public boolean isEngaged(AxisModule axisModule) {
500 String id = Utils.getModuleName(axisModule.getName(), axisModule
501 .getVersion());
502 return engagedModules != null && engagedModules.keySet().contains(id);
503 }
504
505 public void disengageModule(AxisModule module) throws AxisFault {
506 if (module == null || engagedModules == null)
507 return;
508 // String id = Utils.getModuleName(module.getName(),
509 // module.getVersion());
510 if (isEngaged(module)) {
511 onDisengage(module);
512 engagedModules.remove(Utils.getModuleName(module.getName(), module
513 .getVersion()));
514 }
515 }
516
517 protected void onDisengage(AxisModule module) throws AxisFault {
518 // Base version does nothing
519 }
520
521 private Policy getApplicablePolicy(AxisDescription axisDescription) {
522 if (axisDescription instanceof AxisMessage) {
523 AxisMessage axisMessage = (AxisMessage)axisDescription;
524 AxisOperation axisOperation = axisMessage.getAxisOperation();
525 if (axisOperation != null) {
526 AxisService axisService = axisOperation.getAxisService();
527 if (axisService != null) {
528 if (axisService.getEndpointName() != null) {
529 AxisEndpoint axisEndpoint =
530 axisService.getEndpoint(axisService.getEndpointName());
531 if (axisEndpoint != null) {
532 AxisBinding axisBinding = axisEndpoint.getBinding();
533 AxisBindingOperation axisBindingOperation =
534 (AxisBindingOperation)axisBinding
535 .getChild(axisOperation.getName());
536 String direction = axisMessage.getDirection();
537 AxisBindingMessage axisBindingMessage;
538 if (WSDLConstants.WSDL_MESSAGE_DIRECTION_IN.equals(direction)
539 && WSDLUtil
540 .isInputPresentForMEP(axisOperation
541 .getMessageExchangePattern())) {
542 axisBindingMessage = (AxisBindingMessage)axisBindingOperation
543 .getChild(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
544 return axisBindingMessage.getEffectivePolicy();
545
546 } else if (WSDLConstants.WSDL_MESSAGE_DIRECTION_OUT
547 .equals(direction)
548 && WSDLUtil
549 .isOutputPresentForMEP(axisOperation
550 .getMessageExchangePattern())) {
551 axisBindingMessage = (AxisBindingMessage)axisBindingOperation
552 .getChild(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
553 return axisBindingMessage.getEffectivePolicy();
554 }
555 }
556
557 }
558 }
559 }
560 return ((AxisMessage)axisDescription).getEffectivePolicy();
561 }
562 return null;
563 }
564
565 public PolicySubject getPolicySubject() {
566 return policySubject;
567 }
568
569 }