/* | |
* 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.jaxws.description; | |
import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite; | |
import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite; | |
import org.apache.axis2.jaxws.description.impl.DescriptionUtils; | |
import org.apache.axis2.jaxws.description.impl.EndpointInterfaceDescriptionImpl; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* A MethodRetriever is an abstract class which is meant to be sub-classed for each type of | |
* method retrieval behavior. The catalyst for this was the introduction of new spec. | |
* interpretation by SUN RI. | |
* | |
* Please refer to the following links: | |
* | |
* | |
* https://jax-ws.dev.java.net/issues/show_bug.cgi?id=577 | |
* http://forums.java.net/jive/thread.jspa?threadID=61630 | |
* http://forums.java.net/jive/thread.jspa?threadID=55078 | |
* | |
* This base is being used to allow for a cleaner componentization of the old/new and potential | |
* future behavior changes. | |
* | |
* The sub-class is required to implement only the abstract 'retrieveMethods' | |
* | |
*/ | |
public abstract class MethodRetriever { | |
//Logging setup | |
private static final Log log = LogFactory.getLog(MethodRetriever.class); | |
private String legacyWebMethod = null; | |
public String getLegacyWebMethod() { | |
return legacyWebMethod; | |
} | |
public void setLegacyWebMethod(String legacyWebMethod) { | |
this.legacyWebMethod = legacyWebMethod; | |
} | |
protected MethodRetriever() {} | |
/* | |
* Returns a non-null (possibly empty) list of MethodDescriptionComposites | |
*/ | |
public abstract Iterator<MethodDescriptionComposite> retrieveMethods(); | |
/** | |
* A recursive method which peruses and retrieves methods in the super class hierarchy | |
* @param tmpDBC | |
* @param eid | |
* @return | |
*/ | |
protected ArrayList<MethodDescriptionComposite> retrieveSEIMethodsChain( | |
DescriptionBuilderComposite tmpDBC, EndpointInterfaceDescriptionImpl eid) { | |
DescriptionBuilderComposite dbc = tmpDBC; | |
ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>(); | |
retrieveList = retrieveSEIMethods(dbc); | |
//Since this is an interface, anything that is in the extends clause will actually appear | |
// in the interfaces list instead. | |
Iterator<String> iter = null; | |
List<String> interfacesList = dbc.getInterfacesList(); | |
if (interfacesList != null) { | |
iter = dbc.getInterfacesList().iterator(); | |
while (iter.hasNext()) { | |
String interfaceName = iter.next(); | |
DescriptionBuilderComposite superInterface = | |
eid.getEndpointDescriptionImpl().getServiceDescriptionImpl().getDBCMap().get(interfaceName); | |
retrieveList.addAll(retrieveSEIMethodsChain(superInterface, eid)); | |
} | |
} | |
return retrieveList; | |
} | |
/** | |
* This method will loop through each method that was previously determined as being relevant to | |
* the current composite. It will then drive the call to determine if this represents a method | |
* that has been overridden. If it represents an overriding method declaration it will remove | |
* the inherited methods from the list leaving only the most basic method declaration. | |
* | |
* @param methodList - <code>ArrayList</code> list of relevant methods | |
* @param dbc - <code>DescriptionBuilderComposite</code> current composite | |
* @return - <code>ArrayList</code> | |
*/ | |
protected ArrayList<MethodDescriptionComposite> removeOverriddenMethods( | |
ArrayList<MethodDescriptionComposite> methodList, DescriptionBuilderComposite dbc, EndpointInterfaceDescriptionImpl eid) { | |
Map<String, Integer> hierarchyMap = dbc.isInterface() ? getInterfaceHierarchy(dbc, eid) | |
: getClassHierarchy(dbc, eid); | |
ArrayList<MethodDescriptionComposite> returnMethods = new ArrayList<MethodDescriptionComposite>(); | |
for (int i = 0; i < methodList.size(); i++) { | |
if (notFound(returnMethods, methodList.get(i))) { | |
returnMethods.add(getBaseMethod(methodList.get(i), i, methodList, hierarchyMap)); | |
} | |
} | |
return returnMethods; | |
} | |
/** | |
* This method drives the establishment of the hierarchy of interfaces for an SEI. | |
*/ | |
private Map<String, Integer> getInterfaceHierarchy(DescriptionBuilderComposite dbc, EndpointInterfaceDescriptionImpl eid) { | |
if (log.isDebugEnabled()) { | |
log.debug("Getting interface hierarchy for: " + dbc.getClassName()); | |
} | |
Map<String, Integer> hierarchyMap = new HashMap<String, Integer>(); | |
hierarchyMap.put(dbc.getClassName(), 0); | |
return getInterfaceHierarchy(dbc.getInterfacesList(), hierarchyMap, 1, eid); | |
} | |
protected ArrayList<MethodDescriptionComposite> retrieveSEIMethods(DescriptionBuilderComposite dbc) { | |
//Rules for retrieving Methods on an SEI (or a superclass of an SEI) are simple | |
//Just retrieve all methods regardless of WebMethod annotations | |
ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>(); | |
Iterator<MethodDescriptionComposite> iter = null; | |
List<MethodDescriptionComposite> mdcList = dbc.getMethodDescriptionsList(); | |
if (mdcList != null) { | |
iter = dbc.getMethodDescriptionsList().iterator(); | |
while (iter.hasNext()) { | |
MethodDescriptionComposite mdc = iter.next(); | |
mdc.setDeclaringClass(dbc.getClassName()); | |
retrieveList.add(mdc); | |
} | |
} | |
return retrieveList; | |
} | |
/** | |
* This method will establish a <code>HashMap</code> that represents a class name of a composite | |
* and an integer value for the entry. The integer represents the classes level in the Java | |
* hierarchy. 0 represents the most basic class with n representing the highest level class. | |
* | |
* @param dbc - <code>DescriptionBuilderComposite</code> | |
* @return - <code>HashMap</code> | |
*/ | |
private HashMap<String, Integer> getClassHierarchy(DescriptionBuilderComposite dbc, EndpointInterfaceDescriptionImpl eid) { | |
HashMap<String, DescriptionBuilderComposite> dbcMap = eid.getEndpointDescriptionImpl() | |
.getServiceDescriptionImpl().getDBCMap(); | |
HashMap<String, Integer> hierarchyMap = new HashMap<String, Integer>(); | |
if (log.isDebugEnabled()) { | |
log.debug("Putting class at base level: " + dbc.getClassName()); | |
} | |
hierarchyMap.put(dbc.getClassName(), Integer.valueOf(0)); | |
DescriptionBuilderComposite superDBC = dbcMap.get((dbc.getSuperClassName())); | |
int i = 1; | |
while (superDBC != null && !superDBC.getClassName().equals("java.lang.Object")) { | |
hierarchyMap.put(superDBC.getClassName(), Integer.valueOf(i)); | |
if (log.isDebugEnabled()) { | |
log.debug("Putting class: " + superDBC.getClassName() + " at hierarchy rank: " + i); | |
} | |
i++; | |
superDBC = dbcMap.get(superDBC.getSuperClassName()); | |
} | |
return hierarchyMap; | |
} | |
/** | |
* This method will loop through each method we have already identified as a base method and | |
* compare the current method. | |
* | |
* @param mdcList - <code>ArrayList</code> identified base methods | |
* @param mdc - <code>MethodDescriptionComposite</code> current method | |
* @return - boolean | |
*/ | |
private boolean notFound(ArrayList<MethodDescriptionComposite> mdcList, | |
MethodDescriptionComposite mdc) { | |
for (MethodDescriptionComposite method : mdcList) { | |
if (mdc.compare(method)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Recursive method that builds the hierarchy of interfaces. This begins with an | |
* SEI and walks all of its super interfaces. | |
*/ | |
private Map<String, Integer> getInterfaceHierarchy(List<String> interfaces, | |
Map<String, Integer> hierarchyMap, int level, EndpointInterfaceDescriptionImpl eid) { | |
HashMap<String, DescriptionBuilderComposite> dbcMap = eid.getEndpointDescriptionImpl() | |
.getServiceDescriptionImpl().getDBCMap(); | |
// walk through all of the interfaces | |
if (interfaces != null && !interfaces.isEmpty()) { | |
for (String interfaze : interfaces) { | |
DescriptionBuilderComposite interDBC = dbcMap.get(interfaze); | |
if (interDBC != null) { | |
if (log.isDebugEnabled()) { | |
log.debug("Inserting super interface " + interDBC.getClassName() | |
+ " at level " + level); | |
} | |
hierarchyMap.put(interDBC.getClassName(), level); | |
return getInterfaceHierarchy(interDBC.getInterfacesList(), hierarchyMap, | |
level++, eid); | |
} | |
} | |
} | |
return hierarchyMap; | |
} | |
/** | |
* This method is responsible for determining the most basic level of a method declaration in | |
* the <code>DescriptionBuilderComposite</code> hierarchy. | |
* | |
* @param mdc - <code>MethodDescriptionComposite</code> current method | |
* @param index - <code>int</code> current location in method list | |
* @param methodList - <code>List</code> list of methods available on this composite | |
* @param hierarchyMap - <code>HashMap</code> map that represents the hierarchy of the current | |
* <code>DescriptionBuilderComposite</code> | |
* @return - <code>MethodDescriptionComposite</code> most basic method declaration | |
*/ | |
private static MethodDescriptionComposite getBaseMethod(MethodDescriptionComposite mdc, | |
int index, ArrayList<MethodDescriptionComposite> methodList, | |
Map<String, Integer> hierarchyMap) { | |
int baseLevel = hierarchyMap.get(mdc.getDeclaringClass()); | |
if (log.isDebugEnabled()) { | |
log.debug("Base method: " + mdc.getMethodName() + " initial level: " + baseLevel); | |
} | |
for (; index < methodList.size(); index++) { | |
MethodDescriptionComposite compareMDC = methodList.get(index); | |
// If the two methods are the same method that means we have found an inherited | |
// overridden case | |
if (mdc.equals(compareMDC)) { | |
if (log.isDebugEnabled()) { | |
log.debug("Found equivalent methods: " + mdc.getMethodName()); | |
} | |
// get the declaration level of the method we are comparing to | |
int compareLevel = hierarchyMap.get(compareMDC.getDeclaringClass()); | |
// if the method was declared by a class in a lower level of the hierarchy it | |
// becomes the method that we will compare other methods to | |
if (compareLevel < baseLevel) { | |
if (log.isDebugEnabled()) { | |
log.debug("Found method lower in hierarchy chain: " | |
+ compareMDC.getMethodName() + " of class: " | |
+ compareMDC.getMethodName()); | |
} | |
mdc = compareMDC; | |
baseLevel = compareLevel; | |
} | |
} | |
} | |
return mdc; | |
} | |
} |