From 6ba7d12a55d2c610184b0f101c3d1449371104b4 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Tue, 7 Aug 2012 13:44:26 -0700 Subject: [PATCH 01/10] Fixing client tests so they pull credentials from env vars --- .../windowsazure/services/blob/client/BlobTestBase.java | 6 +++++- .../windowsazure/services/queue/client/QueueTestBase.java | 6 +++++- .../windowsazure/services/table/client/TableTestBase.java | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java index bd0671e3ece19..938db64c06d4a 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java @@ -51,7 +51,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("blob.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("blob.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } bClient = httpAcc.createCloudBlobClient(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java index feb5b1ceb4a10..8144378d8577b 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java @@ -52,7 +52,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("queue.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("queue.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } qClient = httpAcc.createCloudQueueClient(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java index d235ed326cc69..7ba57b75322c8 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java @@ -577,7 +577,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("table.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("table.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } bClient = httpAcc.createCloudBlobClient(); From 40f629b74e363136537ec1baf1754f2f9c65d2a9 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Mon, 24 Sep 2012 17:34:31 -0700 Subject: [PATCH 02/10] Adding support for setting timeout in configuration --- .../services/core/Configuration.java | 27 +++++----- .../services/core/utils/pipeline/Exports.java | 18 +++++-- .../pipeline/HttpURLConnectionClient.java | 18 +++---- .../HttpURLConnectionClientHandler.java | 40 ++++++++++++--- .../table/TableServiceIntegrationTest.java | 49 +++++++++++++++++++ 5 files changed, 116 insertions(+), 36 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java index 1664dec987818..67f30dfe880e4 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java @@ -2,15 +2,15 @@ * Copyright 2011 Microsoft Corporation * * 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 + * 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. + * 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 com.microsoft.windowsazure.services.core; @@ -23,8 +23,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.sun.jersey.api.client.config.ClientConfig; - public class Configuration { private static Configuration instance; @@ -36,17 +34,11 @@ public class Configuration { public Configuration() { this.properties = new HashMap(); this.builder = DefaultBuilder.create(); - init(); } public Configuration(Builder builder) { this.properties = new HashMap(); this.builder = builder; - init(); - } - - private void init() { - setProperty("ClientConfig", builder.build("", ClientConfig.class, properties)); } public static Configuration getInstance() { @@ -102,4 +94,7 @@ public void setProperty(String name, Object value) { properties.put(name, value); } + public Map getProperties() { + return properties; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java index 234581b023fb8..026a4254de70b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java @@ -32,7 +32,19 @@ public void register(Registry registry) { public ClientConfig create(String profile, Builder builder, Map properties) { ClientConfig clientConfig = new DefaultClientConfig(); for (Entry entry : properties.entrySet()) { - clientConfig.getProperties().put(entry.getKey(), entry.getValue()); + Object propertyValue = entry.getValue(); + + // ClientConfig requires instance of Integer to properly set + // timeouts, but config file will deliver strings. Special + // case these timeout properties and convert them to Integer + // if necessary. + if (entry.getKey().equals(ClientConfig.PROPERTY_CONNECT_TIMEOUT) + || entry.getKey().equals(ClientConfig.PROPERTY_READ_TIMEOUT)) { + if (propertyValue instanceof String) { + propertyValue = Integer.valueOf((String) propertyValue); + } + } + clientConfig.getProperties().put(entry.getKey(), propertyValue); } return clientConfig; } @@ -41,7 +53,7 @@ public ClientConfig create(String profile, Builder builder, Map registry.add(new Builder.Factory() { @Override public Client create(String profile, Builder builder, Map properties) { - ClientConfig clientConfig = (ClientConfig) properties.get("ClientConfig"); + ClientConfig clientConfig = builder.build(profile, ClientConfig.class, properties); Client client = Client.create(clientConfig); return client; } @@ -50,7 +62,7 @@ public Client create(String profile, Builder builder, Map proper registry.add(new Builder.Factory() { @Override public HttpURLConnectionClient create(String profile, Builder builder, Map properties) { - ClientConfig clientConfig = (ClientConfig) properties.get("ClientConfig"); + ClientConfig clientConfig = builder.build(profile, ClientConfig.class, properties); HttpURLConnectionClient client = HttpURLConnectionClient.create(clientConfig); //client.addFilter(new LoggingFilter()); return client; diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClient.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClient.java index 9b7ca1dd32482..f996e5edc6421 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClient.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClient.java @@ -2,15 +2,15 @@ * Copyright 2011 Microsoft Corporation * * 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 + * 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. + * 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 com.microsoft.windowsazure.services.core.utils.pipeline; @@ -26,7 +26,7 @@ public HttpURLConnectionClient(HttpURLConnectionClientHandler handler, ClientCon } public static HttpURLConnectionClient create(ClientConfig config) { - return new HttpURLConnectionClient(new HttpURLConnectionClientHandler(), config); + return new HttpURLConnectionClient(new HttpURLConnectionClientHandler(config), config); } public HttpURLConnectionClientHandler getRootHandler() { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java index 20d9046c5358c..21b1f3c0b3c3b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java @@ -2,15 +2,15 @@ * Copyright 2011 Microsoft Corporation * * 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 + * 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. + * 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 com.microsoft.windowsazure.services.core.utils.pipeline; @@ -37,10 +37,28 @@ import com.sun.jersey.core.header.InBoundHeaders; public class HttpURLConnectionClientHandler extends TerminatingClientHandler { + + private final int connectionTimeoutMS; + private final int readTimeoutMS; + + public HttpURLConnectionClientHandler(ClientConfig clientConfig) { + connectionTimeoutMS = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_CONNECT_TIMEOUT); + readTimeoutMS = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_READ_TIMEOUT); + } + + private static int readTimeoutFromConfig(ClientConfig config, String propertyName) { + Integer property = (Integer) config.getProperty(propertyName); + if (property != null) { + return property.intValue(); + } + return 0; + } + /** * Empty "no-op" listener if none registered */ private static final EntityStreamingListener EMPTY_STREAMING_LISTENER = new EntityStreamingListener() { + @Override public void onBeforeStreamingEntity(ClientRequest clientRequest) { } }; @@ -164,6 +182,7 @@ public String toString() { } } + @Override public ClientResponse handle(final ClientRequest ro) throws ClientHandlerException { try { return doHandle(ro); @@ -176,6 +195,9 @@ public ClientResponse handle(final ClientRequest ro) throws ClientHandlerExcepti private ClientResponse doHandle(final ClientRequest clientRequest) throws IOException, MalformedURLException, ProtocolException { final HttpURLConnection urlConnection = (HttpURLConnection) clientRequest.getURI().toURL().openConnection(); + urlConnection.setReadTimeout(readTimeoutMS); + urlConnection.setConnectTimeout(connectionTimeoutMS); + final EntityStreamingListener entityStreamingListener = getEntityStreamingListener(clientRequest); urlConnection.setRequestMethod(clientRequest.getMethod()); @@ -202,6 +224,7 @@ private ClientResponse doHandle(final ClientRequest clientRequest) throws IOExce writeRequestEntity(clientRequest, new RequestEntityWriterListener() { private boolean inStreamingMode; + @Override public void onRequestEntitySize(long size) { if (size != -1 && size < Integer.MAX_VALUE) { inStreamingMode = true; @@ -222,6 +245,7 @@ public void onRequestEntitySize(long size) { } } + @Override public OutputStream onGetOutputStream() throws IOException { if (inStreamingMode) return new StreamingOutputStream(urlConnection, clientRequest); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java index 4651f71acf0d6..05cc34eafae09 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java @@ -47,6 +47,7 @@ import com.microsoft.windowsazure.services.table.models.QueryTablesResult; import com.microsoft.windowsazure.services.table.models.ServiceProperties; import com.microsoft.windowsazure.services.table.models.TableEntry; +import com.sun.jersey.api.client.config.ClientConfig; public class TableServiceIntegrationTest extends IntegrationTestBase { private static final String testTablesPrefix = "sdktest"; @@ -1139,4 +1140,52 @@ public void batchNegativeWorks() throws Exception { assertEquals("Second result status code", 412, error.getError().getHttpStatusCode()); assertNull("Third result should be null", result.getEntries().get(2)); } + + @Test + public void settingTimeoutWorks() throws Exception { + Configuration config = createConfiguration(); + + // Set timeout to very short to force failure + config.setProperty(ClientConfig.PROPERTY_CONNECT_TIMEOUT, new Integer(1)); + config.setProperty(ClientConfig.PROPERTY_READ_TIMEOUT, new Integer(1)); + + TableContract service = TableService.create(config); + + try { + service.queryTables(); + fail("Exception should have been thrown"); + } + catch (ServiceException ex) { + assertNotNull(ex.getCause()); + } + finally { + // Clean up timeouts, they interfere with other tests otherwise + config.getProperties().remove(ClientConfig.PROPERTY_CONNECT_TIMEOUT); + config.getProperties().remove(ClientConfig.PROPERTY_READ_TIMEOUT); + } + } + + @Test + public void settingTimeoutFromStringWorks() throws Exception { + Configuration config = createConfiguration(); + + // Set timeout to very short to force failure + config.setProperty(ClientConfig.PROPERTY_CONNECT_TIMEOUT, "1"); + config.setProperty(ClientConfig.PROPERTY_READ_TIMEOUT, "1"); + + TableContract service = TableService.create(config); + + try { + service.queryTables(); + fail("Exception should have been thrown"); + } + catch (ServiceException ex) { + assertNotNull(ex.getCause()); + } + finally { + // Clean up timeouts, they interfere with other tests otherwise + config.getProperties().remove(ClientConfig.PROPERTY_CONNECT_TIMEOUT); + config.getProperties().remove(ClientConfig.PROPERTY_READ_TIMEOUT); + } + } } From e1bafa873026d2f4812d7f48d9a0f78393745123 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Tue, 25 Sep 2012 16:07:54 -0700 Subject: [PATCH 03/10] Setting default timeout at 90 seconds --- .../windowsazure/services/core/Configuration.java | 9 +++++++++ .../pipeline/HttpURLConnectionClientHandler.java | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java index 67f30dfe880e4..a3308a0cf0505 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java @@ -23,6 +23,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import com.sun.jersey.api.client.config.ClientConfig; + public class Configuration { private static Configuration instance; @@ -34,11 +36,18 @@ public class Configuration { public Configuration() { this.properties = new HashMap(); this.builder = DefaultBuilder.create(); + init(); } public Configuration(Builder builder) { this.properties = new HashMap(); this.builder = builder; + init(); + } + + private void init() { + setProperty(ClientConfig.PROPERTY_READ_TIMEOUT, new Integer(90 * 1000)); + setProperty(ClientConfig.PROPERTY_CONNECT_TIMEOUT, new Integer(90 * 1000)); } public static Configuration getInstance() { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java index 21b1f3c0b3c3b..83e0822264e45 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/HttpURLConnectionClientHandler.java @@ -38,12 +38,12 @@ public class HttpURLConnectionClientHandler extends TerminatingClientHandler { - private final int connectionTimeoutMS; - private final int readTimeoutMS; + private final int connectionTimeoutMillis; + private final int readTimeoutMillis; public HttpURLConnectionClientHandler(ClientConfig clientConfig) { - connectionTimeoutMS = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_CONNECT_TIMEOUT); - readTimeoutMS = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_READ_TIMEOUT); + connectionTimeoutMillis = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_CONNECT_TIMEOUT); + readTimeoutMillis = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_READ_TIMEOUT); } private static int readTimeoutFromConfig(ClientConfig config, String propertyName) { @@ -51,7 +51,7 @@ private static int readTimeoutFromConfig(ClientConfig config, String propertyNam if (property != null) { return property.intValue(); } - return 0; + throw new IllegalArgumentException(propertyName); } /** @@ -195,8 +195,8 @@ public ClientResponse handle(final ClientRequest ro) throws ClientHandlerExcepti private ClientResponse doHandle(final ClientRequest clientRequest) throws IOException, MalformedURLException, ProtocolException { final HttpURLConnection urlConnection = (HttpURLConnection) clientRequest.getURI().toURL().openConnection(); - urlConnection.setReadTimeout(readTimeoutMS); - urlConnection.setConnectTimeout(connectionTimeoutMS); + urlConnection.setReadTimeout(readTimeoutMillis); + urlConnection.setConnectTimeout(connectionTimeoutMillis); final EntityStreamingListener entityStreamingListener = getEntityStreamingListener(clientRequest); From 2b5455ca80369b1c3ec464158d45513084d67857 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Wed, 26 Sep 2012 17:57:29 -0700 Subject: [PATCH 04/10] Throwing ServiceTimeoutException on socket timeout. Also fixed bug in default timeout setting --- .../services/core/Configuration.java | 9 -- .../core/ServiceTimeoutException.java | 50 +++++++++++ .../core/utils/ServiceExceptionFactory.java | 90 ++++++++++++++++--- .../services/core/utils/pipeline/Exports.java | 7 ++ .../table/TableServiceIntegrationTest.java | 15 +++- .../utils/ServiceExceptionFactoryTest.java | 46 ++++++---- 6 files changed, 176 insertions(+), 41 deletions(-) create mode 100644 microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java index a3308a0cf0505..67f30dfe880e4 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java @@ -23,8 +23,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.sun.jersey.api.client.config.ClientConfig; - public class Configuration { private static Configuration instance; @@ -36,18 +34,11 @@ public class Configuration { public Configuration() { this.properties = new HashMap(); this.builder = DefaultBuilder.create(); - init(); } public Configuration(Builder builder) { this.properties = new HashMap(); this.builder = builder; - init(); - } - - private void init() { - setProperty(ClientConfig.PROPERTY_READ_TIMEOUT, new Integer(90 * 1000)); - setProperty(ClientConfig.PROPERTY_CONNECT_TIMEOUT, new Integer(90 * 1000)); } public static Configuration getInstance() { diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java new file mode 100644 index 0000000000000..6de101f3d93d3 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java @@ -0,0 +1,50 @@ +/** + * + */ +package com.microsoft.windowsazure.services.core; + +/** + * Exception indicating a service operation has timed out. + */ +public class ServiceTimeoutException extends ServiceException { + + private static final long serialVersionUID = 6612846403178749361L; + + /** + * Construct a ServiceTimeoutException instance + */ + public ServiceTimeoutException() { + } + + /** + * Construct a ServiceTimeoutException instance + * + * @param message + * Exception message + */ + public ServiceTimeoutException(String message) { + super(message); + } + + /** + * Construct a ServiceTimeoutException instance + * + * @param message + * Exception message + * @param cause + * Exception that caused this exception to occur + */ + public ServiceTimeoutException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Construct a ServiceTimeoutException instance + * + * @param cause + * Exception that caused this exception to occur + */ + public ServiceTimeoutException(Throwable cause) { + super(cause); + } +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java index 90210ac0e6254..dd593322c2073 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java @@ -2,19 +2,23 @@ * Copyright 2011 Microsoft Corporation * * 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 + * 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. + * 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 com.microsoft.windowsazure.services.core.utils; +import java.net.SocketTimeoutException; + import com.microsoft.windowsazure.services.core.ServiceException; +import com.microsoft.windowsazure.services.core.ServiceTimeoutException; +import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; import com.sun.jersey.api.client.UniformInterfaceException; @@ -22,14 +26,69 @@ public class ServiceExceptionFactory { public static ServiceException process(String serviceName, ServiceException exception) { + // State machine for figuring out what to do with the exception + // + // Input is the type of the current exception cause. + // FSM starts in state 0. + // + // State | Input | New State | Action + //--------------------------------------------------------------------------- + // 0 | ServiceException | None | populate and return + // | | | + // 0 | UniformInterfaceException | None | populate and return + // | | | + // 0 | ClientHandlerException | 1 | None + // | | | + // 0 | Any other | 0 | None + // | | | + // 1 | ServiceException | None | populate and return + // | | | + // 1 | UniformInterfaceException | None | populate and return + // | | | + // 1 | ClientHandlerException | 1 | None + // | | | + // 1 | SocketTimeoutException | None | populate and return + // | | | + // 1 | Any other | 0 | None + + int state = 0; Throwable cause = exception.getCause(); for (Throwable scan = cause; scan != null; scan = scan.getCause()) { - if (ServiceException.class.isAssignableFrom(scan.getClass())) { - return populate(exception, serviceName, (ServiceException) scan); - } - else if (UniformInterfaceException.class.isAssignableFrom(scan.getClass())) { - return populate(exception, serviceName, (UniformInterfaceException) scan); + Class scanClass = scan.getClass(); + + switch (state) { + case 0: + if (ServiceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (ServiceException) scan); + } + else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (UniformInterfaceException) scan); + } + else if (ClientHandlerException.class.isAssignableFrom(scanClass)) { + state = 1; + } + else { + state = 0; + } + break; + + case 1: + if (ServiceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (ServiceException) scan); + } + else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (UniformInterfaceException) scan); + } + else if (SocketTimeoutException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (SocketTimeoutException) scan); + } + else if (ClientHandlerException.class.isAssignableFrom(scanClass)) { + state = 1; + } + else { + state = 0; + } } } @@ -83,4 +142,9 @@ static ServiceException populate(ServiceException exception, String serviceName, return exception; } + static ServiceException populate(ServiceException exception, String serviceName, SocketTimeoutException cause) { + ServiceTimeoutException newException = new ServiceTimeoutException(cause.getMessage(), cause); + newException.setServiceName(serviceName); + return newException; + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java index 026a4254de70b..e8de5bd31606e 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java @@ -31,6 +31,13 @@ public void register(Registry registry) { @Override public ClientConfig create(String profile, Builder builder, Map properties) { ClientConfig clientConfig = new DefaultClientConfig(); + // Lower levels of the stack assume timeouts are set. + // Set default timeout on clientConfig in case user + // hasn't set it yet in their configuration + + clientConfig.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, new Integer(90 * 1000)); + clientConfig.getProperties().put(ClientConfig.PROPERTY_READ_TIMEOUT, new Integer(90 * 1000)); + for (Entry entry : properties.entrySet()) { Object propertyValue = entry.getValue(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java index 05cc34eafae09..0faee5e7603ca 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java @@ -29,6 +29,7 @@ import com.microsoft.windowsazure.services.core.ExponentialRetryPolicy; import com.microsoft.windowsazure.services.core.RetryPolicyFilter; import com.microsoft.windowsazure.services.core.ServiceException; +import com.microsoft.windowsazure.services.core.ServiceTimeoutException; import com.microsoft.windowsazure.services.table.models.BatchOperations; import com.microsoft.windowsazure.services.table.models.BatchResult; import com.microsoft.windowsazure.services.table.models.BatchResult.DeleteEntity; @@ -1155,8 +1156,11 @@ public void settingTimeoutWorks() throws Exception { service.queryTables(); fail("Exception should have been thrown"); } - catch (ServiceException ex) { - assertNotNull(ex.getCause()); + catch (ServiceTimeoutException ex) { + // No need to assert, test is if correct assertion type is thrown. + } + catch (Exception ex) { + fail("unexpected exception was thrown"); } finally { // Clean up timeouts, they interfere with other tests otherwise @@ -1179,8 +1183,11 @@ public void settingTimeoutFromStringWorks() throws Exception { service.queryTables(); fail("Exception should have been thrown"); } - catch (ServiceException ex) { - assertNotNull(ex.getCause()); + catch (ServiceTimeoutException ex) { + // No need to assert, test is if correct assertion type is thrown. + } + catch (Exception ex) { + fail("unexpected exception was thrown"); } finally { // Clean up timeouts, they interfere with other tests otherwise diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java index 3cc8639eb849c..54c5b84aab75a 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java @@ -2,25 +2,27 @@ * Copyright 2011 Microsoft Corporation * * 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 + * 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. + * 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 com.microsoft.windowsazure.utils; import static org.junit.Assert.*; import java.io.ByteArrayInputStream; +import java.net.SocketTimeoutException; import org.junit.Test; import com.microsoft.windowsazure.services.core.ServiceException; +import com.microsoft.windowsazure.services.core.ServiceTimeoutException; import com.microsoft.windowsazure.services.core.utils.ServiceExceptionFactory; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; @@ -31,11 +33,11 @@ public class ServiceExceptionFactoryTest { public void serviceNameAndMessageAndCauseAppearInException() { // Arrange ClientResponse response = new ClientResponse(404, null, new ByteArrayInputStream(new byte[0]), null); - UniformInterfaceException cause = new UniformInterfaceException( - response); + UniformInterfaceException cause = new UniformInterfaceException(response); // Act - ServiceException exception = ServiceExceptionFactory.process("testing", new ServiceException("this is a test", cause)); + ServiceException exception = ServiceExceptionFactory.process("testing", new ServiceException("this is a test", + cause)); // Assert assertNotNull(exception); @@ -48,11 +50,11 @@ public void serviceNameAndMessageAndCauseAppearInException() { public void httpStatusCodeAndReasonPhraseAppearInException() { // Arrange ClientResponse response = new ClientResponse(404, null, new ByteArrayInputStream(new byte[0]), null); - UniformInterfaceException cause = new UniformInterfaceException( - response); + UniformInterfaceException cause = new UniformInterfaceException(response); // Act - ServiceException exception = ServiceExceptionFactory.process("testing", new ServiceException("this is a test", cause)); + ServiceException exception = ServiceExceptionFactory.process("testing", new ServiceException("this is a test", + cause)); // Assert assertNotNull(exception); @@ -65,7 +67,8 @@ public void informationWillPassUpIfServiceExceptionIsRootCauseOfClientHandlerExc // Arrange ClientResponse response = new ClientResponse(503, null, new ByteArrayInputStream(new byte[0]), null); UniformInterfaceException rootCause = new UniformInterfaceException(response); - ServiceException originalDescription = ServiceExceptionFactory.process("underlying", new ServiceException(rootCause)); + ServiceException originalDescription = ServiceExceptionFactory.process("underlying", new ServiceException( + rootCause)); ClientHandlerException wrappingException = new ClientHandlerException(originalDescription); // Act @@ -76,4 +79,17 @@ public void informationWillPassUpIfServiceExceptionIsRootCauseOfClientHandlerExc assertEquals("underlying", exception.getServiceName()); } + @Test + public void socketTimeoutWillPassUpIfInsideClientHandlerException() { + String expectedMessage = "connect timeout"; + SocketTimeoutException rootCause = new SocketTimeoutException(expectedMessage); + ClientHandlerException wrappingException = new ClientHandlerException(rootCause); + + ServiceException exception = ServiceExceptionFactory + .process("testing", new ServiceException(wrappingException)); + + assertSame(ServiceTimeoutException.class, exception.getClass()); + assertEquals(expectedMessage, exception.getMessage()); + assertEquals("testing", exception.getServiceName()); + } } From 45cec57ca38afbb076e9fd04d0306e7bcb3ee911 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Thu, 27 Sep 2012 12:45:29 -0700 Subject: [PATCH 05/10] Code review feedback applied --- .../core/ServiceTimeoutException.java | 21 ++++-- .../core/utils/ServiceExceptionFactory.java | 68 +++---------------- 2 files changed, 25 insertions(+), 64 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java index 6de101f3d93d3..9c3c5f7fcd134 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/ServiceTimeoutException.java @@ -1,6 +1,18 @@ /** + * Copyright 2012 Microsoft Corporation * + * 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 com.microsoft.windowsazure.services.core; /** @@ -11,13 +23,13 @@ public class ServiceTimeoutException extends ServiceException { private static final long serialVersionUID = 6612846403178749361L; /** - * Construct a ServiceTimeoutException instance + * Construct a ServiceTimeoutException instance with default parameters. */ public ServiceTimeoutException() { } /** - * Construct a ServiceTimeoutException instance + * Construct a ServiceTimeoutException instance with the specified message. * * @param message * Exception message @@ -27,7 +39,8 @@ public ServiceTimeoutException(String message) { } /** - * Construct a ServiceTimeoutException instance + * Construct a ServiceTimeoutException instance with specified + * message and cause * * @param message * Exception message @@ -39,7 +52,7 @@ public ServiceTimeoutException(String message, Throwable cause) { } /** - * Construct a ServiceTimeoutException instance + * Construct a ServiceTimeoutException instance with the specified cause. * * @param cause * Exception that caused this exception to occur diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java index dd593322c2073..d11feceb6d20b 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/ServiceExceptionFactory.java @@ -18,7 +18,6 @@ import com.microsoft.windowsazure.services.core.ServiceException; import com.microsoft.windowsazure.services.core.ServiceTimeoutException; -import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; import com.sun.jersey.api.client.UniformInterfaceException; @@ -26,69 +25,18 @@ public class ServiceExceptionFactory { public static ServiceException process(String serviceName, ServiceException exception) { - // State machine for figuring out what to do with the exception - // - // Input is the type of the current exception cause. - // FSM starts in state 0. - // - // State | Input | New State | Action - //--------------------------------------------------------------------------- - // 0 | ServiceException | None | populate and return - // | | | - // 0 | UniformInterfaceException | None | populate and return - // | | | - // 0 | ClientHandlerException | 1 | None - // | | | - // 0 | Any other | 0 | None - // | | | - // 1 | ServiceException | None | populate and return - // | | | - // 1 | UniformInterfaceException | None | populate and return - // | | | - // 1 | ClientHandlerException | 1 | None - // | | | - // 1 | SocketTimeoutException | None | populate and return - // | | | - // 1 | Any other | 0 | None - - int state = 0; Throwable cause = exception.getCause(); for (Throwable scan = cause; scan != null; scan = scan.getCause()) { Class scanClass = scan.getClass(); - - switch (state) { - case 0: - if (ServiceException.class.isAssignableFrom(scanClass)) { - return populate(exception, serviceName, (ServiceException) scan); - } - else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) { - return populate(exception, serviceName, (UniformInterfaceException) scan); - } - else if (ClientHandlerException.class.isAssignableFrom(scanClass)) { - state = 1; - } - else { - state = 0; - } - break; - - case 1: - if (ServiceException.class.isAssignableFrom(scanClass)) { - return populate(exception, serviceName, (ServiceException) scan); - } - else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) { - return populate(exception, serviceName, (UniformInterfaceException) scan); - } - else if (SocketTimeoutException.class.isAssignableFrom(scanClass)) { - return populate(exception, serviceName, (SocketTimeoutException) scan); - } - else if (ClientHandlerException.class.isAssignableFrom(scanClass)) { - state = 1; - } - else { - state = 0; - } + if (ServiceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (ServiceException) scan); + } + else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (UniformInterfaceException) scan); + } + else if (SocketTimeoutException.class.isAssignableFrom(scanClass)) { + return populate(exception, serviceName, (SocketTimeoutException) scan); } } From ab94bb7d7771fa374075aad307fa35f66c1472e4 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Thu, 27 Sep 2012 14:07:53 -0700 Subject: [PATCH 06/10] Using sdk specific timeout property string, rather than Jersey's. Fixed issues with prefixed client creates. --- .../services/core/Configuration.java | 10 +++++ .../services/core/utils/pipeline/Exports.java | 29 +++++++++++-- .../table/TableServiceIntegrationTest.java | 43 +++++++++++++++---- .../com.microsoft.windowsazure.properties | 4 +- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java index 67f30dfe880e4..e5afff9047a29 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/Configuration.java @@ -25,6 +25,16 @@ public class Configuration { + /** + * Property name for socket connection timeout used by services created with this configuration. + */ + public static final String PROPERTY_CONNECT_TIMEOUT = "com.microsoft.windowsazure.services.core.Configuration.connectTimeout"; + + /** + * Property name for socket read timeout used by services created with this configuration. + */ + public static final String PROPERTY_READ_TIMEOUT = "com.microsoft.windowsazure.services.core.Configuration.readTimeout"; + private static Configuration instance; Map properties; Builder builder; diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java index e8de5bd31606e..d5b9ddc05ce9f 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/Exports.java @@ -19,6 +19,7 @@ import com.microsoft.windowsazure.services.core.Builder; import com.microsoft.windowsazure.services.core.Builder.Registry; +import com.microsoft.windowsazure.services.core.Configuration; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; @@ -31,6 +32,8 @@ public void register(Registry registry) { @Override public ClientConfig create(String profile, Builder builder, Map properties) { ClientConfig clientConfig = new DefaultClientConfig(); + profile = normalizeProfile(profile); + // Lower levels of the stack assume timeouts are set. // Set default timeout on clientConfig in case user // hasn't set it yet in their configuration @@ -40,18 +43,26 @@ public ClientConfig create(String profile, Builder builder, Map for (Entry entry : properties.entrySet()) { Object propertyValue = entry.getValue(); + String propertyKey = entry.getKey(); + + if (propertyKey.equals(profile + Configuration.PROPERTY_CONNECT_TIMEOUT)) { + propertyKey = ClientConfig.PROPERTY_CONNECT_TIMEOUT; + } + if (propertyKey.equals(profile + Configuration.PROPERTY_READ_TIMEOUT)) { + propertyKey = ClientConfig.PROPERTY_READ_TIMEOUT; + } // ClientConfig requires instance of Integer to properly set // timeouts, but config file will deliver strings. Special // case these timeout properties and convert them to Integer // if necessary. - if (entry.getKey().equals(ClientConfig.PROPERTY_CONNECT_TIMEOUT) - || entry.getKey().equals(ClientConfig.PROPERTY_READ_TIMEOUT)) { + if (propertyKey.equals(ClientConfig.PROPERTY_CONNECT_TIMEOUT) + || propertyKey.equals(ClientConfig.PROPERTY_READ_TIMEOUT)) { if (propertyValue instanceof String) { propertyValue = Integer.valueOf((String) propertyValue); } } - clientConfig.getProperties().put(entry.getKey(), propertyValue); + clientConfig.getProperties().put(propertyKey, propertyValue); } return clientConfig; } @@ -76,4 +87,16 @@ public HttpURLConnectionClient create(String profile, Builder builder, Map Date: Tue, 7 Aug 2012 13:44:26 -0700 Subject: [PATCH 07/10] Fixing client tests so they pull credentials from env vars --- .../windowsazure/services/blob/client/BlobTestBase.java | 6 +++++- .../windowsazure/services/queue/client/QueueTestBase.java | 6 +++++- .../windowsazure/services/table/client/TableTestBase.java | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java index bd0671e3ece19..938db64c06d4a 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/client/BlobTestBase.java @@ -51,7 +51,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("blob.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("blob.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } bClient = httpAcc.createCloudBlobClient(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java index feb5b1ceb4a10..8144378d8577b 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/queue/client/QueueTestBase.java @@ -52,7 +52,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("queue.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("queue.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } qClient = httpAcc.createCloudQueueClient(); diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java index d235ed326cc69..7ba57b75322c8 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/client/TableTestBase.java @@ -577,7 +577,11 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK httpAcc = CloudStorageAccount.getDevelopmentStorageAccount(); } else { - httpAcc = CloudStorageAccount.parse(CLOUD_ACCOUNT_HTTP); + String cloudAccount = CLOUD_ACCOUNT_HTTP; + cloudAccount = cloudAccount.replace("[ACCOUNT NAME]", System.getenv("table.accountName")); + cloudAccount = cloudAccount.replace("[ACCOUNT KEY]", System.getenv("table.accountKey")); + + httpAcc = CloudStorageAccount.parse(cloudAccount); } bClient = httpAcc.createCloudBlobClient(); From 9b929240adfe408946c45773940825f32b46a8d2 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Mon, 1 Oct 2012 12:22:40 -0700 Subject: [PATCH 08/10] Access policy crud implementation --- .../services/media/MediaContract.java | 66 ++++++++ .../MediaExceptionProcessor.java | 98 ++++++++++++ .../media/implementation/MediaRestProxy.java | 100 ++++++++++-- .../implementation/ODataAtomMarshaller.java | 2 + .../content/AccessPolicyType.java | 145 ++++++++++++++++++ .../implementation/content/ObjectFactory.java | 9 ++ .../media/models/AccessPolicyInfo.java | 74 +++++++++ .../models/CreateAccessPolicyOptions.java | 41 +++++ .../media/models/ListAccessPolicyOptions.java | 24 +++ .../media/AccessPolicyIntegrationTest.java | 117 ++++++++++++++ .../ODataSerializationFromJerseyTest.java | 1 + .../media/models/AccessPolicyInfoTest.java | 86 +++++++++++ 12 files changed, 747 insertions(+), 16 deletions(-) create mode 100644 microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java create mode 100644 microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java create mode 100644 microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java create mode 100644 microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/ListAccessPolicyOptions.java create mode 100644 microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java create mode 100644 microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java index 7dfa4844ad837..cd0b1c90560b0 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java @@ -18,8 +18,11 @@ import com.microsoft.windowsazure.services.core.FilterableService; import com.microsoft.windowsazure.services.core.ServiceException; +import com.microsoft.windowsazure.services.media.models.AccessPolicyInfo; import com.microsoft.windowsazure.services.media.models.AssetInfo; +import com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.CreateAssetOptions; +import com.microsoft.windowsazure.services.media.models.ListAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.ListAssetsOptions; import com.microsoft.windowsazure.services.media.models.UpdateAssetOptions; @@ -99,4 +102,67 @@ public interface MediaContract extends FilterableService { */ public void updateAsset(String assetId, UpdateAssetOptions updateAssetOptions) throws ServiceException; + /** + * Create the access policy + * + * @param name + * name of access policy + * @param durationInMinutes + * duration access policy is active + * @return Created access policy + * @throws ServiceException + */ + AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes) throws ServiceException; + + /** + * Create the access policy with the given options + * + * @param name + * name of access policy + * @param durationInMinutes + * duration access policy is active + * @param options + * options for creation + * @return the created access policy + * @throws ServiceException + */ + AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes, CreateAccessPolicyOptions options) + throws ServiceException; + + /** + * Delete the access policy with the given id + * + * @param id + * of access policy to delete + * @throws ServiceException + */ + void deleteAccessPolicy(String id) throws ServiceException; + + /** + * Get a single access policy + * + * @param id + * the id of the asset to retrieve + * @return the asset + * @throws ServiceException + */ + AccessPolicyInfo getAccessPolicy(String id) throws ServiceException; + + /** + * List access policies + * + * @return the list + * @throws ServiceException + */ + List listAccessPolicies() throws ServiceException; + + /** + * List access policies + * + * @param options + * the list access policy options + * @return the list + * @throws ServiceException + */ + List listAccessPolicies(ListAccessPolicyOptions options) throws ServiceException; } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java index 9af373b2ae08d..314111bc50b34 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java @@ -26,8 +26,11 @@ import com.microsoft.windowsazure.services.core.ServiceFilter; import com.microsoft.windowsazure.services.core.utils.ServiceExceptionFactory; import com.microsoft.windowsazure.services.media.MediaContract; +import com.microsoft.windowsazure.services.media.models.AccessPolicyInfo; import com.microsoft.windowsazure.services.media.models.AssetInfo; +import com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.CreateAssetOptions; +import com.microsoft.windowsazure.services.media.models.ListAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.ListAssetsOptions; import com.microsoft.windowsazure.services.media.models.UpdateAssetOptions; import com.sun.jersey.api.client.ClientHandlerException; @@ -199,4 +202,99 @@ public void updateAsset(String assetId, UpdateAssetOptions updateAssetOptions) t } } + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#createAccessPolicy(double) + */ + @Override + public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes) throws ServiceException { + try { + return service.createAccessPolicy(name, durationInMinutes); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#createAccessPolicy(double, com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions) + */ + @Override + public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes, CreateAccessPolicyOptions options) + throws ServiceException { + try { + return service.createAccessPolicy(name, durationInMinutes, options); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#getAccessPolicies() + */ + @Override + public List listAccessPolicies() throws ServiceException { + try { + return service.listAccessPolicies(); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#deleteAccessPolicy(java.lang.String) + */ + @Override + public void deleteAccessPolicy(String id) throws ServiceException { + try { + service.deleteAccessPolicy(id); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#getAccessPolicy(java.lang.String) + */ + @Override + public AccessPolicyInfo getAccessPolicy(String id) throws ServiceException { + try { + return service.getAccessPolicy(id); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#listAccessPolicies(com.microsoft.windowsazure.services.media.models.ListAccessPolicyOptions) + */@Override + public List listAccessPolicies(ListAccessPolicyOptions options) throws ServiceException { + try { + return service.listAccessPolicies(); + } + catch (UniformInterfaceException e) { + throw processCatch(new ServiceException(e)); + } + catch (ClientHandlerException e) { + throw processCatch(new ServiceException(e)); + } + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java index eb060a973833f..3ba10b301cd79 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java @@ -31,9 +31,14 @@ import com.microsoft.windowsazure.services.core.utils.pipeline.ClientFilterAdapter; import com.microsoft.windowsazure.services.core.utils.pipeline.PipelineHelpers; import com.microsoft.windowsazure.services.media.MediaContract; +import com.microsoft.windowsazure.services.media.implementation.content.AccessPolicyType; import com.microsoft.windowsazure.services.media.implementation.content.AssetType; +import com.microsoft.windowsazure.services.media.models.AccessPolicyInfo; +import com.microsoft.windowsazure.services.media.models.AccessPolicyPermission; import com.microsoft.windowsazure.services.media.models.AssetInfo; +import com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.CreateAssetOptions; +import com.microsoft.windowsazure.services.media.models.ListAccessPolicyOptions; import com.microsoft.windowsazure.services.media.models.ListAssetsOptions; import com.microsoft.windowsazure.services.media.models.UpdateAssetOptions; import com.sun.jersey.api.client.Client; @@ -134,6 +139,27 @@ private WebResource getResource(String entityName) { return resource; } + private WebResource getResource(String entityType, String entityId) throws ServiceException { + String escapedEntityId = null; + try { + escapedEntityId = URLEncoder.encode(entityId, "UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new ServiceException(e); + } + String entityPath = String.format("%s(\'%s\')", entityType, escapedEntityId); + + return getResource(entityPath); + } + + private T mergeRequest(String path, java.lang.Class c, java.lang.Object requestEntity) { + WebResource resource = getResource(path); + WebResource.Builder builder = resource.getRequestBuilder(); + builder = builder.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) + .header("X-HTTP-Method", "MERGE"); + return builder.post(c, requestEntity); + } + /* (non-Javadoc) * @see com.microsoft.windowsazure.services.media.MediaContract#createAsset(java.lang.String) */ @@ -229,26 +255,68 @@ public void deleteAsset(String assetId) throws ServiceException { getResource("Assets", assetId).delete(); } - private WebResource getResource(String entityType, String entityId) throws ServiceException { - String escapedEntityId = null; - try { - escapedEntityId = URLEncoder.encode(entityId, "UTF-8"); - } - catch (UnsupportedEncodingException e) { - throw new ServiceException(e); - } - String entityPath = String.format("%s(\'%s\')", entityType, escapedEntityId); + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#createAccessPolicy(double) + */ + @Override + public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes) throws ServiceException { + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions(); + options.getPermissions().add(AccessPolicyPermission.WRITE); + return createAccessPolicy(name, durationInMinutes, options); + } - return getResource(entityPath); + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#createAccessPolicy(double, com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions) + */ + @Override + public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes, CreateAccessPolicyOptions options) + throws ServiceException { + + AccessPolicyType requestData = new AccessPolicyType().setDurationInMinutes(durationInMinutes).setName(name) + .setPermissions(AccessPolicyPermission.bitsFromPermissions(options.getPermissions())); + + WebResource resource = getResource("AccessPolicies"); + + return resource.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) + .post(AccessPolicyInfo.class, requestData); } - private T mergeRequest(String path, java.lang.Class c, java.lang.Object requestEntity) { - WebResource resource = getResource(path); - WebResource.Builder builder = resource.getRequestBuilder(); - builder = builder.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) - .header("X-HTTP-Method", "MERGE"); - return builder.post(c, requestEntity); + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#getAccessPolicy(java.lang.String) + */ + @Override + public AccessPolicyInfo getAccessPolicy(String id) throws ServiceException { + WebResource resource = getResource("AccessPolicies", id); + return resource.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) + .get(AccessPolicyInfo.class); + } + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#deleteAccessPolicy(java.lang.String) + */ + @Override + public void deleteAccessPolicy(String id) throws ServiceException { + getResource("AccessPolicies", id).delete(); } + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#listAccessPolicies() + */ + @Override + public List listAccessPolicies() throws ServiceException { + WebResource resource = getResource("AccessPolicies"); + + return resource.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) + .get(new GenericType>() { + }); + } + + /* (non-Javadoc) + * @see com.microsoft.windowsazure.services.media.MediaContract#listAccessPolicies() + */ + @Override + public List listAccessPolicies(ListAccessPolicyOptions options) throws ServiceException { + // Currently no options defined so can call zero arg overload instead + return listAccessPolicies(); + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java index 2556c510a5ff2..13edb3b00de50 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java @@ -33,6 +33,7 @@ import com.microsoft.windowsazure.services.media.implementation.atom.ContentType; import com.microsoft.windowsazure.services.media.implementation.atom.EntryType; import com.microsoft.windowsazure.services.media.implementation.atom.FeedType; +import com.microsoft.windowsazure.services.media.implementation.content.AccessPolicyType; import com.microsoft.windowsazure.services.media.implementation.content.AssetType; import com.microsoft.windowsazure.services.media.implementation.content.Constants; @@ -114,6 +115,7 @@ private static Class[] getMarshalledClasses() { classes.add(FeedType.class); classes.add(EntryType.class); classes.add(AssetType.class); + classes.add(AccessPolicyType.class); return classes.toArray(new Class[0]); } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java new file mode 100644 index 0000000000000..219a65b668f16 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java @@ -0,0 +1,145 @@ +/** + * Copyright 2012 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media.implementation.content; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; + +/** + * Wrapper DTO for Media Services access policies. + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +public class AccessPolicyType implements MediaServiceDTO { + + @XmlElement(name = "Id", namespace = Constants.ODATA_DATA_NS) + protected String id; + + @XmlElement(name = "Created", namespace = Constants.ODATA_DATA_NS) + protected Date created; + + @XmlElement(name = "LastModified", namespace = Constants.ODATA_DATA_NS) + protected Date lastModified; + + @XmlElement(name = "Name", namespace = Constants.ODATA_DATA_NS) + protected String name; + + @XmlElement(name = "DurationInMinutes", namespace = Constants.ODATA_DATA_NS) + protected double durationInMinutes; + + @XmlElement(name = "Permissions", namespace = Constants.ODATA_DATA_NS) + protected int permissions; + + /** + * @return the id + */ + public String getId() { + return id; + } + + /** + * @param id + * the id to set + */ + public AccessPolicyType setId(String id) { + this.id = id; + return this; + } + + /** + * @return the created + */ + public Date getCreated() { + return created; + } + + /** + * @param created + * the created to set + */ + public AccessPolicyType setCreated(Date created) { + this.created = created; + return this; + } + + /** + * @return the lastModified + */ + public Date getLastModified() { + return lastModified; + } + + /** + * @param lastModified + * the lastModified to set + */ + public AccessPolicyType setLastModified(Date lastModified) { + this.lastModified = lastModified; + return this; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name + * the name to set + */ + public AccessPolicyType setName(String name) { + this.name = name; + return this; + } + + /** + * @return the durationInMinutes + */ + public double getDurationInMinutes() { + return durationInMinutes; + } + + /** + * @param durationInMinutes + * the durationInMinutes to set + */ + public AccessPolicyType setDurationInMinutes(double durationInMinutes) { + this.durationInMinutes = durationInMinutes; + return this; + } + + /** + * @return the permissions + */ + public int getPermissions() { + return permissions; + } + + /** + * @param permissions + * the permissions to set + */ + public AccessPolicyType setPermissions(int permissions) { + this.permissions = permissions; + return this; + } + +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java index d353a7d006964..09cc9f513adba 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java @@ -49,4 +49,13 @@ public AssetType createAssetType() { public ODataActionType createODataActionType() { return new ODataActionType(); } + + /** + * Create an instance of {@link AccessPolicyType } + * + * @return a new AccessPolicyType instance. + */ + public AccessPolicyType createAccessPolicyType() { + return new AccessPolicyType(); + } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java new file mode 100644 index 0000000000000..50213d4503654 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java @@ -0,0 +1,74 @@ +package com.microsoft.windowsazure.services.media.models; + +import java.util.Date; +import java.util.EnumSet; + +import com.microsoft.windowsazure.services.media.implementation.ODataEntity; +import com.microsoft.windowsazure.services.media.implementation.atom.EntryType; +import com.microsoft.windowsazure.services.media.implementation.content.AccessPolicyType; + +public class AccessPolicyInfo extends ODataEntity { + + public AccessPolicyInfo(EntryType entry, AccessPolicyType content) { + super(entry, content); + // TODO Auto-generated constructor stub + } + + public AccessPolicyInfo() { + super(new AccessPolicyType()); + } + + public String getId() { + return getContent().getId(); + } + + public AccessPolicyInfo setId(String id) { + getContent().setId(id); + return this; + } + + public Date getCreated() { + return getContent().getCreated(); + } + + public AccessPolicyInfo setCreated(Date created) { + getContent().setCreated(created); + return this; + } + + public Date getLastModified() { + return getContent().getLastModified(); + } + + public AccessPolicyInfo setLastModified(Date lastModified) { + getContent().setLastModified(lastModified); + return this; + } + + public String getName() { + return getContent().getName(); + } + + public AccessPolicyInfo setName(String name) { + getContent().setName(name); + return this; + } + + public double getDurationInMinutes() { + return getContent().getDurationInMinutes(); + } + + public AccessPolicyInfo setDurationInMinutes(double durationInMinutes) { + getContent().setDurationInMinutes(durationInMinutes); + return this; + } + + public EnumSet getPermissions() { + return AccessPolicyPermission.permissionsFromBits(getContent().getPermissions()); + } + + public AccessPolicyInfo setPermissions(EnumSet permissions) { + getContent().setPermissions(AccessPolicyPermission.bitsFromPermissions(permissions)); + return this; + } +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java new file mode 100644 index 0000000000000..d5e4cb87ee0c6 --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java @@ -0,0 +1,41 @@ +package com.microsoft.windowsazure.services.media.models; + +import java.util.EnumSet; + +public class CreateAccessPolicyOptions { + private final EnumSet permissions = EnumSet.noneOf(AccessPolicyPermission.class); + + public CreateAccessPolicyOptions() { + } + + /** + * Returns a live pointer to the underlying permissions set. + * + * @return the permissions + */ + public EnumSet getPermissions() { + return permissions; + } + + /** + * Add the given permissions to this creation request + * + * @param permissionsToAdd + * @return the CreateAccessPolicyOptions object + */ + public CreateAccessPolicyOptions addPermissions(EnumSet permissionsToAdd) { + permissions.addAll(permissionsToAdd); + return this; + } + + /** + * Remove the given permissions from this creation request + * + * @param permissionsToRemove + * @return the CreateAccessPolicyOptions object + */ + public CreateAccessPolicyOptions removePermissions(EnumSet permissionsToRemove) { + permissions.removeAll(permissionsToRemove); + return this; + } +} diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/ListAccessPolicyOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/ListAccessPolicyOptions.java new file mode 100644 index 0000000000000..2327574c985bc --- /dev/null +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/ListAccessPolicyOptions.java @@ -0,0 +1,24 @@ +/** + * Copyright 2012 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media.models; + +/** + * Options class for listing access policies + * No options available at this time. + */ +public class ListAccessPolicyOptions { + +} diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java new file mode 100644 index 0000000000000..2dea4f4e4d86b --- /dev/null +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java @@ -0,0 +1,117 @@ +/** + * Copyright 2011 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media; + +import static org.junit.Assert.*; + +import java.util.EnumSet; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.microsoft.windowsazure.services.core.Configuration; +import com.microsoft.windowsazure.services.media.models.AccessPolicyInfo; +import com.microsoft.windowsazure.services.media.models.AccessPolicyPermission; +import com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions; + +public class AccessPolicyIntegrationTest extends IntegrationTestBase { + private static MediaContract service; + + @BeforeClass + public static void setup() throws Exception { + service = MediaService.create(createConfig()); + } + + private static Configuration createConfig() { + Configuration config = Configuration.getInstance(); + overrideWithEnv(config, MediaConfiguration.URI); + overrideWithEnv(config, MediaConfiguration.OAUTH_URI); + overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_ID); + overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_SECRET); + overrideWithEnv(config, MediaConfiguration.OAUTH_SCOPE); + return config; + } + + @AfterClass + public static void cleanup() throws Exception { + for (AccessPolicyInfo policy : service.listAccessPolicies()) { + if (policy.getName().startsWith("testPolicy")) { + service.deleteAccessPolicy(policy.getId()); + } + } + } + + @Test + public void canCreateAccessPolicy() throws Exception { + AccessPolicyInfo policy = service.createAccessPolicy("testPolicy", 5, + new CreateAccessPolicyOptions().addPermissions(EnumSet.of(AccessPolicyPermission.WRITE))); + + assertTrue(policy.getPermissions().contains(AccessPolicyPermission.WRITE)); + } + + @Test + public void canGetSinglePolicyById() throws Exception { + String expectedName = "testPolicyGetOne"; + AccessPolicyInfo policyToGet = service.createAccessPolicy(expectedName, 1); + + AccessPolicyInfo retrievedPolicy = service.getAccessPolicy(policyToGet.getId()); + + assertEquals(expectedName, retrievedPolicy.getName()); + assertEquals(policyToGet.getId(), retrievedPolicy.getId()); + } + + @Test + public void canRetrieveListOfAccessPolicies() throws Exception { + String[] policyNames = new String[] { "testPolicy1", "testPolicy2" }; + for (String name : policyNames) { + service.createAccessPolicy(name, 3, new CreateAccessPolicyOptions().addPermissions(EnumSet.of( + AccessPolicyPermission.WRITE, AccessPolicyPermission.LIST))); + } + + List policies = service.listAccessPolicies(); + + assertNotNull(policies); + assertTrue(policies.size() >= 2); + + AccessPolicyInfo policy1 = null; + AccessPolicyInfo policy2 = null; + + for (AccessPolicyInfo policy : policies) { + if (policy.getName().equals("testPolicy1")) { + policy1 = policy; + } + if (policy.getName().equals("testPolicy2")) { + policy2 = policy; + } + } + + assertNotNull(policy1); + assertNotNull(policy2); + } + + @Test + public void canDeleteAccessPolicyById() throws Exception { + AccessPolicyInfo policyToDelete = service.createAccessPolicy("testPolicyToDelete", 1); + + service.deleteAccessPolicy(policyToDelete.getId()); + + for (AccessPolicyInfo policy : service.listAccessPolicies()) { + assertFalse(policyToDelete.getId().equals(policy.getId())); + } + } +} diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java index 53c67ba9798bb..84a8d66b47d20 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java @@ -101,4 +101,5 @@ public void canRetrieveListOfAssets() throws Exception { Assert.assertNotNull(assets); } + } diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java new file mode 100644 index 0000000000000..c18e9a5297c56 --- /dev/null +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java @@ -0,0 +1,86 @@ +/** + * Copyright 2012 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media.models; + +import java.util.Date; +import java.util.EnumSet; + +import org.junit.Assert; +import org.junit.Test; + +public class AccessPolicyInfoTest { + + @Test + public void getSetId() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + String expected = "expectedId"; + + String actual = policy.setId(expected).getId(); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getSetCreated() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + Date expected = new Date(); + + Date actual = policy.setCreated(expected).getCreated(); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getSetLastModified() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + Date expected = new Date(); + + Date actual = policy.setLastModified(expected).getLastModified(); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getSetName() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + String expected = "policy name goes here"; + + String actual = policy.setName(expected).getName(); + + Assert.assertEquals(expected, actual); + } + + @Test + public void getSetDurationInMinutes() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + double expected = 60; // arbitrary value + + double actual = policy.setDurationInMinutes(expected).getDurationInMinutes(); + + Assert.assertEquals(expected, actual, 0.0); + } + + @Test + public void getSetPermissions() { + AccessPolicyInfo policy = new AccessPolicyInfo(); + EnumSet expected = EnumSet + .of(AccessPolicyPermission.LIST, AccessPolicyPermission.WRITE); + + EnumSet actual = policy.setPermissions(expected).getPermissions(); + + Assert.assertEquals(expected, actual); + } +} From fc42caf090e754e9e5f5642a1f45e57ac2392af1 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Mon, 1 Oct 2012 14:31:14 -0700 Subject: [PATCH 09/10] Updated for code review feedback --- .../services/media/MediaContract.java | 4 +- .../media/implementation/MediaRestProxy.java | 22 +++---- .../media/models/AccessPolicyInfo.java | 16 ++++- .../media/AccessPolicyIntegrationTest.java | 60 ++++++++++++++++--- 4 files changed, 81 insertions(+), 21 deletions(-) diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java index cd0b1c90560b0..aac6354b6947c 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java @@ -108,7 +108,7 @@ public interface MediaContract extends FilterableService { * @param name * name of access policy * @param durationInMinutes - * duration access policy is active + * Duration in minutes that blob access will be granted when using this access policy * @return Created access policy * @throws ServiceException */ @@ -120,7 +120,7 @@ public interface MediaContract extends FilterableService { * @param name * name of access policy * @param durationInMinutes - * duration access policy is active + * Duration in minutes that blob access will be granted when using this access policy * @param options * options for creation * @return the created access policy diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java index 3ba10b301cd79..c27f83ff48ff0 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java @@ -18,6 +18,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; import javax.inject.Inject; @@ -260,9 +261,7 @@ public void deleteAsset(String assetId) throws ServiceException { */ @Override public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes) throws ServiceException { - CreateAccessPolicyOptions options = new CreateAccessPolicyOptions(); - options.getPermissions().add(AccessPolicyPermission.WRITE); - return createAccessPolicy(name, durationInMinutes, options); + return createAccessPolicy(name, durationInMinutes, null); } /* (non-Javadoc) @@ -272,6 +271,10 @@ public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes public AccessPolicyInfo createAccessPolicy(String name, double durationInMinutes, CreateAccessPolicyOptions options) throws ServiceException { + if (options == null) { + options = new CreateAccessPolicyOptions().addPermissions(EnumSet.of(AccessPolicyPermission.WRITE)); + } + AccessPolicyType requestData = new AccessPolicyType().setDurationInMinutes(durationInMinutes).setName(name) .setPermissions(AccessPolicyPermission.bitsFromPermissions(options.getPermissions())); @@ -304,11 +307,7 @@ public void deleteAccessPolicy(String id) throws ServiceException { */ @Override public List listAccessPolicies() throws ServiceException { - WebResource resource = getResource("AccessPolicies"); - - return resource.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) - .get(new GenericType>() { - }); + return listAccessPolicies(null); } /* (non-Javadoc) @@ -316,7 +315,10 @@ public List listAccessPolicies() throws ServiceException { */ @Override public List listAccessPolicies(ListAccessPolicyOptions options) throws ServiceException { - // Currently no options defined so can call zero arg overload instead - return listAccessPolicies(); + WebResource resource = getResource("AccessPolicies"); + + return resource.type(MediaType.APPLICATION_ATOM_XML).accept(MediaType.APPLICATION_ATOM_XML) + .get(new GenericType>() { + }); } } diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java index 50213d4503654..f4d608dd712a5 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java @@ -1,3 +1,18 @@ +/** + * Copyright 2012 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media.models; import java.util.Date; @@ -11,7 +26,6 @@ public class AccessPolicyInfo extends ODataEntity { public AccessPolicyInfo(EntryType entry, AccessPolicyType content) { super(entry, content); - // TODO Auto-generated constructor stub } public AccessPolicyInfo() { diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java index 2dea4f4e4d86b..f91f09eb06b0a 100644 --- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java +++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2011 Microsoft Corporation + * Copyright 2012 Microsoft Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,16 @@ import java.util.EnumSet; import java.util.List; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import com.microsoft.windowsazure.services.core.Configuration; +import com.microsoft.windowsazure.services.core.ServiceException; import com.microsoft.windowsazure.services.media.models.AccessPolicyInfo; import com.microsoft.windowsazure.services.media.models.AccessPolicyPermission; import com.microsoft.windowsazure.services.media.models.CreateAccessPolicyOptions; @@ -32,6 +37,8 @@ public class AccessPolicyIntegrationTest extends IntegrationTestBase { private static MediaContract service; + private static final String testPrefix = "testPolicy"; + @BeforeClass public static void setup() throws Exception { service = MediaService.create(createConfig()); @@ -50,7 +57,7 @@ private static Configuration createConfig() { @AfterClass public static void cleanup() throws Exception { for (AccessPolicyInfo policy : service.listAccessPolicies()) { - if (policy.getName().startsWith("testPolicy")) { + if (policy.getName().startsWith(testPrefix)) { service.deleteAccessPolicy(policy.getId()); } } @@ -58,7 +65,7 @@ public static void cleanup() throws Exception { @Test public void canCreateAccessPolicy() throws Exception { - AccessPolicyInfo policy = service.createAccessPolicy("testPolicy", 5, + AccessPolicyInfo policy = service.createAccessPolicy(testPrefix + "CanCreate", 5, new CreateAccessPolicyOptions().addPermissions(EnumSet.of(AccessPolicyPermission.WRITE))); assertTrue(policy.getPermissions().contains(AccessPolicyPermission.WRITE)); @@ -66,7 +73,7 @@ public void canCreateAccessPolicy() throws Exception { @Test public void canGetSinglePolicyById() throws Exception { - String expectedName = "testPolicyGetOne"; + String expectedName = testPrefix + "GetOne"; AccessPolicyInfo policyToGet = service.createAccessPolicy(expectedName, 1); AccessPolicyInfo retrievedPolicy = service.getAccessPolicy(policyToGet.getId()); @@ -77,7 +84,7 @@ public void canGetSinglePolicyById() throws Exception { @Test public void canRetrieveListOfAccessPolicies() throws Exception { - String[] policyNames = new String[] { "testPolicy1", "testPolicy2" }; + String[] policyNames = new String[] { testPrefix + "ListOne", testPrefix + "ListTwo" }; for (String name : policyNames) { service.createAccessPolicy(name, 3, new CreateAccessPolicyOptions().addPermissions(EnumSet.of( AccessPolicyPermission.WRITE, AccessPolicyPermission.LIST))); @@ -92,21 +99,58 @@ public void canRetrieveListOfAccessPolicies() throws Exception { AccessPolicyInfo policy2 = null; for (AccessPolicyInfo policy : policies) { - if (policy.getName().equals("testPolicy1")) { + if (policy.getName().equals(policyNames[0])) { policy1 = policy; } - if (policy.getName().equals("testPolicy2")) { + if (policy.getName().equals(policyNames[1])) { policy2 = policy; } } assertNotNull(policy1); assertNotNull(policy2); + + assertTrue(policy1.getPermissions().containsAll( + EnumSet.of(AccessPolicyPermission.WRITE, AccessPolicyPermission.LIST))); + } + + @Rule + public ExpectedException expected = ExpectedException.none(); + + @Test + public void getWithBadIdThrowsServiceException() throws Exception { + expected.expect(ServiceException.class); + AccessPolicyInfo policy = service.getAccessPolicy("notAValidId"); + } + + @Test + public void getWithValidButNonExistentPolicyIdThrows404ServiceException() throws Exception { + expected.expect(new BaseMatcher() { + + @Override + public boolean matches(Object item) { + if (item.getClass() != ServiceException.class) { + return false; + } + + if (((ServiceException) item).getHttpStatusCode() != 404) { + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("Must be ServiceException with a 404 status code"); + } + }); + service.getAccessPolicy("nb:pid:UUID:bce3863e-830b-49f5-9199-7cfaff52935f"); } @Test public void canDeleteAccessPolicyById() throws Exception { - AccessPolicyInfo policyToDelete = service.createAccessPolicy("testPolicyToDelete", 1); + AccessPolicyInfo policyToDelete = service.createAccessPolicy(testPrefix + "ToDelete", 1); service.deleteAccessPolicy(policyToDelete.getId()); From 384a73583f375a8368a6090a555ad3612a68f7e2 Mon Sep 17 00:00:00 2001 From: Chris Tavares Date: Wed, 3 Oct 2012 14:22:58 -0700 Subject: [PATCH 10/10] Added more convenient overloads for getting / setting permissions, issue #340 --- .../models/CreateAccessPolicyOptions.java | 43 ++++++++ .../models/CreateAccessPolicyOptionsTest.java | 97 +++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptionsTest.java diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java index d5e4cb87ee0c6..7c003d2e0cd02 100644 --- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java +++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/models/CreateAccessPolicyOptions.java @@ -1,3 +1,18 @@ +/** + * Copyright 2012 Microsoft Corporation + * + * 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 com.microsoft.windowsazure.services.media.models; import java.util.EnumSet; @@ -28,6 +43,20 @@ public CreateAccessPolicyOptions addPermissions(EnumSet return this; } + /** + * Add the given permissions to this creation request + * + * @param permissionsToAdd + * varargs - permissions to add + * @return the CreateAccessPolicyOptions object + */ + public CreateAccessPolicyOptions addPermissions(AccessPolicyPermission... permissionsToAdd) { + for (AccessPolicyPermission permission : permissionsToAdd) { + permissions.add(permission); + } + return this; + } + /** * Remove the given permissions from this creation request * @@ -38,4 +67,18 @@ public CreateAccessPolicyOptions removePermissions(EnumSet expected, + EnumSet actual) { + assertTrue(actual.containsAll(expected)); + assertTrue(EnumSet.complementOf(actual).containsAll(EnumSet.complementOf(expected))); + } + + @Test + public void optionsCreatedWithNoPermissions() throws Exception { + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions(); + + assertPermissions(EnumSet.noneOf(AccessPolicyPermission.class), options.getPermissions()); + } + + @Test + public void canGetSetPermissionsAsEnumSet() throws Exception { + EnumSet expectedPermissions = EnumSet.of(AccessPolicyPermission.LIST, + AccessPolicyPermission.DELETE); + + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions(); + + options.addPermissions(expectedPermissions); + + EnumSet permissions = options.getPermissions(); + + assertPermissions(expectedPermissions, permissions); + } + + @Test + public void canGetSetPermissionsAsVarargs() throws Exception { + EnumSet expectedPermissions = EnumSet.of(AccessPolicyPermission.READ, + AccessPolicyPermission.WRITE); + + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions().addPermissions(AccessPolicyPermission.READ, + AccessPolicyPermission.WRITE); + + EnumSet permissions = options.getPermissions(); + + assertPermissions(expectedPermissions, permissions); + } + + @Test + public void canRemovePermissionsAsEnumSet() throws Exception { + EnumSet originalPermissions = EnumSet.of(AccessPolicyPermission.READ, + AccessPolicyPermission.WRITE, AccessPolicyPermission.DELETE); + EnumSet permissionsToRemove = EnumSet.of(AccessPolicyPermission.READ, + AccessPolicyPermission.DELETE); + EnumSet expectedPermissions = EnumSet.of(AccessPolicyPermission.WRITE); + + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions().addPermissions(originalPermissions); + + options.removePermissions(permissionsToRemove); + + EnumSet actualPermissions = options.getPermissions(); + + assertPermissions(expectedPermissions, actualPermissions); + } + + @Test + public void canRemovePermissionsAsVarargs() throws Exception { + EnumSet originalPermissions = EnumSet.of(AccessPolicyPermission.READ, + AccessPolicyPermission.WRITE, AccessPolicyPermission.DELETE); + EnumSet expectedPermissions = EnumSet.of(AccessPolicyPermission.WRITE); + + CreateAccessPolicyOptions options = new CreateAccessPolicyOptions().addPermissions(originalPermissions); + + options.removePermissions(AccessPolicyPermission.READ, AccessPolicyPermission.DELETE); + + EnumSet actualPermissions = options.getPermissions(); + + assertPermissions(expectedPermissions, actualPermissions); + } +}