diff --git a/labs/dynect/pom.xml b/labs/dynect/pom.xml new file mode 100644 index 0000000000..d57ae5451c --- /dev/null +++ b/labs/dynect/pom.xml @@ -0,0 +1,109 @@ + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.6.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.labs + dynect + jcloud dynect api + jclouds components for DynECT Managed DNS + bundle + + + https://api2.dynect.net/REST + 3.3.7 + + + + + org.jclouds.dynect.v3*;version="${project.version}" + + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + org.jclouds + jclouds-core + ${project.version} + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + ch.qos.logback + logback-classic + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.dynect.endpoint} + ${test.dynect.api-version} + ${test.dynect.build-version} + ${test.dynect.identity} + ${test.dynect.credential} + + + + + + + + + + + diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java new file mode 100644 index 0000000000..82d56f0b8e --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java @@ -0,0 +1,40 @@ +/** + * 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.dynect.v3; + +import org.jclouds.dynect.v3.features.SessionApi; +import org.jclouds.rest.annotations.Delegate; + +/** + * Provides access to DynECT Managed DNS through the API2 api + *

+ * + * @see DynECTAsyncApi + * @see + * @author Adrian Cole + */ +public interface DynECTApi { + + /** + * Provides synchronous access to Session features. + */ + @Delegate + SessionApi getSessionApi(); +} \ No newline at end of file diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApiMetadata.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApiMetadata.java new file mode 100644 index 0000000000..d18c7949ab --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApiMetadata.java @@ -0,0 +1,98 @@ +/** + * 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.dynect.v3; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.apis.ApiMetadata; +import org.jclouds.dynect.v3.config.DynECTParserModule; +import org.jclouds.dynect.v3.config.DynECTRestClientModule; +import org.jclouds.rest.RestContext; +import org.jclouds.rest.internal.BaseRestApiMetadata; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; +import com.google.inject.Module; + +/** + * Implementation of {@link ApiMetadata} for DynECT 1.0 API + * + * @author Adrian Cole + */ +public class DynECTApiMetadata extends BaseRestApiMetadata { + + public static final String ANONYMOUS_IDENTITY = "ANONYMOUS"; + + public static final TypeToken> CONTEXT_TOKEN = new TypeToken>() { + private static final long serialVersionUID = 1L; + }; + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public DynECTApiMetadata() { + this(new Builder()); + } + + protected DynECTApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = BaseRestApiMetadata.defaultProperties(); + properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + ""); + return properties; + } + + public static class Builder extends BaseRestApiMetadata.Builder { + + protected Builder() { + super(DynECTApi.class, DynECTAsyncApi.class); + id("dynect") + .name("DynECT API2") + .identityName("Username (or " + ANONYMOUS_IDENTITY + " if anonymous)") + .defaultIdentity(ANONYMOUS_IDENTITY) + .credentialName("Password") + .defaultCredential(ANONYMOUS_IDENTITY) + .documentation(URI.create("https://manage.dynect.net/help/docs/api2/rest/")) + .version("3.3.7") + .defaultEndpoint("https://api2.dynect.net/REST") + .defaultProperties(DynECTApiMetadata.defaultProperties()) + .defaultModules(ImmutableSet.>builder() + .add(DynECTParserModule.class) + .add(DynECTRestClientModule.class).build()); + } + + @Override + public DynECTApiMetadata build() { + return new DynECTApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java new file mode 100644 index 0000000000..dd5c8e5e22 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java @@ -0,0 +1,47 @@ +/** + * 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.dynect.v3; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import javax.ws.rs.Produces; + +import org.jclouds.dynect.v3.features.SessionAsyncApi; +import org.jclouds.rest.annotations.Delegate; +import org.jclouds.rest.annotations.Headers; + +/** + * Provides access to DynECT Managed DNS through the API2 api + *

+ * + * @see DynECTApi + * @see + * @author Adrian Cole + */ +// required for all calls +@Produces(APPLICATION_JSON) +@Headers(keys = "API-Version", values = "{jclouds.api-version}") +public interface DynECTAsyncApi { + + /** + * Provides asynchronous access to Session features. + */ + @Delegate + SessionAsyncApi getSessionApi(); +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTFallbacks.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTFallbacks.java new file mode 100644 index 0000000000..f6f9ab1794 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTFallbacks.java @@ -0,0 +1,44 @@ +/** + * 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.dynect.v3; + +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull; + +import com.google.common.util.concurrent.FutureFallback; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * + * @author Adrian Cole + */ +public final class DynECTFallbacks { + private DynECTFallbacks() { + } + + public static class FalseOn400 implements FutureFallback { + public ListenableFuture create(Throwable t) { + if (returnValueOnCodeOrNull(t, false, equalTo(400)) != null) + return immediateFuture(false); + throw propagate(t); + } + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTProviderMetadata.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTProviderMetadata.java new file mode 100644 index 0000000000..ae1a1cca3e --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTProviderMetadata.java @@ -0,0 +1,80 @@ +/** + * 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.dynect.v3; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.providers.internal.BaseProviderMetadata; + +/** + * Implementation of {@link org.jclouds.types.ProviderMetadata} for DynECT Managed DNS. + * @author Adrian Cole + */ +public class DynECTProviderMetadata extends BaseProviderMetadata { + + public static Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return builder().fromProviderMetadata(this); + } + + public DynECTProviderMetadata() { + super(builder()); + } + + public DynECTProviderMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = new Properties(); + return properties; + } + + public static class Builder extends BaseProviderMetadata.Builder { + + protected Builder() { + id("dynect") + .name("DynECT Managed DNS") + .apiMetadata(new DynECTApiMetadata()) + .homepage(URI.create("http://dyn.com/dns/dynect-managed-dns/")) + .console(URI.create("https://manage.dynect.net")) + .iso3166Codes("US-CA", "US-VA") + .endpoint("https://api2.dynect.net/REST") + .defaultProperties(DynECTProviderMetadata.defaultProperties()); + } + + @Override + public DynECTProviderMetadata build() { + return new DynECTProviderMetadata(this); + } + + @Override + public Builder fromProviderMetadata(ProviderMetadata in) { + super.fromProviderMetadata(in); + return this; + } + + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java new file mode 100644 index 0000000000..5ba2b1a5d7 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java @@ -0,0 +1,63 @@ +/** + * 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.dynect.v3.config; + +import java.lang.reflect.Type; +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.dynect.v3.domain.SessionCredentials; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +/** + * @author Adrian Cole + */ +public class DynECTParserModule extends AbstractModule { + + @Override + protected void configure() { + } + + @Provides + @Singleton + public Map provideCustomAdapterBindings() { + return new ImmutableMap.Builder() + .put(SessionCredentials.class, new SessionCredentialsTypeAdapter()) + .build(); + } + + private static class SessionCredentialsTypeAdapter implements JsonSerializer { + @Override + public JsonElement serialize(SessionCredentials src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject metadataObject = new JsonObject(); + metadataObject.addProperty("customer_name", src.getCustomerName()); + metadataObject.addProperty("user_name", src.getUserName()); + metadataObject.addProperty("password", src.getPassword()); + return metadataObject; + } + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java new file mode 100644 index 0000000000..ca25e60bc4 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java @@ -0,0 +1,47 @@ +/** + * 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.dynect.v3.config; + +import java.util.Map; + +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.DynECTAsyncApi; +import org.jclouds.dynect.v3.features.SessionApi; +import org.jclouds.dynect.v3.features.SessionAsyncApi; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.config.RestClientModule; + +import com.google.common.collect.ImmutableMap; + +/** + * Configures the DynECT connection. + * + * @author Adrian Cole + */ +@ConfiguresRestClient +public class DynECTRestClientModule extends RestClientModule { + + public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class> builder() + .put(SessionApi.class, SessionAsyncApi.class) + .build(); + + public DynECTRestClientModule() { + super(DELEGATE_MAP); + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Session.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Session.java new file mode 100644 index 0000000000..1928f06ef4 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Session.java @@ -0,0 +1,80 @@ +/** + * 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, String 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.dynect.v3.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import com.google.common.base.Objects; + +/** + * @author Adrian Cole + */ +public final class Session { + + public static Session forTokenAndVersion(String token, String version) { + return new Session(token, version); + } + + private final String token; + private final String version; + + @ConstructorProperties({"token", "version"}) + private Session(String token, String version) { + this.token = checkNotNull(token, "token"); + this.version = checkNotNull(version, "version for %s", token); + } + + /** + * The authentication token + */ + public String getToken() { + return token; + } + + /** + * The current version of the server + */ + public String getVersion() { + return version; + } + + @Override + public int hashCode() { + return Objects.hashCode(token, version); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Session other = Session.class.cast(obj); + return Objects.equal(this.token, other.token) && Objects.equal(this.version, other.version); + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("token", token).add("version", version).toString(); + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/SessionCredentials.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/SessionCredentials.java new file mode 100644 index 0000000000..87489a3c6a --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/SessionCredentials.java @@ -0,0 +1,135 @@ +package org.jclouds.dynect.v3.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import javax.inject.Named; + +import org.jclouds.domain.Credentials; + +import com.google.common.base.Objects; + +/** + * Session credentials for API authentication. + * + * @see + * + * @author Adrian Cole + */ +public final class SessionCredentials extends Credentials { + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().from(this); + } + + public final static class Builder extends Credentials.Builder { + private String customerName; + private String userName; + private String password; + + /** + * @see SessionCredentials#getCustomerName() + */ + public Builder customerName(String customerName) { + this.customerName = customerName; + return this; + } + + @Override + public Builder identity(String identity) { + return userName(identity); + } + + @Override + public Builder credential(String credential) { + return password(credential); + } + + /** + * @see SessionCredentials#getUserName() + */ + public Builder userName(String userName) { + this.userName = userName; + return this; + } + + /** + * @see SessionCredentials#getPassword() + */ + public Builder password(String password) { + this.password = password; + return this; + } + + public SessionCredentials build() { + return new SessionCredentials(customerName, userName, password); + } + + public Builder from(SessionCredentials in) { + return this.userName(in.identity).password(in.credential).customerName(in.customerName); + } + } + + @Named("customer_name") + private final String customerName; + @Named("user_name") + private final String userName; + private final String password; + + @ConstructorProperties({ "customer_name", "user_name", "password" }) + private SessionCredentials(String customerName, String userName, String password) { + super(checkNotNull(userName, "userName"), checkNotNull(password, "password for %s", userName)); + this.userName = userName; + this.password = password; + this.customerName = checkNotNull(customerName, "customerName for %s", userName); + } + + /** + * UserName ID that identifies the temporary credentials. + */ + public String getUserName() { + return userName; + } + + /** + * The Secret Access Key to sign requests. + */ + public String getPassword() { + return password; + } + + /** + * The security token that users must pass to the service API to use the + * temporary credentials. + */ + public String getCustomerName() { + return customerName; + } + + @Override + public int hashCode() { + return Objects.hashCode(customerName, userName, password); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SessionCredentials other = SessionCredentials.class.cast(obj); + return Objects.equal(this.userName, other.userName) && Objects.equal(this.password, other.password) + && Objects.equal(this.customerName, other.customerName); + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("userName", identity).add("customerName", customerName).toString(); + } +} diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionApi.java new file mode 100644 index 0000000000..fc6fcf2816 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionApi.java @@ -0,0 +1,38 @@ +/** + * 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.dynect.v3.features; + +import org.jclouds.dynect.v3.domain.Session; +import org.jclouds.dynect.v3.domain.SessionCredentials; + +/** + * @see SessionAsyncApi + * @see + * @author Adrian Cole + */ +public interface SessionApi { + + Session login(SessionCredentials credentials); + + boolean isValid(String token); + + void logout(String token); +} \ No newline at end of file diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionAsyncApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionAsyncApi.java new file mode 100644 index 0000000000..20d3ed6d21 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/SessionAsyncApi.java @@ -0,0 +1,78 @@ +/** + * 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.dynect.v3.features; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import javax.inject.Named; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +import org.jclouds.dynect.v3.DynECTFallbacks.FalseOn400; +import org.jclouds.dynect.v3.domain.Session; +import org.jclouds.dynect.v3.domain.SessionCredentials; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.Headers; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.binders.BindToJsonPayload; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides access to DynECT Managed DNS through the API2 api + *

+ * + * @see SessionApi + * @see + * @author Adrian Cole + */ +// required for all calls +@Produces(APPLICATION_JSON) +@Headers(keys = "API-Version", values = "{jclouds.api-version}") +@Path("/Session") +public interface SessionAsyncApi { + + /** + * @see SessionApi#create + */ + @Named("POST:Session") + @POST + @SelectJson("data") + ListenableFuture login(@BinderParam(BindToJsonPayload.class) SessionCredentials credentials); + + /** + * @see SessionApi#isValid + */ + @Named("GET:Session") + @GET + @Fallback(FalseOn400.class) + ListenableFuture isValid(@HeaderParam("Auth-Token") String token); + + /** + * @see SessionApi#logout + */ + @Named("DELETE:Session") + @DELETE + ListenableFuture logout(@HeaderParam("Auth-Token") String token); +} diff --git a/labs/dynect/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/labs/dynect/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata new file mode 100644 index 0000000000..10bc2961f3 --- /dev/null +++ b/labs/dynect/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata @@ -0,0 +1 @@ +org.jclouds.dynect.v3.DynECTProviderMetadata diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/DynECTProviderMetadataTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/DynECTProviderMetadataTest.java new file mode 100644 index 0000000000..3518f321fb --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/DynECTProviderMetadataTest.java @@ -0,0 +1,35 @@ +/** + * 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.dynect.v3; + +import org.jclouds.dynect.v3.DynECTApiMetadata; +import org.jclouds.dynect.v3.DynECTProviderMetadata; +import org.jclouds.providers.internal.BaseProviderMetadataTest; +import org.testng.annotations.Test; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "DynECTProviderMetadataTest") +public class DynECTProviderMetadataTest extends BaseProviderMetadataTest { + public DynECTProviderMetadataTest() { + super(new DynECTProviderMetadata(), new DynECTApiMetadata()); + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiExpectTest.java new file mode 100644 index 0000000000..3cbacf2fa3 --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiExpectTest.java @@ -0,0 +1,97 @@ +/** + * 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 + * + * Unles 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 expres or implied. See the License for the + * specific language governing permisions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.domain.SessionCredentials; +import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest; +import org.jclouds.dynect.v3.parse.ParseSessionTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "SessionApiExpectTest") +public class SessionApiExpectTest extends BaseDynECTApiExpectTest { + + private String authToken = "FFFFFFFFFF"; + + HttpRequest create = HttpRequest.builder().method("POST") + .endpoint("https://api2.dynect.net/REST/Session") + .addHeader("API-Version", "3.3.7") + .payload(payloadFromStringWithContentType("{\"customer_name\":\"jclouds\",\"user_name\":\"joe\",\"password\":\"letmein\"}",APPLICATION_JSON)) + .build(); + + HttpResponse createResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/create_session.json", APPLICATION_JSON)).build(); + + public void testCreateWhenResponseIs2xx() { + DynECTApi apiCreatesSession = requestSendsResponse(create, createResponse); + assertEquals(apiCreatesSession.getSessionApi().login(SessionCredentials.builder() + .customerName("jclouds") + .userName("joe") + .password("letmein").build()).toString(), + new ParseSessionTest().expected().toString()); + } + + HttpRequest isValid = HttpRequest.builder().method("GET") + .endpoint("https://api2.dynect.net/REST/Session") + .addHeader("API-Version", "3.3.7") + .addHeader("Auth-Token", authToken) + .payload(emptyJsonPayload()) + .build(); + + HttpResponse validResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/session_valid.json", APPLICATION_JSON)).build(); + + HttpResponse invalidResponse = HttpResponse.builder().statusCode(400) + .payload(payloadFromResourceWithContentType("/session_invalid.json", APPLICATION_JSON)).build(); + + public void testSessionValid() { + DynECTApi apiWhenValid = requestSendsResponse(isValid, validResponse); + assertTrue(apiWhenValid.getSessionApi().isValid(authToken)); + } + + public void testSessionInvalid() { + DynECTApi apiWhenInvalid = requestSendsResponse(isValid, invalidResponse); + assertFalse(apiWhenInvalid.getSessionApi().isValid(authToken)); + } + + HttpRequest logout = HttpRequest.builder().method("DELETE") + .endpoint("https://api2.dynect.net/REST/Session") + .addHeader("API-Version", "3.3.7") + .addHeader("Auth-Token", authToken) + .payload(emptyJsonPayload()) + .build(); + + HttpResponse logoutResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/logout.json", APPLICATION_JSON)).build(); + + public void testLogout() { + DynECTApi apiWhenLogoutSuccess = requestSendsResponse(logout, logoutResponse); + apiWhenLogoutSuccess.getSessionApi().logout(authToken); + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiLiveTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiLiveTest.java new file mode 100644 index 0000000000..ab44ac23a7 --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/SessionApiLiveTest.java @@ -0,0 +1,63 @@ +/** + * 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.dynect.v3.features; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.dynect.v3.domain.Session; +import org.jclouds.dynect.v3.domain.SessionCredentials; +import org.jclouds.dynect.v3.internal.BaseDynECTApiLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", testName = "SessionApiLiveTest") +public class SessionApiLiveTest extends BaseDynECTApiLiveTest { + + private Session session; + + private void checkSession(Session zone) { + checkNotNull(zone.getToken(), "Token cannot be null for a Session."); + checkNotNull(zone.getVersion(), "Version cannot be null for a Session."); + } + + @Test + protected void testCreateSession() { + SessionCredentials credentials = SessionCredentials.builder() + .customerName(identity.substring(0, identity.indexOf(':'))) + .userName(identity.substring(identity.indexOf(':') + 1)) + .password(credential).build(); + session = api().login(credentials); + checkSession(session); + } + + protected SessionApi api() { + return context.getApi().getSessionApi(); + } + + @AfterClass(groups = { "integration", "live" }) + @Override + protected void tearDownContext() { + if (session != null) + api().logout(session.getToken()); + super.tearDownContext(); + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiExpectTest.java new file mode 100644 index 0000000000..deb3cd0acd --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiExpectTest.java @@ -0,0 +1,45 @@ +/** + * 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.dynect.v3.internal; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.http.HttpRequest; +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; + +/** + * Base class for writing DynECT Expect tests + * + * @author Adrian Cole + */ +public class BaseDynECTApiExpectTest extends BaseDynECTExpectTest { + + public static Payload emptyJsonPayload() { + Payload p = Payloads.newByteArrayPayload(new byte[] {}); + p.getContentMetadata().setContentType(APPLICATION_JSON); + return p; + } + + @Override + protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) { + return HttpRequestComparisonType.JSON; + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiLiveTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiLiveTest.java new file mode 100644 index 0000000000..c8bed8f663 --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTApiLiveTest.java @@ -0,0 +1,41 @@ +/** + * 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.dynect.v3.internal; + +import org.jclouds.apis.BaseContextLiveTest; +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.DynECTApiMetadata; +import org.jclouds.dynect.v3.DynECTAsyncApi; +import org.jclouds.rest.RestContext; +import org.testng.annotations.Test; + +import com.google.common.reflect.TypeToken; + +@Test(groups = "live") +public class BaseDynECTApiLiveTest extends BaseContextLiveTest> { + + public BaseDynECTApiLiveTest() { + provider = "dynect"; + } + + @Override + protected TypeToken> contextType() { + return DynECTApiMetadata.CONTEXT_TOKEN; + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java new file mode 100644 index 0000000000..8fb7fedcdc --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java @@ -0,0 +1,32 @@ +/** + * 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.dynect.v3.internal; + +import org.jclouds.rest.internal.BaseRestApiExpectTest; + +/** + * Base class for writing DynECT Expect tests + * + * @author Adrian Cole + */ +public class BaseDynECTExpectTest extends BaseRestApiExpectTest { + public BaseDynECTExpectTest() { + provider = "dynect"; + } +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTParseTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTParseTest.java new file mode 100644 index 0000000000..333a15e5df --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTParseTest.java @@ -0,0 +1,39 @@ +/** + * 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.dynect.v3.internal; + +import org.jclouds.dynect.v3.config.DynECTParserModule; +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +/** + * @author David Alves + */ +public abstract class BaseDynECTParseTest extends BaseItemParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new GsonModule(), new DynECTParserModule()); + } + +} diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/ParseSessionTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/ParseSessionTest.java new file mode 100644 index 0000000000..e9b353b6ef --- /dev/null +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/ParseSessionTest.java @@ -0,0 +1,47 @@ +/** + * 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.dynect.v3.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.dynect.v3.domain.Session; +import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ParseSessionTest extends BaseDynECTParseTest { + + @Override + public String resource() { + return "/create_session.json"; + } + + @Override + @SelectJson("data") + @Consumes(MediaType.APPLICATION_JSON) + public Session expected() { + return Session.forTokenAndVersion("FFFFFFFFFF", "3.3.7"); + } +} diff --git a/labs/dynect/src/test/resources/create_session.json b/labs/dynect/src/test/resources/create_session.json new file mode 100644 index 0000000000..7b4860fda5 --- /dev/null +++ b/labs/dynect/src/test/resources/create_session.json @@ -0,0 +1 @@ +{"status": "success", "data": {"token": "FFFFFFFFFF", "version": "3.3.7"}, "job_id": 254417252, "msgs": [{"INFO": "login: Login successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/dynect/src/test/resources/logback.xml b/labs/dynect/src/test/resources/logback.xml new file mode 100644 index 0000000000..9679b2e03a --- /dev/null +++ b/labs/dynect/src/test/resources/logback.xml @@ -0,0 +1,38 @@ + + + + target/test-data/jclouds.log + + + %d %-5p [%c] [%thread] %m%n + + + + + target/test-data/jclouds-wire.log + + + %d %-5p [%c] [%thread] %m%n + + + + + + + + + + + + + + + + + + + + + + + diff --git a/labs/dynect/src/test/resources/logout.json b/labs/dynect/src/test/resources/logout.json new file mode 100644 index 0000000000..c14c1e892a --- /dev/null +++ b/labs/dynect/src/test/resources/logout.json @@ -0,0 +1 @@ +{"status": "success", "data": {}, "job_id": 254506373, "msgs": [{"INFO": "logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/dynect/src/test/resources/session_invalid.json b/labs/dynect/src/test/resources/session_invalid.json new file mode 100644 index 0000000000..d3969415ce --- /dev/null +++ b/labs/dynect/src/test/resources/session_invalid.json @@ -0,0 +1 @@ +{"status": "failure", "data": {}, "job_id": 254505048, "msgs": [{"INFO": "login: Bad or expired credentials", "SOURCE": "BLL", "ERR_CD": "INVALID_DATA", "LVL": "ERROR"}, {"INFO": "login: There was a problem with your credentials", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/dynect/src/test/resources/session_valid.json b/labs/dynect/src/test/resources/session_valid.json new file mode 100644 index 0000000000..6ca8158b06 --- /dev/null +++ b/labs/dynect/src/test/resources/session_valid.json @@ -0,0 +1 @@ +{"status": "success", "data": {}, "job_id": 254504748, "msgs": [{"INFO": "isalive: User session is still active", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/pom.xml b/labs/pom.xml index 09e8be00d2..2ecac0a6d8 100644 --- a/labs/pom.xml +++ b/labs/pom.xml @@ -64,6 +64,7 @@ openstack-quantum openstack-glance route53 + dynect aws-route53