Hi Jeremy, TL;DR - The RestAnnotationProcessor can be improved :)
If I understand properly what you want to achieve, you pretend to have a method like the following: @Delegate CDNApi cdnApiInRegionAndServiceType(@Nullable String region, @Nullable ServiceType serviceType); The RestAnnotationProcessor [1] currently supports four ways of generating the endpoint, and they are invoked in the following order: 1. If any parameter of the method is of type HttpRequest, its endpoint is used. 2. If there is any parameter annotated with the @EndpointParam annotation [2], that generator is used. The annotation defines a Function<Object, URI> that given the value of the annotated parameter, returns the appropriate endpoint [3]. 3. If there is an @Endpoint annotation [4] at method or class level, it uses it to get the endpoint. The @Endpoint annotation defines a qualifier annotation that is used to configure a Supplier<URI> in the Guice context. That supplier is invoked to get the configured endpoint [5]. 4. If no endpoint is found by the previous methods, the provider URI is used [6]. The problem in this case, is that method 1 is not an option here; the second approach only receives *one* parameter (region in this example) and you need two (region and serviceType); and the third approach can not be changed at runtime as it receives no parameters, it just uses the context configuration. So what I would do is to add a little code to the RestAnnotationProcessor so it allows APIs to generate endpoints based on multiple parameters. It should be pretty straightforward. What I'd suggest is: 1. Create a new annotation to be configured at method level, such as @EndpointFromParams, which defines a Function<List<Object>, URI>. That function will receive *all* the arguments for the invoked method and return the generated endpoint. 2. Modify the "getEndpointFor" method to fallback to this function if the endpoint can't be found in a concrete param after the step 2 from the list above. I'll add something like the following code after this line [7]: // If endpoint can't be computed from a single param, try with all them endpoint = getEndpointFromAllParametersOrNull(invocation, injector); if (endpoint == null) { ... You should create the "getEndpointFromAllParametersOrNull" that would check if the method has the @EndpointFromParams annotation, and would call the defined function if the annotation is present. The change is not difficult and this would allow you to define the api method like: @Delegate @EndpointFromParams(parser = RegionAndServiceTypeToEndpoint.class) CDNApi cdnApiInRegionAndServiceType(@Nullable String region, @Nullable ServiceType serviceType); HTH! Ignasi [1] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java [2] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/annotations/EndpointParam.java [3] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java#L489-L507 [4] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/annotations/Endpoint.java [5] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java#L523-L534 [6] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java#L377-L380 [7] https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java#L523 On 3 February 2014 19:24, Jeremy Daggett <jeremy.dagg...@gmail.com> wrote: > Hi jclouds devs, > > Last week, I ran into an issue with the new CloudFiles API and I don't know > how to solve it, so I am looking for some help. I am hoping that other > community members have some ideas here! > > From what I have found, the new CloudFiles is the *only* aggregate API that > needs to support two different OpenStack service types from the service > catalog [1]. > > The jclouds OpenStack Keystone API defines the SERVICE_TYPE property [2] > and is set in the defaultProperties() for each of the OpenStack APIs that > are available today via the ApiMetadata (for example [3]). > > The two service types that need to be supported in the CloudFilesApi are > "object-storage" and "rax:object-cdn". If I set the service type in the > properties to "object-storage", the endpoint for the CloudFilesApi (which > extends the SwiftApi) are routed to the endpoint for "object-storage". > Great. Now, if I set it to "rax:object-cdn", then all of the calls are > routed to the "rax:object-cdn" endpoint. > > That makes sense, but how can we support multiple types? I have been > through the RestAnnotationProcessor tracing each of the calls, and I > believe the issue lies in the Keystone suppliers [4] somehow. I wonder if > we need the notion of "Service Types" in the Keystone API and register that > via the properties. ?? > > I am going to continue debugging and looking for a solution, but I am > blocked on this right now and could use any insight. If anyone has ideas on > how to support this, I would be very grateful. Thanks! > > /jd > > [1] > http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_.html > > [2] > https://github.com/jclouds/jclouds/blob/master/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneProperties.java#L72 > > [3] > https://github.com/jclouds/jclouds/blob/master/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java#L59 > > [4] > https://github.com/jclouds/jclouds/tree/master/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/suppliers