updated IAM listing to be inline with other recent aws apis

This commit is contained in:
Adrian Cole 2013-02-24 12:34:25 -08:00
parent 1338daec50
commit 9741babe39
12 changed files with 343 additions and 474 deletions

View File

@ -62,5 +62,4 @@ public interface IAMAsyncApi {
*/ */
@Delegate @Delegate
UserAsyncApi getUserApi(); UserAsyncApi getUserApi();
} }

View File

@ -45,5 +45,4 @@ public class IAMRestClientModule extends FormSigningRestClientModule<IAMApi, IAM
public IAMRestClientModule() { public IAMRestClientModule() {
super(typeToken(IAMApi.class), typeToken(IAMAsyncApi.class), DELEGATE_MAP); super(typeToken(IAMApi.class), typeToken(IAMAsyncApi.class), DELEGATE_MAP);
} }
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.iam.domain; package org.jclouds.iam.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Date; import java.util.Date;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -28,85 +30,7 @@ import com.google.common.base.Optional;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class User { public final class User {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromUser(this);
}
public abstract static class Builder<T extends Builder<T>> {
protected abstract T self();
private Optional<String> path = Optional.absent();
private String id;
private Optional<String> name = Optional.absent();
private String arn;
private Date createDate;
/**
* @see User#getPath()
*/
public T path(String path) {
this.path = Optional.fromNullable(path);
return self();
}
/**
* @see User#getId()
*/
public T id(String id) {
this.id = id;
return self();
}
/**
* @see User#getName()
*/
public T name(String name) {
this.name = Optional.fromNullable(name);
return self();
}
/**
* @see User#getArn()
*/
public T arn(String arn) {
this.arn = arn;
return self();
}
/**
* @see User#getCreateDate()
*/
public T createDate(Date createDate) {
this.createDate = createDate;
return self();
}
public User build() {
return new User(path, name, id, arn, createDate);
}
public T fromUser(User in) {
return this
.path(in.getPath().orNull())
.name(in.getName().orNull())
.id(in.getId())
.arn(in.getArn())
.createDate(in.getCreateDate())
;
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
private final Optional<String> path; private final Optional<String> path;
private final Optional<String> name; private final Optional<String> name;
@ -114,59 +38,43 @@ public class User {
private final String arn; private final String arn;
private final Date createDate; private final Date createDate;
protected User(Optional<String> path, Optional<String> name, String id, String arn, Date createDate) { private User(String id, String arn, Optional<String> path, Optional<String> name, Date createDate) {
this.path = path; this.id = checkNotNull(id, "id");
this.name = name; this.arn = checkNotNull(arn, "arn for %s", id);
this.id = id; this.path = checkNotNull(path, "path for %s", arn);
this.arn = arn; this.name = checkNotNull(name, "name for %s", arn);
this.createDate = createDate; this.createDate = checkNotNull(createDate, "createDate for %s", arn);
} }
/** /**
* you can also optionally give the entity a path that you define. You might use the path to * a globally unique identifier (GUID), returned from the api.
* identify which division or part of the organization the entity belongs in. For example:
* /division_abc/subdivision_xyz/product_1234/engineering/
*/
public Optional<String> getPath() {
return path;
}
/**
* When you create a user, a role, or a group, or when you upload a server certificate, you give
* it a friendly name, such as Bob, TestApp1, Developers, or ProdServerCert. Whenever you need to
* specify a particular entity in an API call to IAM (for example, to delete a user, or update a
* group with a new user), you use the friendly name.
*/
public Optional<String> getName() {
return name;
}
/**
* We assign each user, group, and server certificate a globally unique identifier (GUID), which
* we return to you when you use the API or CLI to create it. We recommend you store the GUID in
* your own database along with the user, group, or certificate name. Internally we use the GUID
* to identify the user, group, or certificate, and we translate the value into the ARN or
* friendly name as appropriate when displaying the user, group, or certificate information to
* you. If you delete a user, group, or server certificate, any residual remote references to
* that item display the GUID as the friendly name part in the ARN. If you've stored the GUID in
* your own system, you can then use the displayed GUID to identify the deleted item being
* referred to.
*/ */
public String getId() { public String getId() {
return id; return id;
} }
/** /**
* Although most resources have a friendly name (for example, a user named Bob or a group named * how to specify the resource in the access policy language ex.
* Developers), the access policy language requires you to specify the resource or resources
* using the following Amazon Resource Name (ARN) format.
*
* {@code arn:aws:<service>:<region>:<namespace>:<relative-id>} * {@code arn:aws:<service>:<region>:<namespace>:<relative-id>}
*/ */
public String getArn() { public String getArn() {
return arn; return arn;
} }
/**
* path ex {@code /division_abc/subdivision_xyz/product_1234/engineering/}
*/
public Optional<String> getPath() {
return path;
}
/**
* friendly name ex. {@code Developers}
*/
public Optional<String> getName() {
return name;
}
/** /**
* Date the user was created * Date the user was created
*/ */
@ -189,9 +97,7 @@ public class User {
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null || getClass() != obj.getClass())
return false;
if (getClass() != obj.getClass())
return false; return false;
User other = (User) obj; User other = (User) obj;
return Objects.equal(this.id, other.id) && Objects.equal(this.arn, other.arn); return Objects.equal(this.id, other.id) && Objects.equal(this.arn, other.arn);
@ -202,8 +108,71 @@ public class User {
*/ */
@Override @Override
public String toString() { public String toString() {
return Objects.toStringHelper(this).add("path", path).add("name", name).add("id", id).add("arn", arn).add( return Objects.toStringHelper(this).add("path", path).add("name", name).add("id", id).add("arn", arn)
"createDate", createDate).toString(); .add("createDate", createDate).toString();
} }
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().from(this);
}
public static class Builder {
private Optional<String> path = Optional.absent();
private String id;
private Optional<String> name = Optional.absent();
private String arn;
private Date createDate;
/**
* @see User#getPath()
*/
public Builder path(String path) {
this.path = Optional.fromNullable(path);
return this;
}
/**
* @see User#getId()
*/
public Builder id(String id) {
this.id = id;
return this;
}
/**
* @see User#getName()
*/
public Builder name(String name) {
this.name = Optional.fromNullable(name);
return this;
}
/**
* @see User#getArn()
*/
public Builder arn(String arn) {
this.arn = arn;
return this;
}
/**
* @see User#getCreateDate()
*/
public Builder createDate(Date createDate) {
this.createDate = createDate;
return this;
}
public User build() {
return new User(id, arn, path, name, createDate);
}
public Builder from(User in) {
return this.path(in.path.orNull()).name(in.name.orNull()).id(in.id).arn(in.arn).createDate(in.createDate);
}
}
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.iam.features;
import org.jclouds.collect.IterableWithMarker; import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable; import org.jclouds.collect.PagedIterable;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.iam.options.ListUsersOptions;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
/** /**
@ -37,6 +36,50 @@ public interface UserApi {
*/ */
User getCurrent(); User getCurrent();
/**
* returns all users in order.
*/
PagedIterable<User> list();
/**
* retrieves up to 100 users in order.
*/
IterableWithMarker<User> listFirstPage();
/**
* retrieves up to 100 users in order, starting at {@code marker}
*
* @param marker
* starting point to resume the list
*/
IterableWithMarker<User> listAt(String marker);
/**
* returns all users in order at the specified {@code pathPrefix}.
*
* @param pathPrefix
* ex. {@code /division_abc/subdivision_xyz/}
*/
PagedIterable<User> listPathPrefix(String pathPrefix);
/**
* retrieves up to 100 users in order at the specified {@code pathPrefix}.
*
* @param pathPrefix
* ex. {@code /division_abc/subdivision_xyz/}
*/
IterableWithMarker<User> listPathPrefixFirstPage(String pathPrefix);
/**
* retrieves up to 100 users in order at the specified {@code pathPrefix}, starting at {@code marker}.
*
* @param pathPrefix
* ex. {@code /division_abc/subdivision_xyz/}
* @param marker
* starting point to resume the list
*/
IterableWithMarker<User> listPathPrefixAt(String pathPrefix, String marker);
/** /**
* Retrieves information about the specified user, including the user's path, GUID, and ARN. * Retrieves information about the specified user, including the user's path, GUID, and ARN.
* *
@ -46,27 +89,4 @@ public interface UserApi {
*/ */
@Nullable @Nullable
User get(String name); User get(String name);
/**
* Lists the users that have the specified path prefix. If there are none, the action returns an
* empty list.
*
* <br/>
* You can paginate the results using the {@link ListUsersOptions parameter}
*
* @param options
* the options describing the users query
*
* @return the response object
*/
IterableWithMarker<User> list(ListUsersOptions options);
/**
* Lists the users that have the specified path prefix. If there are none, the action returns an
* empty list.
*
* @return the response object
*/
PagedIterable<User> list();
} }

View File

@ -29,7 +29,6 @@ import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.PagedIterable; import org.jclouds.collect.PagedIterable;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.iam.functions.UsersToPagedIterable; import org.jclouds.iam.functions.UsersToPagedIterable;
import org.jclouds.iam.options.ListUsersOptions;
import org.jclouds.iam.xml.ListUsersResultHandler; import org.jclouds.iam.xml.ListUsersResultHandler;
import org.jclouds.iam.xml.UserHandler; import org.jclouds.iam.xml.UserHandler;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
@ -52,6 +51,69 @@ import com.google.common.util.concurrent.ListenableFuture;
@VirtualHost @VirtualHost
public interface UserAsyncApi { public interface UserAsyncApi {
/**
* @see UserApi#list()
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
@Transform(UsersToPagedIterable.class)
ListenableFuture<PagedIterable<User>> list();
/**
* @see UserApi#listFirstPage
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
ListenableFuture<IterableWithMarker<User>> listFirstPage();
/**
* @see UserApi#listAt(String)
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
ListenableFuture<IterableWithMarker<User>> listAt(@FormParam("Marker") String marker);
/**
* @see UserApi#listPathPrefix(String)
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
@Transform(UsersToPagedIterable.class)
ListenableFuture<PagedIterable<User>> listPathPrefix(@FormParam("PathPrefix") String pathPrefix);
/**
* @see UserApi#listPathPrefixFirstPage(String)
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
ListenableFuture<IterableWithMarker<User>> listPathPrefixFirstPage(@FormParam("PathPrefix") String pathPrefix);
/**
* @see UserApi#listPathPrefixAt(String, String)
*/
@Named("ListUsers")
@POST
@Path("/")
@FormParams(keys = "Action", values = "ListUsers")
@XMLResponseParser(ListUsersResultHandler.class)
ListenableFuture<IterableWithMarker<User>> listPathPrefixAt(@FormParam("PathPrefix") String pathPrefix,
@FormParam("Marker") String marker);
/** /**
* @see UserApi#getCurrent() * @see UserApi#getCurrent()
*/ */
@ -72,26 +134,4 @@ public interface UserAsyncApi {
@FormParams(keys = "Action", values = "GetUser") @FormParams(keys = "Action", values = "GetUser")
@Fallback(NullOnNotFoundOr404.class) @Fallback(NullOnNotFoundOr404.class)
ListenableFuture<User> get(@FormParam("UserName") String name); ListenableFuture<User> get(@FormParam("UserName") String name);
/**
* @see UserApi#list()
*/
@Named("ListUsers")
@POST
@Path("/")
@XMLResponseParser(ListUsersResultHandler.class)
@Transform(UsersToPagedIterable.class)
@FormParams(keys = "Action", values = "ListUsers")
ListenableFuture<PagedIterable<User>> list();
/**
* @see UserApi#list(ListUsersOptions)
*/
@Named("ListUsers")
@POST
@Path("/")
@XMLResponseParser(ListUsersResultHandler.class)
@FormParams(keys = "Action", values = "ListUsers")
ListenableFuture<IterableWithMarker<User>> list(ListUsersOptions options);
} }

View File

@ -23,43 +23,68 @@ import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.collect.IterableWithMarker; import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.internal.CallerArg0ToPagedIterable; import org.jclouds.collect.internal.Arg0ToPagedIterable;
import org.jclouds.iam.IAMApi; import org.jclouds.iam.IAMApi;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.iam.features.UserApi; import org.jclouds.iam.features.UserApi;
import org.jclouds.iam.options.ListUsersOptions;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Optional;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Beta @Beta
public class UsersToPagedIterable extends CallerArg0ToPagedIterable<User, UsersToPagedIterable> { public class UsersToPagedIterable extends Arg0ToPagedIterable<User, UsersToPagedIterable> {
private final IAMApi api; private final UserApi api;
@Inject @Inject
protected UsersToPagedIterable(IAMApi api) { protected UsersToPagedIterable(IAMApi api) {
this.api = checkNotNull(api, "api"); this.api = checkNotNull(api, "api").getUserApi();
} }
@Override @Override
protected Function<Object, IterableWithMarker<User>> markerToNextForCallingArg0(String ignored) { protected Function<Object, IterableWithMarker<User>> markerToNextForArg0(Optional<Object> pathPrefix) {
final UserApi userApi = api.getUserApi(); if (pathPrefix.isPresent())
return new Function<Object, IterableWithMarker<User>>() { return new ListUsersUnderPathPrefixAtMarker(api, pathPrefix.get().toString());
return new ListUsersAtMarker(api);
@Override
public IterableWithMarker<User> apply(Object input) {
return userApi.list(ListUsersOptions.Builder.afterMarker(input.toString()));
}
@Override
public String toString() {
return "listUsers()";
}
};
} }
private static class ListUsersUnderPathPrefixAtMarker implements Function<Object, IterableWithMarker<User>> {
private final UserApi api;
private final String pathPrefix;
@Inject
protected ListUsersUnderPathPrefixAtMarker(UserApi api, String pathPrefix) {
this.api = checkNotNull(api, "api");
this.pathPrefix = checkNotNull(pathPrefix, "pathPrefix");
}
public IterableWithMarker<User> apply(Object input) {
return api.listPathPrefixAt(pathPrefix, input.toString());
}
public String toString() {
return "ListUsersUnderPathPrefixAtMarker(" + pathPrefix + ")";
}
}
private static class ListUsersAtMarker implements Function<Object, IterableWithMarker<User>> {
private final UserApi api;
@Inject
protected ListUsersAtMarker(UserApi api) {
this.api = checkNotNull(api, "api");
}
public IterableWithMarker<User> apply(Object input) {
return api.listAt(input.toString());
}
public String toString() {
return "listUsersAtMarker()";
}
}
} }

View File

@ -1,144 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.iam.options;
import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.base.Objects;
import com.google.common.collect.Multimap;
/**
* Options used to list available users.
*
* @see <a href="http://docs.amazonwebservices.com/IAM/latest/APIReference/API_ListUsers.html" />
*
* @author Adrian Cole
*/
public class ListUsersOptions extends BaseHttpRequestOptions implements Cloneable {
private Integer maxItems;
private String pathPrefix;
private Object afterMarker;
/**
* Use this parameter only when paginating results, and only in a subsequent request after you've
* received a response where the results are truncated. Set it to the value of the Marker element
* in the response you just received.
*/
public ListUsersOptions afterMarker(Object afterMarker) {
this.afterMarker = afterMarker;
return this;
}
/**
* Use this parameter only when paginating results to indicate the maximum number of user names
* you want in the response. If there are additional user names beyond the maximum you specify,
* the IsTruncated response element is true.
*/
public ListUsersOptions maxItems(Integer maxItems) {
this.maxItems = maxItems;
return this;
}
/**
* The path prefix for filtering the results. For example: /division_abc/subdivision_xyz/, which
* would get all user names whose path starts with /division_abc/subdivision_xyz/.
* <p/>
* This parameter is optional. If it is not included, it defaults to a slash (/), listing all
* user names.
*/
public ListUsersOptions pathPrefix(String pathPrefix) {
this.pathPrefix = pathPrefix;
return this;
}
public static class Builder {
/**
* @see ListUsersOptions#afterMarker
*/
public static ListUsersOptions afterMarker(Object afterMarker) {
return new ListUsersOptions().afterMarker(afterMarker);
}
/**
* @see ListUsersOptions#maxItems
*/
public static ListUsersOptions maxItems(Integer maxItems) {
return new ListUsersOptions().maxItems(maxItems);
}
/**
* @see ListUsersOptions#pathPrefix
*/
public static ListUsersOptions pathPrefix(String pathPrefix) {
return new ListUsersOptions().pathPrefix(pathPrefix);
}
}
@Override
public Multimap<String, String> buildFormParameters() {
Multimap<String, String> params = super.buildFormParameters();
if (afterMarker != null)
params.put("Marker", afterMarker.toString());
if (maxItems != null)
params.put("MaxItems", maxItems.toString());
if (pathPrefix != null)
params.put("PathPrefix", pathPrefix);
return params;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hashCode(afterMarker, maxItems, pathPrefix);
}
@Override
public ListUsersOptions clone() {
return new ListUsersOptions().afterMarker(afterMarker).maxItems(maxItems).pathPrefix(pathPrefix);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ListUsersOptions other = ListUsersOptions.class.cast(obj);
return Objects.equal(this.afterMarker, other.afterMarker) && Objects.equal(this.maxItems, other.maxItems)
&& Objects.equal(this.pathPrefix, other.pathPrefix);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return Objects.toStringHelper(this).omitNullValues().add("afterMarker", afterMarker).add("maxItems", maxItems).add(
"pathPrefix", pathPrefix).toString();
}
}

View File

@ -18,17 +18,17 @@
*/ */
package org.jclouds.iam.xml; package org.jclouds.iam.xml;
import java.util.Set; import static org.jclouds.util.SaxUtils.currentOrNull;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import org.jclouds.collect.IterableWithMarker; import org.jclouds.collect.IterableWithMarker;
import org.jclouds.collect.IterableWithMarkers; import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.Sets; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -41,7 +41,7 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
private final UserHandler userHandler; private final UserHandler userHandler;
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
private Set<User> users = Sets.newLinkedHashSet(); private Builder<User> users = ImmutableList.<User> builder();
private boolean inUsers; private boolean inUsers;
private String afterMarker; private String afterMarker;
@ -50,20 +50,18 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
this.userHandler = userHandler; this.userHandler = userHandler;
} }
/**
* {@inheritDoc}
*/
@Override @Override
public IterableWithMarker<User> getResult() { public IterableWithMarker<User> getResult() {
return IterableWithMarkers.from(users, afterMarker); try {
return IterableWithMarkers.from(users.build(), afterMarker);
} finally {
users = ImmutableList.<User> builder();
}
} }
/**
* {@inheritDoc}
*/
@Override @Override
public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException { public void startElement(String url, String name, String qName, Attributes attributes) {
if (SaxUtils.equalsOrSuffix(qName, "Users")) { if (equalsOrSuffix(qName, "Users")) {
inUsers = true; inUsers = true;
} }
if (inUsers) { if (inUsers) {
@ -71,11 +69,8 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
} }
} }
/**
* {@inheritDoc}
*/
@Override @Override
public void endElement(String uri, String name, String qName) throws SAXException { public void endElement(String uri, String name, String qName) {
if (inUsers) { if (inUsers) {
if (qName.equals("Users")) { if (qName.equals("Users")) {
inUsers = false; inUsers = false;
@ -85,15 +80,12 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
userHandler.endElement(uri, name, qName); userHandler.endElement(uri, name, qName);
} }
} else if (qName.equals("Marker")) { } else if (qName.equals("Marker")) {
afterMarker = SaxUtils.currentOrNull(currentText); afterMarker = currentOrNull(currentText);
} }
currentText = new StringBuilder(); currentText = new StringBuilder();
} }
/**
* {@inheritDoc}
*/
@Override @Override
public void characters(char ch[], int start, int length) { public void characters(char ch[], int start, int length) {
if (inUsers) { if (inUsers) {
@ -102,5 +94,4 @@ public class ListUsersResultHandler extends ParseSax.HandlerForGeneratedRequestW
currentText.append(ch, start, length); currentText.append(ch, start, length);
} }
} }
} }

View File

@ -18,13 +18,14 @@
*/ */
package org.jclouds.iam.xml; package org.jclouds.iam.xml;
import static org.jclouds.util.SaxUtils.currentOrNull;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.util.SaxUtils; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/** /**
* @see <a href="http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUser.html" /> * @see <a href="http://docs.amazonwebservices.com/IAM/latest/APIReference/API_GetUser.html" />
@ -40,11 +41,8 @@ public class UserHandler extends ParseSax.HandlerForGeneratedRequestWithResult<U
} }
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
private User.Builder<?> builder = User.builder(); private User.Builder builder = User.builder();
/**
* {@inheritDoc}
*/
@Override @Override
public User getResult() { public User getResult() {
try { try {
@ -54,31 +52,28 @@ public class UserHandler extends ParseSax.HandlerForGeneratedRequestWithResult<U
} }
} }
/**
* {@inheritDoc}
*/
@Override @Override
public void endElement(String uri, String name, String qName) throws SAXException { public void startElement(String url, String name, String qName, Attributes attributes) {
}
@Override
public void endElement(String uri, String name, String qName) {
if (qName.equals("Path")) { if (qName.equals("Path")) {
builder.path(SaxUtils.currentOrNull(currentText)); builder.path(currentOrNull(currentText));
} else if (qName.equals("UserName")) { } else if (qName.equals("UserName")) {
builder.name(SaxUtils.currentOrNull(currentText)); builder.name(currentOrNull(currentText));
} else if (qName.equals("UserId")) { } else if (qName.equals("UserId")) {
builder.id(SaxUtils.currentOrNull(currentText)); builder.id(currentOrNull(currentText));
} else if (qName.equals("Arn")) { } else if (qName.equals("Arn")) {
builder.arn(SaxUtils.currentOrNull(currentText)); builder.arn(currentOrNull(currentText));
} else if (qName.equals("CreateDate")) { } else if (qName.equals("CreateDate")) {
builder.createDate(dateService.iso8601SecondsDateParse(SaxUtils.currentOrNull(currentText))); builder.createDate(dateService.iso8601SecondsDateParse(currentOrNull(currentText)));
} }
currentText = new StringBuilder(); currentText = new StringBuilder();
} }
/**
* {@inheritDoc}
*/
@Override @Override
public void characters(char ch[], int start, int length) { public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length); currentText.append(ch, start, length);
} }
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.jclouds.iam.features; package org.jclouds.iam.features;
import static org.jclouds.iam.options.ListUsersOptions.Builder.pathPrefix;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull; import static org.testng.Assert.assertNull;
@ -153,6 +152,57 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
ImmutableList.copyOf(Iterables.concat(new ListUsersResponseTest().expected(), new ListUsersResponseTest().expected()))); ImmutableList.copyOf(Iterables.concat(new ListUsersResponseTest().expected(), new ListUsersResponseTest().expected())));
} }
HttpRequest listPathPrefix = HttpRequest.builder()
.method("POST")
.endpoint("https://iam.amazonaws.com/")
.addHeader("Host", "iam.amazonaws.com")
.addFormParam("Action", "ListUsers")
.addFormParam("PathPrefix", "/subdivision")
.addFormParam("Signature", "giw/28vFH9GZoqf60bP4Ka80kBXhJDcncC%2BWA0Dkg/o%3D")
.addFormParam("SignatureMethod", "HmacSHA256")
.addFormParam("SignatureVersion", "2")
.addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
.addFormParam("Version", "2010-05-08")
.addFormParam("AWSAccessKeyId", "identity").build();
public void testListPathPrefixWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_users.xml", "text/xml")).build();
IAMApi apiWhenExist = requestSendsResponse(
listPathPrefix, listResponse);
assertEquals(apiWhenExist.getUserApi().listPathPrefix("/subdivision").get(0).toString(), new ListUsersResponseTest().expected().toString());
}
public void testListPathPrefix2PagesWhenResponseIs2xx() throws Exception {
HttpResponse listResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_users_marker.xml", "text/xml")).build();
HttpRequest listPathPrefix2 = HttpRequest.builder()
.method("POST")
.endpoint("https://iam.amazonaws.com/")
.addHeader("Host", "iam.amazonaws.com")
.addFormParam("Action", "ListUsers")
.addFormParam("Marker", "MARKER")
.addFormParam("PathPrefix", "/subdivision")
.addFormParam("Signature", "JSAWWjJdoz8Twn3CSjkuqWIJmmokjQyKPOdekNeVl30%3D")
.addFormParam("SignatureMethod", "HmacSHA256")
.addFormParam("SignatureVersion", "2")
.addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
.addFormParam("Version", "2010-05-08")
.addFormParam("AWSAccessKeyId", "identity").build();
HttpResponse list2Response = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_users.xml", "text/xml")).build();
IAMApi apiWhenExist = requestsSendResponses(listPathPrefix, listResponse, listPathPrefix2, list2Response);
assertEquals(apiWhenExist.getUserApi().listPathPrefix("/subdivision").concat().toList(),
ImmutableList.copyOf(Iterables.concat(new ListUsersResponseTest().expected(), new ListUsersResponseTest().expected())));
}
// TODO: this should really be an empty set // TODO: this should really be an empty set
@Test(expectedExceptions = ResourceNotFoundException.class) @Test(expectedExceptions = ResourceNotFoundException.class)
@ -166,7 +216,7 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
apiWhenDontExist.getUserApi().list().get(0); apiWhenDontExist.getUserApi().list().get(0);
} }
public void testListWithOptionsWhenResponseIs2xx() throws Exception { public void testListPathPrefixAtWhenResponseIs2xx() throws Exception {
HttpRequest listWithOptions = HttpRequest listWithOptions =
HttpRequest.builder() HttpRequest.builder()
.method("POST") .method("POST")
@ -188,7 +238,7 @@ public class UserApiExpectTest extends BaseIAMApiExpectTest {
IAMApi apiWhenWithOptionsExist = requestSendsResponse(listWithOptions, IAMApi apiWhenWithOptionsExist = requestSendsResponse(listWithOptions,
listWithOptionsResponse); listWithOptionsResponse);
assertEquals(apiWhenWithOptionsExist.getUserApi().list(pathPrefix("/foo").afterMarker("MARKER")).toString(), assertEquals(apiWhenWithOptionsExist.getUserApi().listPathPrefixAt("/foo", "MARKER").toString(),
new ListUsersResponseTest().expected().toString()); new ListUsersResponseTest().expected().toString());
} }
} }

View File

@ -19,15 +19,15 @@
package org.jclouds.iam.features; package org.jclouds.iam.features;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.logging.Logger.getAnonymousLogger;
import static org.testng.Assert.assertEquals;
import org.jclouds.collect.IterableWithMarker;
import org.jclouds.iam.domain.User; import org.jclouds.iam.domain.User;
import org.jclouds.iam.internal.BaseIAMApiLiveTest; import org.jclouds.iam.internal.BaseIAMApiLiveTest;
import org.jclouds.iam.options.ListUsersOptions;
import org.testng.Assert;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -42,30 +42,23 @@ public class UserApiLiveTest extends BaseIAMApiLiveTest {
} }
private void checkUser(User user) { private void checkUser(User user) {
checkNotNull(user.getArn(), "Arn cannot be null for a User."); checkNotNull(user.getArn(), "Arn cannot be null for User %s", user);
checkNotNull(user.getId(), "Id cannot be null for a User."); checkNotNull(user.getId(), "Id cannot be null for User %s", user);
checkNotNull(user.getName(), "While Name can be null for a User, its Optional wrapper cannot."); checkNotNull(user.getName(), "While Name can be null for a User, its Optional wrapper cannot; user %s", user);
checkNotNull(user.getPath(), "While Path can be null for a User, its Optional wrapper cannot."); checkNotNull(user.getPath(), "While Path can be null for a User, its Optional wrapper cannot; user %s", user);
checkNotNull(user.getCreateDate(), "CreateDate cannot be null for a User."); checkNotNull(user.getCreateDate(), "CreateDate cannot be null for a User User %s", user);
} }
@Test @Test
protected void testListUsers() { protected void testListUsers() {
IterableWithMarker<User> response = api().list().get(0); ImmutableList<User> users = api().list().concat().toList();
getAnonymousLogger().info("users: " + users.size());
for (User user : response) { for (User user : users) {
checkUser(user);
}
if (Iterables.size(response) > 0) {
User user = response.iterator().next();
Assert.assertEquals(api().get(user.getName().get()), user);
}
// Test with a Marker, even if it's null
response = api().list(ListUsersOptions.Builder.afterMarker(response.nextMarker().orNull()));
for (User user : response) {
checkUser(user); checkUser(user);
assertEquals(api().get(user.getId()), user);
if (user.getPath().isPresent())
assertEquals(api().listPathPrefix(user.getPath().get()).toSet(), ImmutableSet.of(user));
} }
} }

View File

@ -1,68 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.iam.options;
import static org.jclouds.iam.options.ListUsersOptions.Builder.afterMarker;
import static org.jclouds.iam.options.ListUsersOptions.Builder.maxItems;
import static org.jclouds.iam.options.ListUsersOptions.Builder.pathPrefix;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code ListUsersOptions}
*
* @author Adrian Cole
*/
@Test(groups = "maxItems", testName = "ListUsersOptionsTest")
public class ListUsersOptionsTest {
public void testMarker() {
ListUsersOptions options = new ListUsersOptions().afterMarker("FFFFF");
assertEquals(ImmutableSet.of("FFFFF"), options.buildFormParameters().get("Marker"));
}
public void testMarkerStatic() {
ListUsersOptions options = afterMarker("FFFFF");
assertEquals(ImmutableSet.of("FFFFF"), options.buildFormParameters().get("Marker"));
}
public void testMaxItems() {
ListUsersOptions options = new ListUsersOptions().maxItems(1000);
assertEquals(ImmutableSet.of("1000"), options.buildFormParameters().get("MaxItems"));
}
public void testMaxItemsStatic() {
ListUsersOptions options = maxItems(1000);
assertEquals(ImmutableSet.of("1000"), options.buildFormParameters().get("MaxItems"));
}
public void testPathPrefix() {
ListUsersOptions options = new ListUsersOptions().pathPrefix("/division_abc/subdivision_xyz/");
assertEquals(ImmutableSet.of("/division_abc/subdivision_xyz/"), options.buildFormParameters().get("PathPrefix"));
}
public void testPathPrefixStatic() {
ListUsersOptions options = pathPrefix("/division_abc/subdivision_xyz/");
assertEquals(ImmutableSet.of("/division_abc/subdivision_xyz/"), options.buildFormParameters().get("PathPrefix"));
}
}