diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/ActiveToken.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/ActiveToken.java
new file mode 100644
index 0000000000000..2be96a410507a
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/ActiveToken.java
@@ -0,0 +1,66 @@
+/**
+ * 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 java.util.Date;
+
+/**
+ * A class representing active token.
+ *
+ * @author azurejava@microsoft.com
+ *
+ */
+public class ActiveToken {
+
+ private Date expiresUtc;
+ private String accessToken;
+
+ /**
+ * Gets the expiration time in UTC.
+ *
+ * @return The token expiration time in UTC.
+ */
+ public Date getExpiresUtc() {
+ return expiresUtc;
+ }
+
+ /**
+ * Sets the token expiration time in UTC.
+ *
+ * @param expiresUtc
+ */
+ public void setExpiresUtc(Date expiresUtc) {
+ this.expiresUtc = expiresUtc;
+ }
+
+ /**
+ * Gets access token.
+ *
+ * @return String
+ */
+ public String getAccessToken() {
+ return this.accessToken;
+ }
+
+ /**
+ * Sets the access token.
+ *
+ * @param accessToken
+ */
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/Exports.java
new file mode 100644
index 0000000000000..2a9cd99c4b38c
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/Exports.java
@@ -0,0 +1,31 @@
+/**
+ * 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 com.microsoft.windowsazure.services.core.Builder;
+
+public class Exports implements Builder.Exports {
+
+ /**
+ * register the OAUTH service.
+ */
+ @Override
+ public void register(Builder.Registry registry) {
+ registry.add(OAuthContract.class, OAuthRestProxy.class);
+ registry.add(OAuthTokenManager.class);
+ registry.add(OAuthFilter.class);
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java
new file mode 100644
index 0000000000000..0c4c703fb1dd7
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java
@@ -0,0 +1,155 @@
+/**
+ * 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 com.microsoft.windowsazure.services.core.Configuration;
+
+/**
+ * Provides functionality to create a service bus configuration.
+ *
+ */
+public class MediaConfiguration {
+
+ /**
+ * Defines the media service configuration URI constant.
+ *
+ */
+ public static final String URI = "media.uri";
+
+ /**
+ * Defines the OAUTH configuration URI constant.
+ *
+ */
+ public static final String OAUTH_URI = "oauth.uri";
+
+ /**
+ * Defines the OAUTH configuration client ID constant.
+ *
+ */
+ public static final String OAUTH_CLIENT_ID = "oauth.client.id";
+
+ /**
+ * Defines the OAUTH configuration client secret constant.
+ *
+ */
+ public static final String OAUTH_CLIENT_SECRET = "oauth.client.secret";
+
+ /**
+ * Defines the SCOPE of the media service sent to OAUTH.
+ */
+ public static final String OAUTH_SCOPE = "oauth.scope";
+
+ /**
+ * Creates a media service configuration using the specified media service base URI, OAUTH URI,
+ * client ID, and client secret.
+ *
+ * @param mediaServiceBaseUri
+ * A String
object that represents the media service base URI.
+ *
+ * @param oAuthUri
+ * A String
object that represents the OAUTH URI.
+ *
+ * @param clientId
+ * A String
object that represents the client ID.
+ *
+ * @param clientSecret
+ * A String
object that represents the client secret.
+ *
+ * @return
+ * A Configuration
object that can be used when creating an instance of the
+ * MediaService
class.
+ *
+ */
+ public static Configuration configureWithOAuthAuthentication(String mediaServiceBaseUri, String oAuthUri,
+ String clientId, String clientSecret) {
+ return configureWithOAuthAuthentication(null, Configuration.getInstance(), mediaServiceBaseUri, oAuthUri,
+ clientId, clientSecret);
+ }
+
+ /**
+ * Creates a media service configuration using the specified configuration, media service base URI, OAuth URI,
+ * client ID, and client secret.
+ *
+ * @param configuration
+ * A previously instantiated Configuration
object.
+ *
+ * @param mediaServiceBaseUri
+ * A String
object that represents the base URI of Media service.
+ *
+ * @param oAuthUri
+ * A String
object that represents the URI of OAuth service.
+ *
+ * @param clientId
+ * A String
object that represents the client ID.
+ *
+ * @param clientSecret
+ * A String
object that represents the client secret.
+ *
+ * @return
+ * A Configuration
object that can be used when creating an instance of the
+ * MediaService
class.
+ *
+ */
+ public static Configuration configureWithOAuthAuthentication(Configuration configuration,
+ String mediaServiceBaseUri, String oAuthUri, String clientId, String clientSecret) {
+ return configureWithOAuthAuthentication(null, configuration, mediaServiceBaseUri, oAuthUri, clientId,
+ clientSecret);
+ }
+
+ /**
+ * Creates a media service configuration using the specified profile, configuration, media service base URI,
+ * OAuth URI, client ID, and client secret.
+ *
+ * @param profile
+ * A String
object that represents the profile.
+ *
+ * @param configuration
+ * A previously instantiated Configuration
object.
+ *
+ * @param mediaServiceBaseUri
+ * A String
object that represents the base URI of media service.
+ *
+ * @param oAuthUri
+ * A String
object that represents the URI of OAUTH service.
+ *
+ * @param clientId
+ * A String
object that represents the client ID.
+ *
+ * @param clientSecret
+ * A String
object that represents the client secret.
+ *
+ * @return
+ * A Configuration
object that can be used when creating an instance of the
+ * MediaService
class.
+ *
+ */
+ public static Configuration configureWithOAuthAuthentication(String profile, Configuration configuration,
+ String mediaServiceBaseUri, String oAuthUri, String clientId, String clientSecret) {
+
+ if (profile == null) {
+ profile = "";
+ }
+ else if (profile.length() != 0 && !profile.endsWith(".")) {
+ profile = profile + ".";
+ }
+
+ configuration.setProperty(profile + URI, "https://" + mediaServiceBaseUri);
+ configuration.setProperty(profile + OAUTH_URI, oAuthUri);
+ configuration.setProperty(profile + OAUTH_CLIENT_ID, clientId);
+ configuration.setProperty(profile + OAUTH_CLIENT_SECRET, clientSecret);
+
+ return configuration;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthContract.java
new file mode 100644
index 0000000000000..b74216823c308
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthContract.java
@@ -0,0 +1,44 @@
+/**
+ * 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 java.net.URI;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+
+public interface OAuthContract {
+ /**
+ * Gets an OAuth access token with specified OAUTH URI, client ID, client secret, and scope.
+ *
+ * @param oAuthUri
+ * A URI
object which represents an OAUTH URI.
+ *
+ * @param clientId
+ * A String
object which represents a client ID.
+ *
+ * @param clientSecret
+ * A String
object which represents a client secret.
+ *
+ * @param scope
+ * A String
object which represents the scope.
+ *
+ * @return OAuthTokenResponse
+ * @throws ServiceException
+ */
+ public OAuthTokenResponse getAccessToken(URI oAuthUri, String clientId, String clientSecret, String scope)
+ throws ServiceException;
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthFilter.java
new file mode 100644
index 0000000000000..3fa9f48bc74ec
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthFilter.java
@@ -0,0 +1,69 @@
+/*
+ * 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 java.net.URISyntaxException;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientRequest;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.filter.ClientFilter;
+
+/**
+ * The Jersey filter for OAuth.
+ *
+ * @author azurejava@microsoft.com
+ *
+ */
+public class OAuthFilter extends ClientFilter {
+ private final OAuthTokenManager oAuthTokenManager;
+
+ /**
+ * Creates an OAuthFilter
object with specified OAuthTokenManager
instance.
+ *
+ * @param oAuthTokenManager
+ */
+ public OAuthFilter(OAuthTokenManager oAuthTokenManager) {
+ this.oAuthTokenManager = oAuthTokenManager;
+ }
+
+ /**
+ * Handles response with a specified client request.
+ *
+ * @param clientRequest
+ * A ClientRequest
object representing a client request.
+ */
+ @Override
+ public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException {
+
+ String accessToken;
+ try {
+ accessToken = oAuthTokenManager.getAccessToken();
+ }
+ catch (ServiceException e) {
+ // must wrap exception because of base class signature
+ throw new ClientHandlerException(e);
+ }
+ catch (URISyntaxException e) {
+ // must wrap exception because of base class signature
+ throw new ClientHandlerException(e);
+ }
+
+ clientRequest.getHeaders().add("Authorization", "Bearer " + accessToken);
+
+ return this.getNext().handle(clientRequest);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthRestProxy.java
new file mode 100644
index 0000000000000..9ab60ed9115ce
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthRestProxy.java
@@ -0,0 +1,122 @@
+/**
+ * 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 java.io.IOException;
+import java.net.URI;
+
+import javax.inject.Inject;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.utils.ServiceExceptionFactory;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.representation.Form;
+
+/**
+ * The OAuth rest proxy.
+ *
+ * @author azurejava@microsoft.com
+ *
+ */
+public class OAuthRestProxy implements OAuthContract {
+ Client channel;
+
+ private final String _grantType = "client_credentials";
+
+ static Log log = LogFactory.getLog(OAuthContract.class);
+
+ @Inject
+ public OAuthRestProxy(Client channel) {
+ this.channel = channel;
+ }
+
+ /**
+ * Gets an OAuth access token with specified OAUTH URI, client ID, client secret, and scope.
+ *
+ * @param oAuthUri
+ * A URI
object which represents an OAUTH URI.
+ *
+ * @param clientId
+ * A String
object which represents a client ID.
+ *
+ * @param clientSecret
+ * A String
object which represents a client secret.
+ *
+ * @param scope
+ * A String
object which represents the scope.
+ *
+ * @return OAuthTokenResponse
+ * @throws ServiceException
+ */
+ @Override
+ public OAuthTokenResponse getAccessToken(URI oAuthUri, String clientId, String clientSecret, String scope)
+ throws ServiceException {
+ OAuthTokenResponse response = null;
+ Form requestForm = new Form();
+ ClientResponse clientResponse;
+ String responseJson;
+
+ requestForm.add("grant_type", _grantType);
+ requestForm.add("client_id", clientId);
+ requestForm.add("client_secret", clientSecret);
+ requestForm.add("scope", scope);
+
+ try {
+ clientResponse = channel.resource(oAuthUri).accept(MediaType.APPLICATION_FORM_URLENCODED)
+ .type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class, requestForm);
+ }
+ catch (UniformInterfaceException e) {
+ log.warn("OAuth server returned error acquiring access_token", e);
+ throw ServiceExceptionFactory.process("OAuth", new ServiceException(
+ "OAuth server returned error acquiring access_token", e));
+ }
+
+ responseJson = clientResponse.getEntity(String.class);
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ TypeReference typeReference = new TypeReference() {
+ };
+ response = mapper.readValue(responseJson, typeReference);
+ }
+ catch (JsonParseException e) {
+ log.warn("The response from OAuth server cannot be parsed correctly", e);
+ throw ServiceExceptionFactory.process("OAuth", new ServiceException(
+ "The response from OAuth server cannot be parsed correctly", e));
+ }
+ catch (JsonMappingException e) {
+ log.warn("The response from OAuth server cannot be mapped to OAuthResponse object", e);
+ throw ServiceExceptionFactory.process("OAuth", new ServiceException(
+ "The response from OAuth server cannot be mapped to OAuthResponse object", e));
+ }
+ catch (IOException e) {
+ log.warn("Cannot map the response from OAuth server correctly.", e);
+ throw ServiceExceptionFactory.process("OAuth", new ServiceException(
+ "Cannot map the response from OAuth server correctly.", e));
+ }
+
+ return response;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenManager.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenManager.java
new file mode 100644
index 0000000000000..77f2b020a2cd7
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenManager.java
@@ -0,0 +1,104 @@
+/**
+ * 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 java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+
+import javax.management.timer.Timer;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.utils.DateFactory;
+
+/**
+ * An OAuth token manager class.
+ *
+ * @author azurejava@microsoft.com
+ *
+ */
+public class OAuthTokenManager {
+ private final DateFactory dateFactory;
+ private final URI acsBaseUri;
+ private final String clientId;
+ private final String clientSecret;
+ private final OAuthContract contract;
+ private ActiveToken activeToken;
+ private final String scope;
+
+ /**
+ * Creates an OAuth token manager instance with specified contract, date factory, ACS base URI, client ID,
+ * and client secret.
+ *
+ * @param contract
+ * A OAuthContract
object instance that represents the OAUTH contract.
+ *
+ * @param dateFactory
+ * A DateFactory
object instance that represents the date factory.
+ *
+ * @param acsBaseUri
+ * A URI
object instance that represents the ACS base URI.
+ *
+ * @param clientId
+ * A String
object instance that represents the client ID.
+ *
+ * @param clientSecret
+ * A String
object instance that represents the client secret.
+ *
+ */
+ public OAuthTokenManager(OAuthContract contract, DateFactory dateFactory, URI acsBaseUri, String clientId,
+ String clientSecret, String scope) {
+ this.contract = contract;
+ this.dateFactory = dateFactory;
+ this.acsBaseUri = acsBaseUri;
+ this.clientId = clientId;
+ this.clientSecret = clientSecret;
+ this.scope = scope;
+ this.activeToken = null;
+ }
+
+ /**
+ * Gets an OAuth access token with specified media service scope.
+ *
+ * @param mediaServiceScope
+ * A String
instance that represents the media service scope.
+ *
+ * @return String
+ *
+ * @throws ServiceException
+ * @throws URISyntaxException
+ */
+ public String getAccessToken() throws ServiceException, URISyntaxException {
+ Date now = dateFactory.getDate();
+ OAuthTokenResponse oAuth2TokenResponse = null;
+
+ if (this.activeToken == null) {
+ this.activeToken = new ActiveToken();
+ }
+ else if (now.before(this.activeToken.getExpiresUtc())) {
+ return this.activeToken.getAccessToken();
+ }
+
+ oAuth2TokenResponse = contract.getAccessToken(acsBaseUri, clientId, clientSecret, scope);
+ Date expiresUtc = new Date(now.getTime() + oAuth2TokenResponse.getExpiresIn() * Timer.ONE_SECOND / 2);
+
+ this.activeToken.setAccessToken(oAuth2TokenResponse.getAccessToken());
+ this.activeToken.setExpiresUtc(expiresUtc);
+
+ return oAuth2TokenResponse.getAccessToken();
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenResponse.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenResponse.java
new file mode 100644
index 0000000000000..95a9dae61f674
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/OAuthTokenResponse.java
@@ -0,0 +1,77 @@
+/**
+ * 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 org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * A class representing OAuth token response.
+ *
+ * @author azurejava@microsoft.com
+ *
+ */
+public class OAuthTokenResponse {
+
+ private String _accessToken;
+ private String _scope;
+ private String _tokenType;
+ private long _expiresIn;
+
+ /**
+ * Sets the token type.
+ *
+ * @param tokenType
+ */
+ @JsonProperty("token_type")
+ public void setTokenType(String tokenType) {
+ _tokenType = tokenType;
+ }
+
+ @JsonProperty("token_type")
+ public String getTokenType() {
+ return _tokenType;
+ }
+
+ @JsonProperty("expires_in")
+ public long getExpiresIn() {
+ return _expiresIn;
+ }
+
+ @JsonProperty("expires_in")
+ public void setExpiresIn(long expiresIn) {
+ _expiresIn = expiresIn;
+ }
+
+ @JsonProperty("access_token")
+ public String getAccessToken() {
+ return _accessToken;
+ }
+
+ @JsonProperty("access_token")
+ public void setAccessToken(String accessToken) {
+ _accessToken = accessToken;
+ }
+
+ @JsonProperty("scope")
+ public String getScope() {
+ return _scope;
+ }
+
+ @JsonProperty("scope")
+ public void setScope(String scope) {
+ _scope = scope;
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthRestProxyIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthRestProxyIntegrationTest.java
new file mode 100644
index 0000000000000..1b05d54794c3a
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthRestProxyIntegrationTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.net.URI;
+
+import org.junit.Test;
+
+import com.microsoft.windowsazure.services.core.Configuration;
+import com.sun.jersey.api.client.Client;
+
+public class OAuthRestProxyIntegrationTest {
+ @Test
+ public void serviceCanBeCalledToCreateAccessToken() throws Exception {
+ // Arrange
+ Configuration config = Configuration.getInstance();
+ overrideWithEnv(config, MediaConfiguration.OAUTH_URI);
+ overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_ID);
+ overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_SECRET);
+ OAuthContract oAuthContract = new OAuthRestProxy(config.create(Client.class));
+
+ // Act
+ URI oAuthUri = new URI((String) config.getProperty(MediaConfiguration.OAUTH_URI));
+ String clientId = (String) config.getProperty(MediaConfiguration.OAUTH_CLIENT_ID);
+ String clientSecret = (String) config.getProperty(MediaConfiguration.OAUTH_CLIENT_SECRET);
+ String scope = "urn:WindowsAzureMediaServices";
+ OAuthTokenResponse result = oAuthContract.getAccessToken(oAuthUri, clientId, clientSecret, scope);
+
+ // Assert
+ assertNotNull(result);
+ assertNotNull(result.getAccessToken());
+ }
+
+ private static void overrideWithEnv(Configuration config, String key) {
+ String value = System.getenv(key);
+ if (value == null)
+ return;
+
+ config.setProperty(key, value);
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthTokenManagerTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthTokenManagerTest.java
new file mode 100644
index 0000000000000..241d2ecc91e57
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/OAuthTokenManagerTest.java
@@ -0,0 +1,141 @@
+/**
+ * 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 static org.mockito.Mockito.*;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.utils.DateFactory;
+
+public class OAuthTokenManagerTest {
+ private OAuthContract contract;
+ private OAuthTokenManager client;
+ private DateFactory dateFactory;
+ private Calendar calendar;
+
+ @Before
+ public void init() throws URISyntaxException {
+ calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+
+ dateFactory = mock(DateFactory.class);
+
+ // Client channel = new Client();
+ contract = mock(OAuthRestProxy.class);
+
+ String acsBaseUri = "testurl";
+ String accountName = "testname";
+ String accountPassword = "testpassword";
+ String scope = "urn:WindowsAzureMediaServices";
+
+ client = new OAuthTokenManager(contract, dateFactory, new URI(acsBaseUri), accountName, accountPassword, scope);
+
+ when(dateFactory.getDate()).thenAnswer(new Answer() {
+ @Override
+ public Date answer(InvocationOnMock invocation) throws Throwable {
+ return calendar.getTime();
+ }
+ });
+ }
+
+ private void doIncrementingTokens() throws ServiceException, URISyntaxException, JsonParseException,
+ JsonMappingException, IOException {
+ doAnswer(new Answer() {
+ int count = 0;
+
+ @Override
+ public OAuthTokenResponse answer(InvocationOnMock invocation) throws Throwable {
+ ++count;
+ OAuthTokenResponse wrapResponse = new OAuthTokenResponse();
+ wrapResponse.setAccessToken("testaccesstoken1-" + count);
+ wrapResponse.setExpiresIn(83);
+ return wrapResponse;
+ }
+ }).when(contract).getAccessToken(new URI("testurl"), "testname", "testpassword",
+ "urn:WindowsAzureMediaServices");
+
+ }
+
+ @Test
+ public void clientUsesContractToGetToken() throws ServiceException, URISyntaxException, JsonParseException,
+ JsonMappingException, IOException {
+ // Arrange
+ doIncrementingTokens();
+
+ // Act
+ String accessToken = client.getAccessToken();
+
+ // Assert
+ assertNotNull(accessToken);
+ assertEquals("testaccesstoken1-1", accessToken);
+ }
+
+ @Test
+ public void clientWillNotCallMultipleTimesWhileAccessTokenIsValid() throws ServiceException, URISyntaxException,
+ JsonParseException, JsonMappingException, IOException {
+ // Arrange
+ doIncrementingTokens();
+
+ // Act
+ String accessToken1 = client.getAccessToken();
+ String accessToken2 = client.getAccessToken();
+ calendar.add(Calendar.SECOND, 40);
+ String accessToken3 = client.getAccessToken();
+
+ // Assert
+ assertEquals("testaccesstoken1-1", accessToken1);
+ assertEquals("testaccesstoken1-1", accessToken2);
+ assertEquals("testaccesstoken1-1", accessToken3);
+
+ verify(contract, times(1)).getAccessToken(new URI("testurl"), "testname", "testpassword",
+ "urn:WindowsAzureMediaServices");
+ }
+
+ @Test
+ public void clientWillBeCalledWhenTokenIsHalfwayToExpiring() throws ServiceException, URISyntaxException,
+ JsonParseException, JsonMappingException, IOException {
+ // Arrange
+ doIncrementingTokens();
+
+ // Act
+ String accessToken1 = client.getAccessToken();
+ String accessToken2 = client.getAccessToken();
+ calendar.add(Calendar.SECOND, 45);
+ String accessToken3 = client.getAccessToken();
+
+ // Assert
+ assertEquals("testaccesstoken1-1", accessToken1);
+ assertEquals("testaccesstoken1-1", accessToken2);
+ assertEquals("testaccesstoken1-2", accessToken3);
+
+ verify(contract, times(2)).getAccessToken(new URI("testurl"), "testname", "testpassword",
+ "urn:WindowsAzureMediaServices");
+ }
+
+}