diff --git a/modules/core/src/main/java/org/apache/synapse/api/API.java b/modules/core/src/main/java/org/apache/synapse/api/API.java index 78cfb298c6..2c59db3b47 100644 --- a/modules/core/src/main/java/org/apache/synapse/api/API.java +++ b/modules/core/src/main/java/org/apache/synapse/api/API.java @@ -246,6 +246,10 @@ public Resource[] getResources() { return resources.values().toArray(new Resource[resources.size()]); } + public Map getResourcesMap() { + return resources; + } + public void addHandler(Handler handler) { handlers.add(handler); } @@ -443,12 +447,7 @@ public void process(MessageContext synCtx) { msgCtx.getIncomingTransportName() + "://" + hostHeader); } - Set acceptableResources = new LinkedHashSet(); - for (Resource r : resources.values()) { - if (isBound(r, synCtx) && r.canProcess(synCtx)) { - acceptableResources.add(r); - } - } + Set acceptableResources = ApiUtils.getAcceptableResources(resources, synCtx); boolean processed = false; if (!acceptableResources.isEmpty()) { @@ -530,23 +529,6 @@ private void handleMethodNotAllowed(MessageContext synCtx) { } - /** - * Checks whether the provided resource is capable of processing the message from the provided message context. - * The resource becomes capable to do this when the it contains either the name of the api caller, - * or {@value ApiConstants#DEFAULT_BINDING_ENDPOINT_NAME}, in its binds-to. - * - * @param resource Resource object - * @param synCtx MessageContext object - * @return Whether the provided resource is bound to the provided message context - */ - private boolean isBound(Resource resource, MessageContext synCtx) { - Collection bindings = resource.getBindsTo(); - Object apiCaller = synCtx.getProperty(ApiConstants.API_CALLER); - if (apiCaller != null) { - return bindings.contains(apiCaller.toString()); - } - return bindings.contains(ApiConstants.DEFAULT_BINDING_ENDPOINT_NAME); - } /** * Helper method to use when no matching resource found diff --git a/modules/core/src/main/java/org/apache/synapse/api/ApiUtils.java b/modules/core/src/main/java/org/apache/synapse/api/ApiUtils.java index 03f87607c0..7533f2b6a2 100644 --- a/modules/core/src/main/java/org/apache/synapse/api/ApiUtils.java +++ b/modules/core/src/main/java/org/apache/synapse/api/ApiUtils.java @@ -25,6 +25,9 @@ import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseConstants; import org.apache.synapse.SynapseException; +import org.apache.synapse.api.version.ContextVersionStrategy; +import org.apache.synapse.api.version.DefaultStrategy; +import org.apache.synapse.api.version.URLBasedVersionStrategy; import org.apache.synapse.core.axis2.Axis2MessageContext; import org.apache.synapse.rest.RESTConstants; import org.apache.synapse.api.dispatch.DefaultDispatcher; @@ -40,7 +43,11 @@ import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; public class ApiUtils { @@ -158,6 +165,92 @@ public static String getSubRequestPath(MessageContext synCtx) { return (String) synCtx.getProperty(RESTConstants.REST_SUB_REQUEST_PATH); } + /** + * Checks whether the provided resource is capable of processing the message from the provided message context. + * The resource becomes capable to do this when the it contains either the name of the api caller, + * or {@value ApiConstants#DEFAULT_BINDING_ENDPOINT_NAME}, in its binds-to. + * + * @param resource Resource object + * @param synCtx MessageContext object + * @return Whether the provided resource is bound to the provided message context + */ + public static boolean isBound(Resource resource, MessageContext synCtx) { + Collection bindings = resource.getBindsTo(); + Object apiCaller = synCtx.getProperty(ApiConstants.API_CALLER); + if (apiCaller != null) { + return bindings.contains(apiCaller.toString()); + } + return bindings.contains(ApiConstants.DEFAULT_BINDING_ENDPOINT_NAME); + } + + public static Set getAcceptableResources(Map resources, MessageContext synCtx) { + Set acceptableResources = new LinkedHashSet(); + for (Resource r : resources.values()) { + if (isBound(r, synCtx) && r.canProcess(synCtx)) { + acceptableResources.add(r); + } + } + return acceptableResources; + } + + /** + * This method is used to locate the specific API that has been invoked from the collection of all APIs. + * + * @param synCtx MessageContext of the request + * @return Selected API + */ + public static API getSelectedAPI(MessageContext synCtx) { + //getting the API collection from the synapse configuration to find the invoked API + Collection apiSet = synCtx.getEnvironment().getSynapseConfiguration().getAPIs(); + //Since swapping elements are not possible with sets, Collection is converted to a List + List defaultStrategyApiSet = new ArrayList(apiSet); + //To avoid apiSet being modified concurrently + List duplicateApiSet = new ArrayList<>(apiSet); + //identify the api using canProcess method + for (API api : duplicateApiSet) { + if (identifySelectedAPI(api, synCtx, defaultStrategyApiSet)) { + return api; + } + } + for (API api : defaultStrategyApiSet) { + api.setLogSetterValue(); + if (api.canProcess(synCtx)) { + if (log.isDebugEnabled()) { + log.debug("Located specific API: " + api.getName() + " for processing message"); + } + return api; + } + } + return null; + } + + private static boolean identifySelectedAPI(API api, MessageContext synCtx, List defaultStrategyApiSet) { + API defaultAPI = null; + api.setLogSetterValue(); + if ("/".equals(api.getContext())) { + defaultAPI = api; + } else if (api.getVersionStrategy().getClass().getName().equals(DefaultStrategy.class.getName())) { + //APIs whose VersionStrategy is bound to an instance of DefaultStrategy, should be skipped and processed at + // last.Otherwise they will be always chosen to process the request without matching the version. + defaultStrategyApiSet.add(api); + } else if (api.getVersionStrategy().getClass().getName().equals(ContextVersionStrategy.class.getName()) + || api.getVersionStrategy().getClass().getName().equals(URLBasedVersionStrategy.class.getName())) { + api.setLogSetterValue(); + if (api.canProcess(synCtx)) { + if (log.isDebugEnabled()) { + log.debug("Located specific API: " + api.getName() + " for processing message"); + } + return true; + } + } else if (api.canProcess(synCtx)) { + if (log.isDebugEnabled()) { + log.debug("Located specific API: " + api.getName() + " for processing message"); + } + return true; + } + return false; + } + public static List getDispatchers() { return dispatchers; } @@ -177,10 +270,10 @@ private static void handleException(String msg, Throwable t) { * and false if the two values don't match */ public static boolean matchApiPath(String path, String context) { - if (!path.startsWith(context + "/") && !path.startsWith(context + "?") && - !context.equals(path) && !"/".equals(context)) { + if (!path.startsWith(context + "/") && !path.startsWith(context + "?") + && !context.equals(path) && !"/".equals(context)) { return false; } return true; } -} +} \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/synapse/api/dispatch/DefaultDispatcher.java b/modules/core/src/main/java/org/apache/synapse/api/dispatch/DefaultDispatcher.java index b2ed6f41d1..58ccaa1598 100644 --- a/modules/core/src/main/java/org/apache/synapse/api/dispatch/DefaultDispatcher.java +++ b/modules/core/src/main/java/org/apache/synapse/api/dispatch/DefaultDispatcher.java @@ -20,6 +20,7 @@ import org.apache.synapse.MessageContext; import org.apache.synapse.api.Resource; +import org.apache.synapse.rest.RESTConstants; import java.util.Collection; @@ -28,6 +29,7 @@ public class DefaultDispatcher implements RESTDispatcher { public Resource findResource(MessageContext synCtx, Collection resources) { for (Resource resource : resources) { if (resource.getDispatcherHelper() == null) { + synCtx.setProperty(RESTConstants.SELECTED_RESOURCE, resource); return resource; } } diff --git a/modules/core/src/main/java/org/apache/synapse/api/dispatch/URITemplateBasedDispatcher.java b/modules/core/src/main/java/org/apache/synapse/api/dispatch/URITemplateBasedDispatcher.java index 27f77ff24f..007e684747 100644 --- a/modules/core/src/main/java/org/apache/synapse/api/dispatch/URITemplateBasedDispatcher.java +++ b/modules/core/src/main/java/org/apache/synapse/api/dispatch/URITemplateBasedDispatcher.java @@ -35,12 +35,13 @@ public Resource findResource(MessageContext synCtx, Collection resourc DispatcherHelper helper = r.getDispatcherHelper(); if (helper instanceof URITemplateHelper) { URITemplateHelper templateHelper = (URITemplateHelper) helper; - Map variables = new HashMap(); + Map variables = new HashMap(); if (templateHelper.getUriTemplate().matches(url, variables)) { - for (Map.Entry entry : variables.entrySet()) { + for (Map.Entry entry : variables.entrySet()) { synCtx.setProperty(RESTConstants.REST_URI_VARIABLE_PREFIX + entry.getKey(), entry.getValue()); } + synCtx.setProperty(RESTConstants.SELECTED_RESOURCE, r); return r; } } diff --git a/modules/core/src/main/java/org/apache/synapse/api/dispatch/URLMappingBasedDispatcher.java b/modules/core/src/main/java/org/apache/synapse/api/dispatch/URLMappingBasedDispatcher.java index 5a45551b6b..6a0e2639df 100644 --- a/modules/core/src/main/java/org/apache/synapse/api/dispatch/URLMappingBasedDispatcher.java +++ b/modules/core/src/main/java/org/apache/synapse/api/dispatch/URLMappingBasedDispatcher.java @@ -23,6 +23,7 @@ import org.apache.synapse.MessageContext; import org.apache.synapse.api.ApiUtils; import org.apache.synapse.api.Resource; +import org.apache.synapse.rest.RESTConstants; import java.util.ArrayList; import java.util.Collection; @@ -55,6 +56,7 @@ public Resource findResource(MessageContext synCtx, Collection resourc if (log.isDebugEnabled()) { log.debug("Found exact URL match for: " + url); } + synCtx.setProperty(RESTConstants.SELECTED_RESOURCE, filteredResources.get(i)); return filteredResources.get(i); } } @@ -72,6 +74,7 @@ public Resource findResource(MessageContext synCtx, Collection resourc if (log.isDebugEnabled()) { log.debug("Found path match for: " + url + " with matching length: " + maxLength); } + synCtx.setProperty(RESTConstants.SELECTED_RESOURCE, matchedResource); return matchedResource; } @@ -80,6 +83,7 @@ public Resource findResource(MessageContext synCtx, Collection resourc if (log.isDebugEnabled()) { log.debug("Found extension match for: " + url); } + synCtx.setProperty(RESTConstants.SELECTED_RESOURCE, filteredResources.get(i)); return filteredResources.get(i); } } diff --git a/modules/core/src/main/java/org/apache/synapse/rest/RESTConstants.java b/modules/core/src/main/java/org/apache/synapse/rest/RESTConstants.java index 8c41f33b3c..3dbda87712 100644 --- a/modules/core/src/main/java/org/apache/synapse/rest/RESTConstants.java +++ b/modules/core/src/main/java/org/apache/synapse/rest/RESTConstants.java @@ -91,5 +91,6 @@ public static enum METHODS { */ public static final String IS_PROMETHEUS_ENGAGED = "IS_PROMETHEUS_ENGAGED"; public static final String PROCESSED_API = "PROCESSED_API"; + public static final String SELECTED_RESOURCE = "SELECTED_RESOURCE"; }