blob: e036706a5ebbfdddbe8f2f3c733b177d0f9d2f75 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.axis2.description;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import org.apache.axis2.AxisFault;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.modules.Module;
import org.apache.axis2.util.JavaUtils;
import org.apache.axis2.util.Utils;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;
import javax.xml.stream.XMLStreamException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AxisDescription implements ParameterInclude, DescriptionConstants {
protected AxisDescription parent = null;
private ParameterInclude parameterInclude;
private PolicyInclude policyInclude = null;
private PolicySubject policySubject = null;
private Map<Object, AxisDescription> children;
protected Map<String, AxisModule> engagedModules;
/** List of ParameterObservers who want to be notified of changes */
protected List<ParameterObserver> parameterObservers = null;
private OMFactory omFactory = OMAbstractFactory.getOMFactory();
// Holds the documentation details for each element
private OMNode documentation;
// creating a logger instance
private static Log log = LogFactory.getLog(AxisDescription.class);
public AxisDescription() {
parameterInclude = new ParameterIncludeImpl();
children = new ConcurrentHashMap<Object, AxisDescription>();
policySubject = new PolicySubject();
}
public void addParameterObserver(ParameterObserver observer) {
if (parameterObservers == null)
parameterObservers = new ArrayList<ParameterObserver>();
parameterObservers.add(observer);
}
public void removeParameterObserver(ParameterObserver observer) {
if (parameterObservers != null) {
parameterObservers.remove(observer);
}
}
public void addParameter(Parameter param) throws AxisFault {
if (param == null) {
return;
}
if (isParameterLocked(param.getName())) {
throw new AxisFault(Messages.getMessage("paramterlockedbyparent",
param.getName()));
}
parameterInclude.addParameter(param);
// Tell anyone who wants to know
if (parameterObservers != null) {
for (Object parameterObserver : parameterObservers) {
ParameterObserver observer = (ParameterObserver)parameterObserver;
observer.parameterChanged(param.getName(), param.getValue());
}
}
}
public void addParameter(String name, Object value) throws AxisFault {
addParameter(new Parameter(name, value));
}
public void removeParameter(Parameter param) throws AxisFault {
parameterInclude.removeParameter(param);
}
public void deserializeParameters(OMElement parameterElement)
throws AxisFault {
parameterInclude.deserializeParameters(parameterElement);
}
/**
* If the parameter is found in the current description then the Parameter will be writable else
* it will be read only
*
* @param name name of Parameter to retrieve
* @return the Parameter, if found anywhere in the stack, or null if not
*/
public Parameter getParameter(String name) {
Parameter parameter = parameterInclude.getParameter(name);
if (parameter != null) {
parameter.setEditable(true);
return parameter;
}
if (parent != null) {
parameter = parent.getParameter(name);
if (parameter != null) {
parameter.setEditable(false);
}
return parameter;
}
return null;
}
public Object getParameterValue(String name) {
Parameter param = getParameter(name);
if (param == null) {
return null;
}
return param.getValue();
}
public boolean isParameterTrue(String name) {
Parameter param = getParameter(name);
return param != null && JavaUtils.isTrue(param.getValue());
}
public ArrayList<Parameter> getParameters() {
return parameterInclude.getParameters();
}
public boolean isParameterLocked(String parameterName) {
if (this.parent != null && this.parent.isParameterLocked(parameterName)) {
return true;
}
Parameter parameter = getParameter(parameterName);
return parameter != null && parameter.isLocked();
}
public String getDocumentation() {
if (documentation != null) {
if (documentation.getType() == OMNode.TEXT_NODE) {
return ((OMText)documentation).getText();
} else {
StringWriter writer = new StringWriter();
documentation.build();
try {
documentation.serialize(writer);
} catch (XMLStreamException e) {
log.error(e);
}
writer.flush();
return writer.toString();
}
}
return null;
}
public OMNode getDocumentationNode() {
return documentation;
}
public void setDocumentation(OMNode documentation) {
this.documentation = documentation;
}
public void setDocumentation(String documentation) {
if (!"".equals(documentation)) {
this.documentation = omFactory.createOMText(documentation);
}
}
public void setParent(AxisDescription parent) {
this.parent = parent;
}
public AxisDescription getParent() {
return parent;
}
/**
* @param policyInclude PolicyInclude value
* @see org.apache.axis2.description.AxisDescription#setPolicyInclude(PolicyInclude)
* @deprecated As of release 1.4, if you want to access the policy cache of a particular
* AxisDescription object use {@link #getPolicySubject()} instead.
*/
public void setPolicyInclude(PolicyInclude policyInclude) {
this.policyInclude = policyInclude;
}
/**
* @return the active PolicyInclue
* @see org.apache.axis2.description.AxisDescription#getPolicySubject()
* @deprecated As of release 1.4, replaced by {@link #getPolicySubject()}
*/
public PolicyInclude getPolicyInclude() {
if (policyInclude == null) {
policyInclude = new PolicyInclude(this);
}
return policyInclude;
}
// NOTE - These are NOT typesafe!
public void addChild(AxisDescription child) {
if (child.getKey() == null) {
// FIXME: Several classes that extend AxisDescription pass null in their getKey method.
// throw new IllegalArgumentException("Please specify a key in the child");
} else {
children.put(child.getKey(), child);
}
}
public void addChild(Object key, AxisDescription child) {
children.put(key, child);
}
public Iterator<? extends AxisDescription> getChildren() {
return children.values().iterator();
}
public AxisDescription getChild(Object key) {
if (key == null) {
// FIXME: Why are folks sending in null?
return null;
}
return (AxisDescription)children.get(key);
}
public void removeChild(Object key) {
children.remove(key);
}
/**
* This method sets the policy as the default of this AxisDescription instance. Further more
* this method does the followings. <p/> (1) Engage whatever modules necessary to execute new
* the effective policy of this AxisDescription instance. (2) Disengage whatever modules that
* are not necessary to execute the new effective policy of this AxisDescription instance. (3)
* Check whether each module can execute the new effective policy of this AxisDescription
* instance. (4) If not throw an AxisFault to notify the user. (5) Else notify each module about
* the new effective policy.
*
* @param policy the new policy of this AxisDescription instance. The effective policy is the
* merge of this argument with effective policy of parent of this
* AxisDescription.
* @throws AxisFault if any module is unable to execute the effective policy of this
* AxisDescription instance successfully or no module to execute some portion
* (one or more PrimtiveAssertions ) of that effective policy.
*/
public void applyPolicy(Policy policy) throws AxisFault {
// sets AxisDescription policy
getPolicySubject().clear();
getPolicySubject().attachPolicy(policy);
/*
* now we try to engage appropriate modules based on the merged policy
* of axis description object and the corresponding axis binding
* description object.
*/
applyPolicy();
}
/**
* Applies the policies on the Description Hierarchy recursively.
*
* @throws AxisFault an error occurred applying the policy
*/
public void applyPolicy() throws AxisFault {
AxisConfiguration configuration = getAxisConfiguration();
if (configuration == null) {
return;
}
Policy applicablePolicy = getApplicablePolicy(this);
if (applicablePolicy != null) {
engageModulesForPolicy(applicablePolicy, configuration);
}
for (Iterator<? extends AxisDescription> children = getChildren(); children.hasNext();) {
AxisDescription child = children.next();
child.applyPolicy();
}
}
private boolean canSupportAssertion(Assertion assertion, List<AxisModule> moduleList) {
Module module;
for (AxisModule axisModule : moduleList) {
// FIXME is this step really needed ??
// Shouldn't axisMoudle.getModule always return not-null value ??
module = axisModule.getModule();
if (!(module == null || module.canSupportAssertion(assertion))) {
log.debug(axisModule.getName() + " says it can't support " + assertion.getName());
return false;
}
}
return true;
}
private void engageModulesForPolicy(Policy policy, AxisConfiguration axisConfiguration)
throws AxisFault {
/*
* for the moment we consider policies with only one alternative. If the
* policy contains multiple alternatives only the first alternative will
* be considered.
*/
Iterator iterator = policy.getAlternatives();
if (!iterator.hasNext()) {
throw new AxisFault("Policy doesn't contain any policy alternatives");
}
List assertionList = (List)iterator.next();
Assertion assertion;
String namespaceURI;
List moduleList;
List namespaceList = new ArrayList();
List modulesToEngage = new ArrayList();
for (Object anAssertionList : assertionList) {
assertion = (Assertion)anAssertionList;
namespaceURI = assertion.getName().getNamespaceURI();
moduleList = axisConfiguration.getModulesForPolicyNamesapce(namespaceURI);
if (moduleList == null) {
log.debug("can't find any module to process " + assertion.getName() +
" type assertions");
continue;
}
if (!canSupportAssertion(assertion, moduleList)) {
throw new AxisFault("atleast one module can't support " + assertion.getName());
}
if (!namespaceList.contains(namespaceURI)) {
namespaceList.add(namespaceURI);
modulesToEngage.addAll(moduleList);
}
}
engageModulesToAxisDescription(modulesToEngage, this);
}
private void engageModulesToAxisDescription(List<AxisModule> moduleList, AxisDescription description)
throws AxisFault {
AxisModule axisModule;
Module module;
for (Object aModuleList : moduleList) {
axisModule = (AxisModule)aModuleList;
// FIXME is this step really needed ??
// Shouldn't axisMoudle.getModule always return not-null value ??
module = axisModule.getModule();
if (!(module == null || description.isEngaged(axisModule.getName()))) {
// engages the module to AxisDescription
description.engageModule(axisModule);
// notifies the module about the engagement
axisModule.getModule().engageNotify(description);
}
}
}
public AxisConfiguration getAxisConfiguration() {
if (this instanceof AxisConfiguration) {
return (AxisConfiguration)this;
}
if (this.parent != null) {
return this.parent.getAxisConfiguration();
}
return null;
}
public abstract Object getKey();
/**
* Engage a Module at this level
*
* @param axisModule the Module to engage
* @throws AxisFault if there's a problem engaging
*/
public void engageModule(AxisModule axisModule) throws AxisFault {
engageModule(axisModule, this);
}
/**
* Engage a Module at this level, keeping track of which level the engage was originally called
* from. This is meant for internal use only.
*
* @param axisModule module to engage
* @param source the AxisDescription which originally called engageModule()
* @throws AxisFault if there's a problem engaging
*/
public void engageModule(AxisModule axisModule, AxisDescription source) throws AxisFault {
if (engagedModules == null) engagedModules = new ConcurrentHashMap<String, AxisModule>();
String moduleName = axisModule.getName();
for (Object o : engagedModules.values()) {
AxisModule tempAxisModule = ((AxisModule)o);
String tempModuleName = tempAxisModule.getName();
if (moduleName.equals(tempModuleName)) {
String existing = tempAxisModule.getVersion();
if (!Utils.checkVersion(axisModule.getVersion(), existing)) {
throw new AxisFault(Messages.getMessage("mismatchedModuleVersions",
getClass().getName(),
moduleName,
existing));
}
}
}
// Let the Module know it's being engaged. If it's not happy about it, it can throw.
Module module = axisModule.getModule();
if (module != null) {
module.engageNotify(this);
}
// If we have anything specific to do, let that happen
onEngage(axisModule, source);
engagedModules.put(Utils.getModuleName(axisModule.getName(), axisModule.getVersion()),
axisModule);
}
protected void onEngage(AxisModule module, AxisDescription engager)
throws AxisFault {
// Default version does nothing, feel free to override
}
static Collection<AxisModule> NULL_MODULES = new ArrayList<AxisModule>(0);
public Collection<AxisModule> getEngagedModules() {
return engagedModules == null ? NULL_MODULES : engagedModules.values();
}
/**
* Check if a given module is engaged at this level.
*
* @param moduleName module to investigate.
* @return true if engaged, false if not. TODO: Handle versions? isEngaged("addressing") should
* be true even for versioned modulename...
*/
public boolean isEngaged(String moduleName) {
return engagedModules != null
&& engagedModules.keySet().contains(moduleName);
}
public boolean isEngaged(AxisModule axisModule) {
String id = Utils.getModuleName(axisModule.getName(), axisModule
.getVersion());
return engagedModules != null && engagedModules.keySet().contains(id);
}
public void disengageModule(AxisModule module) throws AxisFault {
if (module == null || engagedModules == null)
return;
// String id = Utils.getModuleName(module.getName(),
// module.getVersion());
if (isEngaged(module)) {
onDisengage(module);
engagedModules.remove(Utils.getModuleName(module.getName(), module
.getVersion()));
}
}
protected void onDisengage(AxisModule module) throws AxisFault {
// Base version does nothing
}
private Policy getApplicablePolicy(AxisDescription axisDescription) {
if (axisDescription instanceof AxisMessage) {
AxisMessage axisMessage = (AxisMessage)axisDescription;
AxisOperation axisOperation = axisMessage.getAxisOperation();
if (axisOperation != null) {
AxisService axisService = axisOperation.getAxisService();
if (axisService != null) {
if (axisService.getEndpointName() != null) {
AxisEndpoint axisEndpoint =
axisService.getEndpoint(axisService.getEndpointName());
if (axisEndpoint != null) {
AxisBinding axisBinding = axisEndpoint.getBinding();
AxisBindingOperation axisBindingOperation =
(AxisBindingOperation)axisBinding
.getChild(axisOperation.getName());
String direction = axisMessage.getDirection();
AxisBindingMessage axisBindingMessage;
if (WSDLConstants.WSDL_MESSAGE_DIRECTION_IN.equals(direction)
&& WSDLUtil
.isInputPresentForMEP(axisOperation
.getMessageExchangePattern())) {
axisBindingMessage = (AxisBindingMessage)axisBindingOperation
.getChild(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
return axisBindingMessage.getEffectivePolicy();
} else if (WSDLConstants.WSDL_MESSAGE_DIRECTION_OUT
.equals(direction)
&& WSDLUtil
.isOutputPresentForMEP(axisOperation
.getMessageExchangePattern())) {
axisBindingMessage = (AxisBindingMessage)axisBindingOperation
.getChild(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
return axisBindingMessage.getEffectivePolicy();
}
}
}
}
}
return ((AxisMessage)axisDescription).getEffectivePolicy();
}
return null;
}
public PolicySubject getPolicySubject() {
return policySubject;
}
}