From 7b204d2f94c03ad143365fa46ef0d83fd5d4be5e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Mon, 7 Jun 2010 08:43:08 -0700 Subject: [PATCH] Issue 190: created skeleton for box.net --- .../java/__providerName__AsyncClientTest.java | 10 +- boxdotnet/.gitignore | 9 ++ boxdotnet/pom.xml | 92 ++++++++++++ .../java/org/jclouds/boxdotnet/BoxDotNet.java | 39 +++++ .../boxdotnet/BoxDotNetAsyncClient.java | 81 ++++++++++ .../jclouds/boxdotnet/BoxDotNetClient.java | 55 +++++++ .../boxdotnet/BoxDotNetContextBuilder.java | 62 ++++++++ .../boxdotnet/BoxDotNetContextFactory.java | 69 +++++++++ .../boxdotnet/BoxDotNetPropertiesBuilder.java | 69 +++++++++ .../config/BoxDotNetContextModule.java | 84 +++++++++++ .../config/BoxDotNetRestClientModule.java | 114 ++++++++++++++ .../handlers/BoxDotNetErrorHandler.java | 89 +++++++++++ .../reference/BoxDotNetConstants.java | 53 +++++++ .../boxdotnet/BoxDotNetAsyncClientTest.java | 141 ++++++++++++++++++ .../boxdotnet/BoxDotNetClientLiveTest.java | 67 +++++++++ boxdotnet/src/test/resources/log4j.xml | 110 ++++++++++++++ pom.xml | 3 +- 17 files changed, 1141 insertions(+), 6 deletions(-) create mode 100644 boxdotnet/.gitignore create mode 100644 boxdotnet/pom.xml create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNet.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetAsyncClient.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetClient.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextBuilder.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextFactory.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetPropertiesBuilder.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetContextModule.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetRestClientModule.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/handlers/BoxDotNetErrorHandler.java create mode 100644 boxdotnet/src/main/java/org/jclouds/boxdotnet/reference/BoxDotNetConstants.java create mode 100644 boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetAsyncClientTest.java create mode 100644 boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetClientLiveTest.java create mode 100644 boxdotnet/src/test/resources/log4j.xml diff --git a/archetypes/json-client-archetype/src/main/resources/archetype-resources/src/test/java/__providerName__AsyncClientTest.java b/archetypes/json-client-archetype/src/main/resources/archetype-resources/src/test/java/__providerName__AsyncClientTest.java index a08d79db9e..448e25410d 100644 --- a/archetypes/json-client-archetype/src/main/resources/archetype-resources/src/test/java/__providerName__AsyncClientTest.java +++ b/archetypes/json-client-archetype/src/main/resources/archetype-resources/src/test/java/__providerName__AsyncClientTest.java @@ -62,7 +62,7 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam Method method = ${providerName}AsyncClient.class.getMethod("list"); GeneratedHttpRequest<${providerName}AsyncClient> httpRequest = processor.createRequest(method); - assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/item HTTP/1.1"); + assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items HTTP/1.1"); assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertPayloadEquals(httpRequest, null); @@ -70,9 +70,9 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); - assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/item HTTP/1.1"); + assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items HTTP/1.1"); // for example, using basic authentication, we should get "only one" header - assertHeadersEqual(httpRequest, "Accept: application/json\nAuthorization: Basic Zm9vOmJhcg==\n"); + assertHeadersEqual(httpRequest, "Accept: application/json\nAuthorization: Basic dXNlcjprZXk=\n"); assertPayloadEquals(httpRequest, null); // TODO: insert expected response class, which probably extends ParseJson @@ -88,7 +88,7 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam Method method = ${providerName}AsyncClient.class.getMethod("get", long.class); GeneratedHttpRequest<${providerName}AsyncClient> httpRequest = processor.createRequest(method, 1); - assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/item/1 HTTP/1.1"); + assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items/1 HTTP/1.1"); assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertPayloadEquals(httpRequest, null); @@ -108,7 +108,7 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam method, 1); assertRequestLineEquals(httpRequest, - "DELETE ${providerEndpoint}/item/1 HTTP/1.1"); + "DELETE ${providerEndpoint}/items/1 HTTP/1.1"); assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertPayloadEquals(httpRequest, null); diff --git a/boxdotnet/.gitignore b/boxdotnet/.gitignore new file mode 100644 index 0000000000..5252166b05 --- /dev/null +++ b/boxdotnet/.gitignore @@ -0,0 +1,9 @@ +# use glob syntax. +syntax: glob +target +.settings +.classpath +.project +jclouds-boxdotnet.iml +jclouds-boxdotnet.ipr +jclouds-boxdotnet.iws \ No newline at end of file diff --git a/boxdotnet/pom.xml b/boxdotnet/pom.xml new file mode 100644 index 0000000000..e16d4f5e3f --- /dev/null +++ b/boxdotnet/pom.xml @@ -0,0 +1,92 @@ + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.0-SNAPSHOT + ../project/pom.xml + + org.jclouds + jclouds-boxdotnet + jclouds BoxDotNet core + jclouds components to access BoxDotNet + + + scm:svn:http://jclouds.googlecode.com/svn/trunk/boxdotnet + scm:svn:https://jclouds.googlecode.com/svn/trunk/boxdotnet + http://jclouds.googlecode.com/svn/trunk/boxdotnet + + + + + + jclouds-googlecode-deploy + http://jclouds.googlecode.com/svn/repo + + + jclouds-rimu-snapshots-nexus + http://jclouds.rimuhosting.com:8081/nexus/content/repositories/snapshots + + true + + + + + + apiKey + authToken + + + + ${project.groupId} + jclouds-core + ${project.version} + + + ${project.groupId} + jclouds-core + ${project.version} + test-jar + test + + + log4j + log4j + 1.2.14 + test + + + ${project.groupId} + jclouds-log4j + ${project.version} + test + + + diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNet.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNet.java new file mode 100644 index 0000000000..eca0696fc1 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNet.java @@ -0,0 +1,39 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.boxdotnet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Related to a BoxDotNet resource. + * + * @author Adrian Cole + * + */ +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) +@Qualifier +public @interface BoxDotNet { + +} \ No newline at end of file diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetAsyncClient.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetAsyncClient.java new file mode 100644 index 0000000000..1550eb3f51 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetAsyncClient.java @@ -0,0 +1,81 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.boxdotnet.BoxDotNetClient; +import org.jclouds.rest.annotations.Endpoint; +import org.jclouds.rest.annotations.ExceptionParser; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides asynchronous access to BoxDotNet via their REST API. + *

+ * + * @see BoxDotNetClient + * @see + * @author Adrian Cole + */ +@Endpoint(BoxDotNet.class) +@RequestFilters(BasicAuthentication.class) +@Consumes(MediaType.APPLICATION_JSON) +public interface BoxDotNetAsyncClient { + /* + * TODO: define interface methods for BoxDotNet + */ + + /** + * @see BoxDotNetClient#list() + */ + @GET + @Path("/items") + ListenableFuture list(); + + /** + * @see BoxDotNetClient#get(long) + */ + @GET + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/items/{itemId}") + ListenableFuture get(@PathParam("itemId") long id); + + /** + * @see BoxDotNetClient#delete + */ + @DELETE + @Path("/items/{itemId}") + @ExceptionParser(ReturnVoidOnNotFoundOr404.class) + ListenableFuture delete(@PathParam("itemId") long id); +} diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetClient.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetClient.java new file mode 100644 index 0000000000..b1b76f4aed --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetClient.java @@ -0,0 +1,55 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import java.util.concurrent.TimeUnit; + +import org.jclouds.concurrent.Timeout; + +/** + * Provides synchronous access to BoxDotNet. + *

+ * + * @see BoxDotNetAsyncClient + * @see + * @author Adrian Cole + */ +@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS) +public interface BoxDotNetClient { + /* + * Note all these delegate to methods in BoxDotNetAsyncClient with a specified or inherited timeout. + * The singatures should match those of BoxDotNetAsyncClient, except the returnvals should not be + * wrapped in a ListenableFuture + */ + + String list(); + + /** + * @return null, if not found + */ + String get(long id); + + void delete(long id); + +} diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextBuilder.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextBuilder.java new file mode 100644 index 0000000000..668f3f7287 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextBuilder.java @@ -0,0 +1,62 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Properties; + +import org.jclouds.rest.RestContextBuilder; +import org.jclouds.boxdotnet.BoxDotNetAsyncClient; +import org.jclouds.boxdotnet.BoxDotNetClient; + +import org.jclouds.boxdotnet.config.BoxDotNetContextModule; +import org.jclouds.boxdotnet.config.BoxDotNetRestClientModule; +import org.jclouds.boxdotnet.reference.BoxDotNetConstants; + +import com.google.inject.Module; + +/** + * + * @author Adrian Cole + */ +public class BoxDotNetContextBuilder extends RestContextBuilder { + + public BoxDotNetContextBuilder(String providerName, Properties props) { + super(providerName, BoxDotNetClient.class, BoxDotNetAsyncClient.class, props); + checkNotNull(properties.getProperty(BoxDotNetConstants.PROPERTY_BOXDOTNET_USER)); + checkNotNull(properties.getProperty(BoxDotNetConstants.PROPERTY_BOXDOTNET_PASSWORD)); + } + + protected void addClientModule(List modules) { + modules.add(new BoxDotNetRestClientModule()); + } + + @Override + protected void addContextModule(String providerName, List modules) { + modules.add(new BoxDotNetContextModule(providerName)); + } + +} diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextFactory.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextFactory.java new file mode 100644 index 0000000000..3a833b323a --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetContextFactory.java @@ -0,0 +1,69 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; +import org.jclouds.logging.jdk.config.JDKLoggingModule; +import org.jclouds.rest.RestContext; + +import com.google.inject.Module; + +/** + * Creates {@link RestContext} for {@link BoxDotNetClient} instances based on the most commonly + * requested arguments. + *

+ * Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. + *

+ *

+ * If no Modules are specified, the default {@link JDKLoggingModule logging} and + * {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed. + * + * @author Adrian Cole + * @see RestContext + * @see BoxDotNetClient + * @see BoxDotNetAsyncClient + */ +public class BoxDotNetContextFactory { + + public static RestContext createContext(String user, String password, + Module... modules) { + return new BoxDotNetContextBuilder("boxdotnet", new BoxDotNetPropertiesBuilder(user, password).build()) + .withModules(modules).buildContext(); + } + + public static RestContext createContext(URI endpoint, String user, String password, + Module... modules) { + return new BoxDotNetContextBuilder("boxdotnet", new BoxDotNetPropertiesBuilder(user, password).withEndpoint(endpoint).build()) + .withModules(modules).buildContext(); + } + + public static RestContext createContext(Properties properties, Module... modules) { + return new BoxDotNetContextBuilder("boxdotnet", new BoxDotNetPropertiesBuilder(properties).build()) + .withModules(modules).buildContext(); + } + +} diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetPropertiesBuilder.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetPropertiesBuilder.java new file mode 100644 index 0000000000..40476e3633 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/BoxDotNetPropertiesBuilder.java @@ -0,0 +1,69 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.boxdotnet.reference.BoxDotNetConstants.PROPERTY_BOXDOTNET_ENDPOINT; +import static org.jclouds.boxdotnet.reference.BoxDotNetConstants.PROPERTY_BOXDOTNET_PASSWORD; +import static org.jclouds.boxdotnet.reference.BoxDotNetConstants.PROPERTY_BOXDOTNET_USER; + +import java.net.URI; +import java.util.Properties; + +import org.jclouds.PropertiesBuilder; + +/** + * Builds properties used in BoxDotNet Clients + * + * @author Adrian Cole + */ +public class BoxDotNetPropertiesBuilder extends PropertiesBuilder { + @Override + protected Properties defaultProperties() { + Properties properties = super.defaultProperties(); + properties.setProperty(PROPERTY_BOXDOTNET_ENDPOINT, "https://www.box.net/api/1.0/rest"); + return properties; + } + + public BoxDotNetPropertiesBuilder(Properties properties) { + super(properties); + } + + public BoxDotNetPropertiesBuilder(String id, String secret) { + super(); + withCredentials(id, secret); + } + + public BoxDotNetPropertiesBuilder withCredentials(String id, String secret) { + properties.setProperty(PROPERTY_BOXDOTNET_USER, checkNotNull(id, "user")); + properties.setProperty(PROPERTY_BOXDOTNET_PASSWORD, checkNotNull(secret, "password")); + return this; + } + + public BoxDotNetPropertiesBuilder withEndpoint(URI endpoint) { + properties.setProperty(PROPERTY_BOXDOTNET_ENDPOINT, checkNotNull(endpoint, "endpoint") + .toString()); + return this; + } +} diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetContextModule.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetContextModule.java new file mode 100644 index 0000000000..ea366dcf56 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetContextModule.java @@ -0,0 +1,84 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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. + * ==================================================================== + */ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet.config; + +import java.net.URI; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.lifecycle.Closer; +import org.jclouds.rest.RestContext; +import org.jclouds.rest.internal.RestContextImpl; +import org.jclouds.boxdotnet.BoxDotNet; +import org.jclouds.boxdotnet.BoxDotNetAsyncClient; +import org.jclouds.boxdotnet.BoxDotNetClient; +import org.jclouds.boxdotnet.reference.BoxDotNetConstants; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; + +/** + * Configures the BoxDotNet connection, including logging and http transport. + * + * @author Adrian Cole + */ +public class BoxDotNetContextModule extends AbstractModule { + + public BoxDotNetContextModule(String providerName) { + // providerName ignored right now + } + + @Override + protected void configure() { + // example of how to customize bindings + // bind(DateAdapter.class).to(CDateAdapter.class); + } + + @Provides + @Singleton + RestContext provideContext(Closer closer, BoxDotNetAsyncClient asyncApi, + BoxDotNetClient syncApi, @BoxDotNet URI endPoint, @Named(BoxDotNetConstants.PROPERTY_BOXDOTNET_USER) String account) { + return new RestContextImpl(closer, asyncApi, syncApi, endPoint, account); + } + +} \ No newline at end of file diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetRestClientModule.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetRestClientModule.java new file mode 100644 index 0000000000..f9ad42d513 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/config/BoxDotNetRestClientModule.java @@ -0,0 +1,114 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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. + * ==================================================================== + */ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet.config; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.RequiresHttp; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.config.RestClientModule; +import org.jclouds.encryption.EncryptionService; + +import org.jclouds.boxdotnet.BoxDotNet; +import org.jclouds.boxdotnet.BoxDotNetClient; +import org.jclouds.boxdotnet.BoxDotNetAsyncClient; +import org.jclouds.boxdotnet.reference.BoxDotNetConstants; +import org.jclouds.boxdotnet.handlers.BoxDotNetErrorHandler; + +import com.google.inject.Provides; + +/** + * Configures the BoxDotNet connection. + * + * @author Adrian Cole + */ +@RequiresHttp +@ConfiguresRestClient +public class BoxDotNetRestClientModule extends + RestClientModule { + + public BoxDotNetRestClientModule() { + super(BoxDotNetClient.class, BoxDotNetAsyncClient.class); + } + + @Provides + @Singleton + public BasicAuthentication provideBasicAuthentication( + @Named(BoxDotNetConstants.PROPERTY_BOXDOTNET_USER) String user, + @Named(BoxDotNetConstants.PROPERTY_BOXDOTNET_PASSWORD) String password, + EncryptionService encryptionService) + throws UnsupportedEncodingException { + return new BasicAuthentication(user, password, encryptionService); + } + + @Provides + @Singleton + @BoxDotNet + protected URI provideURI(@Named(BoxDotNetConstants.PROPERTY_BOXDOTNET_ENDPOINT) String endpoint) { + return URI.create(endpoint); + } + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to( + BoxDotNetErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to( + BoxDotNetErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to( + BoxDotNetErrorHandler.class); + } + + @Override + protected void bindRetryHandlers() { + // TODO + } + +} \ No newline at end of file diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/handlers/BoxDotNetErrorHandler.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/handlers/BoxDotNetErrorHandler.java new file mode 100644 index 0000000000..bd4ecfbcb5 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/handlers/BoxDotNetErrorHandler.java @@ -0,0 +1,89 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.boxdotnet.handlers; + +import java.io.IOException; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceNotFoundException; +import org.jclouds.util.Utils; + +import com.google.common.base.Throwables; +import com.google.common.io.Closeables; + +/** + * This will parse and set an appropriate exception on the command object. + * + * @author Adrian Cole + * + */ +@Singleton +public class BoxDotNetErrorHandler implements HttpErrorHandler { + @Resource + protected Logger logger = Logger.NULL; + + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + String message = parseMessage(response); + Exception exception = message != null ? new HttpResponseException(command, response, message) + : new HttpResponseException(command, response); + try { + message = message != null ? message : String.format("%s -> %s", command.getRequest() + .getRequestLine(), response.getStatusLine()); + switch (response.getStatusCode()) { + case 401: + case 403: + exception = new AuthorizationException(message, exception); + break; + case 404: + if (!command.getRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + } + } finally { + Closeables.closeQuietly(response.getContent()); + command.setException(exception); + } + } + + public String parseMessage(HttpResponse response) { + if (response.getContent() == null) + return null; + try { + return Utils.toStringAndClose(response.getContent()); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + response.getContent().close(); + } catch (IOException e) { + Throwables.propagate(e); + } + } + } +} \ No newline at end of file diff --git a/boxdotnet/src/main/java/org/jclouds/boxdotnet/reference/BoxDotNetConstants.java b/boxdotnet/src/main/java/org/jclouds/boxdotnet/reference/BoxDotNetConstants.java new file mode 100644 index 0000000000..7d79af3a06 --- /dev/null +++ b/boxdotnet/src/main/java/org/jclouds/boxdotnet/reference/BoxDotNetConstants.java @@ -0,0 +1,53 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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. + * ==================================================================== + */ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet.reference; + +/** + * Configuration properties and constants used in BoxDotNet connections. + * + * @author Adrian Cole + */ +public interface BoxDotNetConstants { + public static final String PROPERTY_BOXDOTNET_ENDPOINT = "jclouds.boxdotnet.endpoint"; + public static final String PROPERTY_BOXDOTNET_USER = "jclouds.boxdotnet.user"; + public static final String PROPERTY_BOXDOTNET_PASSWORD = "jclouds.boxdotnet.password"; +} diff --git a/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetAsyncClientTest.java b/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetAsyncClientTest.java new file mode 100644 index 0000000000..8f3ccd798a --- /dev/null +++ b/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetAsyncClientTest.java @@ -0,0 +1,141 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.lang.reflect.Method; + +import org.jclouds.boxdotnet.config.BoxDotNetRestClientModule; +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.http.functions.CloseContentAndReturn; +import org.jclouds.http.functions.ReturnStringIf200; +import org.jclouds.logging.config.NullLoggingModule; +import org.jclouds.rest.RestClientTest; +import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; +import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; +import org.jclouds.rest.internal.GeneratedHttpRequest; +import org.jclouds.rest.internal.RestAnnotationProcessor; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +/** + * Tests annotation parsing of {@code BoxDotNetAsyncClient} + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "boxdotnet.BoxDotNetAsyncClientTest") +public class BoxDotNetAsyncClientTest extends RestClientTest { + + + public void testList() throws SecurityException, NoSuchMethodException, IOException { + Method method = BoxDotNetAsyncClient.class.getMethod("list"); + GeneratedHttpRequest httpRequest = processor.createRequest(method); + + assertRequestLineEquals(httpRequest, "GET https://www.box.net/api/1.0/rest/items HTTP/1.1"); + assertHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null); + + // now make sure request filters apply by replaying + Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); + Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); + + assertRequestLineEquals(httpRequest, "GET https://www.box.net/api/1.0/rest/items HTTP/1.1"); + // for example, using basic authentication, we should get "only one" header + assertHeadersEqual(httpRequest, "Accept: application/json\nAuthorization: Basic dXNlcjprZXk=\n"); + assertPayloadEquals(httpRequest, null); + + // TODO: insert expected response class, which probably extends ParseJson + assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, null); + + checkFilters(httpRequest); + + } + + public void testGet() throws SecurityException, NoSuchMethodException, IOException { + Method method = BoxDotNetAsyncClient.class.getMethod("get", long.class); + GeneratedHttpRequest httpRequest = processor.createRequest(method, 1); + + assertRequestLineEquals(httpRequest, "GET https://www.box.net/api/1.0/rest/items/1 HTTP/1.1"); + assertHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null); + + // TODO: insert expected response class, which probably extends ParseJson + assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class); + assertSaxResponseParserClassEquals(method, null); + // note that get methods should convert 404's to null + assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + + public void testDelete() throws SecurityException, NoSuchMethodException, IOException { + Method method = BoxDotNetAsyncClient.class.getMethod("delete", long.class); + GeneratedHttpRequest httpRequest = processor.createRequest( + method, 1); + + assertRequestLineEquals(httpRequest, + "DELETE https://www.box.net/api/1.0/rest/items/1 HTTP/1.1"); + assertHeadersEqual(httpRequest, "Accept: application/json\n"); + assertPayloadEquals(httpRequest, null); + + assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class); + assertSaxResponseParserClassEquals(method, null); + assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class); + + checkFilters(httpRequest); + + } + @Override + protected void checkFilters(GeneratedHttpRequest httpRequest) { + assertEquals(httpRequest.getFilters().size(), 1); + assertEquals(httpRequest.getFilters().get(0).getClass(), BasicAuthentication.class); + } + + @Override + protected TypeLiteral> createTypeLiteral() { + return new TypeLiteral>() { + }; + } + + @Override + protected Module createModule() { + return new BoxDotNetRestClientModule() { + @Override + protected void configure() { + Names.bindProperties(binder(), new BoxDotNetPropertiesBuilder("user", "key").build()); + install(new NullLoggingModule()); + super.configure(); + } + }; + } +} diff --git a/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetClientLiveTest.java b/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetClientLiveTest.java new file mode 100644 index 0000000000..7d3b4d19d6 --- /dev/null +++ b/boxdotnet/src/test/java/org/jclouds/boxdotnet/BoxDotNetClientLiveTest.java @@ -0,0 +1,67 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.boxdotnet; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertNotNull; + +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +/** + * Tests behavior of {@code BoxDotNetClient} + * + * @author Adrian Cole + */ +@Test(groups = "live", testName = "boxdotnet.BoxDotNetClientLiveTest") +public class BoxDotNetClientLiveTest { + + private BoxDotNetClient connection; + + @BeforeGroups(groups = { "live" }) + public void setupClient() { + String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); + String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); + + connection = BoxDotNetContextFactory.createContext(user, password, new Log4JLoggingModule()) + .getApi(); + } + + @Test + public void testList() throws Exception { + String response = connection.list(); + assertNotNull(response); + } + + @Test + public void testGet() throws Exception { + String response = connection.get(1l); + assertNotNull(response); + } + + /* + * TODO: add tests for BoxDotNet interface methods + */ +} diff --git a/boxdotnet/src/test/resources/log4j.xml b/boxdotnet/src/test/resources/log4j.xml new file mode 100644 index 0000000000..6e388b9373 --- /dev/null +++ b/boxdotnet/src/test/resources/log4j.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 32a78e0e75..83fe2b1832 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,7 @@ chef opscodeplatform ibmdev + boxdotnet @@ -143,4 +144,4 @@ pageTracker._trackPageview(); - + \ No newline at end of file