WritableBlobContainerContract
API that will
+ * write to the blob container given by the provided locator.
+ *
+ * @param locator
+ * locator specifying where to upload to
+ * @return the implementation of WritableBlobContainerContract
+ */
+ public static WritableBlobContainerContract createBlobWriter(LocatorInfo locator) {
+ if (locator.getLocatorType() != LocatorType.SAS) {
+ throw new IllegalArgumentException("Can only write to SAS locators");
+ }
+
+ LocatorParser p = new LocatorParser(locator);
+
+ return new MediaBlobContainerWriter(createUploaderClient(), p.getAccountName(), p.getStorageUri(),
+ p.getContainer(), p.getSASToken());
+ }
+
+ /**
+ * Helper class to encapsulate pulling information out of the locator.
+ */
+ private static class LocatorParser {
+ URI locatorPath;
+
+ LocatorParser(LocatorInfo locator) {
+ locatorPath = URI.create(locator.getPath());
+ }
+
+ String getAccountName() {
+ return locatorPath.getHost().split("\\.")[0];
+ }
+
+ String getStorageUri() {
+ return locatorPath.getScheme() + "://" + locatorPath.getAuthority();
+ }
+
+ String getContainer() {
+ return locatorPath.getPath().substring(1);
+ }
+
+ String getSASToken() {
+ return locatorPath.getRawQuery();
+ }
+ }
+
+ private static Client createUploaderClient() {
+ Client client = Client.create();
+ return client;
+ }
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java
new file mode 100644
index 0000000000000..808e5c0460ece
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java
@@ -0,0 +1,173 @@
+/**
+ * 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;
+
+import java.io.InputStream;
+
+import com.microsoft.windowsazure.services.blob.models.BlockList;
+import com.microsoft.windowsazure.services.blob.models.CommitBlobBlocksOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobBlockOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobResult;
+import com.microsoft.windowsazure.services.core.FilterableService;
+import com.microsoft.windowsazure.services.core.ServiceException;
+
+/**
+ * Contract for uploading media files to blob storage managed
+ * by Media Services.
+ *
+ */
+public interface WritableBlobContainerContract extends FilterableService+ * Use the {@link CreateBlobOptions options} parameter to optionally specify the server timeout for the operation, + * the MIME content type and content encoding for the blob, the content language, the MD5 hash, a cache control + * value, and blob metadata. + * + * @param blob + * A {@link String} containing the name of the blob to create. A blob name can contain any combination of + * characters, but reserved URL characters must be properly escaped. A blob name must be at least one + * character long and cannot be more than 1,024 characters long, and must be unique within the container. + * @param contentStream + * An {@link InputStream} reference to the content to upload to the new blob. + * @param options + * A {@link CreateBlobOptions} instance containing options for the request. + * @throws ServiceException + * if an error occurs accessing the storage service. + */ + CreateBlobResult createBlockBlob(String blob, InputStream contentStream, CreateBlobOptions options) + throws ServiceException; + + /** + * Creates a new uncommited block from a content stream. + *
+ * This method creates an uncommitted block for a block blob specified by the blob and container + * parameters. The blockId parameter is a client-specified ID for the block, which must be less than or + * equal to 64 bytes in size. For a given blob, the length of the value specified for the blockId parameter + * must be the same size for each block. The contentStream parameter specifies the content to be copied to + * the block. The content for the block must be less than or equal to 4 MB in size. + *
+ * To create or update a block blob, the blocks that have been successfully written to the server with this method + * must be committed using a call to {@link WritableBlobContainerContract#commitBlobBlocks(String, BlockList)} or + * {@link WritableBlobContainerContract#commitBlobBlocks(String, BlockList, CommitBlobBlocksOptions)}. + * + * @param blob + * A {@link String} containing the name of the blob to create the block for. + * @param blockId + * A {@link String} containing a client-specified ID for the block. + * @param contentStream + * An {@link InputStream} reference to the content to copy to the block. + * @throws ServiceException + * if an error occurs accessing the storage service. + */ + void createBlobBlock(String blob, String blockId, InputStream contentStream) throws ServiceException; + + /** + * Creates a new uncommitted block from a content stream, using the specified options. + *
+ * This method creates an uncommitted block for a block blob specified by the blob and container + * parameters. The blockId parameter is a client-specified ID for the block, which must be less than or + * equal to 64 bytes in size. For a given blob, the length of the value specified for the blockId parameter + * must be the same size for each block. The contentStream parameter specifies the content to be copied to + * the block. The content for the block must be less than or equal to 4 MB in size. Use the + * {@link CreateBlobBlockOptions options} parameter to optionally specify the server timeout for the operation, the + * lease ID if the blob has an active lease, and the MD5 hash value for the block content. + *
+ * To create or update a block blob, the blocks that have been successfully written to the server with this method + * must be committed using a call to {@link WritableBlobContainerContract#commitBlobBlocks(String, BlockList)} or + * {@link WritableBlobContainerContract#commitBlobBlocks(String, BlockList, CommitBlobBlocksOptions)}. + * + * @param blob + * A {@link String} containing the name of the blob to create the block for. + * @param blockId + * A {@link String} containing a client-specified ID for the block. + * @param contentStream + * An {@link InputStream} reference to the content to copy to the block. + * @param options + * A {@link CreateBlobBlockOptions} instance containing options for the request. + * @throws ServiceException + * if an error occurs accessing the storage service. + */ + void createBlobBlock(String blob, String blockId, InputStream contentStream, CreateBlobBlockOptions options) + throws ServiceException; + + /** + * Commits a list of blocks to a block blob. + *
+ * This method creates or updates the block blob specified by the blob and container parameters. + * You can call this method to update a blob by uploading only those blocks that have changed, then committing the + * new and existing blocks together. You can do this with the blockList parameter by specifying whether to + * commit a block from the committed block list or from the uncommitted block list, or to commit the most recently + * uploaded version of the block, whichever list it may belong to. + *
+ * In order to be written as part of a blob, each block in the list must have been successfully written to the + * server with a call to {@link WritableBlobContainerContract#createBlobBlock(String, String, InputStream)} or + * {@link WritableBlobContainerContract#createBlobBlock(String, String, InputStream, CreateBlobBlockOptions)}. + * + * @param blob + * A {@link String} containing the name of the block blob to create or update. + * @param blockList + * A {@link BlockList} containing the list of blocks to commit to the block blob. + * @throws ServiceException + * if an error occurs accessing the storage service. + */ + void commitBlobBlocks(String blob, BlockList blockList) throws ServiceException; + + /** + * Commits a block list to a block blob, using the specified options. + *
+ * This method creates or updates the block blob specified by the blob and container parameters. + * You can call this method to update a blob by uploading only those blocks that have changed, then committing the + * new and existing blocks together. You can do this with the blockList parameter by specifying whether to + * commit a block from the committed block list or from the uncommitted block list, or to commit the most recently + * uploaded version of the block, whichever list it may belong to. Use the {@link CommitBlobBlocksOptions options} + * parameter to optionally specify the server timeout for the operation, the MIME content type and content encoding + * for the blob, the content language, the MD5 hash, a cache control value, blob metadata, the lease ID if the blob + * has an active lease, and any access conditions for the operation. + *
+ * In order to be written as part of a blob, each block in the list must have been successfully written to the
+ * server with a call to {@link WritableBlobContainerContract#createBlobBlock(String, String, InputStream)} or
+ * {@link WritableBlobContainerContract#createBlobBlock(String, String, InputStream, CreateBlobBlockOptions)}.
+ *
+ * @param blob
+ * A {@link String} containing the name of the block blob to create or update.
+ * @param blockList
+ * A {@link BlockList} containing the list of blocks to commit to the block blob.
+ * @param options
+ * A {@link CommitBlobBlocksOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs accessing the storage service.
+ */
+ void commitBlobBlocks(String blob, BlockList blockList, CommitBlobBlocksOptions options) throws ServiceException;
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java
new file mode 100644
index 0000000000000..d6831a3dc11cf
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java
@@ -0,0 +1,118 @@
+/**
+ * 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;
+
+import java.io.InputStream;
+
+import com.microsoft.windowsazure.services.blob.BlobContract;
+import com.microsoft.windowsazure.services.blob.implementation.BlobExceptionProcessor;
+import com.microsoft.windowsazure.services.blob.models.BlockList;
+import com.microsoft.windowsazure.services.blob.models.CommitBlobBlocksOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobBlockOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobOptions;
+import com.microsoft.windowsazure.services.blob.models.CreateBlobResult;
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.ServiceFilter;
+import com.microsoft.windowsazure.services.media.WritableBlobContainerContract;
+import com.sun.jersey.api.client.Client;
+
+/**
+ * Implementation of WritableBlobContainerContract, used to upload blobs to the
+ * Media Services storage.
+ *
+ */
+public class MediaBlobContainerWriter implements WritableBlobContainerContract {
+
+ private final BlobContract blobService;
+ private final BlobContract restProxy;
+ private final String containerName;
+
+ /**
+ *
+ */
+ public MediaBlobContainerWriter(Client client, String accountName, String blobServiceUri, String containerName,
+ String sasToken) {
+ this.containerName = containerName;
+ this.restProxy = new MediaBlobRestProxy(client, accountName, blobServiceUri, new SASTokenFilter(sasToken));
+ this.blobService = new BlobExceptionProcessor(this.restProxy);
+ }
+
+ private MediaBlobContainerWriter(MediaBlobContainerWriter baseWriter, ServiceFilter filter) {
+ this.containerName = baseWriter.containerName;
+ this.restProxy = baseWriter.restProxy.withFilter(filter);
+ this.blobService = new BlobExceptionProcessor(this.restProxy);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.core.FilterableService#withFilter(com.microsoft.windowsazure.services.core.ServiceFilter)
+ */
+ @Override
+ public WritableBlobContainerContract withFilter(ServiceFilter filter) {
+ return new MediaBlobContainerWriter(this, filter);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#createBlockBlob(java.lang.String, java.io.InputStream)
+ */
+ @Override
+ public CreateBlobResult createBlockBlob(String blob, InputStream contentStream) throws ServiceException {
+ return blobService.createBlockBlob(containerName, blob, contentStream);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#createBlockBlob(java.lang.String, java.io.InputStream, com.microsoft.windowsazure.services.blob.models.CreateBlobOptions)
+ */
+ @Override
+ public CreateBlobResult createBlockBlob(String blob, InputStream contentStream, CreateBlobOptions options)
+ throws ServiceException {
+ return blobService.createBlockBlob(containerName, blob, contentStream, options);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#createBlobBlock(java.lang.String, java.lang.String, java.io.InputStream)
+ */
+ @Override
+ public void createBlobBlock(String blob, String blockId, InputStream contentStream) throws ServiceException {
+ blobService.createBlobBlock(containerName, blob, blockId, contentStream);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#createBlobBlock(java.lang.String, java.lang.String, java.io.InputStream, com.microsoft.windowsazure.services.blob.models.CreateBlobBlockOptions)
+ */
+ @Override
+ public void createBlobBlock(String blob, String blockId, InputStream contentStream, CreateBlobBlockOptions options)
+ throws ServiceException {
+ blobService.createBlobBlock(containerName, blob, blockId, contentStream, options);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#commitBlobBlocks(java.lang.String, com.microsoft.windowsazure.services.blob.models.BlockList)
+ */
+ @Override
+ public void commitBlobBlocks(String blob, BlockList blockList) throws ServiceException {
+ blobService.commitBlobBlocks(containerName, blob, blockList);
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.media.WritableBlobContainerContract#commitBlobBlocks(java.lang.String, com.microsoft.windowsazure.services.blob.models.BlockList, com.microsoft.windowsazure.services.blob.models.CommitBlobBlocksOptions)
+ */
+ @Override
+ public void commitBlobBlocks(String blob, BlockList blockList, CommitBlobBlocksOptions options)
+ throws ServiceException {
+ blobService.commitBlobBlocks(containerName, blob, blockList, options);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java
new file mode 100644
index 0000000000000..3f799b69cd601
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java
@@ -0,0 +1,85 @@
+/**
+ * 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;
+
+import java.util.Arrays;
+
+import com.microsoft.windowsazure.services.blob.BlobContract;
+import com.microsoft.windowsazure.services.blob.implementation.BlobOperationRestProxy;
+import com.microsoft.windowsazure.services.blob.implementation.RFC1123DateConverter;
+import com.microsoft.windowsazure.services.core.ServiceFilter;
+import com.sun.jersey.api.client.Client;
+
+/**
+ * Rest proxy for blob operations that's specialized for working
+ * with the blobs created by and for Media Services storage.
+ *
+ */
+class MediaBlobRestProxy extends BlobOperationRestProxy {
+ private final SASTokenFilter tokenFilter;
+
+ /**
+ * Construct instance of MediaBlobRestProxy with given parameters.
+ *
+ * @param channel
+ * Jersey Client object used to communicate with blob service
+ * @param accountName
+ * Account name for blob storage
+ * @param url
+ * URL for blob storage
+ * @param tokenFilter
+ * filter used to add SAS tokens to requests.
+ */
+ public MediaBlobRestProxy(Client channel, String accountName, String url, SASTokenFilter tokenFilter) {
+ super(channel, accountName, url);
+
+ this.tokenFilter = tokenFilter;
+ channel.addFilter(tokenFilter);
+ }
+
+ /**
+ * Construct instance of MediaBlobRestProxy with given parameters.
+ *
+ * @param channel
+ * Jersey Client object used to communicate with blob service
+ * @param filters
+ * Additional ServiceFilters to manipulate requests and responses
+ * @param accountName
+ * Account name for blob storage
+ * @param url
+ * URL for blob storage
+ * @param dateMapper
+ * date conversion helper object
+ */
+ public MediaBlobRestProxy(Client channel, ServiceFilter[] filters, String accountName, String url,
+ SASTokenFilter tokenFilter, RFC1123DateConverter dateMapper) {
+ super(channel, filters, accountName, url, dateMapper);
+
+ this.tokenFilter = tokenFilter;
+ }
+
+ /* (non-Javadoc)
+ * @see com.microsoft.windowsazure.services.blob.implementation.BlobOperationRestProxy#withFilter(com.microsoft.windowsazure.services.core.ServiceFilter)
+ */
+ @Override
+ public BlobContract withFilter(ServiceFilter filter) {
+ ServiceFilter[] currentFilters = getFilters();
+ ServiceFilter[] newFilters = Arrays.copyOf(currentFilters, currentFilters.length + 1);
+ newFilters[currentFilters.length] = filter;
+ return new MediaBlobRestProxy(getChannel(), newFilters, getAccountName(), getUrl(), this.tokenFilter,
+ getDateMapper());
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java
index efc4a219ac1fa..0b88485694e21 100644
--- a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java
@@ -14,6 +14,7 @@ public void beforeEachTest() {
overrideWithEnv(config, MediaConfiguration.OAUTH_URI);
overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_ID);
overrideWithEnv(config, MediaConfiguration.OAUTH_CLIENT_SECRET);
+ overrideWithEnv(config, MediaConfiguration.OAUTH_SCOPE);
}
public static Configuration createConfig() {
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java
new file mode 100644
index 0000000000000..11162a491ebff
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java
@@ -0,0 +1,113 @@
+/**
+ * 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.windowsazure.services.core.ExponentialRetryPolicy;
+import com.microsoft.windowsazure.services.core.RetryPolicyFilter;
+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.CreateLocatorOptions;
+import com.microsoft.windowsazure.services.media.models.LocatorInfo;
+import com.microsoft.windowsazure.services.media.models.LocatorType;
+
+/**
+ * Testing uploading in various permutations.
+ *
+ */
+public class UploadingIntegrationTest extends IntegrationTestBase {
+ private static ArrayList