This SDK allows you to build Windows Azure applications in Java that allow
+#Windows Azure SDK for Java
+
+This SDK allows you to build Windows Azure applications in Java that allow
you to take advantage of Azure scalable cloud computing resources: table and blob
-storage, messaging through Service Bus.
To get the binaries of this library as distributed by Microsoft, ready for use
-within your project you can also have them installed by the Java package manager Maven.
-
To use this SDK to call Windows Azure services, you need to first create an
+storage, messaging through Service Bus.
+
+For documentation please see the [Windows Azure Java Developer Center](http://www.windowsazure.com/en-us/develop/java/)
+
+#Features
+* Blob
+ * Create/Read/Update/Delete Blobs
+* Queue
+ * Create/Delete Queues
+ * Insert/Peek Queue Messages
+ * Advanced Queue Operations
+* Service Bus
+ * Use either the Queue or Topic/Subscription Model
+* Service Runtime
+ * Retrieve information about the state of your Azure Compute instances
+* Table
+ * Manage Tables
+ * Work with Table Entities (CRUD)
+ * Entity Group Transactions (Batch)
+
+#Getting Started
+
+##Download
+###Option 1: Via Git
+
+To get the source code of the SDK via git just type:
+
+ git clone git://github.com/WindowsAzure/azure-sdk-for-java.git
+ cd ./azure-sdk-for-java
+ mvn compile
+
+###Option 2: Via Maven
+
+To get the binaries of this library as distributed by Microsoft, ready for use
+within your project you can also have them installed by the Java package manager Maven.
+
+
+ com.microsoft.windowsazure
+ microsoft-windowsazure-api
+ 0.1.0
+
+
+##Minimum Requirements
+
+* Java 1.6
+* (Optional) Maven
+
+
+##Usage
+
+To use this SDK to call Windows Azure services, you need to first create an
account. To host your Java code in Windows Azure, you additionally need to download
the full Windows Azure SDK for Java - which includes packaging, emulation, and
-deployment tools.
+deployment tools.
+
+##Code Samples
-
Code Samples
-
The following is a quick example on how to set up a Azure blob using the API
-and uploading a file to it. For additional information on using the client libraries to access Azure services see the How To guides listed
-here.
+The following is a quick example on how to set up a Azure blob using the API
+and uploading a file to it. For additional information on using the client libraries to access Azure services see the How To guides listed [here](http://www.windowsazure.com/en-us/develop/java/).
-
+
+#Need Help?
+
+Be sure to check out the Windows Azure [Developer Forums on Stack Overflow](http://go.microsoft.com/fwlink/?LinkId=234489) if you have trouble with the provided code.
+
+#Contribute Code or Provide Feedback
+
+If you would like to become an active contributor to this project please follow the instructions provided in [Windows Azure Projects Contribution Guidelines](http://windowsazure.github.com/guidelines.html).
+
+If you encounter any bugs with the library please file an issue in the [Issues](https://github.com/WindowsAzure/azure-sdk-for-java/issues) section of the project.
+
+#Learn More
+
+* [Windows Azure Java Developer Center](http://www.windowsazure.com/en-us/develop/java/)
+* [JavaDocs](http://dl.windowsazure.com/javadoc/)
diff --git a/microsoft-azure-api/pom.xml b/microsoft-azure-api/pom.xml
index c83d5dcc1a333..01567851ee74f 100644
--- a/microsoft-azure-api/pom.xml
+++ b/microsoft-azure-api/pom.xml
@@ -1,228 +1,228 @@
-
- 4.0.0
- com.microsoft.windowsazure
- microsoft-windowsazure-api
- 0.2.0
- jar
-
- Microsoft Windows Azure Client API
- API for Microsoft Windows Azure Clients
- https://github.com/WindowsAzure/azure-sdk-for-java
-
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
-
- scm:git:https://github.com/WindowsAzure/azure-sdk-for-java
- scm:git:git://github.com/WindowsAzure/azure-sdk-for-java.git
-
-
-
- UTF-8
-
-
-
-
-
- microsoft
- Microsoft
-
-
-
-
-
- com.sun.jersey
- jersey-client
- 1.10-b02
-
-
- javax.xml.bind
- jaxb-api
- 2.1
- provided
-
-
- junit
- junit
- 4.8
- test
-
-
- org.hamcrest
- hamcrest-all
- 1.1
- test
-
-
- org.mockito
- mockito-all
- test
- 1.9.0-rc1
-
-
- javax.inject
- javax.inject
- 1
-
-
- com.sun.jersey
- jersey-json
- 1.10-b02
-
-
- commons-logging
- commons-logging
- 1.1.1
-
-
- javax.mail
- mail
- 1.4
-
-
- org.apache.commons
- commons-lang3
- 3.1
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-help-plugin
- 2.1.1
-
-
- validate
-
- evaluate
-
-
- legal
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 2.3.2
-
-
- 1.6
-
-
-
- org.jvnet.jaxb2.maven2
- maven-jaxb2-plugin
- 0.8.0
-
-
- generate-sources
-
- generate
-
-
-
-
- true
-
-
- org.jvnet.jaxb2_commons
- jaxb2-basics
- 0.6.0
-
-
- org.jvnet.jaxb2_commons
- jaxb2-basics-annotate
- 0.6.0
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 2.8
-
- *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization
- /**
- * 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.
- */]]>
-
-
-
-
- org.codehaus.mojo
- findbugs-maven-plugin
- 2.3.2
-
- true
- true
- true
-
-
-
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
- 2.8
-
- src/config/checkstyle.xml
-
-
-
-
-
-
-
-
-
- org.eclipse.m2e
- lifecycle-mapping
- 1.0.0
-
-
-
-
-
- org.apache.maven.plugins
- maven-help-plugin
- [2.1.1,)
-
- evaluate
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ 4.0.0
+ com.microsoft.windowsazure
+ microsoft-windowsazure-api
+ 0.2.1
+ jar
+
+ Microsoft Windows Azure Client API
+ API for Microsoft Windows Azure Clients
+ https://github.com/WindowsAzure/azure-sdk-for-java
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ scm:git:https://github.com/WindowsAzure/azure-sdk-for-java
+ scm:git:git://github.com/WindowsAzure/azure-sdk-for-java.git
+
+
+
+ UTF-8
+
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+ com.sun.jersey
+ jersey-client
+ 1.10-b02
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.1
+ provided
+
+
+ junit
+ junit
+ 4.8
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.1
+ test
+
+
+ org.mockito
+ mockito-all
+ test
+ 1.9.0-rc1
+
+
+ javax.inject
+ javax.inject
+ 1
+
+
+ com.sun.jersey
+ jersey-json
+ 1.10-b02
+
+
+ commons-logging
+ commons-logging
+ 1.1.1
+
+
+ javax.mail
+ mail
+ 1.4
+
+
+ org.apache.commons
+ commons-lang3
+ 3.1
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-help-plugin
+ 2.1.1
+
+
+ validate
+
+ evaluate
+
+
+ legal
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ 1.6
+
+
+
+ org.jvnet.jaxb2.maven2
+ maven-jaxb2-plugin
+ 0.8.0
+
+
+ generate-sources
+
+ generate
+
+
+
+
+ true
+
+
+ org.jvnet.jaxb2_commons
+ jaxb2-basics
+ 0.6.0
+
+
+ org.jvnet.jaxb2_commons
+ jaxb2-basics-annotate
+ 0.6.0
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+ *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization
+ /**
+ * 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.
+ */]]>
+
+
+
+
+ org.codehaus.mojo
+ findbugs-maven-plugin
+ 2.3.2
+
+ true
+ true
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 2.8
+
+ src/config/checkstyle.xml
+
+
+
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-help-plugin
+ [2.1.1,)
+
+ evaluate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java
index 197537a9db826..8d9d63bc8972d 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java
@@ -2,20 +2,21 @@
* 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.blob;
import com.microsoft.windowsazure.services.blob.implementation.BlobExceptionProcessor;
import com.microsoft.windowsazure.services.blob.implementation.BlobRestProxy;
+import com.microsoft.windowsazure.services.blob.implementation.ISO8601DateConverter;
import com.microsoft.windowsazure.services.blob.implementation.SharedKeyFilter;
import com.microsoft.windowsazure.services.blob.implementation.SharedKeyLiteFilter;
import com.microsoft.windowsazure.services.core.Builder;
@@ -28,5 +29,6 @@ public void register(Builder.Registry registry) {
registry.add(BlobRestProxy.class);
registry.add(SharedKeyLiteFilter.class);
registry.add(SharedKeyFilter.class);
+ registry.add(ISO8601DateConverter.class);
}
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java
index 3907ac20db407..861cd21f3672f 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.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.blob.implementation;
@@ -69,10 +69,10 @@
import com.microsoft.windowsazure.services.blob.models.SetContainerMetadataOptions;
import com.microsoft.windowsazure.services.core.ServiceException;
import com.microsoft.windowsazure.services.core.ServiceFilter;
+import com.microsoft.windowsazure.services.core.utils.CommaStringBuilder;
import com.microsoft.windowsazure.services.core.utils.pipeline.ClientFilterAdapter;
import com.microsoft.windowsazure.services.core.utils.pipeline.HttpURLConnectionClient;
import com.microsoft.windowsazure.services.core.utils.pipeline.PipelineHelpers;
-import com.microsoft.windowsazure.services.core.utils.pipeline.PipelineHelpers.EnumCommaStringBuilder;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
@@ -122,6 +122,10 @@ private void ThrowIfError(ClientResponse r) {
PipelineHelpers.ThrowIfError(r);
}
+ private void ThrowIfNotSuccess(ClientResponse clientResponse) {
+ PipelineHelpers.ThrowIfNotSuccess(clientResponse);
+ }
+
private WebResource addOptionalQueryParam(WebResource webResource, String key, Object value) {
return PipelineHelpers.addOptionalQueryParam(webResource, key, value);
}
@@ -155,18 +159,18 @@ private HashMap getMetadataFromHeaders(ClientResponse response)
}
private WebResource addOptionalBlobListingIncludeQueryParam(ListBlobsOptions options, WebResource webResource) {
- EnumCommaStringBuilder sb = new EnumCommaStringBuilder();
+ CommaStringBuilder sb = new CommaStringBuilder();
sb.addValue(options.isIncludeSnapshots(), "snapshots");
sb.addValue(options.isIncludeUncommittedBlobs(), "uncommittedblobs");
sb.addValue(options.isIncludeMetadata(), "metadata");
- webResource = addOptionalQueryParam(webResource, "include", sb.getValue());
+ webResource = addOptionalQueryParam(webResource, "include", sb.toString());
return webResource;
}
private WebResource addOptionalContainerIncludeQueryParam(ListContainersOptions options, WebResource webResource) {
- EnumCommaStringBuilder sb = new EnumCommaStringBuilder();
+ CommaStringBuilder sb = new CommaStringBuilder();
sb.addValue(options.isIncludeMetadata(), "metadata");
- webResource = addOptionalQueryParam(webResource, "include", sb.getValue());
+ webResource = addOptionalQueryParam(webResource, "include", sb.toString());
return webResource;
}
@@ -630,7 +634,7 @@ public GetBlobResult getBlob(String container, String blob, GetBlobOptions optio
builder = addOptionalAccessContitionHeader(builder, options.getAccessCondition());
ClientResponse response = builder.get(ClientResponse.class);
- ThrowIfError(response);
+ ThrowIfNotSuccess(response);
GetBlobPropertiesResult properties = getBlobPropertiesResultFromResponse(response);
GetBlobResult blobResult = new GetBlobResult();
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java
index 39e67d931a384..f1ea12dbaa76f 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java
@@ -25,11 +25,11 @@ public class ContainerACLDateAdapter extends XmlAdapter {
@Override
public Date unmarshal(String arg0) throws Exception {
- return new ContainerACLDateConverter().parse(arg0);
+ return new ISO8601DateConverter().parse(arg0);
}
@Override
public String marshal(Date arg0) throws Exception {
- return new ContainerACLDateConverter().format(arg0);
+ return new ISO8601DateConverter().shortFormat(arg0);
}
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateConverter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateConverter.java
deleted file mode 100644
index 209a345d26a0a..0000000000000
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateConverter.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * 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.blob.implementation;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/*
- * "not quite" ISO 8601 date time conversion routines
- */
-public class ContainerACLDateConverter {
- // Note: because of the trailing "0000000", this is not quite ISO 8601 compatible
- private static final String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'";
-
- public String format(Date date) {
- return getFormat().format(date);
- }
-
- public Date parse(String date) throws ParseException {
- return getFormat().parse(date);
- }
-
- public Date parseNoThrow(String date) {
- try {
- return parse(date);
- }
- catch (ParseException e) {
- return null;
- }
- }
-
- private DateFormat getFormat() {
- DateFormat iso8601Format = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
- iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
- return iso8601Format;
- }
-}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverter.java
new file mode 100644
index 0000000000000..34444b858a039
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverter.java
@@ -0,0 +1,86 @@
+/**
+ * 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.blob.implementation;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/*
+ * "not quite" ISO 8601 date time conversion routines
+ */
+public class ISO8601DateConverter {
+ // Note: because of the trailing "0000000", this is not quite ISO 8601 compatible
+ private static final String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+ private static final String SHORT_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ private static final String DATETIME_PATTERN_NO_S = "yyyy-MM-dd'T'HH:mm'Z'";
+ private static final String DATETIME_PATTERN_TO_DECIMAL = "yyyy-MM-dd'T'HH:mm:ss.";
+
+ public String format(Date date) {
+ DateFormat iso8601Format = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
+ iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return iso8601Format.format(date);
+ }
+
+ public String shortFormat(Date date) {
+ DateFormat iso8601Format = new SimpleDateFormat(SHORT_DATETIME_PATTERN, Locale.US);
+ iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return iso8601Format.format(date);
+ }
+
+ public Date parse(String date) throws ParseException {
+ if (date == null)
+ return null;
+
+ int length = date.length();
+ if (length == 17) {
+ // [2012-01-04T23:21Z] length = 17
+ return parseDateFromString(date, DATETIME_PATTERN_NO_S);
+ }
+ else if (length == 20) {
+ // [2012-01-04T23:21:59Z] length = 20
+ return parseDateFromString(date, SHORT_DATETIME_PATTERN);
+ }
+ else if (length >= 22 && length <= 28) {
+ // [2012-01-04T23:21:59.1Z] length = 22
+ // [2012-01-04T23:21:59.1234567Z] length = 28
+ // Need to handle the milliseconds gently.
+
+ Date allExceptMilliseconds = parseDateFromString(date, DATETIME_PATTERN_TO_DECIMAL);
+ long timeWithSecondGranularity = allExceptMilliseconds.getTime();
+ // Decimal point is at 19
+ String secondDecimalString = date.substring(19, date.indexOf('Z'));
+ Float secondDecimal = Float.parseFloat(secondDecimalString);
+ int milliseconds = Math.round(secondDecimal * 1000);
+ long timeInMS = timeWithSecondGranularity + milliseconds;
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(timeInMS);
+ return calendar.getTime();
+ }
+ else {
+ throw new IllegalArgumentException(String.format("Invalid Date String: %s", date));
+ }
+ }
+
+ private static Date parseDateFromString(final String value, final String pattern) throws ParseException {
+ DateFormat iso8601Format = new SimpleDateFormat(pattern, Locale.US);
+ iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return iso8601Format.parse(value);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java
index 6481932c7cde0..9072ead435645 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.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.blob.implementation;
@@ -44,6 +44,18 @@ public SharedKeyFilter(@Named(BlobConfiguration.ACCOUNT_NAME) String accountName
this.signer = new HmacSHA256Sign(accountKey);
}
+ protected String getHeader(ClientRequest cr, String headerKey) {
+ return SharedKeyUtils.getHeader(cr, headerKey);
+ }
+
+ protected HmacSHA256Sign getSigner() {
+ return signer;
+ }
+
+ protected String getAccountName() {
+ return accountName;
+ }
+
@Override
public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
// Only sign if no other filter is handling authorization
@@ -60,6 +72,7 @@ public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
return this.getNext().handle(cr);
}
+ @Override
public void onBeforeStreamingEntity(ClientRequest clientRequest) {
// All headers should be known at this point, time to sign!
sign(clientRequest);
@@ -105,11 +118,11 @@ public void sign(ClientRequest cr) {
cr.getHeaders().putSingle("Authorization", "SharedKey " + this.accountName + ":" + signature);
}
- private void addOptionalDateHeader(ClientRequest cr) {
+ protected void addOptionalDateHeader(ClientRequest cr) {
String date = getHeader(cr, "Date");
if (date == "") {
date = new RFC1123DateConverter().format(new Date());
- cr.getHeaders().add("Date", date);
+ cr.getHeaders().putSingle("Date", date);
}
}
@@ -209,8 +222,4 @@ private String getCanonicalizedResource(ClientRequest cr) {
return result;
}
-
- private String getHeader(ClientRequest cr, String headerKey) {
- return SharedKeyUtils.getHeader(cr, headerKey);
- }
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java
index 0134195d5c3aa..37ff1321d5d96 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.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.blob.implementation;
@@ -59,6 +59,7 @@ public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
return this.getNext().handle(cr);
}
+ @Override
public void onBeforeStreamingEntity(ClientRequest clientRequest) {
// All headers should be known at this point, time to sign!
sign(clientRequest);
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/CommaStringBuilder.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/CommaStringBuilder.java
new file mode 100644
index 0000000000000..3623028e5ef16
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/CommaStringBuilder.java
@@ -0,0 +1,47 @@
+package com.microsoft.windowsazure.services.core.utils;
+
+import java.util.List;
+
+public class CommaStringBuilder {
+ private final StringBuilder sb = new StringBuilder();
+
+ public void add(String representation) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(representation);
+ }
+
+ public void addValue(boolean value, String representation) {
+ if (value) {
+ add(representation);
+ }
+ }
+
+ public static String join(List values) {
+ CommaStringBuilder sb = new CommaStringBuilder();
+
+ for (String value : values) {
+ sb.add(value);
+ }
+
+ return sb.toString();
+ }
+
+ public static String join(String... values) {
+ CommaStringBuilder sb = new CommaStringBuilder();
+
+ for (String value : values) {
+ sb.add(value);
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ if (sb.length() == 0)
+ return null;
+ return sb.toString();
+ }
+}
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 a562b7c2122e7..234581b023fb8 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
@@ -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;
@@ -25,8 +25,10 @@
public class Exports implements Builder.Exports {
+ @Override
public void register(Registry registry) {
registry.add(new Builder.Factory() {
+ @Override
public ClientConfig create(String profile, Builder builder, Map properties) {
ClientConfig clientConfig = new DefaultClientConfig();
for (Entry entry : properties.entrySet()) {
@@ -37,6 +39,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");
Client client = Client.create(clientConfig);
@@ -45,6 +48,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");
HttpURLConnectionClient client = HttpURLConnectionClient.create(clientConfig);
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 0610eb8d7bc94..20d9046c5358c 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
@@ -27,7 +27,7 @@
import javax.ws.rs.core.MultivaluedMap;
-import com.microsoft.windowsazure.services.core.utils.pipeline.PipelineHelpers.EnumCommaStringBuilder;
+import com.microsoft.windowsazure.services.core.utils.CommaStringBuilder;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
@@ -269,7 +269,7 @@ private void setURLConnectionHeaders(MultivaluedMap headers, Htt
urlConnection.setRequestProperty(e.getKey(), ClientRequest.getHeaderValue(vs.get(0)));
}
else {
- EnumCommaStringBuilder sb = new EnumCommaStringBuilder();
+ CommaStringBuilder sb = new CommaStringBuilder();
for (Object v : e.getValue()) {
sb.add(ClientRequest.getHeaderValue(v));
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/PipelineHelpers.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/PipelineHelpers.java
index 95fce9e9dbeb2..21b95538f6e11 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/PipelineHelpers.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/core/utils/pipeline/PipelineHelpers.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;
@@ -27,32 +27,17 @@
import com.sun.jersey.api.client.WebResource.Builder;
public class PipelineHelpers {
- public static void ThrowIfError(ClientResponse r) {
- if (r.getStatus() >= 300) {
- throw new UniformInterfaceException(r);
- }
- }
-
- public static class EnumCommaStringBuilder {
- private final StringBuilder sb = new StringBuilder();
-
- public void add(String representation) {
- if (sb.length() > 0) {
- sb.append(",");
- }
- sb.append(representation);
- }
+ public static void ThrowIfNotSuccess(ClientResponse clientResponse) {
+ int statusCode = clientResponse.getStatus();
- public void addValue(boolean value, String representation) {
- if (value) {
- add(representation);
- }
+ if ((statusCode < 200) || (statusCode >= 300)) {
+ throw new UniformInterfaceException(clientResponse);
}
+ }
- public String getValue() {
- if (sb.length() == 0)
- return null;
- return sb.toString();
+ public static void ThrowIfError(ClientResponse clientResponse) {
+ if (clientResponse.getStatus() >= 400) {
+ throw new UniformInterfaceException(clientResponse);
}
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java
index 165df11b234b0..1fad44dfe643f 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java
@@ -2,18 +2,24 @@
* 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.queue;
+/**
+ * A class that contains static strings used to identify parts of a service configuration instance associated with the
+ * Windows Azure Queue service.
+ *
+ * These values must not be altered.
+ */
public class QueueConfiguration {
public final static String ACCOUNT_NAME = "queue.accountName";
public final static String ACCOUNT_KEY = "queue.accountKey";
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java
index 62a6e2b5fb801..aa86eaf4ffcdc 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java
@@ -2,20 +2,21 @@
* 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.queue;
import java.util.HashMap;
+import com.microsoft.windowsazure.services.core.Configuration;
import com.microsoft.windowsazure.services.core.FilterableService;
import com.microsoft.windowsazure.services.core.ServiceException;
import com.microsoft.windowsazure.services.queue.models.CreateMessageOptions;
@@ -32,61 +33,399 @@
import com.microsoft.windowsazure.services.queue.models.ServiceProperties;
import com.microsoft.windowsazure.services.queue.models.UpdateMessageResult;
+/**
+ * Defines the methods available on the Windows Azure storage queue service. Construct an object instance implementing
+ * QueueContract with one of the static create methods on {@link QueueService}. These methods
+ * associate a {@link Configuration} with the implementation, so the methods on the instance of
+ * QueueContract all work with a particular storage account.
+ */
public interface QueueContract extends FilterableService {
+ /**
+ * Gets the service properties of the queue.
+ *
+ * @return
+ * A {@link GetServicePropertiesResult} reference to the queue service properties.
+ *
+ * @throws ServiceException
+ * if an error occurs accessing the storage service.
+ */
GetServicePropertiesResult getServiceProperties() throws ServiceException;
+ /**
+ * Gets the service properties of the queue, using the specified options. Use the {@link QueueServiceOptions
+ * options} parameter to specify the server timeout for the operation.
+ *
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @return
+ * A {@link GetServicePropertiesResult} reference to the queue service properties.
+ *
+ * @throws ServiceException
+ * if an error occurs accessing the storage service.
+ */
GetServicePropertiesResult getServiceProperties(QueueServiceOptions options) throws ServiceException;
+ /**
+ * Sets the service properties of the queue.
+ *
+ * @param serviceProperties
+ * A {@link ServiceProperties} instance containing the queue service properties to set.
+ *
+ * @throws ServiceException
+ * if an error occurs accessing the storage service.
+ */
void setServiceProperties(ServiceProperties serviceProperties) throws ServiceException;
+ /**
+ * Sets the service properties of the queue, using the specified options. Use the {@link QueueServiceOptions
+ * options} parameter to specify the server timeout for the operation.
+ *
+ * @param serviceProperties
+ * A {@link ServiceProperties} instance containing the queue service properties to set.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs accessing the storage service.
+ */
void setServiceProperties(ServiceProperties serviceProperties, QueueServiceOptions options) throws ServiceException;
+ /**
+ * Creates a queue in the storage account with the specified queue name.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to create.
+ *
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void createQueue(String queue) throws ServiceException;
+ /**
+ * Creates a queue in the storage account with the specified queue name, using the specified options. Use the
+ * {@link QueueServiceOptions options} parameter to specify the server timeout for the operation.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to create.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void createQueue(String queue, CreateQueueOptions options) throws ServiceException;
+ /**
+ * Deletes the queue in the storage account with the specified queue name.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to delete.
+ *
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void deleteQueue(String queue) throws ServiceException;
+ /**
+ * Deletes the queue in the storage account with the specified queue name, using the specified options. Use the
+ * {@link QueueServiceOptions options} parameter to specify the server timeout for the operation.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to delete.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void deleteQueue(String queue, QueueServiceOptions options) throws ServiceException;
+ /**
+ * Gets a list of the queues in the storage account.
+ *
+ * @return
+ * A {@link ListQueuesResult} reference to the queues returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
ListQueuesResult listQueues() throws ServiceException;
+ /**
+ * Gets a list of the queues in the storage account, using the specified options. Use the {@link ListQueuesOptions
+ * options} parameter to specify the server timeout for the operation, the prefix for queue names to match, the
+ * marker for the beginning of the queues to list, the maximum number of results to return, and whether to include
+ * queue metadata with the results.
+ *
+ * @param options
+ * A {@link ListQueuesOptions} instance containing options for the request.
+ * @return
+ * A {@link ListQueuesResult} reference to the queues returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
ListQueuesResult listQueues(ListQueuesOptions options) throws ServiceException;
+ /**
+ * Gets the metadata for the named queue in the storage account. Queue metadata is a user-defined collection of
+ * key-value {@link String} pairs that is opaque to the server.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to get the metadata for.
+ * @return
+ * A {@link GetQueueMetadataResult} reference to the metadata for the queue.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
GetQueueMetadataResult getQueueMetadata(String queue) throws ServiceException;
+ /**
+ * Gets the metadata for the named queue in the storage account, using the specified options. Use the
+ * {@link QueueServiceOptions options} parameter to specify the server timeout for the operation. Queue metadata is
+ * a user-defined collection of key-value {@link String} pairs that is opaque to the server.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to get the metadata for.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @return
+ * A {@link ListQueuesResult} reference to the queues returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
GetQueueMetadataResult getQueueMetadata(String queue, QueueServiceOptions options) throws ServiceException;
+ /**
+ * Sets the specified metadata on the named queue in the storage account. Queue metadata is a user-defined
+ * collection of key-value {@link String} pairs that is opaque to the server.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to set the metadata on.
+ * @param metadata
+ * A {@link java.util.HashMap} of metadata key-value {@link String} pairs to set on the queue.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void setQueueMetadata(String queue, HashMap metadata) throws ServiceException;
+ /**
+ * Sets the specified metadata on the named queue in the storage account, using the specified options. Use the
+ * {@link QueueServiceOptions options} parameter to specify the server timeout for the operation. Queue metadata is
+ * a user-defined collection of key-value {@link String} pairs that is opaque to the server.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to set the metadata on.
+ * @param metadata
+ * A {@link java.util.HashMap} of metadata key-value {@link String} pairs to set on the queue.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void setQueueMetadata(String queue, HashMap metadata, QueueServiceOptions options)
throws ServiceException;
+ /**
+ * Appends a message with the specified text to the tail of the named queue in the storage account.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to append the message to.
+ * @param messageText
+ * A {@link String} containing the text of the message to append to the queue.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void createMessage(String queue, String messageText) throws ServiceException;
+ /**
+ * Appends a message with the specified text to the tail of the named queue in the storage account, using the
+ * specified options. Use the {@link CreateMessageOptions options} parameter to specify the server timeout for the
+ * operation, the message visibility timeout, and the message time to live in the queue.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to append the message to.
+ * @param messageText
+ * A {@link String} containing the text of the message to append to the queue.
+ * @param options
+ * A {@link CreateMessageOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void createMessage(String queue, String messageText, CreateMessageOptions options) throws ServiceException;
+ /**
+ * Updates the message in the named queue with the specified message ID and pop receipt value to have the specified
+ * message text and visibility timeout value.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue with the message to update.
+ * @param messageId
+ * A {@link String} containing the ID of the message to update.
+ * @param popReceipt
+ * A {@link String} containing the pop receipt for the message returned by a call to updateMessage or
+ * listMessages.
+ * @param messageText
+ * A {@link String} containing the updated text to set for the message.
+ * @param visibilityTimeoutInSeconds
+ * The new visibility timeout to set on the message, in seconds.
+ * @return
+ * An {@link UpdateMessageResult} reference to the updated message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
UpdateMessageResult updateMessage(String queue, String messageId, String popReceipt, String messageText,
int visibilityTimeoutInSeconds) throws ServiceException;
+ /**
+ * Updates the message in the named queue with the specified message ID and pop receipt value to have the specified
+ * message text and visibility timeout value, using the specified options. Use the {@link QueueServiceOptions
+ * options} parameter to specify the server timeout for the operation.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue with the message to update.
+ * @param messageId
+ * A {@link String} containing the ID of the message to update.
+ * @param popReceipt
+ * A {@link String} containing the pop receipt for the message returned by a call to updateMessage or
+ * listMessages.
+ * @param messageText
+ * A {@link String} containing the updated text to set for the message.
+ * @param visibilityTimeoutInSeconds
+ * The new visibility timeout to set on the message, in seconds.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @return
+ * An {@link UpdateMessageResult} reference to the updated message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
UpdateMessageResult updateMessage(String queue, String messageId, String popReceipt, String messageText,
int visibilityTimeoutInSeconds, QueueServiceOptions options) throws ServiceException;
+ /**
+ * Deletes the message in the named queue with the specified message ID and pop receipt value.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue with the message to delete.
+ * @param messageId
+ * A {@link String} containing the ID of the message to delete.
+ * @param popReceipt
+ * A {@link String} containing the pop receipt for the message returned by a call to updateMessage or
+ * listMessages.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void deleteMessage(String queue, String messageId, String popReceipt) throws ServiceException;
+ /**
+ * Deletes the message in the named queue with the specified message ID and popReceipt value, using the specified
+ * options. Use the {@link QueueServiceOptions options} parameter to specify the server timeout for the operation.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue with the message to delete.
+ * @param messageId
+ * A {@link String} containing the ID of the message to delete.
+ * @param popReceipt
+ * A {@link String} containing the pop receipt for the message returned by a call to updateMessage or
+ * listMessages.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void deleteMessage(String queue, String messageId, String popReceipt, QueueServiceOptions options)
throws ServiceException;
+ /**
+ * Retrieves the first message from head of the named queue in the storage account. This marks the message as
+ * invisible for the default visibility timeout period. When message processing is complete, the message must be
+ * deleted with a call to {@link QueueContract#deleteMessage(String, String, String, QueueServiceOptions)
+ * deleteMessage}. If message processing will take longer than the visibility timeout period,
+ * use the {@link QueueContract#updateMessage(String, String, String, String, int, QueueServiceOptions)
+ * updateMessage} method to extend the visibility timeout. The message will become visible in the queue again
+ * when the timeout completes if it is not deleted.
+ *
+ * To get a list of multiple messages from the head of the queue, call the
+ * {@link QueueContract#listMessages(String, ListMessagesOptions)} method with options set specifying the number of
+ * messages to return.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to get the message from.
+ * @return
+ * A {@link ListMessagesResult} reference to the message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
ListMessagesResult listMessages(String queue) throws ServiceException;
+ /**
+ * Retrieves up to 32 messages from the head of the named queue in the storage account, using the specified options.
+ * Use the {@link ListMessagesOptions options} parameter to specify the server timeout for the operation, the number
+ * of messages to retrieve, and the visibility timeout to set on the retrieved messages. When message processing is
+ * complete, each message must be deleted with a call to
+ * {@link QueueContract#deleteMessage(String, String, String, QueueServiceOptions) deleteMessage}. If message
+ * processing takes longer than the default timeout period, use the
+ * {@link QueueContract#updateMessage(String, String, String, String, int, QueueServiceOptions) updateMessage}
+ * method to extend the visibility timeout. Each message will become
+ * visible in the queue again when the timeout completes if it is not deleted.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to get the messages from.
+ * @param options
+ * A {@link ListMessagesOptions} instance containing options for the request.
+ * @return
+ * A {@link ListMessagesResult} reference to the message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
ListMessagesResult listMessages(String queue, ListMessagesOptions options) throws ServiceException;
+ /**
+ * Peeks a message from the named queue. A peek request retrieves a message from the head of the queue without
+ * changing its visibility.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to peek the message from.
+ * @return
+ * A {@link PeekMessagesResult} reference to the message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
PeekMessagesResult peekMessages(String queue) throws ServiceException;
+ /**
+ * Peeks messages from the named queue, using the specified options. A peek request retrieves messages from the
+ * head of the queue without changing their visibility. Use the {@link PeekMessagesOptions options} parameter to
+ * specify the server timeout for the operation and the number of messages to retrieve.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to peek the message from.
+ * @param options
+ * A {@link PeekMessagesOptions} instance containing options for the request.
+ * @return
+ * A {@link PeekMessagesResult} reference to the message result returned.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
PeekMessagesResult peekMessages(String queue, PeekMessagesOptions options) throws ServiceException;
+ /**
+ * Deletes all messages in the named queue.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to delete all messages from.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void clearMessages(String queue) throws ServiceException;
+ /**
+ * Deletes all messages in the named queue, using the specified options. Use the {@link QueueServiceOptions options}
+ * parameter to specify the server timeout for the operation.
+ *
+ * @param queue
+ * A {@link String} containing the name of the queue to delete all messages from.
+ * @param options
+ * A {@link QueueServiceOptions} instance containing options for the request.
+ * @throws ServiceException
+ * if an error occurs in the storage service.
+ */
void clearMessages(String queue, QueueServiceOptions options) throws ServiceException;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java
index c457b6b34d39f..a610b75007065 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java
@@ -2,36 +2,86 @@
* 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.queue;
import com.microsoft.windowsazure.services.core.Configuration;
+/**
+ * A class for static factory methods that return instances implementing {@link QueueContract}.
+ */
public class QueueService {
+ /**
+ * Private default constructor.
+ */
private QueueService() {
}
+ /**
+ * A static factory method that returns an instance implementing {@link QueueContract} using default values for
+ * initializing a {@link Configuration} instance. Note that the returned interface will not work unless storage
+ * account credentials have been added to the "META-INF/com.microsoft.windowsazure.properties" resource file.
+ *
+ * @return
+ * An instance implementing {@link QueueContract} for interacting with the queue service.
+ */
public static QueueContract create() {
return create(null, Configuration.getInstance());
}
+ /**
+ * A static factory method that returns an instance implementing {@link QueueContract} using the specified
+ * {@link Configuration} instance. The {@link Configuration} instance must have storage account information and
+ * credentials set before this method is called for the returned interface to work.
+ *
+ * @param config
+ * A {@link Configuration} instance configured with storage account information and credentials.
+ *
+ * @return
+ * An instance implementing {@link QueueContract} for interacting with the queue service.
+ */
public static QueueContract create(Configuration config) {
return create(null, config);
}
+ /**
+ * A static factory method that returns an instance implementing {@link QueueContract} using default values for
+ * initializing a {@link Configuration} instance, and using the specified profile prefix for service settings. Note
+ * that the returned interface will not work unless storage account settings and credentials have been added to the
+ * "META-INF/com.microsoft.windowsazure.properties" resource file with the specified profile prefix.
+ *
+ * @param profile
+ * A string prefix for the account name and credentials settings in the {@link Configuration} instance.
+ * @return
+ * An instance implementing {@link QueueContract} for interacting with the queue service.
+ */
public static QueueContract create(String profile) {
return create(profile, Configuration.getInstance());
}
+ /**
+ * A static factory method that returns an instance implementing {@link QueueContract} using the specified
+ * {@link Configuration} instance and profile prefix for service settings. The {@link Configuration} instance must
+ * have storage account information and credentials set with the specified profile prefix before this method is
+ * called for the returned interface to work.
+ *
+ * @param profile
+ * A string prefix for the account name and credentials settings in the {@link Configuration} instance.
+ * @param config
+ * A {@link Configuration} instance configured with storage account information and credentials.
+ *
+ * @return
+ * An instance implementing {@link QueueContract} for interacting with the queue service.
+ */
public static QueueContract create(String profile, Configuration config) {
return config.create(profile, QueueContract.class);
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java
index 4677d0431b818..5816a1bec264d 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java
@@ -152,6 +152,9 @@ public void createQueue(String queue) throws ServiceException {
}
public void createQueue(String queue, CreateQueueOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue);
WebResource.Builder builder = webResource.header("x-ms-version", API_VERSION);
@@ -165,6 +168,9 @@ public void deleteQueue(String queue) throws ServiceException {
}
public void deleteQueue(String queue, QueueServiceOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue);
WebResource.Builder builder = webResource.header("x-ms-version", API_VERSION);
@@ -195,6 +201,9 @@ public GetQueueMetadataResult getQueueMetadata(String queue) throws ServiceExcep
}
public GetQueueMetadataResult getQueueMetadata(String queue, QueueServiceOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).queryParam("comp", "metadata");
Builder builder = webResource.header("x-ms-version", API_VERSION);
@@ -216,6 +225,9 @@ public void setQueueMetadata(String queue, HashMap metadata) thr
public void setQueueMetadata(String queue, HashMap metadata, QueueServiceOptions options)
throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).queryParam("comp", "metadata");
WebResource.Builder builder = webResource.header("x-ms-version", API_VERSION);
@@ -229,6 +241,9 @@ public void createMessage(String queue, String messageText) throws ServiceExcept
}
public void createMessage(String queue, String messageText, CreateMessageOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages");
webResource = addOptionalQueryParam(webResource, "visibilitytimeout", options.getVisibilityTimeoutInSeconds());
webResource = addOptionalQueryParam(webResource, "messagettl", options.getTimeToLiveInSeconds());
@@ -249,6 +264,11 @@ public UpdateMessageResult updateMessage(String queue, String messageId, String
public UpdateMessageResult updateMessage(String queue, String messageId, String popReceipt, String messageText,
int visibilityTimeoutInSeconds, QueueServiceOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+ if (messageId == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages").path(messageId);
webResource = addOptionalQueryParam(webResource, "popreceipt", popReceipt);
webResource = addOptionalQueryParam(webResource, "visibilitytimeout", visibilityTimeoutInSeconds);
@@ -272,6 +292,9 @@ public ListMessagesResult listMessages(String queue) throws ServiceException {
}
public ListMessagesResult listMessages(String queue, ListMessagesOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages");
webResource = addOptionalQueryParam(webResource, "visibilitytimeout", options.getVisibilityTimeoutInSeconds());
webResource = addOptionalQueryParam(webResource, "numofmessages", options.getNumberOfMessages());
@@ -286,6 +309,9 @@ public PeekMessagesResult peekMessages(String queue) throws ServiceException {
}
public PeekMessagesResult peekMessages(String queue, PeekMessagesOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages").queryParam("peekonly", "true");
webResource = addOptionalQueryParam(webResource, "numofmessages", options.getNumberOfMessages());
@@ -300,6 +326,11 @@ public void deleteMessage(String queue, String messageId, String popReceipt) thr
public void deleteMessage(String queue, String messageId, String popReceipt, QueueServiceOptions options)
throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+ if (messageId == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages").path(messageId);
webResource = addOptionalQueryParam(webResource, "popreceipt", popReceipt);
@@ -313,6 +344,9 @@ public void clearMessages(String queue) throws ServiceException {
}
public void clearMessages(String queue, QueueServiceOptions options) throws ServiceException {
+ if (queue == null)
+ throw new NullPointerException();
+
WebResource webResource = getResource(options).path(queue).path("messages");
Builder builder = webResource.header("x-ms-version", API_VERSION);
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java
index f227771970f49..1ce3ba2a191b9 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java
@@ -2,41 +2,106 @@
* 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the options that may be set on the Queue service for
+ * {@link QueueContract#createMessage(String, String, CreateMessageOptions) createMessage} requests. These options
+ * include a server response timeout for the request, the visibility timeout to set on the created message, and the
+ * time-to-live value to set on the message.
+ */
public class CreateMessageOptions extends QueueServiceOptions {
private Integer visibilityTimeoutInSeconds;
private Integer timeToLiveInSeconds;
+ /**
+ * Sets the server request timeout value associated with this {@link CreateMessageOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link CreateMessageOptions} instance is
+ * passed as a parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link CreateMessageOptions} instance.
+ */
@Override
public CreateMessageOptions setTimeout(Integer timeout) {
super.setTimeout(timeout);
return this;
}
+ /**
+ * Gets the message visibility timeout in seconds value in this {@link CreateMessageOptions} instance.
+ * to set on messages when making a {@link QueueContract#createMessage(String, String, CreateMessageOptions)
+ * createMessage} request.
+ *
+ * @return
+ * The message visibility timeout in seconds.
+ */
public Integer getVisibilityTimeoutInSeconds() {
return visibilityTimeoutInSeconds;
}
+ /**
+ * Sets the message visibility timeout in seconds value to set on messages when making a
+ * {@link QueueContract#createMessage(String, String, CreateMessageOptions) createMessage} request. This allows
+ * messages to be loaded into the queue but not become visible until the visibility timeout has passed.
+ * Valid visibility timeout values range from 0 to 604800 seconds (0 to 7 days), and must be less than the
+ * time-to-live value.
+ *
+ * The visibilityTimeoutInSeconds value only affects calls made on methods where this
+ * {@link CreateMessageOptions} instance is passed as a parameter.
+ *
+ * @param visibilityTimeoutInSeconds
+ * The length of time during which the message will be invisible, starting when it is added to the queue,
+ * or 0 to make the message visible immediately. This value must be greater than or equal to zero and
+ * less than or equal to the time-to-live value.
+ * @return
+ * A reference to this {@link CreateMessageOptions} instance.
+ */
public CreateMessageOptions setVisibilityTimeoutInSeconds(Integer visibilityTimeoutInSeconds) {
this.visibilityTimeoutInSeconds = visibilityTimeoutInSeconds;
return this;
}
+ /**
+ * Gets the message time-to-live in seconds value associated with this {@link CreateMessageOptions} instance.
+ *
+ * @return
+ * The message time-to-live value in seconds.
+ */
public Integer getTimeToLiveInSeconds() {
return timeToLiveInSeconds;
}
+ /**
+ * Sets the message time-to-live timeout value to set on messages when making a
+ * {@link QueueContract#createMessage(String, String, CreateMessageOptions) createMessage} request. This is the
+ * maximum duration in seconds for the message to remain in the queue after it is created.
+ * Valid timeToLiveInSeconds values range from 0 to 604800 seconds (0 to 7 days), with the default value
+ * set to seven days.
+ *
+ * The timeToLiveInSeconds value only affects calls made on methods where this {@link CreateMessageOptions}
+ * instance is passed as a parameter.
+ *
+ * @param timeToLiveInSeconds
+ * The maximum time to allow the message to be in the queue, in seconds.
+ * @return
+ * A reference to this {@link CreateMessageOptions} instance.
+ */
public CreateMessageOptions setTimeToLiveInSeconds(Integer timeToLiveInSeconds) {
this.timeToLiveInSeconds = timeToLiveInSeconds;
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java
index cb79876571241..81ff8debedf30 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java
@@ -2,38 +2,92 @@
* 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.queue.models;
import java.util.HashMap;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the options that may be set on a queue when created in the storage service with a
+ * {@link QueueContract#createQueue(String, CreateQueueOptions) createQueue} request. These options include a server
+ * response timeout for the request and the metadata to associate with the created queue.
+ */
public class CreateQueueOptions extends QueueServiceOptions {
private HashMap metadata = new HashMap();
+ /**
+ * Sets the server request timeout value associated with this {@link CreateQueueOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link CreateQueueOptions} instance is
+ * passed as a parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link CreateQueueOptions} instance.
+ */
@Override
public CreateQueueOptions setTimeout(Integer timeout) {
super.setTimeout(timeout);
return this;
}
+ /**
+ * Gets the metadata collection of key-value {@link String} pairs to set on a queue when the queue is created.
+ *
+ * @return
+ * A {@link java.util.HashMap} of key-value {@link String} pairs containing the metadata to set on the
+ * queue.
+ */
public HashMap getMetadata() {
return metadata;
}
+ /**
+ * Sets the metadata collection of key-value {@link String} pairs to set on a queue when the queue is created. Queue
+ * metadata is a user-defined collection of key-value pairs that is opaque to the server.
+ *
+ * The metadata value is only added to a newly created queue where this {@link CreateQueueOptions} instance
+ * is passed as a parameter.
+ *
+ * @param metadata
+ * The {@link java.util.HashMap} of key-value {@link String} pairs containing the metadata to set on the
+ * queue.
+ * @return
+ * A reference to this {@link CreateQueueOptions} instance.
+ */
public CreateQueueOptions setMetadata(HashMap metadata) {
this.metadata = metadata;
return this;
}
+ /**
+ * Adds a key-value pair of {@link String} to the metadata collection to set on a queue when the queue is created.
+ * Queue metadata is a user-defined collection of key-value pairs that is opaque to the server. If the key already
+ * exists in the metadata collection, the value parameter will overwrite the existing value paired with that key
+ * without notification.
+ *
+ * The updated metadata is only added to a newly created queue where this {@link CreateQueueOptions} instance is
+ * passed as a parameter.
+ *
+ * @param key
+ * A {@link String} containing the key part of the key-value pair to add to the metadata.
+ * @param value
+ * A {@link String} containing the value part of the key-value pair to add to the metadata.
+ * @return
+ * A reference to this {@link CreateQueueOptions} instance.
+ */
public CreateQueueOptions addMetadata(String key, String value) {
this.metadata.put(key, value);
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java
index e412e00ece63a..b522a7c589e90 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java
@@ -2,36 +2,75 @@
* 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.queue.models;
import java.util.HashMap;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * A wrapper class for the result returned from a Queue Service REST API operation to get queue metadata. This is
+ * returned by calls to implementations of {@link QueueContract#getQueueMetadata(String)} and
+ * {@link QueueContract#getQueueMetadata(String, QueueServiceOptions)}.
+ *
+ * See the Get Queue Metadata
+ * documentation on MSDN for details of the underlying Queue Service REST API operation.
+ */
public class GetQueueMetadataResult {
private long approximateMessageCount;
private HashMap metadata;
+ /**
+ * Gets the queue's approximate message count, as reported by the server.
+ *
+ * @return
+ * The queue's approximate message count.
+ */
public long getApproximateMessageCount() {
return approximateMessageCount;
}
+ /**
+ * Reserved for internal use. This method is invoked by the API as part of the response generation from the
+ * Queue Service REST API operation to set the value for the approximate message count returned by the server.
+ *
+ * @param approximateMessageCount
+ * The queue's approximate message count to set.
+ */
public void setApproximateMessageCount(long approximateMessageCount) {
this.approximateMessageCount = approximateMessageCount;
}
+ /**
+ * Gets the metadata collection of key-value {@link String} pairs currently set on a queue. Queue metadata is a
+ * user-defined collection of key-value pairs that is opaque to the server.
+ *
+ * @return
+ * A {@link java.util.HashMap} of key-value {@link String} pairs containing the metadata set on the
+ * queue.
+ */
public HashMap getMetadata() {
return metadata;
}
+ /**
+ * Reserved for internal use. This method is invoked by the API as part of the response generation from the
+ * Queue Service REST API operation to set the value from the queue metadata returned by the server.
+ *
+ * @param metadata
+ * A {@link java.util.HashMap} of key-value {@link String} pairs containing the metadata set on the
+ * queue.
+ */
public void setMetadata(HashMap metadata) {
this.metadata = metadata;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java
index 2a7e788205659..4dff09479acf2 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java
@@ -2,25 +2,56 @@
* 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * A wrapper class for the service properties returned in response to Queue Service REST API operations. This is
+ * returned by calls to implementations of {@link QueueContract#getServiceProperties()} and
+ * {@link QueueContract#getServiceProperties(QueueServiceOptions)}.
+ *
+ * See the Get Queue Service Properties
+ * documentation on MSDN for details of the underlying Queue Service REST API operation.
+ */
public class GetServicePropertiesResult {
private ServiceProperties value;
+ /**
+ * Gets a {@link ServiceProperties} instance containing the service property values associated with the storage
+ * account.
+ *
+ * Modifying the values in the {@link ServiceProperties} instance returned does not affect the values associated
+ * with the storage account. To change the values in the storage account, call the
+ * {@link QueueContract#setServiceProperties} method and pass the modified {@link ServiceProperties} instance as a
+ * parameter.
+ *
+ * @return
+ * A {@link ServiceProperties} instance containing the property values associated with the storage account.
+ */
public ServiceProperties getValue() {
return value;
}
+ /**
+ * Reserved for internal use. Sets the value of the {@link ServiceProperties} instance associated with a
+ * storage service call result. This method is invoked by the API to store service properties returned by
+ * a call to a REST operation and is not intended for public use.
+ *
+ * @param value
+ * A {@link ServiceProperties} instance containing the property values associated with the storage
+ * account.
+ */
public void setValue(ServiceProperties value) {
this.value = value;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java
index 2aa19b6409441..0fb34021981c2 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java
@@ -2,41 +2,96 @@
* 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the options that may be set on a {@link QueueContract#listMessages(String, ListMessagesOptions)
+ * listMessages} request. These options include a server response timeout for the request, the number of messages to
+ * retrieve from the queue, and the visibility timeout to set on the retrieved messages.
+ */
public class ListMessagesOptions extends QueueServiceOptions {
private Integer numberOfMessages;
private Integer visibilityTimeoutInSeconds;
+ /**
+ * Sets the server request timeout value associated with this {@link ListMessagesOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link ListMessagesOptions} instance is
+ * passed as a parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link ListMessagesOptions} instance.
+ */
@Override
public ListMessagesOptions setTimeout(Integer timeout) {
super.setTimeout(timeout);
return this;
}
+ /**
+ * Gets the number of messages to request from the queue with this {@link ListMessagesOptions} instance.
+ *
+ * @return
+ * The number of messages requested.
+ */
public Integer getNumberOfMessages() {
return numberOfMessages;
}
+ /**
+ * Sets the number of messages to request from the queue with this {@link ListMessagesOptions} instance.
+ *
+ * The numberOfMessages value is only used for requests where this {@link ListMessagesOptions} instance is
+ * passed as a parameter.
+ *
+ * @param numberOfMessages
+ * The number of messages to request. The valid range of values is 0 to 32.
+ * @return
+ * A reference to this {@link ListMessagesOptions} instance.
+ */
public ListMessagesOptions setNumberOfMessages(Integer numberOfMessages) {
this.numberOfMessages = numberOfMessages;
return this;
}
+ /**
+ * Gets the visibility timeout to set on the messages requested from the queue with this {@link ListMessagesOptions}
+ * instance.
+ *
+ * @return
+ * The visibility timeout to set on the messages requested from the queue.
+ */
public Integer getVisibilityTimeoutInSeconds() {
return visibilityTimeoutInSeconds;
}
+ /**
+ * Sets the visibility timeout value to set on the messages requested from the queue with this
+ * {@link ListMessagesOptions} instance.
+ *
+ * The visibilityTimeoutInSeconds value is only used for requests where this {@link ListMessagesOptions}
+ * instance is passed as a parameter.
+ *
+ * @param visibilityTimeoutInSeconds
+ * The visibility timeout to set on the messages requested from the queue. The valid range of values is 0
+ * to 604800 seconds.
+ * @return
+ * A reference to this {@link ListMessagesOptions} instance.
+ */
public ListMessagesOptions setVisibilityTimeoutInSeconds(Integer visibilityTimeoutInSeconds) {
this.visibilityTimeoutInSeconds = visibilityTimeoutInSeconds;
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java
index af7c53f87ff18..facfb73283440 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.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.queue.models;
@@ -23,20 +23,50 @@
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.microsoft.windowsazure.services.blob.implementation.RFC1123DateAdapter;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+/**
+ * A wrapper class for the result returned from a Queue Service REST API operation to get a list of messages. This is
+ * returned by calls to implementations of {@link QueueContract#listMessages(String)} and
+ * {@link QueueContract#listMessages(String, ListMessagesOptions)}.
+ *
+ * See the Get Messages documentation
+ * on MSDN for details of the underlying Queue Service REST API operation.
+ */
@XmlRootElement(name = "QueueMessagesList")
public class ListMessagesResult {
private List queueMessages = new ArrayList();
+ /**
+ * Gets the list of queue messages returned by a {@link QueueContract}.listMessages request. The queue
+ * messages returned have their visibility timeout set to allow for processing by the client. The client must
+ * delete the messages once processing is complete, or they will become visible in the queue when the visibility
+ * timeout period is over.
+ *
+ * @return
+ * A {@link List} of {@link QueueMessage} instances representing the messages returned by the request.
+ */
@XmlElement(name = "QueueMessage")
public List getQueueMessages() {
return queueMessages;
}
+ /**
+ * Reserved for internal use. Sets the list of queue messages returned by a {@link QueueContract}
+ * .listMessages request. This method is invoked by the API as part of the response generation from the
+ * Queue Service REST API operation to set the value from the queue message list returned by the server.
+ *
+ * @param queueMessages
+ * A {@link List} of {@link QueueMessage} instances representing the messages returned by the request.
+ */
public void setQueueMessages(List queueMessages) {
this.queueMessages = queueMessages;
}
+ /**
+ * Represents a message in the queue returned by the server. A {@link QueueMessage} instance contains a copy of the
+ * queue message data in the storage service as of the time the message was requested.
+ */
public static class QueueMessage {
private String messageId;
private Date insertionDate;
@@ -46,68 +76,168 @@ public static class QueueMessage {
private int dequeueCount;
private String messageText;
+ /**
+ * Gets the message ID for the message in the queue. The message ID is a value that is opaque to the client
+ * that must be used along with the pop receipt to validate an update message or delete message operation.
+ *
+ * @return
+ * A {@link String} containing the message ID.
+ */
@XmlElement(name = "MessageId")
public String getMessageId() {
return messageId;
}
+ /**
+ * Reserved for internal use. Sets the value of the message ID for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the message ID returned by the server.
+ *
+ * @param messageId
+ * A {@link String} containing the message ID.
+ */
public void setMessageId(String messageId) {
this.messageId = messageId;
}
+ /**
+ * Gets the {@link Date} when this message was added to the queue.
+ *
+ * @return
+ * The {@link Date} when this message was added to the queue.
+ */
@XmlElement(name = "InsertionTime")
@XmlJavaTypeAdapter(RFC1123DateAdapter.class)
public Date getInsertionDate() {
return insertionDate;
}
+ /**
+ * Reserved for internal use. Sets the value of the insertion time for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the insertion time returned by the server.
+ *
+ * @param insertionDate
+ * The {@link Date} when this message was added to the queue.
+ */
public void setInsertionDate(Date insertionDate) {
this.insertionDate = insertionDate;
}
+ /**
+ * Gets the {@link Date} when this message will expire and be automatically removed from the queue.
+ *
+ * @return
+ * The {@link Date} when this message will expire.
+ */
@XmlElement(name = "ExpirationTime")
@XmlJavaTypeAdapter(RFC1123DateAdapter.class)
public Date getExpirationDate() {
return expirationDate;
}
+ /**
+ * Reserved for internal use. Sets the value of the expiration time for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the expiration time returned by the server.
+ *
+ * @param expirationDate
+ * The {@link Date} when this message will expire.
+ */
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
+ /**
+ * Gets the pop receipt value for the queue message. The pop receipt is a value that is opaque to the client
+ * that must be used along with the message ID to validate an update message or delete message operation.
+ *
+ * @return
+ * A {@link String} containing the pop receipt value for the queue message.
+ */
@XmlElement(name = "PopReceipt")
public String getPopReceipt() {
return popReceipt;
}
+ /**
+ * Reserved for internal use. Sets the value of the pop receipt for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the pop receipt returned by the server.
+ *
+ * @param popReceipt
+ * A {@link String} containing the pop receipt value for the queue message.
+ */
public void setPopReceipt(String popReceipt) {
this.popReceipt = popReceipt;
}
+ /**
+ * Gets the {@link Date} when this message will become visible in the queue.
+ *
+ * @return
+ * The {@link Date} when this message will become visible in the queue.
+ */
@XmlElement(name = "TimeNextVisible")
@XmlJavaTypeAdapter(RFC1123DateAdapter.class)
public Date getTimeNextVisible() {
return timeNextVisible;
}
+ /**
+ * Reserved for internal use. Sets the value of the time the message will become visible. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the time next visible returned by the server.
+ *
+ * @param timeNextVisible
+ * The {@link Date} when this message will become visible in the queue.
+ */
public void setTimeNextVisible(Date timeNextVisible) {
this.timeNextVisible = timeNextVisible;
}
+ /**
+ * Gets the number of times this queue message has been retrieved with a list messages operation.
+ *
+ * @return
+ * The number of times this queue message has been retrieved.
+ */
@XmlElement(name = "DequeueCount")
public int getDequeueCount() {
return dequeueCount;
}
+ /**
+ * Reserved for internal use. Sets the value of the dequeue count of the message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the queue message dequeue count returned by the server.
+ *
+ * @param dequeueCount
+ * The number of times this queue message has been retrieved.
+ */
public void setDequeueCount(int dequeueCount) {
this.dequeueCount = dequeueCount;
}
+ /**
+ * Gets the {@link String} containing the content of the queue message.
+ *
+ * @return
+ * A {@link String} containing the content of the queue message.
+ */
@XmlElement(name = "MessageText")
public String getMessageText() {
return messageText;
}
+ /**
+ * Reserved for internal use. Sets the {@link String} containing the content of the message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the queue message content returned by the server.
+ *
+ * @param messageText
+ * A {@link String} containing the content of the message.
+ */
public void setMessageText(String messageText) {
this.messageText = messageText;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java
index 6b62c7cacd2a7..7d4d346570b82 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java
@@ -2,61 +2,166 @@
* 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the options that may be set on the Queue service for {@link QueueContract#listQueues(ListQueuesOptions)}
+ * requests. These options include a server response timeout for the request, a prefix to match queue names to return, a
+ * marker to specify where to resume a list queues query, the maximum number of queues to return in a single response,
+ * and whether to include queue metadata with the response.
+ */
public class ListQueuesOptions extends QueueServiceOptions {
private String prefix;
private String marker;
private int maxResults;
private boolean includeMetadata;
+ /**
+ * Sets the server request timeout value associated with this {@link ListQueuesOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link ListQueuesOptions} instance is passed as a
+ * parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link ListQueuesOptions} instance.
+ */
@Override
public ListQueuesOptions setTimeout(Integer timeout) {
super.setTimeout(timeout);
return this;
}
+ /**
+ * Gets the prefix {@link String} used to match queue names to return in a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ *
+ * @return
+ * The prefix {@link String} used to match queue names to return in a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ */
public String getPrefix() {
return prefix;
}
+ /**
+ * Sets the prefix {@link String} to use to match queue names to return in a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ *
+ * The prefix value only affects calls made on methods where this {@link ListQueuesOptions} instance is passed as a
+ * parameter.
+ *
+ * @param prefix
+ * The prefix {@link String} to use to match queue names to return in a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ * @return
+ * A reference to this {@link ListQueuesOptions} instance.
+ */
public ListQueuesOptions setPrefix(String prefix) {
this.prefix = prefix;
return this;
}
+ /**
+ * Gets a {@link String} value that identifies the beginning of the list of queues to be returned with a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ *
+ * The {@link QueueContract#listQueues(ListQueuesOptions) listQueues} method returns a NextMarker
+ * element within the response if the list returned was not complete, which can be accessed with the
+ * {@link ListQueuesResult#getNextMarker()} method. This opaque value may then be set on a {@link ListQueuesOptions}
+ * instance with a call to {@link ListQueuesOptions#setMarker(String) setMarker} to be used in a subsequent
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} call to request the next portion of the list of
+ * queues.
+ *
+ * @return
+ * The marker value that identifies the beginning of the list of queues to be returned.
+ */
public String getMarker() {
return marker;
}
+ /**
+ * Sets a {@link String} marker value that identifies the beginning of the list of queues to be returned with a
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request.
+ *
+ * The {@link QueueContract#listQueues(ListQueuesOptions) listQueues} method returns a NextMarker
+ * element within the response if the list returned was not complete, which can be accessed with the
+ * {@link ListQueuesResult#getNextMarker()} method. This opaque value may then be set on a {@link ListQueuesOptions}
+ * instance with a call to {@link ListQueuesOptions#setMarker(String) setMarker} to be used in a subsequent
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} call to request the next portion of the list of
+ * queues.
+ *
+ * @param marker
+ * The {@link String} marker value to set.
+ * @return
+ * A reference to this {@link ListQueuesOptions} instance.
+ */
public ListQueuesOptions setMarker(String marker) {
this.marker = marker;
return this;
}
+ /**
+ * Gets the maximum number of queues to return with a {@link QueueContract#listQueues(ListQueuesOptions) listQueues}
+ * request. If the value is not specified, the server will return up to 5,000 items.
+ *
+ * @return
+ * The maximum number of queues to return.
+ */
public int getMaxResults() {
return maxResults;
}
+ /**
+ * Sets the maximum number of queues to return with a {@link QueueContract#listQueues(ListQueuesOptions) listQueues}
+ * request. If the value is not specified, by default the server will return up to 5,000 items.
+ *
+ * The maxResults value only affects calls made on methods where this {@link ListQueuesOptions} instance is passed
+ * as a parameter.
+ *
+ * @param maxResults
+ * The maximum number of queues to return.
+ * @return
+ * A reference to this {@link ListQueuesOptions} instance.
+ */
public ListQueuesOptions setMaxResults(int maxResults) {
this.maxResults = maxResults;
return this;
}
+ /**
+ * Gets a flag indicating whether to return metadata with a {@link QueueContract#listQueues(ListQueuesOptions)
+ * listQueues} request.
+ *
+ * @return
+ * true to return metadata.
+ */
public boolean isIncludeMetadata() {
return includeMetadata;
}
+ /**
+ * Sets a flag indicating whether to return metadata with a {@link QueueContract#listQueues(ListQueuesOptions)
+ * listQueues} request.
+ *
+ * @param includeMetadata
+ * true to return metadata.
+ * @return
+ * A reference to this {@link ListQueuesOptions} instance.
+ */
public ListQueuesOptions setIncludeMetadata(boolean includeMetadata) {
this.includeMetadata = includeMetadata;
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java
index 6dc3a704a930d..144dddada23c2 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.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.queue.models;
@@ -25,7 +25,16 @@
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.microsoft.windowsazure.services.blob.implementation.MetadataAdapter;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+/**
+ * A wrapper class for the results returned in response to Queue service REST API operations to list queues. This
+ * is returned by calls to implementations of {@link QueueContract#listQueues()} and
+ * {@link QueueContract#listQueues(ListQueuesOptions)}.
+ *
+ * See the List Queues documentation on
+ * MSDN for details of the underlying Queue service REST API operation.
+ */
@XmlRootElement(name = "EnumerationResults")
public class ListQueuesResult {
private List queues = new ArrayList();
@@ -35,90 +44,248 @@ public class ListQueuesResult {
private String nextMarker;
private int maxResults;
+ /**
+ * Gets the list of queues returned by a {@link QueueContract}.listQueues request.
+ *
+ * @return
+ * A {@link List} of {@link Queue} instances representing the queues returned by the request.
+ */
@XmlElementWrapper(name = "Queues")
@XmlElement(name = "Queue")
public List getQueues() {
return queues;
}
+ /**
+ * Reserved for internal use. Sets the list of queues returned by a {@link QueueContract}.listQueues
+ * request. This method is invoked by the API as part of the response generation from the Queue service REST API
+ * operation to set the value from the queue list returned by the server.
+ *
+ * @param value
+ * A {@link List} of {@link Queue} instances representing the queues returned by the request.
+ */
public void setQueues(List value) {
this.queues = value;
}
+ /**
+ * Gets the base URI for Queue service REST API operations on the storage account. The URI consists of the protocol
+ * along with the DNS prefix name for the account followed by ".queue.core.windows.net". For example, if the DNS
+ * prefix name for the storage account is "myaccount" then the value returned by this method is
+ * "http://myaccount.queue.core.windows.net".
+ *
+ * @return
+ * A {@link String} containing the base URI for Queue service REST API operations on the storage account.
+ */
@XmlAttribute(name = "AccountName")
public String getAccountName() {
return accountName;
}
+ /**
+ * Reserved for internal use. Sets the base URI for Queue service REST API operations on the storage account. This
+ * method is invoked by the API as part of the response generation from the Queue service REST API operation to set
+ * the value from the response returned by the server.
+ *
+ * @param accountName
+ * A {@link String} containing the base URI for Queue service REST API operations on the storage account.
+ */
public void setAccountName(String accountName) {
this.accountName = accountName;
}
+ /**
+ * Gets the prefix {@link String} used to qualify the results returned by the
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request. Only queues with names that start with
+ * the prefix are returned by the request. By default, the prefix is empty and all queues are returned.
+ *
+ * @return
+ * The {@link String} prefix used to qualify the names of the queues returned.
+ */
@XmlElement(name = "Prefix")
public String getPrefix() {
return prefix;
}
+ /**
+ * Reserved for internal use. Sets the prefix {@link String} used to qualify the results returned by the Queue
+ * service REST API list queues operation invoked with a call to {@link QueueContract#listQueues(ListQueuesOptions)
+ * listQueues}. This method is invoked by the API as part of the response generation from the Queue service REST API
+ * operation to set the value from the Prefix element returned by the server.
+ *
+ * @param prefix
+ * The {@link String} prefix used to qualify the names of the queues returned.
+ */
public void setPrefix(String prefix) {
this.prefix = prefix;
}
+ /**
+ * Gets the marker value for the beginning of the queue results returned by the
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request. The marker is used by the server to
+ * specify the place to resume a query for queues. The marker value is a {@link String} opaque to the client. A
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request response may include a
+ * NextMarker value if there are more queue results than can be returned in a single response. Call
+ * the {@link ListQueuesResult#getNextMarker() getNextMarker} method to get this value. The
+ * client can request the next set of queue results by setting the marker to this value in the
+ * {@link ListQueuesOptions} parameter. By default, this value is empty and the server responds with the first
+ * queues that match the request.
+ *
+ * @return
+ * A {@link String} containing the marker value used for the response.
+ */
@XmlElement(name = "Marker")
public String getMarker() {
return marker;
}
+ /**
+ * Reserved for internal use. Sets the marker value specifying the beginning of the results returned by the Queue
+ * service REST API list queues operation invoked with a call to {@link QueueContract#listQueues(ListQueuesOptions)
+ * listQueues}. This method is invoked by the API as part of the response generation from the Queue service REST API
+ * operation to set the value from the Marker element returned by the server.
+ *
+ * @param marker
+ * A {@link String} containing the marker value used for the response.
+ */
public void setMarker(String marker) {
this.marker = marker;
}
+ /**
+ * Gets the next marker value needed to retrieve additional queues. If more queues are available that satisfy a
+ * listQueues request than can be returned in the response, the server generates a marker value to specify
+ * the beginning of the queues to return in a subsequent request. The client can request the next set of queue
+ * results by setting the marker to this value in the {@link ListQueuesOptions} parameter. This value is
+ * empty if there are no more queues that satisfy the request than are included in the response.
+ *
+ * @return
+ * A {@link String} containing the marker value to use to resume the list queues request.
+ */
@XmlElement(name = "NextMarker")
public String getNextMarker() {
return nextMarker;
}
+ /**
+ * Reserved for internal use. Sets the next marker value specifying the place to resume a list queues query if more
+ * results are available than have been returned by the Queue service REST API list queues operation response. This
+ * method is invoked by the API as part of the response generation from the Queue service REST API operation to set
+ * the value from the NextMarker element returned by the server.
+ *
+ * @param nextMarker
+ * A {@link String} containing the marker value to use to resume the list queues request.
+ */
public void setNextMarker(String nextMarker) {
this.nextMarker = nextMarker;
}
+ /**
+ * Gets the value specified for the number of queue results to return for the
+ * {@link QueueContract#listQueues(ListQueuesOptions) listQueues} request. The server will not return more than this
+ * number of queues in the response. If the value is not specified, the server will return up to 5,000 items.
+ *
+ * If there are more queues available that match the request than the number returned, the response will include a
+ * next marker value to specify the beginning of the queues to return in a subsequent request. Call the
+ * {@link ListQueuesResult#getNextMarker() getNextMarker} method to get this value. The client can request the next
+ * set of queue results by setting the marker to this value in the {@link ListQueuesOptions} parameter.
+ *
+ * @return
+ * The maximum number of results to return specified by the request.
+ */
@XmlElement(name = "MaxResults")
public int getMaxResults() {
return maxResults;
}
+ /**
+ * Reserved for internal use. Sets the value returned by the Queue service REST API list queues operation response
+ * for the maximum number of queues to return. This method is invoked by the API as part of the response generation
+ * from the Queue service REST API operation to set the value from the MaxResults element returned
+ * by the server.
+ *
+ * @param maxResults
+ * The maximum number of results to return specified by the request.
+ */
public void setMaxResults(int maxResults) {
this.maxResults = maxResults;
}
+ /**
+ * Represents a queue in the storage account returned by the server. A {@link Queue} instance contains a copy of the
+ * queue name, URI, and metadata in the storage service as of the time the queue was requested.
+ */
public static class Queue {
private String name;
private String url;
private HashMap metadata = new HashMap();
+ /**
+ * Gets the name of this queue.
+ *
+ * @return
+ * A {@link String} containing the name of this queue.
+ */
@XmlElement(name = "Name")
public String getName() {
return name;
}
+ /**
+ * Reserved for internal use. Sets the name of this queue. This method is invoked by the API as part of the
+ * response generation from the Queue service REST API operation to set the value from the
+ * Name element returned by the server.
+ *
+ * @param name
+ * A {@link String} containing the name of this queue.
+ */
public void setName(String name) {
this.name = name;
}
+ /**
+ * Gets the URI for Queue service REST API operations on this queue.
+ *
+ * @return
+ * A {@link String} containing the URI for Queue service REST API operations on this queue.
+ */
@XmlElement(name = "Url")
public String getUrl() {
return url;
}
+ /**
+ * Reserved for internal use. Sets the URI of this queue. This method is invoked by the API as part of the
+ * response generation from the Queue service REST API operation to set the value from the
+ * Url element returned by the server.
+ *
+ * @param url
+ * A {@link String} containing the URI for Queue service REST API operations on this queue.
+ */
public void setUrl(String url) {
this.url = url;
}
+ /**
+ * Gets the metadata collection of key-value {@link String} pairs associated with this queue.
+ *
+ * @return
+ * A {@link java.util.HashMap} of key-value {@link String} pairs containing the queue metadata.
+ */
@XmlElement(name = "Metadata")
@XmlJavaTypeAdapter(MetadataAdapter.class)
public HashMap getMetadata() {
return metadata;
}
+ /**
+ * Reserved for internal use. Sets the metadata of this queue. This method is invoked by the API as part of the
+ * response generation from the Queue service REST API operation to set the value from the
+ * Metadata element returned by the server.
+ *
+ * @param metadata
+ * A {@link java.util.HashMap} of key-value {@link String} pairs containing the queue metadata.
+ */
public void setMetadata(HashMap metadata) {
this.metadata = metadata;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java
index 9339f83eb958b..eff229bf1657c 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java
@@ -2,31 +2,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
+ * 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the options that may be set on a {@link QueueContract#peekMessages(String, PeekMessagesOptions)
+ * peekMessages} request. These options include a server response timeout for the request and the number of messages to
+ * peek from the queue.
+ */
public class PeekMessagesOptions extends QueueServiceOptions {
private Integer numberOfMessages;
+ /**
+ * Sets the server request timeout value associated with this {@link PeekMessagesOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link PeekMessagesOptions} instance is passed as
+ * a parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link PeekMessagesOptions} instance.
+ */
@Override
public PeekMessagesOptions setTimeout(Integer timeout) {
super.setTimeout(timeout);
return this;
}
+ /**
+ * Gets the number of messages to return in the response to a
+ * {@link QueueContract#peekMessages(String, PeekMessagesOptions) peekMessages} request specified in this instance.
+ *
+ * @return
+ * The number of messages to return in the response.
+ */
public Integer getNumberOfMessages() {
return numberOfMessages;
}
+ /**
+ * Sets the number of messages to return in the response to a
+ * {@link QueueContract#peekMessages(String, PeekMessagesOptions) peekMessages} request.
+ *
+ * The numberOfMessages value only affects calls made on methods where this {@link PeekMessagesOptions}
+ * instance is passed as a parameter.
+ *
+ *
+ * @param numberOfMessages
+ * The number of messages to return in the response. This value must be in the range from 0 to 32.
+ * @return
+ * A reference to this {@link PeekMessagesOptions} instance.
+ */
public PeekMessagesOptions setNumberOfMessages(Integer numberOfMessages) {
this.numberOfMessages = numberOfMessages;
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java
index 79990e4391d69..602f2bee8e8c9 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.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.queue.models;
@@ -23,20 +23,49 @@
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.microsoft.windowsazure.services.blob.implementation.RFC1123DateAdapter;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+/**
+ * A wrapper class for the results returned in response to Queue Service REST API operations to peek messages. This
+ * is returned by calls to implementations of {@link QueueContract#peekMessages(String)} and
+ * {@link QueueContract#peekMessages(String, PeekMessagesOptions)}.
+ *
+ * See the Peek Messages documentation
+ * on MSDN for details of the underlying Queue Service REST API operation.
+ */
@XmlRootElement(name = "QueueMessagesList")
public class PeekMessagesResult {
private List queueMessages = new ArrayList();
+ /**
+ * Gets the list of queue messages returned by a {@link QueueContract}.peekMessages request. The queue
+ * messages returned do not have a visibility timeout set, and they can be retrieved by other clients for
+ * processing.
+ *
+ * @return
+ * A {@link List} of {@link QueueMessage} instances representing the messages returned by the request.
+ */
@XmlElement(name = "QueueMessage")
public List getQueueMessages() {
return queueMessages;
}
+ /**
+ * Reserved for internal use. Sets the list of queue messages returned by a {@link QueueContract}
+ * .peekMessages request. This method is invoked by the API as part of the response generation from the
+ * Queue Service REST API operation to set the value from the queue message list returned by the server.
+ *
+ * @param queueMessages
+ * A {@link List} of {@link QueueMessage} instances representing the messages returned by the request.
+ */
public void setQueueMessages(List queueMessages) {
this.queueMessages = queueMessages;
}
+ /**
+ * Represents a message in the queue returned by the server. A {@link QueueMessage} instance contains a copy of the
+ * queue message data in the storage service as of the time the message was requested.
+ */
public static class QueueMessage {
private String messageId;
private Date insertionDate;
@@ -44,49 +73,119 @@ public static class QueueMessage {
private int dequeueCount;
private String messageText;
+ /**
+ * Gets the message ID for the message in the queue. *
+ *
+ * @return
+ * A {@link String} containing the message ID.
+ */
@XmlElement(name = "MessageId")
public String getMessageId() {
return messageId;
}
+ /**
+ * Reserved for internal use. Sets the value of the message ID for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the message ID returned by the server.
+ *
+ * @param messageId
+ * A {@link String} containing the message ID.
+ */
public void setMessageId(String messageId) {
this.messageId = messageId;
}
+ /**
+ * Gets the {@link Date} when this message was added to the queue.
+ *
+ * @return
+ * The {@link Date} when this message was added to the queue.
+ */
@XmlElement(name = "InsertionTime")
@XmlJavaTypeAdapter(RFC1123DateAdapter.class)
public Date getInsertionDate() {
return insertionDate;
}
+ /**
+ * Reserved for internal use. Sets the value of the insertion time for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the insertion time returned by the server.
+ *
+ * @param insertionDate
+ * The {@link Date} when this message was added to the queue.
+ */
public void setInsertionDate(Date insertionDate) {
this.insertionDate = insertionDate;
}
+ /**
+ * Gets the {@link Date} when this message will expire and be automatically removed from the queue.
+ *
+ * @return
+ * The {@link Date} when this message will expire.
+ */
@XmlElement(name = "ExpirationTime")
@XmlJavaTypeAdapter(RFC1123DateAdapter.class)
public Date getExpirationDate() {
return expirationDate;
}
+ /**
+ * Reserved for internal use. Sets the value of the expiration time for the queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the expiration time returned by the server.
+ *
+ * @param expirationDate
+ * The {@link Date} when this message will expire.
+ */
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
+ /**
+ * Gets the number of times this queue message has been retrieved with a list messages operation.
+ *
+ * @return
+ * The number of times this queue message has been retrieved.
+ */
@XmlElement(name = "DequeueCount")
public int getDequeueCount() {
return dequeueCount;
}
+ /**
+ * Reserved for internal use. Sets the value of the dequeue count of the message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the queue message dequeue count returned by the server.
+ *
+ * @param dequeueCount
+ * The number of times this queue message has been retrieved.
+ */
public void setDequeueCount(int dequeueCount) {
this.dequeueCount = dequeueCount;
}
+ /**
+ * Gets the {@link String} containing the content of the queue message.
+ *
+ * @return
+ * A {@link String} containing the content of the queue message.
+ */
@XmlElement(name = "MessageText")
public String getMessageText() {
return messageText;
}
+ /**
+ * Reserved for internal use. Sets the {@link String} containing the content of the message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the queue message content returned by the server.
+ *
+ * @param messageText
+ * A {@link String} containing the content of the message.
+ */
public void setMessageText(String messageText) {
this.messageText = messageText;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java
index ff574f82e1790..9f22a1f5fa1bc 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java
@@ -2,26 +2,52 @@
* 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.queue.models;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * Represents the base class for options that may be set on Queue Service REST API operations invoked through the
+ * {@link QueueContract} interface. This class defines a server request timeout, which can be applied to all operations.
+ */
public class QueueServiceOptions {
// Nullable because it is optional
private Integer timeout;
+ /**
+ * Gets the current server request timeout value associated with this {@link QueueServiceOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link QueueServiceOptions} instance is passed as
+ * a parameter.
+ *
+ * @return
+ * The server request timeout value in milliseconds.
+ */
public Integer getTimeout() {
return timeout;
}
+ /**
+ * Sets the server request timeout value associated with this {@link QueueServiceOptions} instance.
+ *
+ * The timeout value only affects calls made on methods where this {@link QueueServiceOptions} instance is passed as
+ * a parameter.
+ *
+ * @param timeout
+ * The server request timeout value to set in milliseconds.
+ * @return
+ * A reference to this {@link QueueServiceOptions} instance.
+ */
public QueueServiceOptions setTimeout(Integer timeout) {
this.timeout = timeout;
return this;
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java
index f676d600b63b7..9f2715a7fe0d6 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java
@@ -2,44 +2,106 @@
* 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.queue.models;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * A wrapper class for the Queue service properties set or retrieved with Queue Service REST API operations. This
+ * is returned by calls to implementations of {@link QueueContract#getServiceProperties()} and
+ * {@link QueueContract#getServiceProperties(QueueServiceOptions)} and passed to the server with calls to
+ * {@link QueueContract#setServiceProperties(ServiceProperties)} and
+ * {@link QueueContract#setServiceProperties(ServiceProperties, QueueServiceOptions)}.
+ *
+ * See the Get Queue Service Properties
+ * and Set Queue Service Properties
+ * documentation on MSDN for details of the underlying Queue Service REST API operations. See the Storage Analytics Overview
+ * documentation on MSDN for more information about logging and metrics.
+ */
@XmlRootElement(name = "StorageServiceProperties")
public class ServiceProperties {
private Logging logging = new Logging();
private Metrics metrics = new Metrics();
+ /**
+ * Gets a reference to the {@link Logging} instance in this {@link ServiceProperties} instance.
+ *
+ * This {@link ServiceProperties} instance holds a local copy of the Queue service properties when returned by a
+ * call to {@link QueueContract}.getServiceProperties.
+ *
+ * Note that changes to this value are not reflected in the Queue service properties until they have been set on the
+ * storage account with a call to {@link QueueContract}.setServiceProperties.
+ *
+ * @return
+ * A reference to the {@link Logging} instance in this {@link ServiceProperties} instance.
+ */
@XmlElement(name = "Logging")
public Logging getLogging() {
return logging;
}
+ /**
+ * Sets the {@link Logging} instance in this {@link ServiceProperties} instance.
+ *
+ * Note that changes to this value are not reflected in the Queue service properties until they have been set on the
+ * storage account with a call to {@link QueueContract}.setServiceProperties.
+ *
+ * @param logging
+ * The {@link Logging} instance to set in this {@link ServiceProperties} instance.
+ */
public void setLogging(Logging logging) {
this.logging = logging;
}
+ /**
+ * Gets a reference to the {@link Metrics} instance in this {@link ServiceProperties} instance.
+ *
+ * This {@link ServiceProperties} instance holds a local copy of the Queue service properties when returned by a
+ * call to {@link QueueContract}.getServiceProperties.
+ *
+ * Note that changes to this value are not reflected in the Queue service properties until they have been set on the
+ * storage account with a call to {@link QueueContract}.setServiceProperties.
+ *
+ * @return
+ * A reference to the {@link Metrics} instance in this {@link ServiceProperties} instance.
+ */
@XmlElement(name = "Metrics")
public Metrics getMetrics() {
return metrics;
}
+ /**
+ * Sets the {@link Metrics} instance in this {@link ServiceProperties} instance.
+ *
+ * Note that changes to this value are not reflected in the Queue service properties until they have been set on the
+ * storage account with a call to {@link QueueContract}.setServiceProperties.
+ *
+ * @param metrics
+ * The {@link Metrics} instance to set in this {@link ServiceProperties} instance.
+ */
public void setMetrics(Metrics metrics) {
this.metrics = metrics;
}
+ /**
+ * This inner class represents the settings for logging on the Queue service of the storage account. These settings
+ * include the Storage Analytics version, whether to log delete requests, read requests, or write requests, and a
+ * {@link RetentionPolicy} instance for retention policy settings.
+ */
public static class Logging {
private String version;
private Boolean delete;
@@ -47,113 +109,283 @@ public static class Logging {
private Boolean write;
private RetentionPolicy retentionPolicy;
+ /**
+ * Gets a reference to the {@link RetentionPolicy} instance in this {@link Logging} instance.
+ *
+ * @return
+ * A reference to the {@link RetentionPolicy} instance in this {@link Logging} instance.
+ */
@XmlElement(name = "RetentionPolicy")
public RetentionPolicy getRetentionPolicy() {
return retentionPolicy;
}
+ /**
+ * Sets the {@link RetentionPolicy} instance in this {@link Logging} instance.
+ *
+ * @param retentionPolicy
+ * The {@link RetentionPolicy} instance to set in this {@link Logging} instance.
+ */
public void setRetentionPolicy(RetentionPolicy retentionPolicy) {
this.retentionPolicy = retentionPolicy;
}
+ /**
+ * Gets a flag indicating whether queue write operations are logged. If this value is true then all
+ * requests that write to the Queue service will be logged. These requests include adding a message, updating a
+ * message, setting queue metadata, and creating a queue.
+ *
+ * @return
+ * true if queue write operations are logged, otherwise false.
+ */
@XmlElement(name = "Write")
public boolean isWrite() {
return write;
}
+ /**
+ * Sets a flag indicating whether queue write operations are logged. If this value is true then all
+ * requests that write to the Queue service will be logged. These requests include adding a message, updating a
+ * message, setting queue metadata, and creating a queue.
+ *
+ * @param write
+ * true to enable logging of queue write operations, otherwise false.
+ */
public void setWrite(boolean write) {
this.write = write;
}
+ /**
+ * Gets a flag indicating whether queue read operations are logged. If this value is true then all
+ * requests that read from the Queue service will be logged. These requests include listing queues, getting
+ * queue metadata, listing messages, and peeking messages.
+ *
+ * @return
+ * true if queue read operations are logged, otherwise false.
+ */
@XmlElement(name = "Read")
public boolean isRead() {
return read;
}
+ /**
+ * Sets a flag indicating whether queue read operations are logged. If this value is true then all
+ * requests that read from the Queue service will be logged. These requests include listing queues, getting
+ * queue metadata, listing messages, and peeking messages.
+ *
+ * @param read
+ * true to enable logging of queue read operations, otherwise false.
+ */
public void setRead(boolean read) {
this.read = read;
}
+ /**
+ * Gets a flag indicating whether queue delete operations are logged. If this value is true then
+ * all requests that delete from the Queue service will be logged. These requests include deleting queues,
+ * deleting messages, and clearing messages.
+ *
+ * @return
+ * true if queue delete operations are logged, otherwise false.
+ */
@XmlElement(name = "Delete")
public boolean isDelete() {
return delete;
}
+ /**
+ * Sets a flag indicating whether queue delete operations are logged. If this value is true then
+ * all requests that delete from the Queue service will be logged. These requests include deleting queues,
+ * deleting messages, and clearing messages.
+ *
+ * @param delete
+ * true to enable logging of queue delete operations, otherwise false.
+ */
public void setDelete(boolean delete) {
this.delete = delete;
}
+ /**
+ * Gets the Storage Analytics version number associated with this {@link Logging} instance.
+ *
+ * @return
+ * A {@link String} containing the Storage Analytics version number.
+ */
@XmlElement(name = "Version")
public String getVersion() {
return version;
}
+ /**
+ * Sets the Storage Analytics version number to associate with this {@link Logging} instance. The current
+ * supported
+ * version number is "1.0".
+ *
+ * See the Storage Analytics
+ * Overview documentation on MSDN for more information.
+ *
+ * @param version
+ * A {@link String} containing the Storage Analytics version number to set.
+ */
public void setVersion(String version) {
this.version = version;
}
}
+ /**
+ * This inner class represents the settings for metrics on the Queue service of the storage account. These settings
+ * include the Storage Analytics version, whether metrics are enabled, whether to include API operation summary
+ * statistics, and a {@link RetentionPolicy} instance for retention policy settings.
+ */
public static class Metrics {
private String version;
private boolean enabled;
private Boolean includeAPIs;
private RetentionPolicy retentionPolicy;
+ /**
+ * Gets a reference to the {@link RetentionPolicy} instance in this {@link Metrics} instance.
+ *
+ * @return
+ * A reference to the {@link RetentionPolicy} instance in this {@link Metrics} instance.
+ */
@XmlElement(name = "RetentionPolicy")
public RetentionPolicy getRetentionPolicy() {
return retentionPolicy;
}
+ /**
+ * Sets the {@link RetentionPolicy} instance in this {@link Metrics} instance.
+ *
+ * @param retentionPolicy
+ * The {@link RetentionPolicy} instance to set in this {@link Metrics} instance.
+ */
public void setRetentionPolicy(RetentionPolicy retentionPolicy) {
this.retentionPolicy = retentionPolicy;
}
+ /**
+ * Gets a flag indicating whether metrics should generate summary statistics for called API operations. If this
+ * value is true then all Queue service REST API operations will be included in the metrics.
+ *
+ * @return
+ * true if Queue service REST API operations are included in metrics, otherwise
+ * false.
+ */
@XmlElement(name = "IncludeAPIs")
public Boolean isIncludeAPIs() {
return includeAPIs;
}
+ /**
+ * Sets a flag indicating whether metrics should generate summary statistics for called API operations. If this
+ * value is true then all Queue service REST API operations will be included in the metrics.
+ *
+ * @param includeAPIs
+ * true to include Queue service REST API operations in metrics, otherwise
+ * false.
+ */
public void setIncludeAPIs(Boolean includeAPIs) {
this.includeAPIs = includeAPIs;
}
+ /**
+ * Gets a flag indicating whether metrics is enabled for the Queue storage service.
+ *
+ * @return
+ * A flag indicating whether metrics is enabled for the Queue storage service.
+ */
@XmlElement(name = "Enabled")
public boolean isEnabled() {
return enabled;
}
+ /**
+ * Sets a flag indicating whether to enable metrics for the Queue storage service.
+ *
+ * @param enabled
+ * true to enable metrics for the Queue storage service, otherwise false.
+ */
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
+ /**
+ * Gets the Storage Analytics version number associated with this {@link Metrics} instance.
+ *
+ * @return
+ * A {@link String} containing the Storage Analytics version number.
+ */
@XmlElement(name = "Version")
public String getVersion() {
return version;
}
+ /**
+ * Sets the Storage Analytics version number to associate with this {@link Metrics} instance. The current
+ * supported version number is "1.0".
+ *
+ * See the Storage Analytics
+ * Overview documentation on MSDN for more information.
+ *
+ * @param version
+ * A {@link String} containing the Storage Analytics version number to set.
+ */
public void setVersion(String version) {
this.version = version;
}
}
+ /**
+ * This inner class represents the retention policy settings for logging or metrics on the Queue service of the
+ * storage account. These settings include whether a retention policy is enabled for the data, and the number of
+ * days that metrics or logging data should be retained.
+ */
public static class RetentionPolicy {
private boolean enabled;
private Integer days; // nullable, because optional if "enabled" is false
+ /**
+ * Gets the number of days that metrics or logging data should be retained. All data older than this value will
+ * be deleted. The value may be null if a retention policy is not enabled.
+ *
+ * @return
+ * The number of days that metrics or logging data should be retained.
+ */
@XmlElement(name = "Days")
public Integer getDays() {
return days;
}
+ /**
+ * Sets the number of days that metrics or logging data should be retained. All data older than this value will
+ * be deleted. The value must be in the range from 1 to 365. This value must be set if a retention policy is
+ * enabled, but is not required if a retention policy is not enabled.
+ *
+ * @param days
+ * The number of days that metrics or logging data should be retained.
+ */
public void setDays(Integer days) {
this.days = days;
}
+ /**
+ * Gets a flag indicating whether a retention policy is enabled for the storage service.
+ *
+ * @return
+ * true if data retention is enabled, otherwise false.
+ */
@XmlElement(name = "Enabled")
public boolean isEnabled() {
return enabled;
}
+ /**
+ * Sets a flag indicating whether a retention policy is enabled for the storage service.
+ *
+ * @param enabled
+ * Set true to enable data retention.
+ */
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java
index a57f8be013ffe..7c81179931e43 100644
--- a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java
@@ -2,36 +2,75 @@
* 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.queue.models;
import java.util.Date;
+import com.microsoft.windowsazure.services.queue.QueueContract;
+
+/**
+ * A wrapper class for the results returned in response to Queue Service REST API operations to update a message. This
+ * is returned by calls to implementations of {@link QueueContract#updateMessage(String, String, String, String, int)}
+ * and {@link QueueContract#updateMessage(String, String, String, String, int, QueueServiceOptions)}.
+ *
+ * See the Update Message documentation
+ * on MSDN for details of the underlying Queue Service REST API operation.
+ */
public class UpdateMessageResult {
private String popReceipt;
private Date timeNextVisible;
+ /**
+ * Gets the pop receipt value for the updated queue message. The pop receipt is a value that is opaque to the client
+ * that must be used along with the message ID to validate an update message or delete message operation.
+ *
+ * @return
+ * A {@link String} containing the pop receipt value for the queue message.
+ */
public String getPopReceipt() {
return popReceipt;
}
+ /**
+ * Reserved for internal use. Sets the value of the pop receipt for the updated queue message. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the pop receipt returned by the server.
+ *
+ * @param popReceipt
+ * A {@link String} containing the pop receipt value for the queue message.
+ */
public void setPopReceipt(String popReceipt) {
this.popReceipt = popReceipt;
}
+ /**
+ * Gets the {@link Date} when the updated message will become visible in the queue.
+ *
+ * @return
+ * The {@link Date} when the updated message will become visible in the queue.
+ */
public Date getTimeNextVisible() {
return timeNextVisible;
}
+ /**
+ * Reserved for internal use. Sets the value of the time the updated message will become visible. This method is
+ * invoked by the API as part of the response generation from the Queue Service REST API operation to set the
+ * value with the time next visible returned by the server.
+ *
+ * @param timeNextVisible
+ * The {@link Date} when the updated message will become visible in the queue.
+ */
public void setTimeNextVisible(Date timeNextVisible) {
this.timeNextVisible = timeNextVisible;
}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html
new file mode 100644
index 0000000000000..6d2f45a3fae7d
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html
@@ -0,0 +1,5 @@
+
+
+This package contains the queue data transfer object classes.
+
+
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/package.html b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/package.html
new file mode 100644
index 0000000000000..4847f5461cb62
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/queue/package.html
@@ -0,0 +1,5 @@
+
+
+This package contains the queue service class, interface, and associated configuration and utility classes.
+
+
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/EdmValueConverter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/EdmValueConverter.java
new file mode 100644
index 0000000000000..4a6fd5fb37fbc
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/EdmValueConverter.java
@@ -0,0 +1,21 @@
+/**
+ * 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.table;
+
+public interface EdmValueConverter {
+ String serialize(String edmType, Object value);
+
+ Object deserialize(String edmType, String value);
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/Exports.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/Exports.java
new file mode 100644
index 0000000000000..ad0334ab03de4
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/Exports.java
@@ -0,0 +1,43 @@
+/**
+ * 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.table;
+
+import com.microsoft.windowsazure.services.core.Builder;
+import com.microsoft.windowsazure.services.table.implementation.AtomReaderWriter;
+import com.microsoft.windowsazure.services.table.implementation.DefaultEdmValueConterter;
+import com.microsoft.windowsazure.services.table.implementation.DefaultXMLStreamFactory;
+import com.microsoft.windowsazure.services.table.implementation.HttpReaderWriter;
+import com.microsoft.windowsazure.services.table.implementation.MimeReaderWriter;
+import com.microsoft.windowsazure.services.table.implementation.SharedKeyFilter;
+import com.microsoft.windowsazure.services.table.implementation.SharedKeyLiteFilter;
+import com.microsoft.windowsazure.services.table.implementation.TableExceptionProcessor;
+import com.microsoft.windowsazure.services.table.implementation.TableRestProxy;
+import com.microsoft.windowsazure.services.table.implementation.XMLStreamFactory;
+
+public class Exports implements Builder.Exports {
+ @Override
+ public void register(Builder.Registry registry) {
+ registry.add(TableContract.class, TableExceptionProcessor.class);
+ registry.add(TableExceptionProcessor.class);
+ registry.add(TableRestProxy.class);
+ registry.add(SharedKeyLiteFilter.class);
+ registry.add(SharedKeyFilter.class);
+ registry.add(XMLStreamFactory.class, DefaultXMLStreamFactory.class);
+ registry.add(AtomReaderWriter.class);
+ registry.add(MimeReaderWriter.class);
+ registry.add(HttpReaderWriter.class);
+ registry.add(EdmValueConverter.class, DefaultEdmValueConterter.class);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableConfiguration.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableConfiguration.java
new file mode 100644
index 0000000000000..33391fc9e711f
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableConfiguration.java
@@ -0,0 +1,21 @@
+/**
+ * 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.table;
+
+public class TableConfiguration {
+ public final static String ACCOUNT_NAME = "table.accountName";
+ public final static String ACCOUNT_KEY = "table.accountKey";
+ public final static String URI = "table.uri";
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableContract.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableContract.java
new file mode 100644
index 0000000000000..2bb4e1a3ac6ae
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableContract.java
@@ -0,0 +1,99 @@
+/**
+ * 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.table;
+
+import com.microsoft.windowsazure.services.core.FilterableService;
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.table.models.BatchOperations;
+import com.microsoft.windowsazure.services.table.models.BatchResult;
+import com.microsoft.windowsazure.services.table.models.DeleteEntityOptions;
+import com.microsoft.windowsazure.services.table.models.Entity;
+import com.microsoft.windowsazure.services.table.models.GetEntityResult;
+import com.microsoft.windowsazure.services.table.models.GetServicePropertiesResult;
+import com.microsoft.windowsazure.services.table.models.GetTableResult;
+import com.microsoft.windowsazure.services.table.models.InsertEntityResult;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesResult;
+import com.microsoft.windowsazure.services.table.models.QueryTablesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryTablesResult;
+import com.microsoft.windowsazure.services.table.models.ServiceProperties;
+import com.microsoft.windowsazure.services.table.models.TableServiceOptions;
+import com.microsoft.windowsazure.services.table.models.UpdateEntityResult;
+
+public interface TableContract extends FilterableService {
+ GetServicePropertiesResult getServiceProperties() throws ServiceException;
+
+ GetServicePropertiesResult getServiceProperties(TableServiceOptions options) throws ServiceException;
+
+ void setServiceProperties(ServiceProperties serviceProperties) throws ServiceException;
+
+ void setServiceProperties(ServiceProperties serviceProperties, TableServiceOptions options) throws ServiceException;
+
+ void createTable(String table) throws ServiceException;
+
+ void createTable(String table, TableServiceOptions options) throws ServiceException;
+
+ void deleteTable(String table) throws ServiceException;
+
+ void deleteTable(String table, TableServiceOptions options) throws ServiceException;
+
+ GetTableResult getTable(String table) throws ServiceException;
+
+ GetTableResult getTable(String table, TableServiceOptions options) throws ServiceException;
+
+ QueryTablesResult queryTables() throws ServiceException;
+
+ QueryTablesResult queryTables(QueryTablesOptions options) throws ServiceException;
+
+ InsertEntityResult insertEntity(String table, Entity entity) throws ServiceException;
+
+ InsertEntityResult insertEntity(String table, Entity entity, TableServiceOptions options) throws ServiceException;
+
+ UpdateEntityResult updateEntity(String table, Entity entity) throws ServiceException;
+
+ UpdateEntityResult updateEntity(String table, Entity entity, TableServiceOptions options) throws ServiceException;
+
+ UpdateEntityResult mergeEntity(String table, Entity entity) throws ServiceException;
+
+ UpdateEntityResult mergeEntity(String table, Entity entity, TableServiceOptions options) throws ServiceException;
+
+ UpdateEntityResult insertOrReplaceEntity(String table, Entity entity) throws ServiceException;
+
+ UpdateEntityResult insertOrReplaceEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException;
+
+ UpdateEntityResult insertOrMergeEntity(String table, Entity entity) throws ServiceException;
+
+ UpdateEntityResult insertOrMergeEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException;
+
+ void deleteEntity(String table, String partitionKey, String rowKey) throws ServiceException;
+
+ void deleteEntity(String table, String partitionKey, String rowKey, DeleteEntityOptions options)
+ throws ServiceException;
+
+ GetEntityResult getEntity(String table, String partitionKey, String rowKey) throws ServiceException;
+
+ GetEntityResult getEntity(String table, String partitionKey, String rowKey, TableServiceOptions options)
+ throws ServiceException;
+
+ QueryEntitiesResult queryEntities(String table) throws ServiceException;
+
+ QueryEntitiesResult queryEntities(String table, QueryEntitiesOptions options) throws ServiceException;
+
+ BatchResult batch(BatchOperations operations) throws ServiceException;
+
+ BatchResult batch(BatchOperations operations, TableServiceOptions options) throws ServiceException;
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableService.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableService.java
new file mode 100644
index 0000000000000..c37f20da147f8
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/TableService.java
@@ -0,0 +1,38 @@
+/**
+ * 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.table;
+
+import com.microsoft.windowsazure.services.core.Configuration;
+
+public class TableService {
+ private TableService() {
+ }
+
+ public static TableContract create() {
+ return create(null, Configuration.getInstance());
+ }
+
+ public static TableContract create(Configuration config) {
+ return create(null, config);
+ }
+
+ public static TableContract create(String profile) {
+ return create(profile, Configuration.getInstance());
+ }
+
+ public static TableContract create(String profile, Configuration config) {
+ return config.create(profile, TableContract.class);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriter.java
new file mode 100644
index 0000000000000..ddff3f9aa8895
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriter.java
@@ -0,0 +1,330 @@
+/**
+ * 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.table.implementation;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.inject.Inject;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import com.microsoft.windowsazure.services.blob.implementation.ISO8601DateConverter;
+import com.microsoft.windowsazure.services.core.utils.DateFactory;
+import com.microsoft.windowsazure.services.table.EdmValueConverter;
+import com.microsoft.windowsazure.services.table.models.Entity;
+import com.microsoft.windowsazure.services.table.models.Property;
+import com.microsoft.windowsazure.services.table.models.TableEntry;
+
+public class AtomReaderWriter {
+ private final XMLStreamFactory xmlStreamFactory;
+ private final DateFactory dateFactory;
+ private final ISO8601DateConverter iso8601DateConverter;
+ private final EdmValueConverter edmValueConverter;
+
+ @Inject
+ public AtomReaderWriter(XMLStreamFactory xmlStreamFactory, DateFactory dateFactory,
+ ISO8601DateConverter iso8601DateConverter, EdmValueConverter edmValueConverter) {
+ this.xmlStreamFactory = xmlStreamFactory;
+ this.dateFactory = dateFactory;
+ this.iso8601DateConverter = iso8601DateConverter;
+ this.edmValueConverter = edmValueConverter;
+ }
+
+ public InputStream generateTableEntry(String table) {
+ final String tableTemp = table;
+ return generateEntry(new PropertiesWriter() {
+ @Override
+ public void write(XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeStartElement("d:TableName");
+ writer.writeCharacters(tableTemp);
+ writer.writeEndElement(); // d:TableName
+ }
+ });
+ }
+
+ public InputStream generateEntityEntry(Entity entity) {
+ final Entity entityTemp = entity;
+ return generateEntry(new PropertiesWriter() {
+ @Override
+ public void write(XMLStreamWriter writer) throws XMLStreamException {
+ for (Entry entry : entityTemp.getProperties().entrySet()) {
+ writer.writeStartElement("d:" + entry.getKey());
+
+ String edmType = entry.getValue().getEdmType();
+ if (edmType != null) {
+ writer.writeAttribute("m:type", edmType);
+ }
+
+ String value = edmValueConverter.serialize(edmType, entry.getValue().getValue());
+ if (value != null) {
+ writer.writeCharacters(value);
+ }
+ else {
+ writer.writeAttribute("m:null", "true");
+ }
+
+ writer.writeEndElement(); // property name
+
+ }
+ }
+ });
+ }
+
+ public List parseTableEntries(InputStream stream) {
+ try {
+ XMLStreamReader xmlr = xmlStreamFactory.getReader(stream);
+
+ expect(xmlr, XMLStreamConstants.START_DOCUMENT);
+ expect(xmlr, XMLStreamConstants.START_ELEMENT, "feed");
+
+ List result = new ArrayList();
+ while (!isEndElement(xmlr, "feed")) {
+ // Process "entry" elements only
+ if (isStartElement(xmlr, "entry")) {
+ result.add(parseTableEntry(xmlr));
+ }
+ else {
+ nextSignificant(xmlr);
+ }
+ }
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, "feed");
+ expect(xmlr, XMLStreamConstants.END_DOCUMENT);
+
+ return result;
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public TableEntry parseTableEntry(InputStream stream) {
+ try {
+ XMLStreamReader xmlr = xmlStreamFactory.getReader(stream);
+
+ expect(xmlr, XMLStreamConstants.START_DOCUMENT);
+ TableEntry result = parseTableEntry(xmlr);
+ expect(xmlr, XMLStreamConstants.END_DOCUMENT);
+
+ return result;
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List parseEntityEntries(InputStream stream) {
+ try {
+ XMLStreamReader xmlr = xmlStreamFactory.getReader(stream);
+
+ expect(xmlr, XMLStreamConstants.START_DOCUMENT);
+ expect(xmlr, XMLStreamConstants.START_ELEMENT, "feed");
+
+ List result = new ArrayList();
+ while (!isEndElement(xmlr, "feed")) {
+ // Process "entry" elements only
+ if (isStartElement(xmlr, "entry")) {
+ result.add(parseEntityEntry(xmlr));
+ }
+ else {
+ nextSignificant(xmlr);
+ }
+ }
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, "feed");
+ expect(xmlr, XMLStreamConstants.END_DOCUMENT);
+
+ return result;
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Entity parseEntityEntry(InputStream stream) {
+ try {
+ XMLStreamReader xmlr = xmlStreamFactory.getReader(stream);
+
+ expect(xmlr, XMLStreamConstants.START_DOCUMENT);
+ Entity result = parseEntityEntry(xmlr);
+ expect(xmlr, XMLStreamConstants.END_DOCUMENT);
+
+ return result;
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private interface PropertiesWriter {
+ void write(XMLStreamWriter writer) throws XMLStreamException;
+ }
+
+ private InputStream generateEntry(PropertiesWriter propertiesWriter) {
+ try {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ XMLStreamWriter writer = xmlStreamFactory.getWriter(stream);
+ writer.writeStartDocument("utf-8", "1.0");
+
+ writer.writeStartElement("entry");
+ writer.writeAttribute("xmlns:d", "http://schemas.microsoft.com/ado/2007/08/dataservices");
+ writer.writeAttribute("xmlns:m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
+ writer.writeAttribute("xmlns", "http://www.w3.org/2005/Atom");
+
+ writer.writeStartElement("title");
+ writer.writeEndElement(); // title
+
+ writer.writeStartElement("updated");
+ writer.writeCharacters(iso8601DateConverter.format(dateFactory.getDate()));
+ writer.writeEndElement(); // updated
+
+ writer.writeStartElement("author");
+ writer.writeStartElement("name");
+ writer.writeEndElement(); // name
+ writer.writeEndElement(); // author
+
+ writer.writeStartElement("id");
+ writer.writeEndElement(); // id
+
+ writer.writeStartElement("content");
+ writer.writeAttribute("type", "application/xml");
+
+ writer.writeStartElement("m:properties");
+ propertiesWriter.write(writer);
+ writer.writeEndElement(); // m:properties
+
+ writer.writeEndElement(); // content
+
+ writer.writeEndElement(); // entry
+
+ writer.writeEndDocument();
+ writer.close();
+
+ return new ByteArrayInputStream(stream.toByteArray());
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private TableEntry parseTableEntry(XMLStreamReader xmlr) throws XMLStreamException {
+ TableEntry result = new TableEntry();
+
+ expect(xmlr, XMLStreamConstants.START_ELEMENT, "entry");
+
+ while (!isEndElement(xmlr, "entry")) {
+ if (isStartElement(xmlr, "properties")) {
+ Map properties = parseEntryProperties(xmlr);
+
+ result.setName((String) properties.get("TableName").getValue());
+ }
+ else {
+ nextSignificant(xmlr);
+ }
+ }
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, "entry");
+
+ return result;
+ }
+
+ private Entity parseEntityEntry(XMLStreamReader xmlr) throws XMLStreamException {
+ Entity result = new Entity();
+
+ result.setEtag(xmlr.getAttributeValue(null, "etag"));
+ expect(xmlr, XMLStreamConstants.START_ELEMENT, "entry");
+
+ while (!isEndElement(xmlr, "entry")) {
+ if (isStartElement(xmlr, "properties")) {
+ result.setProperties(parseEntryProperties(xmlr));
+ }
+ else {
+ nextSignificant(xmlr);
+ }
+ }
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, "entry");
+
+ return result;
+ }
+
+ private Map parseEntryProperties(XMLStreamReader xmlr) throws XMLStreamException {
+ Map result = new HashMap();
+
+ expect(xmlr, XMLStreamConstants.START_ELEMENT, "properties");
+
+ while (!isEndElement(xmlr, "properties")) {
+ String name = xmlr.getLocalName();
+ String edmType = xmlr.getAttributeValue(null, "type");
+
+ xmlr.next();
+
+ // Use concatenation instead of StringBuilder as most text is just one element.
+ String serializedValue = "";
+ while (!xmlr.isEndElement()) {
+ serializedValue += xmlr.getText();
+ xmlr.next();
+ }
+
+ Object value = edmValueConverter.deserialize(edmType, serializedValue);
+
+ result.put(name, new Property().setEdmType(edmType).setValue(value));
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, name);
+ }
+
+ expect(xmlr, XMLStreamConstants.END_ELEMENT, "properties");
+
+ return result;
+ }
+
+ private void nextSignificant(XMLStreamReader xmlr) throws XMLStreamException {
+ if (!xmlr.hasNext())
+ return;
+ xmlr.next();
+
+ while (xmlr.isCharacters()) {
+ if (!xmlr.hasNext())
+ return;
+ xmlr.next();
+ }
+ }
+
+ private boolean isStartElement(XMLStreamReader xmlr, String localName) {
+ return xmlr.isStartElement() && localName.equals(xmlr.getLocalName());
+ }
+
+ private boolean isEndElement(XMLStreamReader xmlr, String localName) {
+ return xmlr.isEndElement() && localName.equals(xmlr.getLocalName());
+ }
+
+ private void expect(XMLStreamReader xmlr, int eventType) throws XMLStreamException {
+ expect(xmlr, eventType, null);
+ }
+
+ private void expect(XMLStreamReader xmlr, int eventType, String localName) throws XMLStreamException {
+ xmlr.require(eventType, null, localName);
+ nextSignificant(xmlr);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultEdmValueConterter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultEdmValueConterter.java
new file mode 100644
index 0000000000000..d35293670c1b8
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultEdmValueConterter.java
@@ -0,0 +1,90 @@
+/**
+ * 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.table.implementation;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import com.microsoft.windowsazure.services.blob.implementation.ISO8601DateConverter;
+import com.microsoft.windowsazure.services.table.EdmValueConverter;
+import com.microsoft.windowsazure.services.table.models.EdmType;
+import com.sun.jersey.core.util.Base64;
+
+public class DefaultEdmValueConterter implements EdmValueConverter {
+
+ private final ISO8601DateConverter iso8601DateConverter;
+
+ @Inject
+ public DefaultEdmValueConterter(ISO8601DateConverter iso8601DateConverter) {
+ this.iso8601DateConverter = iso8601DateConverter;
+ }
+
+ @Override
+ public String serialize(String edmType, Object value) {
+ if (value == null)
+ return null;
+
+ String serializedValue;
+ if (value instanceof Date) {
+ serializedValue = iso8601DateConverter.format((Date) value);
+ }
+ else if (value instanceof byte[]) {
+ serializedValue = new String(Base64.encode((byte[]) value));
+ }
+ else {
+ serializedValue = value.toString();
+ }
+
+ return serializedValue;
+ }
+
+ @Override
+ public Object deserialize(String edmType, String value) {
+ if (edmType == null)
+ return value;
+
+ if (EdmType.DATETIME.equals(edmType)) {
+ try {
+ return iso8601DateConverter.parse(value);
+ }
+ catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ else if (EdmType.BOOLEAN.equals(edmType)) {
+ return Boolean.parseBoolean(value);
+ }
+ else if (EdmType.DOUBLE.equals(edmType)) {
+ return Double.parseDouble(value);
+ }
+ else if (EdmType.INT32.equals(edmType)) {
+ return Integer.parseInt(value);
+ }
+ else if (EdmType.INT64.equals(edmType)) {
+ return Long.parseLong(value);
+ }
+ else if (EdmType.BINARY.equals(edmType)) {
+ return Base64.decode(value);
+ }
+ else if (EdmType.GUID.equals(edmType)) {
+ return UUID.fromString(value);
+ }
+
+ return value;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultXMLStreamFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultXMLStreamFactory.java
new file mode 100644
index 0000000000000..6202250942d4f
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/DefaultXMLStreamFactory.java
@@ -0,0 +1,54 @@
+/**
+ * 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.table.implementation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+public class DefaultXMLStreamFactory implements XMLStreamFactory {
+ private final XMLOutputFactory xmlOutputFactory;
+ private final XMLInputFactory xmlInputFactory;
+
+ public DefaultXMLStreamFactory() {
+ this.xmlOutputFactory = XMLOutputFactory.newInstance();
+ this.xmlInputFactory = XMLInputFactory.newInstance();
+ }
+
+ @Override
+ public XMLStreamWriter getWriter(OutputStream stream) {
+ try {
+ return xmlOutputFactory.createXMLStreamWriter(stream, "UTF-8");
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public XMLStreamReader getReader(InputStream stream) {
+ try {
+ return xmlInputFactory.createXMLStreamReader(stream);
+ }
+ catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/HttpReaderWriter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/HttpReaderWriter.java
new file mode 100644
index 0000000000000..347538853151a
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/HttpReaderWriter.java
@@ -0,0 +1,183 @@
+/**
+ * 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.table.implementation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.Enumeration;
+
+import javax.activation.DataSource;
+import javax.inject.Inject;
+import javax.mail.Header;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetHeaders;
+
+import com.sun.mail.util.LineInputStream;
+
+public class HttpReaderWriter {
+
+ @Inject
+ public HttpReaderWriter() {
+ }
+
+ public StatusLine parseStatusLine(DataSource ds) {
+ try {
+ LineInputStream stream = new LineInputStream(ds.getInputStream());
+ String line = stream.readLine();
+ StringReader lineReader = new StringReader(line);
+
+ expect(lineReader, "HTTP/1.1");
+ expect(lineReader, " ");
+ String statusString = extractInput(lineReader, ' ');
+ String reason = extractInput(lineReader, -1);
+
+ return new StatusLine().setStatus(Integer.parseInt(statusString)).setReason(reason);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public InternetHeaders parseHeaders(DataSource ds) {
+ try {
+ return new InternetHeaders(ds.getInputStream());
+ }
+ catch (MessagingException e) {
+ throw new RuntimeException(e);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public InputStream parseEntity(DataSource ds) {
+ try {
+ return ds.getInputStream();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void appendMethod(OutputStream stream, String verb, URI uri) {
+ try {
+ String method = String.format("%s %s %s\r\n", verb, uri, "HTTP/1.1");
+ stream.write(method.getBytes("UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void appendHeaders(OutputStream stream, InternetHeaders headers) {
+ try {
+ // Headers
+ @SuppressWarnings("unchecked")
+ Enumeration e = headers.getAllHeaders();
+ while (e.hasMoreElements()) {
+ Header header = e.nextElement();
+
+ String headerLine = String.format("%s: %s\r\n", header.getName(), header.getValue());
+ stream.write(headerLine.getBytes("UTF-8"));
+ }
+
+ // Empty line
+ stream.write("\r\n".getBytes("UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void appendEntity(OutputStream stream, InputStream entity) {
+ try {
+ byte[] buffer = new byte[1024];
+ while (true) {
+ int n = entity.read(buffer);
+ if (n == -1)
+ break;
+ stream.write(buffer, 0, n);
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void expect(Reader reader, String string) {
+ try {
+ for (int i = 0; i < string.length(); i++) {
+ int ch = reader.read();
+ if (ch < 0)
+ throw new RuntimeException(String.format("Expected '%s', found '%s' instead", string,
+ string.substring(0, i) + ch));
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String extractInput(Reader reader, int delimiter) {
+ try {
+ StringBuilder sb = new StringBuilder();
+ while (true) {
+ int ch = reader.read();
+ if (ch == -1 || ch == delimiter)
+ break;
+
+ sb.append((char) ch);
+ }
+ return sb.toString();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public class StatusLine {
+ private int status;
+ private String reason;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public StatusLine setStatus(int status) {
+ this.status = status;
+ return this;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public StatusLine setReason(String reason) {
+ this.reason = reason;
+ return this;
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/InputStreamDataSource.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/InputStreamDataSource.java
new file mode 100644
index 0000000000000..a15d80844155d
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/InputStreamDataSource.java
@@ -0,0 +1,52 @@
+/**
+ * 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.table.implementation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataSource;
+
+public class InputStreamDataSource implements DataSource {
+ private final InputStream stream;
+ private final String contentType;
+
+ public InputStreamDataSource(InputStream stream, String contentType) {
+ this.stream = stream;
+ this.contentType = contentType;
+
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return stream;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/MimeReaderWriter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/MimeReaderWriter.java
new file mode 100644
index 0000000000000..30aa13ec6bfe8
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/MimeReaderWriter.java
@@ -0,0 +1,161 @@
+/**
+ * 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.table.implementation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.inject.Inject;
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.MultipartDataSource;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimePartDataSource;
+
+public class MimeReaderWriter {
+
+ @Inject
+ public MimeReaderWriter() {
+ }
+
+ public MimeMultipart getMimeMultipart(List bodyPartContents) {
+ try {
+ return getMimeMultipartCore(bodyPartContents);
+ }
+ catch (MessagingException e) {
+ throw new RuntimeException(e);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private MimeMultipart getMimeMultipartCore(List bodyPartContents) throws MessagingException,
+ IOException {
+ // Create unique part boundary strings
+ String batchId = String.format("batch_%s", UUID.randomUUID().toString());
+ String changeSet = String.format("changeset_%s", UUID.randomUUID().toString());
+
+ //
+ // Build inner list of change sets containing the list of body part content
+ //
+ MimeMultipart changeSets = new MimeMultipart(new SetBoundaryMultipartDataSource(changeSet));
+
+ for (DataSource bodyPart : bodyPartContents) {
+ MimeBodyPart mimeBodyPart = new MimeBodyPart();
+
+ mimeBodyPart.setDataHandler(new DataHandler(bodyPart));
+ mimeBodyPart.setHeader("Content-Type", bodyPart.getContentType());
+ mimeBodyPart.setHeader("Content-Transfer-Encoding", "binary");
+
+ changeSets.addBodyPart(mimeBodyPart);
+ }
+
+ //
+ // Build outer "batch" body part
+ //
+ MimeBodyPart batchbody = new MimeBodyPart();
+ batchbody.setContent(changeSets);
+ //Note: Both content type and encoding need to be set *after* setting content, because
+ // MimeBodyPart implementation replaces them when calling "setContent".
+ batchbody.setHeader("Content-Type", changeSets.getContentType());
+
+ //
+ // Build outer "batch" multipart
+ //
+ MimeMultipart batch = new MimeMultipart(new SetBoundaryMultipartDataSource(batchId));
+ batch.addBodyPart(batchbody);
+ return batch;
+ }
+
+ /**
+ * The only purpose of this class is to force the boundary of a MimeMultipart instance.
+ * This is done by simple passing an instance of this class to the constructor of MimeMultipart.
+ */
+ private class SetBoundaryMultipartDataSource implements MultipartDataSource {
+
+ private final String boundary;
+
+ public SetBoundaryMultipartDataSource(String boundary) {
+ this.boundary = boundary;
+ }
+
+ @Override
+ public String getContentType() {
+ return "multipart/mixed; boundary=" + boundary;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public int getCount() {
+ return 0;
+ }
+
+ @Override
+ public BodyPart getBodyPart(int index) throws MessagingException {
+ return null;
+ }
+ }
+
+ public List parseParts(final InputStream entityInputStream, final String contentType) {
+ try {
+ return parsePartsCore(entityInputStream, contentType);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ catch (MessagingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private List parsePartsCore(InputStream entityInputStream, String contentType)
+ throws MessagingException, IOException {
+ DataSource ds = new InputStreamDataSource(entityInputStream, contentType);
+ MimeMultipart batch = new MimeMultipart(ds);
+ MimeBodyPart batchBody = (MimeBodyPart) batch.getBodyPart(0);
+
+ MimeMultipart changeSets = new MimeMultipart(new MimePartDataSource(batchBody));
+
+ List result = new ArrayList();
+ for (int i = 0; i < changeSets.getCount(); i++) {
+ BodyPart part = changeSets.getBodyPart(i);
+
+ result.add(new InputStreamDataSource(part.getInputStream(), part.getContentType()));
+ }
+ return result;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java
new file mode 100644
index 0000000000000..7e2e95bb88f9a
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyFilter.java
@@ -0,0 +1,90 @@
+/**
+ * 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.table.implementation;
+
+import java.util.List;
+
+import javax.inject.Named;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.microsoft.windowsazure.services.blob.implementation.SharedKeyUtils;
+import com.microsoft.windowsazure.services.blob.implementation.SharedKeyUtils.QueryParam;
+import com.microsoft.windowsazure.services.table.TableConfiguration;
+import com.sun.jersey.api.client.ClientRequest;
+
+public class SharedKeyFilter extends com.microsoft.windowsazure.services.blob.implementation.SharedKeyFilter {
+ private static Log log = LogFactory.getLog(SharedKeyFilter.class);
+
+ public SharedKeyFilter(@Named(TableConfiguration.ACCOUNT_NAME) String accountName,
+ @Named(TableConfiguration.ACCOUNT_KEY) String accountKey) {
+ super(accountName, accountKey);
+ }
+
+ /*
+ * StringToSign = VERB + "\n" +
+ * Content-MD5 + "\n" +
+ * Content-Type + "\n" +
+ * Date + "\n" +
+ * CanonicalizedResource;
+ */
+ @Override
+ public void sign(ClientRequest cr) {
+ // gather signed material
+ addOptionalDateHeader(cr);
+
+ // build signed string
+ String stringToSign = cr.getMethod() + "\n" + getHeader(cr, "Content-MD5") + "\n"
+ + getHeader(cr, "Content-Type") + "\n" + getHeader(cr, "Date") + "\n";
+
+ stringToSign += getCanonicalizedResource(cr);
+
+ if (log.isDebugEnabled()) {
+ log.debug(String.format("String to sign: \"%s\"", stringToSign));
+ }
+ //TODO: Remove or comment the following line
+ //System.out.println(String.format("String to sign: \"%s\"", stringToSign));
+
+ String signature = this.getSigner().sign(stringToSign);
+ cr.getHeaders().putSingle("Authorization", "SharedKey " + this.getAccountName() + ":" + signature);
+ }
+
+ /**
+ * This format supports Shared Key and Shared Key Lite for all versions of the Table service, and Shared Key Lite
+ * for the 2009-09-19 version of the Blob and Queue services. This format is identical to that used with previous
+ * versions of the storage services. Construct the CanonicalizedResource string in this format as follows:
+ *
+ * 1. Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns
+ * the resource being accessed.
+ *
+ * 2. Append the resource's encoded URI path. If the request URI addresses a component of the resource, append the
+ * appropriate query string. The query string should include the question mark and the comp parameter (for example,
+ * ?comp=metadata). No other parameters should be included on the query string.
+ */
+ private String getCanonicalizedResource(ClientRequest cr) {
+ String result = "/" + this.getAccountName();
+
+ result += cr.getURI().getRawPath();
+
+ List queryParams = SharedKeyUtils.getQueryParams(cr.getURI().getQuery());
+ for (QueryParam p : queryParams) {
+ if ("comp".equals(p.getName())) {
+ result += "?" + p.getName() + "=" + p.getValues().get(0);
+ }
+ }
+ return result;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyLiteFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyLiteFilter.java
new file mode 100644
index 0000000000000..6f9990616a822
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/SharedKeyLiteFilter.java
@@ -0,0 +1,26 @@
+/**
+ * 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.table.implementation;
+
+import javax.inject.Named;
+
+import com.microsoft.windowsazure.services.table.TableConfiguration;
+
+public class SharedKeyLiteFilter extends com.microsoft.windowsazure.services.blob.implementation.SharedKeyLiteFilter {
+ public SharedKeyLiteFilter(@Named(TableConfiguration.ACCOUNT_NAME) String accountName,
+ @Named(TableConfiguration.ACCOUNT_KEY) String accountKey) {
+ super(accountName, accountKey);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableExceptionProcessor.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableExceptionProcessor.java
new file mode 100644
index 0000000000000..29e8bd6dd8129
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableExceptionProcessor.java
@@ -0,0 +1,464 @@
+/**
+ * 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.table.implementation;
+
+import javax.inject.Inject;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.ServiceFilter;
+import com.microsoft.windowsazure.services.core.utils.ServiceExceptionFactory;
+import com.microsoft.windowsazure.services.table.TableContract;
+import com.microsoft.windowsazure.services.table.models.BatchOperations;
+import com.microsoft.windowsazure.services.table.models.BatchResult;
+import com.microsoft.windowsazure.services.table.models.DeleteEntityOptions;
+import com.microsoft.windowsazure.services.table.models.Entity;
+import com.microsoft.windowsazure.services.table.models.GetEntityResult;
+import com.microsoft.windowsazure.services.table.models.GetServicePropertiesResult;
+import com.microsoft.windowsazure.services.table.models.GetTableResult;
+import com.microsoft.windowsazure.services.table.models.InsertEntityResult;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesResult;
+import com.microsoft.windowsazure.services.table.models.QueryTablesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryTablesResult;
+import com.microsoft.windowsazure.services.table.models.ServiceProperties;
+import com.microsoft.windowsazure.services.table.models.TableServiceOptions;
+import com.microsoft.windowsazure.services.table.models.UpdateEntityResult;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+public class TableExceptionProcessor implements TableContract {
+ private static Log log = LogFactory.getLog(TableExceptionProcessor.class);
+ private final TableContract service;
+
+ @Inject
+ public TableExceptionProcessor(TableRestProxy service) {
+ this.service = service;
+ }
+
+ public TableExceptionProcessor(TableContract service) {
+ this.service = service;
+ }
+
+ @Override
+ public TableContract withFilter(ServiceFilter filter) {
+ return new TableExceptionProcessor(service.withFilter(filter));
+ }
+
+ private ServiceException processCatch(ServiceException e) {
+ log.warn(e.getMessage(), e.getCause());
+ return ServiceExceptionFactory.process("table", e);
+ }
+
+ @Override
+ public GetServicePropertiesResult getServiceProperties() throws ServiceException {
+ try {
+ return service.getServiceProperties();
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public GetServicePropertiesResult getServiceProperties(TableServiceOptions options) throws ServiceException {
+ try {
+ return service.getServiceProperties(options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void setServiceProperties(ServiceProperties serviceProperties) throws ServiceException {
+ try {
+ service.setServiceProperties(serviceProperties);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void setServiceProperties(ServiceProperties serviceProperties, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ service.setServiceProperties(serviceProperties, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void createTable(String table) throws ServiceException {
+ try {
+ service.createTable(table);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void createTable(String table, TableServiceOptions options) throws ServiceException {
+ try {
+ service.createTable(table, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public GetTableResult getTable(String table) throws ServiceException {
+ try {
+ return service.getTable(table);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public GetTableResult getTable(String table, TableServiceOptions options) throws ServiceException {
+ try {
+ return service.getTable(table, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void deleteTable(String table) throws ServiceException {
+ try {
+ service.deleteTable(table);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void deleteTable(String table, TableServiceOptions options) throws ServiceException {
+ try {
+ service.deleteTable(table, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public QueryTablesResult queryTables() throws ServiceException {
+ try {
+ return service.queryTables();
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public QueryTablesResult queryTables(QueryTablesOptions options) throws ServiceException {
+ try {
+ return service.queryTables(options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public InsertEntityResult insertEntity(String table, Entity entity) throws ServiceException {
+ try {
+ return service.insertEntity(table, entity);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public InsertEntityResult insertEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.insertEntity(table, entity, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult updateEntity(String table, Entity entity) throws ServiceException {
+ try {
+ return service.updateEntity(table, entity);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult updateEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.updateEntity(table, entity, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult mergeEntity(String table, Entity entity) throws ServiceException {
+ try {
+ return service.mergeEntity(table, entity);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult mergeEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.mergeEntity(table, entity, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult insertOrReplaceEntity(String table, Entity entity) throws ServiceException {
+ try {
+ return service.insertOrReplaceEntity(table, entity);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult insertOrReplaceEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.insertOrReplaceEntity(table, entity, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult insertOrMergeEntity(String table, Entity entity) throws ServiceException {
+ try {
+ return service.insertOrMergeEntity(table, entity);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public UpdateEntityResult insertOrMergeEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.insertOrMergeEntity(table, entity, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void deleteEntity(String table, String partitionKey, String rowKey) throws ServiceException {
+ try {
+ service.deleteEntity(table, partitionKey, rowKey);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public void deleteEntity(String table, String partitionKey, String rowKey, DeleteEntityOptions options)
+ throws ServiceException {
+ try {
+ service.deleteEntity(table, partitionKey, rowKey, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public GetEntityResult getEntity(String table, String partitionKey, String rowKey) throws ServiceException {
+ try {
+ return service.getEntity(table, partitionKey, rowKey);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public GetEntityResult getEntity(String table, String partitionKey, String rowKey, TableServiceOptions options)
+ throws ServiceException {
+ try {
+ return service.getEntity(table, partitionKey, rowKey, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public QueryEntitiesResult queryEntities(String table) throws ServiceException {
+ try {
+ return service.queryEntities(table);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public QueryEntitiesResult queryEntities(String table, QueryEntitiesOptions options) throws ServiceException {
+ try {
+ return service.queryEntities(table, options);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public BatchResult batch(BatchOperations operations) throws ServiceException {
+ try {
+ return service.batch(operations);
+ }
+ catch (UniformInterfaceException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ catch (ClientHandlerException e) {
+ throw processCatch(new ServiceException(e));
+ }
+ }
+
+ @Override
+ public BatchResult batch(BatchOperations operations, TableServiceOptions options) throws ServiceException {
+ try {
+ return service.batch(operations, options);
+ }
+ 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/table/implementation/TableRestProxy.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java
new file mode 100644
index 0000000000000..7da2c6a1b4905
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/TableRestProxy.java
@@ -0,0 +1,908 @@
+/**
+ * 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.table.implementation;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Formatter;
+import java.util.List;
+import java.util.UUID;
+
+import javax.activation.DataSource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.mail.Header;
+import javax.mail.internet.InternetHeaders;
+import javax.mail.internet.MimeMultipart;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import com.microsoft.windowsazure.services.blob.implementation.ISO8601DateConverter;
+import com.microsoft.windowsazure.services.blob.implementation.RFC1123DateConverter;
+import com.microsoft.windowsazure.services.core.ServiceException;
+import com.microsoft.windowsazure.services.core.ServiceFilter;
+import com.microsoft.windowsazure.services.core.utils.CommaStringBuilder;
+import com.microsoft.windowsazure.services.core.utils.DateFactory;
+import com.microsoft.windowsazure.services.core.utils.ServiceExceptionFactory;
+import com.microsoft.windowsazure.services.core.utils.pipeline.ClientFilterAdapter;
+import com.microsoft.windowsazure.services.core.utils.pipeline.HttpURLConnectionClient;
+import com.microsoft.windowsazure.services.core.utils.pipeline.PipelineHelpers;
+import com.microsoft.windowsazure.services.table.TableConfiguration;
+import com.microsoft.windowsazure.services.table.TableContract;
+import com.microsoft.windowsazure.services.table.implementation.HttpReaderWriter.StatusLine;
+import com.microsoft.windowsazure.services.table.models.BatchOperations;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.DeleteEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.InsertEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.InsertOrMergeEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.InsertOrReplaceEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.MergeEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.Operation;
+import com.microsoft.windowsazure.services.table.models.BatchOperations.UpdateEntityOperation;
+import com.microsoft.windowsazure.services.table.models.BatchResult;
+import com.microsoft.windowsazure.services.table.models.BatchResult.DeleteEntity;
+import com.microsoft.windowsazure.services.table.models.BatchResult.Entry;
+import com.microsoft.windowsazure.services.table.models.BatchResult.Error;
+import com.microsoft.windowsazure.services.table.models.BatchResult.InsertEntity;
+import com.microsoft.windowsazure.services.table.models.BatchResult.UpdateEntity;
+import com.microsoft.windowsazure.services.table.models.BinaryFilter;
+import com.microsoft.windowsazure.services.table.models.ConstantFilter;
+import com.microsoft.windowsazure.services.table.models.DeleteEntityOptions;
+import com.microsoft.windowsazure.services.table.models.Entity;
+import com.microsoft.windowsazure.services.table.models.Filter;
+import com.microsoft.windowsazure.services.table.models.GetEntityResult;
+import com.microsoft.windowsazure.services.table.models.GetServicePropertiesResult;
+import com.microsoft.windowsazure.services.table.models.GetTableResult;
+import com.microsoft.windowsazure.services.table.models.InsertEntityResult;
+import com.microsoft.windowsazure.services.table.models.PropertyNameFilter;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesResult;
+import com.microsoft.windowsazure.services.table.models.QueryStringFilter;
+import com.microsoft.windowsazure.services.table.models.QueryTablesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryTablesResult;
+import com.microsoft.windowsazure.services.table.models.ServiceProperties;
+import com.microsoft.windowsazure.services.table.models.TableServiceOptions;
+import com.microsoft.windowsazure.services.table.models.UnaryFilter;
+import com.microsoft.windowsazure.services.table.models.UpdateEntityResult;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.WebResource.Builder;
+import com.sun.jersey.core.header.InBoundHeaders;
+import com.sun.jersey.core.util.ReaderWriter;
+
+public class TableRestProxy implements TableContract {
+ private static final String API_VERSION = "2011-08-18";
+ private final HttpURLConnectionClient channel;
+ private final String url;
+ private final RFC1123DateConverter dateMapper;
+ private final ISO8601DateConverter iso8601DateConverter;
+ private final DateFactory dateFactory;
+ private final ServiceFilter[] filters;
+ private final SharedKeyFilter filter;
+ private final AtomReaderWriter atomReaderWriter;
+ private final MimeReaderWriter mimeReaderWriter;
+ private final HttpReaderWriter httpReaderWriter;
+
+ @Inject
+ public TableRestProxy(HttpURLConnectionClient channel, @Named(TableConfiguration.URI) String url,
+ SharedKeyFilter filter, DateFactory dateFactory, ISO8601DateConverter iso8601DateConverter,
+ AtomReaderWriter atomReaderWriter, MimeReaderWriter mimeReaderWriter, HttpReaderWriter httpReaderWriter) {
+
+ this.channel = channel;
+ this.url = url;
+ this.filter = filter;
+ this.dateMapper = new RFC1123DateConverter();
+ this.iso8601DateConverter = iso8601DateConverter;
+ this.filters = new ServiceFilter[0];
+ this.dateFactory = dateFactory;
+ this.atomReaderWriter = atomReaderWriter;
+ this.mimeReaderWriter = mimeReaderWriter;
+ this.httpReaderWriter = httpReaderWriter;
+ channel.addFilter(filter);
+ }
+
+ public TableRestProxy(HttpURLConnectionClient channel, ServiceFilter[] filters, String url, SharedKeyFilter filter,
+ DateFactory dateFactory, AtomReaderWriter atomReaderWriter, MimeReaderWriter mimeReaderWriter,
+ HttpReaderWriter httpReaderWriter, RFC1123DateConverter dateMapper,
+ ISO8601DateConverter iso8601DateConverter) {
+
+ this.channel = channel;
+ this.filters = filters;
+ this.url = url;
+ this.filter = filter;
+ this.dateFactory = dateFactory;
+ this.atomReaderWriter = atomReaderWriter;
+ this.mimeReaderWriter = mimeReaderWriter;
+ this.httpReaderWriter = httpReaderWriter;
+ this.dateMapper = dateMapper;
+ this.iso8601DateConverter = iso8601DateConverter;
+ }
+
+ @Override
+ public TableContract withFilter(ServiceFilter filter) {
+ ServiceFilter[] newFilters = Arrays.copyOf(filters, filters.length + 1);
+ newFilters[filters.length] = filter;
+ return new TableRestProxy(this.channel, newFilters, this.url, this.filter, this.dateFactory,
+ this.atomReaderWriter, this.mimeReaderWriter, this.httpReaderWriter, this.dateMapper,
+ this.iso8601DateConverter);
+ }
+
+ private void ThrowIfError(ClientResponse r) {
+ PipelineHelpers.ThrowIfError(r);
+ }
+
+ private String encodeODataURIValue(String value) {
+ //TODO: Unclear if OData value in URI's need to be encoded or not
+ return value;
+ }
+
+ private List encodeODataURIValues(List values) {
+ List list = new ArrayList();
+ for (String value : values) {
+ list.add(encodeODataURIValue(value));
+ }
+ return list;
+ }
+
+ private String getEntityPath(String table, String partitionKey, String rowKey) {
+ return table + "(" + "PartitionKey='" + safeEncode(partitionKey) + "',RowKey='" + safeEncode(rowKey) + "')";
+ }
+
+ private String safeEncode(String input) {
+ String fixSingleQuotes = input.replace("'", "''");
+ try {
+ return URLEncoder.encode(fixSingleQuotes, "UTF-8").replace("+", "%20");
+ }
+ catch (UnsupportedEncodingException e) {
+ return fixSingleQuotes;
+ }
+ }
+
+ private WebResource addOptionalQueryParam(WebResource webResource, String key, Object value) {
+ return PipelineHelpers.addOptionalQueryParam(webResource, key, value);
+ }
+
+ private WebResource addOptionalQueryEntitiesOptions(WebResource webResource,
+ QueryEntitiesOptions queryEntitiesOptions) {
+ if (queryEntitiesOptions == null)
+ return webResource;
+
+ if (queryEntitiesOptions.getSelectFields() != null && queryEntitiesOptions.getSelectFields().size() > 0) {
+ webResource = addOptionalQueryParam(webResource, "$select",
+ CommaStringBuilder.join(encodeODataURIValues(queryEntitiesOptions.getSelectFields())));
+ }
+
+ if (queryEntitiesOptions.getTop() != null) {
+ webResource = addOptionalQueryParam(webResource, "$top", encodeODataURIValue(queryEntitiesOptions.getTop()
+ .toString()));
+ }
+
+ if (queryEntitiesOptions.getFilter() != null) {
+ webResource = addOptionalQueryParam(webResource, "$filter",
+ buildFilterExpression(queryEntitiesOptions.getFilter()));
+ }
+
+ if (queryEntitiesOptions.getOrderByFields() != null) {
+ webResource = addOptionalQueryParam(webResource, "$orderby",
+ CommaStringBuilder.join(encodeODataURIValues(queryEntitiesOptions.getOrderByFields())));
+ }
+
+ return webResource;
+ }
+
+ private String buildFilterExpression(Filter filter) {
+ StringBuilder sb = new StringBuilder();
+ buildFilterExpression(filter, sb);
+ return sb.toString();
+ }
+
+ private void buildFilterExpression(Filter filter, StringBuilder sb) {
+ if (filter == null)
+ return;
+
+ if (filter instanceof PropertyNameFilter) {
+ sb.append(((PropertyNameFilter) filter).getPropertyName());
+ }
+ else if (filter instanceof ConstantFilter) {
+ Object value = ((ConstantFilter) filter).getValue();
+ if (value == null) {
+ sb.append("null");
+ }
+ else if (value.getClass() == Long.class) {
+ sb.append(value);
+ sb.append("L");
+ }
+ else if (value.getClass() == Date.class) {
+ ISO8601DateConverter dateConverter = new ISO8601DateConverter();
+ sb.append("datetime'");
+ sb.append(dateConverter.format((Date) value));
+ sb.append("'");
+ }
+ else if (value.getClass() == UUID.class) {
+ sb.append("(guid'");
+ sb.append(value);
+ sb.append("')");
+ }
+ else if (value.getClass() == String.class) {
+ sb.append("'");
+ sb.append(((String) value).replace("'", "''"));
+ sb.append("'");
+ }
+ else if (value.getClass() == byte[].class) {
+ sb.append("X'");
+ byte[] byteArray = (byte[]) value;
+ Formatter formatter = new Formatter(sb);
+ for (byte b : byteArray) {
+ formatter.format("%02x", b);
+ }
+ sb.append("'");
+ }
+ else if (value.getClass() == Byte[].class) {
+ sb.append("X'");
+ Byte[] byteArray = (Byte[]) value;
+ Formatter formatter = new Formatter(sb);
+ for (Byte b : byteArray) {
+ formatter.format("%02x", b);
+ }
+ sb.append("'");
+ }
+ else {
+ sb.append(value);
+ }
+ }
+ else if (filter instanceof UnaryFilter) {
+ sb.append(((UnaryFilter) filter).getOperator());
+ sb.append("(");
+ buildFilterExpression(((UnaryFilter) filter).getOperand(), sb);
+ sb.append(")");
+ }
+ else if (filter instanceof BinaryFilter) {
+ sb.append("(");
+ buildFilterExpression(((BinaryFilter) filter).getLeft(), sb);
+ sb.append(" ");
+ sb.append(((BinaryFilter) filter).getOperator());
+ sb.append(" ");
+ buildFilterExpression(((BinaryFilter) filter).getRight(), sb);
+ sb.append(")");
+ }
+ else if (filter instanceof QueryStringFilter) {
+ sb.append(((QueryStringFilter) filter).getQueryString());
+ }
+ }
+
+ private Builder addOptionalHeader(Builder builder, String name, Object value) {
+ return PipelineHelpers.addOptionalHeader(builder, name, value);
+ }
+
+ private WebResource.Builder addTableRequestHeaders(WebResource.Builder builder) {
+ builder = addOptionalHeader(builder, "x-ms-version", API_VERSION);
+ builder = addOptionalHeader(builder, "DataServiceVersion", "1.0;NetFx");
+ builder = addOptionalHeader(builder, "MaxDataServiceVersion", "2.0;NetFx");
+ builder = addOptionalHeader(builder, "Accept", "application/atom+xml,application/xml");
+ builder = addOptionalHeader(builder, "Accept-Charset", "UTF-8");
+ return builder;
+ }
+
+ private WebResource.Builder addIfMatchHeader(WebResource.Builder builder, String eTag) {
+ builder = addOptionalHeader(builder, "If-Match", eTag == null ? "*" : eTag);
+ return builder;
+ }
+
+ private WebResource getResource(TableServiceOptions options) {
+ WebResource webResource = channel.resource(url).path("/");
+ for (ServiceFilter filter : filters) {
+ webResource.addFilter(new ClientFilterAdapter(filter));
+ }
+
+ return webResource;
+ }
+
+ @Override
+ public GetServicePropertiesResult getServiceProperties() throws ServiceException {
+ return getServiceProperties(new TableServiceOptions());
+ }
+
+ @Override
+ public GetServicePropertiesResult getServiceProperties(TableServiceOptions options) throws ServiceException {
+ WebResource webResource = getResource(options).path("/").queryParam("resType", "service")
+ .queryParam("comp", "properties");
+
+ WebResource.Builder builder = webResource.header("x-ms-version", API_VERSION);
+
+ GetServicePropertiesResult result = new GetServicePropertiesResult();
+ result.setValue(builder.get(ServiceProperties.class));
+ return result;
+ }
+
+ @Override
+ public void setServiceProperties(ServiceProperties serviceProperties) throws ServiceException {
+ setServiceProperties(serviceProperties, new TableServiceOptions());
+ }
+
+ @Override
+ public void setServiceProperties(ServiceProperties serviceProperties, TableServiceOptions options)
+ throws ServiceException {
+ if (serviceProperties == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path("/").queryParam("resType", "service")
+ .queryParam("comp", "properties");
+
+ WebResource.Builder builder = webResource.header("x-ms-version", API_VERSION);
+
+ builder.put(serviceProperties);
+ }
+
+ @Override
+ public GetTableResult getTable(String table) throws ServiceException {
+ return getTable(table, new TableServiceOptions());
+ }
+
+ @Override
+ public GetTableResult getTable(String table, TableServiceOptions options) throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path("Tables" + "('" + table + "')");
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ ClientResponse response = builder.get(ClientResponse.class);
+ ThrowIfError(response);
+
+ GetTableResult result = new GetTableResult();
+ result.setTableEntry(atomReaderWriter.parseTableEntry(response.getEntityInputStream()));
+ return result;
+ }
+
+ @Override
+ public QueryTablesResult queryTables() throws ServiceException {
+ return queryTables(new QueryTablesOptions());
+ }
+
+ @Override
+ public QueryTablesResult queryTables(QueryTablesOptions options) throws ServiceException {
+ Filter queryFilter = options.getFilter();
+ String nextTableName = options.getNextTableName();
+ String prefix = options.getPrefix();
+
+ if (prefix != null) {
+ // Append Max char to end '{' is 1 + 'z' in AsciiTable ==> upperBound is prefix + '{'
+ Filter prefixFilter = Filter.and(Filter.ge(Filter.propertyName("TableName"), Filter.constant(prefix)),
+ Filter.le(Filter.propertyName("TableName"), Filter.constant(prefix + "{")));
+
+ if (queryFilter == null) {
+ queryFilter = prefixFilter;
+ }
+ else {
+ queryFilter = Filter.and(queryFilter, prefixFilter);
+ }
+ }
+
+ WebResource webResource = getResource(options).path("Tables");
+ webResource = addOptionalQueryParam(webResource, "$filter", buildFilterExpression(queryFilter));
+ webResource = addOptionalQueryParam(webResource, "NextTableName", nextTableName);
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ ClientResponse response = builder.get(ClientResponse.class);
+ ThrowIfError(response);
+
+ QueryTablesResult result = new QueryTablesResult();
+ result.setNextTableName(response.getHeaders().getFirst("x-ms-continuation-NextTableName"));
+ result.setTables(atomReaderWriter.parseTableEntries(response.getEntityInputStream()));
+
+ return result;
+ }
+
+ @Override
+ public void createTable(String table) throws ServiceException {
+ createTable(table, new TableServiceOptions());
+
+ }
+
+ @Override
+ public void createTable(String table, TableServiceOptions options) throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path("Tables");
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ builder.entity(atomReaderWriter.generateTableEntry(table), "application/atom+xml");
+
+ ClientResponse response = builder.post(ClientResponse.class);
+ ThrowIfError(response);
+ }
+
+ @Override
+ public void deleteTable(String table) throws ServiceException {
+ deleteTable(table, new TableServiceOptions());
+ }
+
+ @Override
+ public void deleteTable(String table, TableServiceOptions options) throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path("Tables" + "('" + table + "')");
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+ builder = addOptionalHeader(builder, "Content-Type", "application/atom+xml");
+
+ ClientResponse response = builder.delete(ClientResponse.class);
+ ThrowIfError(response);
+ }
+
+ @Override
+ public InsertEntityResult insertEntity(String table, Entity entity) throws ServiceException {
+ return insertEntity(table, entity, new TableServiceOptions());
+ }
+
+ @Override
+ public InsertEntityResult insertEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path(table);
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ builder = builder.entity(atomReaderWriter.generateEntityEntry(entity), "application/atom+xml");
+
+ ClientResponse response = builder.post(ClientResponse.class);
+ ThrowIfError(response);
+
+ InsertEntityResult result = new InsertEntityResult();
+ result.setEntity(atomReaderWriter.parseEntityEntry(response.getEntityInputStream()));
+
+ return result;
+ }
+
+ @Override
+ public UpdateEntityResult updateEntity(String table, Entity entity) throws ServiceException {
+ return updateEntity(table, entity, new TableServiceOptions());
+ }
+
+ @Override
+ public UpdateEntityResult updateEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ return putOrMergeEntityCore(table, entity, "PUT", true/*includeEtag*/, options);
+ }
+
+ @Override
+ public UpdateEntityResult mergeEntity(String table, Entity entity) throws ServiceException {
+ return mergeEntity(table, entity, new TableServiceOptions());
+ }
+
+ @Override
+ public UpdateEntityResult mergeEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ return putOrMergeEntityCore(table, entity, "MERGE", true/*includeEtag*/, options);
+ }
+
+ @Override
+ public UpdateEntityResult insertOrReplaceEntity(String table, Entity entity) throws ServiceException {
+ return insertOrReplaceEntity(table, entity, new TableServiceOptions());
+ }
+
+ @Override
+ public UpdateEntityResult insertOrReplaceEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ return putOrMergeEntityCore(table, entity, "PUT", false/*includeEtag*/, options);
+ }
+
+ @Override
+ public UpdateEntityResult insertOrMergeEntity(String table, Entity entity) throws ServiceException {
+ return insertOrMergeEntity(table, entity, new TableServiceOptions());
+ }
+
+ @Override
+ public UpdateEntityResult insertOrMergeEntity(String table, Entity entity, TableServiceOptions options)
+ throws ServiceException {
+ return putOrMergeEntityCore(table, entity, "MERGE", false/*includeEtag*/, options);
+ }
+
+ private UpdateEntityResult putOrMergeEntityCore(String table, Entity entity, String verb, boolean includeEtag,
+ TableServiceOptions options) throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path(
+ getEntityPath(table, entity.getPartitionKey(), entity.getRowKey()));
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+ if (includeEtag) {
+ builder = addIfMatchHeader(builder, entity.getEtag());
+ }
+ if (verb == "MERGE") {
+ builder = builder.header("X-HTTP-Method", "MERGE");
+ verb = "POST";
+ }
+
+ builder = builder.entity(atomReaderWriter.generateEntityEntry(entity), "application/atom+xml");
+
+ ClientResponse response = builder.method(verb, ClientResponse.class);
+ ThrowIfError(response);
+
+ UpdateEntityResult result = new UpdateEntityResult();
+ result.setEtag(response.getHeaders().getFirst("ETag"));
+
+ return result;
+ }
+
+ @Override
+ public void deleteEntity(String table, String partitionKey, String rowKey) throws ServiceException {
+ deleteEntity(table, partitionKey, rowKey, new DeleteEntityOptions());
+ }
+
+ @Override
+ public void deleteEntity(String table, String partitionKey, String rowKey, DeleteEntityOptions options)
+ throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path(getEntityPath(table, partitionKey, rowKey));
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+ builder = addIfMatchHeader(builder, options.getEtag());
+
+ ClientResponse response = builder.delete(ClientResponse.class);
+ ThrowIfError(response);
+ }
+
+ @Override
+ public GetEntityResult getEntity(String table, String partitionKey, String rowKey) throws ServiceException {
+ return getEntity(table, partitionKey, rowKey, new TableServiceOptions());
+ }
+
+ @Override
+ public GetEntityResult getEntity(String table, String partitionKey, String rowKey, TableServiceOptions options)
+ throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ WebResource webResource = getResource(options).path(getEntityPath(table, partitionKey, rowKey));
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ ClientResponse response = builder.get(ClientResponse.class);
+ ThrowIfError(response);
+
+ GetEntityResult result = new GetEntityResult();
+ result.setEntity(atomReaderWriter.parseEntityEntry(response.getEntityInputStream()));
+
+ return result;
+ }
+
+ @Override
+ public QueryEntitiesResult queryEntities(String table) throws ServiceException {
+ return queryEntities(table, new QueryEntitiesOptions());
+ }
+
+ @Override
+ public QueryEntitiesResult queryEntities(String table, QueryEntitiesOptions options) throws ServiceException {
+ if (table == null)
+ throw new NullPointerException();
+
+ if (options == null)
+ options = new QueryEntitiesOptions();
+
+ WebResource webResource = getResource(options).path(table);
+ webResource = addOptionalQueryEntitiesOptions(webResource, options);
+ webResource = addOptionalQueryParam(webResource, "NextPartitionKey",
+ encodeODataURIValue(options.getNextPartitionKey()));
+ webResource = addOptionalQueryParam(webResource, "NextRowKey", encodeODataURIValue(options.getNextRowKey()));
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ ClientResponse response = builder.get(ClientResponse.class);
+ ThrowIfError(response);
+
+ QueryEntitiesResult result = new QueryEntitiesResult();
+ result.setNextPartitionKey(response.getHeaders().getFirst("x-ms-continuation-NextPartitionKey"));
+ result.setNextRowKey(response.getHeaders().getFirst("x-ms-continuation-NextRowKey"));
+ result.setEntities(atomReaderWriter.parseEntityEntries(response.getEntityInputStream()));
+
+ return result;
+ }
+
+ @Override
+ public BatchResult batch(BatchOperations operations) throws ServiceException {
+ return batch(operations, new TableServiceOptions());
+ }
+
+ @Override
+ public BatchResult batch(BatchOperations operations, TableServiceOptions options) throws ServiceException {
+ WebResource webResource = getResource(options).path("$batch");
+
+ WebResource.Builder builder = webResource.getRequestBuilder();
+ builder = addTableRequestHeaders(builder);
+
+ MimeMultipart entity = createBatchRequestBody(operations);
+ builder = builder.type(entity.getContentType());
+
+ ClientResponse response = builder.post(ClientResponse.class, entity);
+ ThrowIfError(response);
+
+ BatchResult result = new BatchResult();
+
+ try {
+ result.setEntries(parseBatchResponse(response, operations));
+ }
+ catch (IOException e) {
+ throw new ServiceException(e);
+ }
+
+ return result;
+ }
+
+ private MimeMultipart createBatchRequestBody(BatchOperations operations) {
+ List bodyPartContents = new ArrayList();
+ int contentId = 1;
+ for (Operation operation : operations.getOperations()) {
+
+ DataSource bodyPartContent = null;
+ if (operation instanceof InsertEntityOperation) {
+ InsertEntityOperation op = (InsertEntityOperation) operation;
+ bodyPartContent = createBatchInsertOrUpdateEntityPart(op.getTable(), op.getEntity(), "POST",
+ false/*includeEtag*/, contentId);
+ contentId++;
+ }
+ else if (operation instanceof UpdateEntityOperation) {
+ UpdateEntityOperation op = (UpdateEntityOperation) operation;
+ bodyPartContent = createBatchInsertOrUpdateEntityPart(op.getTable(), op.getEntity(), "PUT",
+ true/*includeEtag*/, contentId);
+ contentId++;
+ }
+ else if (operation instanceof MergeEntityOperation) {
+ MergeEntityOperation op = (MergeEntityOperation) operation;
+ bodyPartContent = createBatchInsertOrUpdateEntityPart(op.getTable(), op.getEntity(), "MERGE",
+ true/*includeEtag*/, contentId);
+ contentId++;
+ }
+ else if (operation instanceof InsertOrReplaceEntityOperation) {
+ InsertOrReplaceEntityOperation op = (InsertOrReplaceEntityOperation) operation;
+ bodyPartContent = createBatchInsertOrUpdateEntityPart(op.getTable(), op.getEntity(), "PUT",
+ false/*includeEtag*/, contentId);
+ contentId++;
+ }
+ else if (operation instanceof InsertOrMergeEntityOperation) {
+ InsertOrMergeEntityOperation op = (InsertOrMergeEntityOperation) operation;
+ bodyPartContent = createBatchInsertOrUpdateEntityPart(op.getTable(), op.getEntity(), "MERGE",
+ false/*includeEtag*/, contentId);
+ contentId++;
+ }
+ else if (operation instanceof DeleteEntityOperation) {
+ DeleteEntityOperation op = (DeleteEntityOperation) operation;
+ bodyPartContent = createBatchDeleteEntityPart(op.getTable(), op.getPartitionKey(), op.getRowKey(),
+ op.getEtag(), contentId);
+ contentId++;
+ }
+
+ if (bodyPartContent != null) {
+ bodyPartContents.add(bodyPartContent);
+ }
+ }
+
+ return mimeReaderWriter.getMimeMultipart(bodyPartContents);
+ }
+
+ private DataSource createBatchInsertOrUpdateEntityPart(String table, Entity entity, String verb,
+ boolean includeEtag, int contentId) {
+
+ URI path;
+ if ("POST".equals(verb)) {
+ path = channel.resource(url).path(table).getURI();
+ }
+ else {
+ path = channel.resource(url).path(getEntityPath(table, entity.getPartitionKey(), entity.getRowKey()))
+ .getURI();
+ }
+
+ //
+ // Stream content into byte[] so that we have the length
+ //
+ InputStream stream = atomReaderWriter.generateEntityEntry(entity);
+ byte[] bytes = inputStreamToByteArray(stream);
+
+ //
+ // Create body of MIME part as the HTTP request
+ //
+ InternetHeaders headers = new InternetHeaders();
+ headers.addHeader("Content-ID", Integer.toString(contentId));
+ headers.addHeader("Content-Type", "application/atom+xml;type=entry");
+ headers.addHeader("Content-Length", Integer.toString(bytes.length));
+ if (includeEtag) {
+ headers.addHeader("If-Match", entity.getEtag());
+ }
+
+ //TODO: Review code to make sure encoding is correct
+ ByteArrayOutputStream httpRequest = new ByteArrayOutputStream();
+ httpReaderWriter.appendMethod(httpRequest, verb, path);
+ httpReaderWriter.appendHeaders(httpRequest, headers);
+ httpReaderWriter.appendEntity(httpRequest, new ByteArrayInputStream(bytes));
+
+ DataSource bodyPartContent = new InputStreamDataSource(new ByteArrayInputStream(httpRequest.toByteArray()),
+ "application/http");
+ return bodyPartContent;
+ }
+
+ private DataSource createBatchDeleteEntityPart(String table, String partitionKey, String rowKey, String etag,
+ int contentId) {
+
+ URI path = channel.resource(url).path(getEntityPath(table, partitionKey, rowKey)).getURI();
+
+ //
+ // Create body of MIME part as the HTTP request
+ //
+ InternetHeaders headers = new InternetHeaders();
+ headers.addHeader("Content-ID", Integer.toString(contentId));
+ headers.addHeader("If-Match", etag == null ? "*" : etag);
+
+ //TODO: Review code to make sure encoding is correct
+ ByteArrayOutputStream httpRequest = new ByteArrayOutputStream();
+ httpReaderWriter.appendMethod(httpRequest, "DELETE", path);
+ httpReaderWriter.appendHeaders(httpRequest, headers);
+ httpReaderWriter.appendEntity(httpRequest, new ByteArrayInputStream(new byte[0]));
+
+ DataSource bodyPartContent = new InputStreamDataSource(new ByteArrayInputStream(httpRequest.toByteArray()),
+ "application/http");
+ return bodyPartContent;
+ }
+
+ private List parseBatchResponse(ClientResponse response, BatchOperations operations) throws IOException {
+ // Default stream cannot be reset, but it is needed by multiple parts of this method.
+ // Replace the default response stream with one that can be read multiple times.
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ InputStream inputStream = response.getEntityInputStream();
+ ReaderWriter.writeTo(inputStream, byteArrayOutputStream);
+ response.setEntityInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
+
+ List parts = mimeReaderWriter.parseParts(response.getEntityInputStream(), response.getHeaders()
+ .getFirst("Content-Type"));
+
+ if (parts.size() == 0 || parts.size() > operations.getOperations().size()) {
+ throw new UniformInterfaceException(String.format(
+ "Batch response from server does not contain the correct amount "
+ + "of parts (expecting %d, received %d instead)", parts.size(), operations.getOperations()
+ .size()), response);
+ }
+
+ Entry[] entries = new Entry[operations.getOperations().size()];
+ for (int i = 0; i < parts.size(); i++) {
+ DataSource ds = parts.get(i);
+ Operation operation = operations.getOperations().get(i);
+
+ StatusLine status = httpReaderWriter.parseStatusLine(ds);
+ InternetHeaders headers = httpReaderWriter.parseHeaders(ds);
+ InputStream content = httpReaderWriter.parseEntity(ds);
+ ByteArrayOutputStream contentByteArrayOutputStream = new ByteArrayOutputStream();
+ ReaderWriter.writeTo(content, contentByteArrayOutputStream);
+ content = new ByteArrayInputStream(contentByteArrayOutputStream.toByteArray());
+
+ if (status.getStatus() >= 400) {
+ // Create dummy client response with status, headers and content
+ InBoundHeaders inBoundHeaders = new InBoundHeaders();
+
+ @SuppressWarnings("unchecked")
+ Enumeration e = headers.getAllHeaders();
+ while (e.hasMoreElements()) {
+ Header header = e.nextElement();
+ inBoundHeaders.putSingle(header.getName(), header.getValue());
+ }
+
+ ClientResponse dummyResponse = new ClientResponse(status.getStatus(), inBoundHeaders, content, null);
+
+ // Wrap into a ServiceException
+ UniformInterfaceException exception = new UniformInterfaceException(dummyResponse);
+ ServiceException serviceException = new ServiceException(exception);
+ serviceException = ServiceExceptionFactory.process("table", serviceException);
+ Error error = new Error().setError(serviceException);
+
+ // Parse the message to find which operation caused this error.
+ try {
+ XMLInputFactory xmlStreamFactory = XMLInputFactory.newFactory();
+ content.reset();
+ XMLStreamReader xmlStreamReader = xmlStreamFactory.createXMLStreamReader(content);
+
+ while (xmlStreamReader.hasNext()) {
+ xmlStreamReader.next();
+ if (xmlStreamReader.isStartElement() && "message".equals(xmlStreamReader.getLocalName())) {
+ xmlStreamReader.next();
+ // Process "message" elements only
+ String message = xmlStreamReader.getText();
+ int colonIndex = message.indexOf(':');
+ String errorOpId = message.substring(0, colonIndex);
+ int opId = Integer.parseInt(errorOpId);
+ entries[opId] = error;
+ break;
+ }
+ }
+ xmlStreamReader.close();
+ }
+ catch (XMLStreamException e1) {
+ throw new UniformInterfaceException(
+ "Batch response from server does not contain XML in the expected format", response);
+ }
+ }
+ else if (operation instanceof InsertEntityOperation) {
+ InsertEntity opResult = new InsertEntity().setEntity(atomReaderWriter.parseEntityEntry(content));
+ entries[i] = opResult;
+ }
+ else if ((operation instanceof UpdateEntityOperation) || (operation instanceof MergeEntityOperation)
+ || (operation instanceof InsertOrReplaceEntityOperation)
+ || (operation instanceof InsertOrMergeEntityOperation)) {
+ UpdateEntity opResult = new UpdateEntity().setEtag(headers.getHeader("ETag", null));
+ entries[i] = opResult;
+ }
+ else if (operation instanceof DeleteEntityOperation) {
+ DeleteEntity opResult = new DeleteEntity();
+ entries[i] = opResult;
+ }
+ }
+
+ List result = new ArrayList();
+ for (int i = 0; i < entries.length; i++) {
+ result.add(entries[i]);
+ }
+
+ return result;
+ }
+
+ private byte[] inputStreamToByteArray(InputStream inputStream) {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ byte[] buffer = new byte[1024];
+ try {
+ while (true) {
+ int n = inputStream.read(buffer);
+ if (n == -1)
+ break;
+ outputStream.write(buffer, 0, n);
+ }
+ }
+ finally {
+ inputStream.close();
+ }
+ return outputStream.toByteArray();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/XMLStreamFactory.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/XMLStreamFactory.java
new file mode 100644
index 0000000000000..064becc8b8650
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/implementation/XMLStreamFactory.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.implementation;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+public interface XMLStreamFactory {
+ XMLStreamWriter getWriter(OutputStream stream);
+
+ XMLStreamReader getReader(InputStream stream);
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchOperations.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchOperations.java
new file mode 100644
index 0000000000000..5de01c01542a8
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchOperations.java
@@ -0,0 +1,222 @@
+/**
+ * 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.table.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BatchOperations {
+ private List operations = new ArrayList();
+
+ public List getOperations() {
+ return operations;
+ }
+
+ public void setOperations(List operations) {
+ this.operations = operations;
+ }
+
+ public BatchOperations addInsertEntity(String table, Entity entity) {
+ this.operations.add(new InsertEntityOperation().setTable(table).setEntity(entity));
+ return this;
+ }
+
+ public BatchOperations addUpdateEntity(String table, Entity entity) {
+ this.operations.add(new UpdateEntityOperation().setTable(table).setEntity(entity));
+ return this;
+ }
+
+ public BatchOperations addMergeEntity(String table, Entity entity) {
+ this.operations.add(new MergeEntityOperation().setTable(table).setEntity(entity));
+ return this;
+ }
+
+ public BatchOperations addInsertOrReplaceEntity(String table, Entity entity) {
+ this.operations.add(new InsertOrReplaceEntityOperation().setTable(table).setEntity(entity));
+ return this;
+ }
+
+ public BatchOperations addInsertOrMergeEntity(String table, Entity entity) {
+ this.operations.add(new InsertOrMergeEntityOperation().setTable(table).setEntity(entity));
+ return this;
+ }
+
+ public BatchOperations addDeleteEntity(String table, String partitionKey, String rowKey, String etag) {
+ this.operations.add(new DeleteEntityOperation().setTable(table).setPartitionKey(partitionKey).setRowKey(rowKey)
+ .setEtag(etag));
+ return this;
+ }
+
+ public static abstract class Operation {
+ }
+
+ public static class InsertEntityOperation extends Operation {
+ private String table;
+ private Entity entity;
+
+ public String getTable() {
+ return table;
+ }
+
+ public InsertEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public InsertEntityOperation setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class UpdateEntityOperation extends Operation {
+ private String table;
+ private Entity entity;
+
+ public String getTable() {
+ return table;
+ }
+
+ public UpdateEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public UpdateEntityOperation setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class MergeEntityOperation extends Operation {
+ private String table;
+ private Entity entity;
+
+ public String getTable() {
+ return table;
+ }
+
+ public MergeEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public MergeEntityOperation setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class InsertOrReplaceEntityOperation extends Operation {
+ private String table;
+ private Entity entity;
+
+ public String getTable() {
+ return table;
+ }
+
+ public InsertOrReplaceEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public InsertOrReplaceEntityOperation setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class InsertOrMergeEntityOperation extends Operation {
+ private String table;
+ private Entity entity;
+
+ public String getTable() {
+ return table;
+ }
+
+ public InsertOrMergeEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public InsertOrMergeEntityOperation setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class DeleteEntityOperation extends Operation {
+ private String table;
+ private String partitionKey;
+ private String rowKey;
+ private String etag;
+
+ public String getTable() {
+ return table;
+ }
+
+ public DeleteEntityOperation setTable(String table) {
+ this.table = table;
+ return this;
+ }
+
+ public String getPartitionKey() {
+ return partitionKey;
+ }
+
+ public DeleteEntityOperation setPartitionKey(String partitionKey) {
+ this.partitionKey = partitionKey;
+ return this;
+ }
+
+ public String getRowKey() {
+ return rowKey;
+ }
+
+ public DeleteEntityOperation setRowKey(String rowKey) {
+ this.rowKey = rowKey;
+ return this;
+ }
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public DeleteEntityOperation setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchResult.java
new file mode 100644
index 0000000000000..6ca4400068bb0
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BatchResult.java
@@ -0,0 +1,79 @@
+/**
+ * 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.table.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.microsoft.windowsazure.services.core.ServiceException;
+
+public class BatchResult {
+ private List entries = new ArrayList();
+
+ public List getEntries() {
+ return entries;
+ }
+
+ public BatchResult setEntries(List entries) {
+ this.entries = entries;
+ return this;
+ }
+
+ public static abstract class Entry {
+ }
+
+ public static class InsertEntity extends Entry {
+ private Entity entity;
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public InsertEntity setEntity(Entity entity) {
+ this.entity = entity;
+ return this;
+ }
+ }
+
+ public static class UpdateEntity extends Entry {
+ private String etag;
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public UpdateEntity setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+ }
+
+ public static class DeleteEntity extends Entry {
+
+ }
+
+ public static class Error extends Entry {
+ private ServiceException error;
+
+ public ServiceException getError() {
+ return error;
+ }
+
+ public Error setError(ServiceException error) {
+ this.error = error;
+ return this;
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BinaryFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BinaryFilter.java
new file mode 100644
index 0000000000000..7666da869e056
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/BinaryFilter.java
@@ -0,0 +1,40 @@
+/**
+ * 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.table.models;
+
+public class BinaryFilter extends Filter {
+ private final String operator;
+ private final Filter left;
+ private final Filter right;
+
+ public BinaryFilter(Filter left, String operator, Filter right) {
+ this.left = left;
+ this.operator = operator;
+ this.right = right;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public Filter getLeft() {
+ return left;
+ }
+
+ public Filter getRight() {
+ return right;
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ConstantFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ConstantFilter.java
new file mode 100644
index 0000000000000..aa3dd041be7cc
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ConstantFilter.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class ConstantFilter extends Filter {
+ private final Object value;
+
+ public ConstantFilter(Object value) {
+ this.value = value;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/DeleteEntityOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/DeleteEntityOptions.java
new file mode 100644
index 0000000000000..4cce1e14a24a9
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/DeleteEntityOptions.java
@@ -0,0 +1,29 @@
+/**
+ * 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.table.models;
+
+public class DeleteEntityOptions extends TableServiceOptions {
+ private String etag;
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public DeleteEntityOptions setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/EdmType.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/EdmType.java
new file mode 100644
index 0000000000000..0f0585f2e22a9
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/EdmType.java
@@ -0,0 +1,26 @@
+/**
+ * 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.table.models;
+
+public class EdmType {
+ public static final String DATETIME = "Edm.DateTime";
+ public static final String BINARY = "Edm.Binary";
+ public static final String BOOLEAN = "Edm.Boolean";
+ public static final String DOUBLE = "Edm.Double";
+ public static final String GUID = "Edm.Guid";
+ public static final String INT32 = "Edm.Int32";
+ public static final String INT64 = "Edm.Int64";
+ public static final String STRING = "Edm.String";
+}
\ No newline at end of file
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Entity.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Entity.java
new file mode 100644
index 0000000000000..f74bda6d7003f
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Entity.java
@@ -0,0 +1,91 @@
+/**
+ * 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.table.models;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Entity {
+ private String etag;
+ private Map properties = new HashMap();
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public Entity setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+
+ public String getPartitionKey() {
+ Property p = getProperty("PartitionKey");
+ return p == null ? null : (String) p.getValue();
+ }
+
+ public Entity setPartitionKey(String partitionKey) {
+ setProperty("PartitionKey", null, partitionKey);
+ return this;
+ }
+
+ public String getRowKey() {
+ Property p = getProperty("RowKey");
+ return p == null ? null : (String) p.getValue();
+ }
+
+ public Entity setRowKey(String rowKey) {
+ setProperty("RowKey", null, rowKey);
+ return this;
+ }
+
+ public Date getTimestamp() {
+ Property p = getProperty("Timestamp");
+ return p == null ? null : (Date) p.getValue();
+ }
+
+ public Entity setTimestamp(Date timestamp) {
+ setProperty("Timestamp", null, timestamp);
+ return this;
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public Entity setProperties(Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public Property getProperty(String name) {
+ return properties.get(name);
+ }
+
+ public Entity setProperty(String name, Property property) {
+ this.properties.put(name, property);
+ return this;
+ }
+
+ public Entity setProperty(String name, String edmType, Object value) {
+ setProperty(name, new Property().setEdmType(edmType).setValue(value));
+ return this;
+ }
+
+ public Object getPropertyValue(String name) {
+ Property p = getProperty(name);
+ return p == null ? null : p.getValue();
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Filter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Filter.java
new file mode 100644
index 0000000000000..1e410d2adfb46
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Filter.java
@@ -0,0 +1,65 @@
+/**
+ * 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.table.models;
+
+public class Filter {
+ public static UnaryFilter not(Filter operand) {
+ return new UnaryFilter("not", operand);
+ }
+
+ public static BinaryFilter and(Filter left, Filter right) {
+ return new BinaryFilter(left, "and", right);
+ }
+
+ public static BinaryFilter or(Filter left, Filter right) {
+ return new BinaryFilter(left, "or", right);
+ }
+
+ public static BinaryFilter eq(Filter left, Filter right) {
+ return new BinaryFilter(left, "eq", right);
+ }
+
+ public static BinaryFilter ne(Filter left, Filter right) {
+ return new BinaryFilter(left, "ne", right);
+ }
+
+ public static BinaryFilter ge(Filter left, Filter right) {
+ return new BinaryFilter(left, "ge", right);
+ }
+
+ public static BinaryFilter gt(Filter left, Filter right) {
+ return new BinaryFilter(left, "gt", right);
+ }
+
+ public static BinaryFilter lt(Filter left, Filter right) {
+ return new BinaryFilter(left, "lt", right);
+ }
+
+ public static BinaryFilter le(Filter left, Filter right) {
+ return new BinaryFilter(left, "le", right);
+ }
+
+ public static ConstantFilter constant(Object value) {
+ return new ConstantFilter(value);
+ }
+
+ public static PropertyNameFilter propertyName(String value) {
+ return new PropertyNameFilter(value);
+ }
+
+ public static QueryStringFilter queryString(String value) {
+ return new QueryStringFilter(value);
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetEntityResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetEntityResult.java
new file mode 100644
index 0000000000000..336c436da06c8
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetEntityResult.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class GetEntityResult {
+ private Entity entity;
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public void setEntity(Entity entity) {
+ this.entity = entity;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetServicePropertiesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetServicePropertiesResult.java
new file mode 100644
index 0000000000000..e56a2c8f9368d
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetServicePropertiesResult.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class GetServicePropertiesResult {
+ private ServiceProperties value;
+
+ public ServiceProperties getValue() {
+ return value;
+ }
+
+ public void setValue(ServiceProperties value) {
+ this.value = value;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetTableResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetTableResult.java
new file mode 100644
index 0000000000000..0e23a0d752c20
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/GetTableResult.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class GetTableResult {
+ private TableEntry tableEntry;
+
+ public TableEntry getTableEntry() {
+ return tableEntry;
+ }
+
+ public void setTableEntry(TableEntry tableEntry) {
+ this.tableEntry = tableEntry;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/InsertEntityResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/InsertEntityResult.java
new file mode 100644
index 0000000000000..eca0203954967
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/InsertEntityResult.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class InsertEntityResult {
+ private Entity entity;
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public void setEntity(Entity entity) {
+ this.entity = entity;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Property.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Property.java
new file mode 100644
index 0000000000000..197584f920e6d
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/Property.java
@@ -0,0 +1,38 @@
+/**
+ * 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.table.models;
+
+public class Property {
+ private String edmType;
+ private Object value;
+
+ public String getEdmType() {
+ return edmType;
+ }
+
+ public Property setEdmType(String edmType) {
+ this.edmType = edmType;
+ return this;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Property setValue(Object value) {
+ this.value = value;
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/PropertyNameFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/PropertyNameFilter.java
new file mode 100644
index 0000000000000..49cb129d86e03
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/PropertyNameFilter.java
@@ -0,0 +1,28 @@
+/**
+ * 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.table.models;
+
+public class PropertyNameFilter extends Filter {
+ private final String propertyName;
+
+ public PropertyNameFilter(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesOptions.java
new file mode 100644
index 0000000000000..e5d7a7c511513
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesOptions.java
@@ -0,0 +1,103 @@
+/**
+ * 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.table.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QueryEntitiesOptions extends TableServiceOptions {
+
+ private List selectFields = new ArrayList();
+ private String from;
+ private Filter filter;
+ private List orderByFields = new ArrayList();
+ private Integer top;
+
+ public String nextPartitionKey;
+ public String nextRowKey;
+
+ public String getNextPartitionKey() {
+ return nextPartitionKey;
+ }
+
+ public QueryEntitiesOptions setNextPartitionKey(String nextPartitionKey) {
+ this.nextPartitionKey = nextPartitionKey;
+ return this;
+ }
+
+ public String getNextRowKey() {
+ return nextRowKey;
+ }
+
+ public QueryEntitiesOptions setNextRowKey(String nextRowKey) {
+ this.nextRowKey = nextRowKey;
+ return this;
+ }
+
+ public List getSelectFields() {
+ return selectFields;
+ }
+
+ public QueryEntitiesOptions setSelectFields(List selectFields) {
+ this.selectFields = selectFields;
+ return this;
+ }
+
+ public QueryEntitiesOptions addSelectField(String selectField) {
+ this.selectFields.add(selectField);
+ return this;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public QueryEntitiesOptions setFrom(String from) {
+ this.from = from;
+ return this;
+ }
+
+ public Filter getFilter() {
+ return filter;
+ }
+
+ public QueryEntitiesOptions setFilter(Filter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ public List getOrderByFields() {
+ return orderByFields;
+ }
+
+ public QueryEntitiesOptions setOrderByFields(List orderByFields) {
+ this.orderByFields = orderByFields;
+ return this;
+ }
+
+ public QueryEntitiesOptions addOrderByField(String orderByField) {
+ this.orderByFields.add(orderByField);
+ return this;
+ }
+
+ public Integer getTop() {
+ return top;
+ }
+
+ public QueryEntitiesOptions setTop(Integer top) {
+ this.top = top;
+ return this;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesResult.java
new file mode 100644
index 0000000000000..9756661eef96b
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryEntitiesResult.java
@@ -0,0 +1,48 @@
+/**
+ * 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.table.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QueryEntitiesResult {
+ private String nextPartitionKey;
+ private String nextRowKey;
+ private List entities = new ArrayList();
+
+ public List getEntities() {
+ return entities;
+ }
+
+ public void setEntities(List entities) {
+ this.entities = entities;
+ }
+
+ public String getNextPartitionKey() {
+ return nextPartitionKey;
+ }
+
+ public void setNextPartitionKey(String nextPartitionKey) {
+ this.nextPartitionKey = nextPartitionKey;
+ }
+
+ public String getNextRowKey() {
+ return nextRowKey;
+ }
+
+ public void setNextRowKey(String nextRowKey) {
+ this.nextRowKey = nextRowKey;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryStringFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryStringFilter.java
new file mode 100644
index 0000000000000..77341e2477c57
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryStringFilter.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class QueryStringFilter extends Filter {
+ private final String queryString;
+
+ public QueryStringFilter(String queryString) {
+ this.queryString = queryString;
+ }
+
+ public String getQueryString() {
+ return queryString;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesOptions.java
new file mode 100644
index 0000000000000..d72c580a402f4
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesOptions.java
@@ -0,0 +1,48 @@
+/**
+ * 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.table.models;
+
+public class QueryTablesOptions extends TableServiceOptions {
+ private Filter filter;
+ private String nextTableName;
+ private String prefix;
+
+ public Filter getFilter() {
+ return filter;
+ }
+
+ public QueryTablesOptions setFilter(Filter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ public String getNextTableName() {
+ return nextTableName;
+ }
+
+ public QueryTablesOptions setNextTableName(String nextTableName) {
+ this.nextTableName = nextTableName;
+ return this;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public QueryTablesOptions setPrefix(String prefix) {
+ this.prefix = prefix;
+ return this;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesResult.java
new file mode 100644
index 0000000000000..9c6158382dba3
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/QueryTablesResult.java
@@ -0,0 +1,38 @@
+/**
+ * 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.table.models;
+
+import java.util.List;
+
+public class QueryTablesResult {
+ private String nextTableName;
+ private List tables;
+
+ public String getNextTableName() {
+ return nextTableName;
+ }
+
+ public void setNextTableName(String nextTableName) {
+ this.nextTableName = nextTableName;
+ }
+
+ public List getTables() {
+ return tables;
+ }
+
+ public void setTables(List tables) {
+ this.tables = tables;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ServiceProperties.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ServiceProperties.java
new file mode 100644
index 0000000000000..01a18543864b1
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/ServiceProperties.java
@@ -0,0 +1,161 @@
+/**
+ * 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.table.models;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "StorageServiceProperties")
+public class ServiceProperties {
+ private Logging logging = new Logging();
+ private Metrics metrics = new Metrics();
+
+ @XmlElement(name = "Logging")
+ public Logging getLogging() {
+ return logging;
+ }
+
+ public void setLogging(Logging logging) {
+ this.logging = logging;
+ }
+
+ @XmlElement(name = "Metrics")
+ public Metrics getMetrics() {
+ return metrics;
+ }
+
+ public void setMetrics(Metrics metrics) {
+ this.metrics = metrics;
+ }
+
+ public static class Logging {
+ private String version;
+ private boolean delete;
+ private boolean read;
+ private boolean write;
+ private RetentionPolicy retentionPolicy;
+
+ @XmlElement(name = "RetentionPolicy")
+ public RetentionPolicy getRetentionPolicy() {
+ return retentionPolicy;
+ }
+
+ public void setRetentionPolicy(RetentionPolicy retentionPolicy) {
+ this.retentionPolicy = retentionPolicy;
+ }
+
+ @XmlElement(name = "Write")
+ public boolean isWrite() {
+ return write;
+ }
+
+ public void setWrite(boolean write) {
+ this.write = write;
+ }
+
+ @XmlElement(name = "Read")
+ public boolean isRead() {
+ return read;
+ }
+
+ public void setRead(boolean read) {
+ this.read = read;
+ }
+
+ @XmlElement(name = "Delete")
+ public boolean isDelete() {
+ return delete;
+ }
+
+ public void setDelete(boolean delete) {
+ this.delete = delete;
+ }
+
+ @XmlElement(name = "Version")
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+ }
+
+ public static class Metrics {
+ private String version;
+ private boolean enabled;
+ private Boolean includeAPIs;
+ private RetentionPolicy retentionPolicy;
+
+ @XmlElement(name = "RetentionPolicy")
+ public RetentionPolicy getRetentionPolicy() {
+ return retentionPolicy;
+ }
+
+ public void setRetentionPolicy(RetentionPolicy retentionPolicy) {
+ this.retentionPolicy = retentionPolicy;
+ }
+
+ @XmlElement(name = "IncludeAPIs")
+ public Boolean isIncludeAPIs() {
+ return includeAPIs;
+ }
+
+ public void setIncludeAPIs(Boolean includeAPIs) {
+ this.includeAPIs = includeAPIs;
+ }
+
+ @XmlElement(name = "Enabled")
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @XmlElement(name = "Version")
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+ }
+
+ public static class RetentionPolicy {
+ private boolean enabled;
+ private Integer days; // nullable, because optional if "enabled" is false
+
+ @XmlElement(name = "Days")
+ public Integer getDays() {
+ return days;
+ }
+
+ public void setDays(Integer days) {
+ this.days = days;
+ }
+
+ @XmlElement(name = "Enabled")
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableEntry.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableEntry.java
new file mode 100644
index 0000000000000..2e520bc36db17
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableEntry.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class TableEntry {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableServiceOptions.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableServiceOptions.java
new file mode 100644
index 0000000000000..c4a733a6e3a6b
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/TableServiceOptions.java
@@ -0,0 +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.table.models;
+
+public class TableServiceOptions {
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UnaryFilter.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UnaryFilter.java
new file mode 100644
index 0000000000000..99aa90409830b
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UnaryFilter.java
@@ -0,0 +1,34 @@
+/**
+ * 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.table.models;
+
+public class UnaryFilter extends Filter {
+ private final String operator;
+ private final Filter operand;
+
+ public UnaryFilter(String operator, Filter operand) {
+ this.operator = operator;
+ this.operand = operand;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public Filter getOperand() {
+ return operand;
+ }
+
+}
diff --git a/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UpdateEntityResult.java b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UpdateEntityResult.java
new file mode 100644
index 0000000000000..dc18aa98996ec
--- /dev/null
+++ b/microsoft-azure-api/src/main/java/com/microsoft/windowsazure/services/table/models/UpdateEntityResult.java
@@ -0,0 +1,27 @@
+/**
+ * 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.table.models;
+
+public class UpdateEntityResult {
+ private String etag;
+
+ public String getEtag() {
+ return etag;
+ }
+
+ public void setEtag(String etag) {
+ this.etag = etag;
+ }
+}
diff --git a/microsoft-azure-api/src/main/resources/META-INF/services/com.microsoft.windowsazure.services.core.Builder$Exports b/microsoft-azure-api/src/main/resources/META-INF/services/com.microsoft.windowsazure.services.core.Builder$Exports
index cc7087393981f..07fdb1c4e7b67 100644
--- a/microsoft-azure-api/src/main/resources/META-INF/services/com.microsoft.windowsazure.services.core.Builder$Exports
+++ b/microsoft-azure-api/src/main/resources/META-INF/services/com.microsoft.windowsazure.services.core.Builder$Exports
@@ -1,5 +1,6 @@
com.microsoft.windowsazure.services.blob.Exports
com.microsoft.windowsazure.services.queue.Exports
+com.microsoft.windowsazure.services.table.Exports
com.microsoft.windowsazure.services.serviceBus.Exports
com.microsoft.windowsazure.services.serviceBus.implementation.Exports
com.microsoft.windowsazure.services.core.utils.Exports
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverterTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverterTests.java
new file mode 100644
index 0000000000000..c69d18d8f1ebb
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/blob/implementation/ISO8601DateConverterTests.java
@@ -0,0 +1,123 @@
+/**
+ * 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.blob.implementation;
+
+import static org.junit.Assert.*;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.junit.Test;
+
+public class ISO8601DateConverterTests {
+ @Test
+ public void shortFormatWorks() throws Exception {
+ // Arrange
+ ISO8601DateConverter converter = new ISO8601DateConverter();
+ String value = "2012-01-12T00:35:58Z";
+
+ // Act
+ Date result = converter.parse(value);
+ String value2 = converter.format(result);
+
+ // Assert
+ assertNotNull(result);
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(result);
+ calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
+ assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
+ assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
+ assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
+ assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
+ assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
+ assertEquals("Second", 58, calendar.get(Calendar.SECOND));
+ assertEquals("Millisecond", 0, calendar.get(Calendar.MILLISECOND));
+
+ assertEquals("2012-01-12T00:35:58.000Z", value2);
+ }
+
+ @Test
+ public void longFormatWorks() throws Exception {
+ // Arrange
+ ISO8601DateConverter converter = new ISO8601DateConverter();
+ String value = "2012-01-12T00:35:58.1234567Z";
+
+ // Act
+ Date result = converter.parse(value);
+ String value2 = converter.format(result);
+
+ // Assert
+ assertNotNull(result);
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(result);
+ calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
+ assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
+ assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
+ assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
+ assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
+ assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
+ assertEquals("Second", 58, calendar.get(Calendar.SECOND));
+ assertEquals("Millisecond", 123, calendar.get(Calendar.MILLISECOND));
+
+ assertEquals("2012-01-12T00:35:58.123Z", value2);
+ }
+
+ @Test
+ public void mixedFormatWorks() throws Exception {
+ // Arrange
+ ISO8601DateConverter converter = new ISO8601DateConverter();
+ String value = "2012-01-12T00:35:58.12Z";
+
+ // Act
+ Date result = converter.parse(value);
+ String value2 = converter.format(result);
+
+ // Assert
+ assertNotNull(result);
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(result);
+ calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
+ assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
+ assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
+ assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
+ assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
+ assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
+ assertEquals("Second", 58, calendar.get(Calendar.SECOND));
+ assertEquals("Millisecond", 120, calendar.get(Calendar.MILLISECOND));
+
+ assertEquals("2012-01-12T00:35:58.120Z", value2);
+ }
+
+ @Test
+ public void shortFormatRoundTrips() throws Exception {
+ // Arrange
+ ISO8601DateConverter converter = new ISO8601DateConverter();
+ String value = "2012-01-12T00:35:58Z";
+
+ // Act
+ Date result = converter.parse(value);
+ String value2 = converter.shortFormat(result);
+ String value3 = converter.format(result);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(value, value2);
+ assertEquals("2012-01-12T00:35:58.000Z", value3);
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/IntegrationTestBase.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/IntegrationTestBase.java
new file mode 100644
index 0000000000000..8b7b18382d59d
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/IntegrationTestBase.java
@@ -0,0 +1,43 @@
+/**
+ * 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.table;
+
+import com.microsoft.windowsazure.services.core.Configuration;
+
+public abstract class IntegrationTestBase {
+ protected static Configuration createConfiguration() {
+ Configuration config = Configuration.getInstance();
+ overrideWithEnv(config, TableConfiguration.ACCOUNT_NAME);
+ overrideWithEnv(config, TableConfiguration.ACCOUNT_KEY);
+ overrideWithEnv(config, TableConfiguration.URI);
+ return config;
+ }
+
+ private static void overrideWithEnv(Configuration config, String key) {
+ String value = System.getenv(key);
+ if (value == null)
+ return;
+
+ config.setProperty(key, value);
+ }
+
+ protected static boolean isRunningWithEmulator(Configuration config) {
+ String accountName = "devstoreaccount1";
+ String accountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
+
+ return accountName.equals(config.getProperty(TableConfiguration.ACCOUNT_NAME))
+ && accountKey.equals(config.getProperty(TableConfiguration.ACCOUNT_KEY));
+ }
+}
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
new file mode 100644
index 0000000000000..07b25300bc20b
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/TableServiceIntegrationTest.java
@@ -0,0 +1,1088 @@
+/**
+ * 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.table;
+
+import static org.junit.Assert.*;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.windowsazure.services.core.Configuration;
+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.table.models.BatchOperations;
+import com.microsoft.windowsazure.services.table.models.BatchResult;
+import com.microsoft.windowsazure.services.table.models.BatchResult.DeleteEntity;
+import com.microsoft.windowsazure.services.table.models.BatchResult.InsertEntity;
+import com.microsoft.windowsazure.services.table.models.BatchResult.UpdateEntity;
+import com.microsoft.windowsazure.services.table.models.DeleteEntityOptions;
+import com.microsoft.windowsazure.services.table.models.EdmType;
+import com.microsoft.windowsazure.services.table.models.Entity;
+import com.microsoft.windowsazure.services.table.models.Filter;
+import com.microsoft.windowsazure.services.table.models.GetEntityResult;
+import com.microsoft.windowsazure.services.table.models.GetTableResult;
+import com.microsoft.windowsazure.services.table.models.InsertEntityResult;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryEntitiesResult;
+import com.microsoft.windowsazure.services.table.models.QueryTablesOptions;
+import com.microsoft.windowsazure.services.table.models.QueryTablesResult;
+import com.microsoft.windowsazure.services.table.models.ServiceProperties;
+import com.microsoft.windowsazure.services.table.models.TableEntry;
+
+public class TableServiceIntegrationTest extends IntegrationTestBase {
+ private static final String testTablesPrefix = "sdktest";
+ private static final String createableTablesPrefix = "csdktest";
+ private static String TEST_TABLE_1;
+ private static String TEST_TABLE_2;
+ private static String TEST_TABLE_3;
+ private static String TEST_TABLE_4;
+ private static String TEST_TABLE_5;
+ private static String TEST_TABLE_6;
+ private static String TEST_TABLE_7;
+ private static String TEST_TABLE_8;
+ private static String CREATABLE_TABLE_1;
+ private static String CREATABLE_TABLE_2;
+ //private static String CREATABLE_TABLE_3;
+ private static String[] creatableTables;
+ private static String[] testTables;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ //System.setProperty("http.proxyHost", "127.0.0.1");
+ //System.setProperty("http.proxyPort", "8888");
+
+ // Setup container names array (list of container names used by
+ // integration tests)
+ testTables = new String[10];
+ for (int i = 0; i < testTables.length; i++) {
+ testTables[i] = String.format("%s%d", testTablesPrefix, i + 1);
+ }
+
+ creatableTables = new String[10];
+ for (int i = 0; i < creatableTables.length; i++) {
+ creatableTables[i] = String.format("%s%d", createableTablesPrefix, i + 1);
+ }
+
+ TEST_TABLE_1 = testTables[0];
+ TEST_TABLE_2 = testTables[1];
+ TEST_TABLE_3 = testTables[2];
+ TEST_TABLE_4 = testTables[3];
+ TEST_TABLE_5 = testTables[4];
+ TEST_TABLE_6 = testTables[5];
+ TEST_TABLE_7 = testTables[6];
+ TEST_TABLE_8 = testTables[7];
+
+ CREATABLE_TABLE_1 = creatableTables[0];
+ CREATABLE_TABLE_2 = creatableTables[1];
+ //CREATABLE_TABLE_3 = creatableTables[2];
+
+ // Create all test containers and their content
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ deleteAllTables(service, testTables);
+ deleteAllTables(service, creatableTables);
+ createTables(service, testTablesPrefix, testTables);
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ deleteTables(service, testTablesPrefix, testTables);
+ deleteTables(service, createableTablesPrefix, creatableTables);
+ }
+
+ private static void createTables(TableContract service, String prefix, String[] list) throws Exception {
+ // Retry creating every table as long as we get "409 - Table being deleted" error
+ service = service.withFilter(new RetryPolicyFilter(new ExponentialRetryPolicy(new int[] { 409 })));
+
+ Set containers = queryTables(service, prefix);
+ for (String item : list) {
+ if (!containers.contains(item)) {
+ service.createTable(item);
+ }
+ }
+ }
+
+ private static void deleteTables(TableContract service, String prefix, String[] list) throws Exception {
+ Set containers = queryTables(service, prefix);
+ for (String item : list) {
+ if (containers.contains(item)) {
+ service.deleteTable(item);
+ }
+ }
+ }
+
+ private static void deleteAllTables(TableContract service, String[] list) throws Exception {
+ for (String item : list) {
+ try {
+ service.deleteTable(item);
+ }
+ catch (ServiceException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private static Set queryTables(TableContract service, String prefix) throws Exception {
+ HashSet result = new HashSet();
+ QueryTablesResult list = service.queryTables(new QueryTablesOptions().setPrefix(prefix));
+ for (TableEntry item : list.getTables()) {
+ result.add(item.getName());
+ }
+ return result;
+ }
+
+ @Test
+ public void getServicePropertiesWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Don't run this test with emulator, as v1.6 doesn't support this method
+ if (isRunningWithEmulator(config)) {
+ return;
+ }
+
+ // Act
+ ServiceProperties props = service.getServiceProperties().getValue();
+
+ // Assert
+ assertNotNull(props);
+ assertNotNull(props.getLogging());
+ assertNotNull(props.getLogging().getRetentionPolicy());
+ assertNotNull(props.getLogging().getVersion());
+ assertNotNull(props.getMetrics().getRetentionPolicy());
+ assertNotNull(props.getMetrics().getVersion());
+ }
+
+ @Test
+ public void setServicePropertiesWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Don't run this test with emulator, as v1.6 doesn't support this method
+ if (isRunningWithEmulator(config)) {
+ return;
+ }
+
+ // Act
+ ServiceProperties props = service.getServiceProperties().getValue();
+
+ props.getLogging().setRead(true);
+ service.setServiceProperties(props);
+
+ props = service.getServiceProperties().getValue();
+
+ // Assert
+ assertNotNull(props);
+ assertNotNull(props.getLogging());
+ assertNotNull(props.getLogging().getRetentionPolicy());
+ assertNotNull(props.getLogging().getVersion());
+ assertTrue(props.getLogging().isRead());
+ assertNotNull(props.getMetrics().getRetentionPolicy());
+ assertNotNull(props.getMetrics().getVersion());
+ }
+
+ @Test
+ public void createTablesWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Act
+ Exception error;
+ try {
+ service.getTable(CREATABLE_TABLE_1);
+ error = null;
+ }
+ catch (Exception e) {
+ error = e;
+ }
+ service.createTable(CREATABLE_TABLE_1);
+ GetTableResult result = service.getTable(CREATABLE_TABLE_1);
+
+ // Assert
+ assertNotNull(error);
+ assertNotNull(result);
+ }
+
+ @Test
+ public void deleteTablesWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Act
+ service.createTable(CREATABLE_TABLE_2);
+ GetTableResult result = service.getTable(CREATABLE_TABLE_2);
+
+ service.deleteTable(CREATABLE_TABLE_2);
+ Exception error;
+ try {
+ service.getTable(CREATABLE_TABLE_2);
+ error = null;
+ }
+ catch (Exception e) {
+ error = e;
+ }
+
+ // Assert
+ assertNotNull(error);
+ assertNotNull(result);
+ }
+
+ @Test
+ public void queryTablesWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Act
+ QueryTablesResult result = service.queryTables();
+
+ // Assert
+ assertNotNull(result);
+ }
+
+ @Test
+ public void queryTablesWithPrefixWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Act
+ QueryTablesResult result = service.queryTables(new QueryTablesOptions().setPrefix(testTablesPrefix));
+
+ // Assert
+ assertNotNull(result);
+ }
+
+ @Test
+ public void getTableWorks() throws Exception {
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+
+ // Act
+ GetTableResult result = service.getTable(TEST_TABLE_1);
+
+ // Assert
+ assertNotNull(result);
+ }
+
+ @Test
+ public void insertEntityWorks() throws Exception {
+ System.out.println("insertEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ byte[] binaryData = new byte[] { 1, 2, 3, 4 };
+ UUID uuid = UUID.randomUUID();
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("insertEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date()).setProperty("test6", EdmType.BINARY, binaryData)
+ .setProperty("test7", EdmType.GUID, uuid);
+
+ // Act
+ InsertEntityResult result = service.insertEntity(TEST_TABLE_2, entity);
+
+ // Assert
+ assertNotNull(result);
+ assertNotNull(result.getEntity());
+
+ assertEquals("001", result.getEntity().getPartitionKey());
+ assertEquals("insertEntityWorks", result.getEntity().getRowKey());
+ assertNotNull(result.getEntity().getTimestamp());
+ assertNotNull(result.getEntity().getEtag());
+
+ assertNotNull(result.getEntity().getProperty("test"));
+ assertEquals(true, result.getEntity().getProperty("test").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test2"));
+ assertEquals("value", result.getEntity().getProperty("test2").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test3"));
+ assertEquals(3, result.getEntity().getProperty("test3").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test4"));
+ assertEquals(12345678901L, result.getEntity().getProperty("test4").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test5"));
+ assertTrue(result.getEntity().getProperty("test5").getValue() instanceof Date);
+
+ assertNotNull(result.getEntity().getProperty("test6"));
+ assertTrue(result.getEntity().getProperty("test6").getValue() instanceof byte[]);
+ byte[] returnedBinaryData = (byte[]) result.getEntity().getProperty("test6").getValue();
+ assertEquals(binaryData.length, returnedBinaryData.length);
+ for (int i = 0; i < binaryData.length; i++) {
+ assertEquals(binaryData[i], returnedBinaryData[i]);
+ }
+
+ assertNotNull(result.getEntity().getProperty("test7"));
+ assertTrue(result.getEntity().getProperty("test7").getValue() instanceof UUID);
+ assertEquals(uuid.toString(), result.getEntity().getProperty("test7").getValue().toString());
+ }
+
+ @Test
+ public void updateEntityWorks() throws Exception {
+ System.out.println("updateEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("updateEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ InsertEntityResult result = service.insertEntity(TEST_TABLE_2, entity);
+ result.getEntity().setProperty("test4", EdmType.INT32, 5);
+ service.updateEntity(TEST_TABLE_2, result.getEntity());
+
+ // Assert
+ }
+
+ @Test
+ public void insertOrReplaceEntityWorks() throws Exception {
+ System.out.println("insertOrReplaceEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("insertOrReplaceEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ service.insertOrReplaceEntity(TEST_TABLE_2, entity);
+ entity.setProperty("test4", EdmType.INT32, 5);
+ entity.setProperty("test6", EdmType.INT32, 6);
+ service.insertOrReplaceEntity(TEST_TABLE_2, entity);
+
+ // Assert
+ }
+
+ @Test
+ public void insertOrMergeEntityWorks() throws Exception {
+ System.out.println("insertOrMergeEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("insertOrMergeEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ service.insertOrMergeEntity(TEST_TABLE_2, entity);
+ entity.setProperty("test4", EdmType.INT32, 5);
+ entity.setProperty("test6", EdmType.INT32, 6);
+ service.insertOrMergeEntity(TEST_TABLE_2, entity);
+
+ // Assert
+ }
+
+ @Test
+ public void mergeEntityWorks() throws Exception {
+ System.out.println("mergeEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("mergeEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ InsertEntityResult result = service.insertEntity(TEST_TABLE_2, entity);
+
+ result.getEntity().setProperty("test4", EdmType.INT32, 5);
+ result.getEntity().setProperty("test6", EdmType.INT32, 6);
+ service.mergeEntity(TEST_TABLE_2, result.getEntity());
+
+ // Assert
+ }
+
+ @Test
+ public void deleteEntityWorks() throws Exception {
+ System.out.println("deleteEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("deleteEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ InsertEntityResult result = service.insertEntity(TEST_TABLE_2, entity);
+
+ service.deleteEntity(TEST_TABLE_2, result.getEntity().getPartitionKey(), result.getEntity().getRowKey());
+
+ // Assert
+ }
+
+ @Test
+ public void deleteEntityTroublesomeKeyWorks() throws Exception {
+ System.out.println("deleteEntityTroublesomeKeyWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity1 = new Entity().setPartitionKey("001").setRowKey("key with spaces");
+ Entity entity2 = new Entity().setPartitionKey("001").setRowKey("key'with'quotes");
+ Entity entity3 = new Entity().setPartitionKey("001").setRowKey("keyWithUnicode \uB2E4");
+ Entity entity4 = new Entity().setPartitionKey("001").setRowKey("key 'with'' \uB2E4");
+
+ // Act
+ InsertEntityResult result1 = service.insertEntity(TEST_TABLE_2, entity1);
+ InsertEntityResult result2 = service.insertEntity(TEST_TABLE_2, entity2);
+ InsertEntityResult result3 = service.insertEntity(TEST_TABLE_2, entity3);
+ InsertEntityResult result4 = service.insertEntity(TEST_TABLE_2, entity4);
+
+ service.deleteEntity(TEST_TABLE_2, result1.getEntity().getPartitionKey(), result1.getEntity().getRowKey());
+ service.deleteEntity(TEST_TABLE_2, result2.getEntity().getPartitionKey(), result2.getEntity().getRowKey());
+ service.deleteEntity(TEST_TABLE_2, result3.getEntity().getPartitionKey(), result3.getEntity().getRowKey());
+ service.deleteEntity(TEST_TABLE_2, result4.getEntity().getPartitionKey(), result4.getEntity().getRowKey());
+
+ // Assert
+ try {
+ service.getEntity(TEST_TABLE_2, result1.getEntity().getPartitionKey(), result1.getEntity().getRowKey());
+ assertFalse("Expect an exception when getting an entity that does not exist", true);
+ }
+ catch (ServiceException e) {
+ assertEquals("expect getHttpStatusCode", 404, e.getHttpStatusCode());
+
+ }
+
+ QueryEntitiesResult assertResult2 = service.queryEntities(
+ TEST_TABLE_2,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("RowKey"),
+ Filter.constant("key'with'quotes"))));
+
+ assertEquals(0, assertResult2.getEntities().size());
+
+ QueryEntitiesResult assertResult3 = service.queryEntities(TEST_TABLE_2);
+ for (Entity entity : assertResult3.getEntities()) {
+ assertFalse("Entity3 should be removed from the table", entity3.getRowKey().equals(entity.getRowKey()));
+ assertFalse("Entity4 should be removed from the table", entity4.getRowKey().equals(entity.getRowKey()));
+ }
+ }
+
+ @Test
+ public void deleteEntityWithETagWorks() throws Exception {
+ System.out.println("deleteEntityWithETagWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("deleteEntityWithETagWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ InsertEntityResult result = service.insertEntity(TEST_TABLE_2, entity);
+
+ service.deleteEntity(TEST_TABLE_2, result.getEntity().getPartitionKey(), result.getEntity().getRowKey(),
+ new DeleteEntityOptions().setEtag(result.getEntity().getEtag()));
+
+ // Assert
+ }
+
+ @Test
+ public void getEntityWorks() throws Exception {
+ System.out.println("getEntityWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ byte[] binaryData = new byte[] { 1, 2, 3, 4 };
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("getEntityWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date()).setProperty("test6", EdmType.BINARY, binaryData);
+
+ // Act
+ InsertEntityResult insertResult = service.insertEntity(TEST_TABLE_2, entity);
+ GetEntityResult result = service.getEntity(TEST_TABLE_2, insertResult.getEntity().getPartitionKey(),
+ insertResult.getEntity().getRowKey());
+
+ // Assert
+ assertNotNull(result);
+ assertNotNull(result.getEntity());
+
+ assertEquals("001", result.getEntity().getPartitionKey());
+ assertEquals("getEntityWorks", result.getEntity().getRowKey());
+ assertNotNull(result.getEntity().getTimestamp());
+ assertNotNull(result.getEntity().getEtag());
+
+ assertNotNull(result.getEntity().getProperty("test"));
+ assertEquals(true, result.getEntity().getProperty("test").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test2"));
+ assertEquals("value", result.getEntity().getProperty("test2").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test3"));
+ assertEquals(3, result.getEntity().getProperty("test3").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test4"));
+ assertEquals(12345678901L, result.getEntity().getProperty("test4").getValue());
+
+ assertNotNull(result.getEntity().getProperty("test5"));
+ assertTrue(result.getEntity().getProperty("test5").getValue() instanceof Date);
+
+ assertNotNull(result.getEntity().getProperty("test6"));
+ assertTrue(result.getEntity().getProperty("test6").getValue() instanceof byte[]);
+ byte[] returnedBinaryData = (byte[]) result.getEntity().getProperty("test6").getValue();
+ assertEquals(binaryData.length, returnedBinaryData.length);
+ for (int i = 0; i < binaryData.length; i++) {
+ assertEquals(binaryData[i], returnedBinaryData[i]);
+ }
+ }
+
+ @Test
+ public void queryEntitiesWorks() throws Exception {
+ System.out.println("queryEntitiesWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("queryEntitiesWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ // Act
+ service.insertEntity(TEST_TABLE_3, entity);
+ QueryEntitiesResult result = service.queryEntities(TEST_TABLE_3);
+
+ // Assert
+ assertNotNull(result);
+ assertNotNull(result.getEntities());
+ assertEquals(1, result.getEntities().size());
+
+ assertNotNull(result.getEntities().get(0));
+
+ assertEquals("001", result.getEntities().get(0).getPartitionKey());
+ assertEquals("queryEntitiesWorks", result.getEntities().get(0).getRowKey());
+ assertNotNull(result.getEntities().get(0).getTimestamp());
+ assertNotNull(result.getEntities().get(0).getEtag());
+
+ assertNotNull(result.getEntities().get(0).getProperty("test"));
+ assertEquals(true, result.getEntities().get(0).getProperty("test").getValue());
+
+ assertNotNull(result.getEntities().get(0).getProperty("test2"));
+ assertEquals("value", result.getEntities().get(0).getProperty("test2").getValue());
+
+ assertNotNull(result.getEntities().get(0).getProperty("test3"));
+ assertEquals(3, result.getEntities().get(0).getProperty("test3").getValue());
+
+ assertNotNull(result.getEntities().get(0).getProperty("test4"));
+ assertEquals(12345678901L, result.getEntities().get(0).getProperty("test4").getValue());
+
+ assertNotNull(result.getEntities().get(0).getProperty("test5"));
+ assertTrue(result.getEntities().get(0).getProperty("test5").getValue() instanceof Date);
+ }
+
+ @Test
+ public void queryEntitiesWithPaginationWorks() throws Exception {
+ System.out.println("queryEntitiesWithPaginationWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_4;
+ int numberOfEntries = 20;
+ for (int i = 0; i < numberOfEntries; i++) {
+ Entity entity = new Entity().setPartitionKey("001").setRowKey("queryEntitiesWithPaginationWorks-" + i)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ service.insertEntity(table, entity);
+ }
+
+ // Act
+ int entryCount = 0;
+ String nextPartitionKey = null;
+ String nextRowKey = null;
+ while (true) {
+ QueryEntitiesResult result = service.queryEntities(table,
+ new QueryEntitiesOptions().setNextPartitionKey(nextPartitionKey).setNextRowKey(nextRowKey));
+
+ entryCount += result.getEntities().size();
+
+ if (nextPartitionKey == null)
+ break;
+
+ nextPartitionKey = result.getNextPartitionKey();
+ nextRowKey = result.getNextRowKey();
+ }
+
+ // Assert
+ assertEquals(numberOfEntries, entryCount);
+ }
+
+ @Test
+ public void queryEntitiesWithFilterWorks() throws Exception {
+ System.out.println("queryEntitiesWithFilterWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_5;
+ int numberOfEntries = 5;
+ Entity[] entities = new Entity[numberOfEntries];
+ for (int i = 0; i < numberOfEntries; i++) {
+ entities[i] = new Entity().setPartitionKey("001").setRowKey("queryEntitiesWithFilterWorks-" + i)
+ .setProperty("test", EdmType.BOOLEAN, (i % 2 == 0))
+ .setProperty("test2", EdmType.STRING, "'value'" + i).setProperty("test3", EdmType.INT32, i)
+ .setProperty("test4", EdmType.INT64, 12345678901L + i)
+ .setProperty("test5", EdmType.DATETIME, new Date(i * 1000))
+ .setProperty("test6", EdmType.GUID, UUID.randomUUID());
+
+ service.insertEntity(table, entities[i]);
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("RowKey"),
+ Filter.constant("queryEntitiesWithFilterWorks-3"))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-3", result.getEntities().get(0).getRowKey());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(table, new QueryEntitiesOptions().setFilter(Filter
+ .queryString("RowKey eq 'queryEntitiesWithFilterWorks-3'")));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-3", result.getEntities().get(0).getRowKey());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service
+ .queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("test"),
+ Filter.constant(true))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(3, result.getEntities().size());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("test2"),
+ Filter.constant("'value'3"))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-3", result.getEntities().get(0).getRowKey());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("test4"),
+ Filter.constant(12345678903L))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-2", result.getEntities().get(0).getRowKey());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("test5"),
+ Filter.constant(new Date(3000)))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-3", result.getEntities().get(0).getRowKey());
+ }
+
+ {
+ // Act
+ QueryEntitiesResult result = service.queryEntities(
+ table,
+ new QueryEntitiesOptions().setFilter(Filter.eq(Filter.propertyName("test6"),
+ Filter.constant(entities[3].getPropertyValue("test6")))));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntities().size());
+ assertEquals("queryEntitiesWithFilterWorks-3", result.getEntities().get(0).getRowKey());
+ }
+ }
+
+ @Test
+ public void batchInsertWorks() throws Exception {
+ System.out.println("batchInsertWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+
+ // Act
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchInsertWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ BatchResult result = service.batch(new BatchOperations().addInsertEntity(table, entity));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(InsertEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchUpdateWorks() throws Exception {
+ System.out.println("batchUpdateWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchUpdateWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+ entity = service.insertEntity(table, entity).getEntity();
+
+ // Act
+ entity.setProperty("test", EdmType.BOOLEAN, false);
+ BatchResult result = service.batch(new BatchOperations().addUpdateEntity(table, entity));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(UpdateEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchMergeWorks() throws Exception {
+ System.out.println("batchMergeWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchMergeWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+ entity = service.insertEntity(table, entity).getEntity();
+
+ // Act
+ BatchResult result = service.batch(new BatchOperations().addMergeEntity(table, entity));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(UpdateEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchInsertOrReplaceWorks() throws Exception {
+ System.out.println("batchInsertOrReplaceWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+
+ // Act
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchInsertOrReplaceWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ BatchResult result = service.batch(new BatchOperations().addInsertOrReplaceEntity(table, entity));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(UpdateEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchInsertOrMergeWorks() throws Exception {
+ System.out.println("batchInsertOrMergeWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+
+ // Act
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchInsertOrMergeWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ BatchResult result = service.batch(new BatchOperations().addInsertOrMergeEntity(table, entity));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(UpdateEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchDeleteWorks() throws Exception {
+ System.out.println("batchDeleteWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_6;
+ String partitionKey = "001";
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchDeleteWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+ entity = service.insertEntity(table, entity).getEntity();
+
+ // Act
+ BatchResult result = service.batch(new BatchOperations().addDeleteEntity(table, entity.getPartitionKey(),
+ entity.getRowKey(), entity.getEtag()));
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(1, result.getEntries().size());
+ assertEquals(DeleteEntity.class, result.getEntries().get(0).getClass());
+ }
+
+ @Test
+ public void batchLotsOfInsertsWorks() throws Exception {
+ System.out.println("batchMultipleWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_7;
+ String partitionKey = "001";
+ int insertCount = 100;
+
+ // Act
+ BatchOperations batchOperations = new BatchOperations();
+ for (int i = 0; i < insertCount; i++) {
+
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchWorks-" + i)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ batchOperations.addInsertEntity(table, entity);
+ }
+ BatchResult result = service.batch(batchOperations);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(insertCount, result.getEntries().size());
+ for (int i = 0; i < insertCount; i++) {
+ assertEquals(InsertEntity.class, result.getEntries().get(i).getClass());
+
+ Entity entity = ((InsertEntity) result.getEntries().get(i)).getEntity();
+
+ assertEquals("001", entity.getPartitionKey());
+ assertEquals("batchWorks-" + i, entity.getRowKey());
+ assertNotNull(entity.getTimestamp());
+ assertNotNull(entity.getEtag());
+
+ assertNotNull(entity.getProperty("test"));
+ assertEquals(true, entity.getProperty("test").getValue());
+
+ assertNotNull(entity.getProperty("test2"));
+ assertEquals("value", entity.getProperty("test2").getValue());
+
+ assertNotNull(entity.getProperty("test3"));
+ assertEquals(3, entity.getProperty("test3").getValue());
+
+ assertNotNull(entity.getProperty("test4"));
+ assertEquals(12345678901L, entity.getProperty("test4").getValue());
+
+ assertNotNull(entity.getProperty("test5"));
+ assertTrue(entity.getProperty("test5").getValue() instanceof Date);
+ }
+ }
+
+ @Test
+ public void batchAllOperationsTogetherWorks() throws Exception {
+ System.out.println("batchAllOperationsWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_8;
+ String partitionKey = "001";
+
+ // Insert a few entities to allow updating them in batch
+ Entity entity1 = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks-" + 1)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ entity1 = service.insertEntity(table, entity1).getEntity();
+
+ Entity entity2 = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks-" + 2)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ entity2 = service.insertEntity(table, entity2).getEntity();
+
+ Entity entity3 = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks-" + 3)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ entity3 = service.insertEntity(table, entity3).getEntity();
+
+ Entity entity4 = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks-" + 4)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+
+ entity4 = service.insertEntity(table, entity4).getEntity();
+
+ // Act
+ BatchOperations batchOperations = new BatchOperations();
+
+ Entity entity = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks")
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+ batchOperations.addInsertEntity(table, entity);
+
+ batchOperations.addDeleteEntity(table, entity1.getPartitionKey(), entity1.getRowKey(), entity1.getEtag());
+
+ batchOperations.addUpdateEntity(table, entity2.setProperty("test", EdmType.INT32, 5));
+ batchOperations.addMergeEntity(table, entity3.setProperty("test", EdmType.INT32, 5));
+ batchOperations.addInsertOrReplaceEntity(table, entity4.setProperty("test", EdmType.INT32, 5));
+
+ Entity entity5 = new Entity().setPartitionKey(partitionKey).setRowKey("batchAllOperationsWorks-" + 5)
+ .setProperty("test", EdmType.BOOLEAN, true).setProperty("test2", EdmType.STRING, "value")
+ .setProperty("test3", EdmType.INT32, 3).setProperty("test4", EdmType.INT64, 12345678901L)
+ .setProperty("test5", EdmType.DATETIME, new Date());
+ batchOperations.addInsertOrMergeEntity(table, entity5);
+
+ BatchResult result = service.batch(batchOperations);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(batchOperations.getOperations().size(), result.getEntries().size());
+ assertEquals(InsertEntity.class, result.getEntries().get(0).getClass());
+ assertEquals(DeleteEntity.class, result.getEntries().get(1).getClass());
+ assertEquals(UpdateEntity.class, result.getEntries().get(2).getClass());
+ assertEquals(UpdateEntity.class, result.getEntries().get(3).getClass());
+ assertEquals(UpdateEntity.class, result.getEntries().get(4).getClass());
+ assertEquals(UpdateEntity.class, result.getEntries().get(5).getClass());
+ }
+
+ @Test
+ public void batchNegativeWorks() throws Exception {
+ System.out.println("batchNegativeWorks()");
+
+ // Arrange
+ Configuration config = createConfiguration();
+ TableContract service = TableService.create(config);
+ String table = TEST_TABLE_8;
+ String partitionKey = "001";
+
+ // Insert an entity the modify it outside of the batch
+ Entity entity1 = new Entity().setPartitionKey(partitionKey).setRowKey("batchNegativeWorks1")
+ .setProperty("test", EdmType.INT32, 1);
+ Entity entity2 = new Entity().setPartitionKey(partitionKey).setRowKey("batchNegativeWorks2")
+ .setProperty("test", EdmType.INT32, 2);
+ Entity entity3 = new Entity().setPartitionKey(partitionKey).setRowKey("batchNegativeWorks3")
+ .setProperty("test", EdmType.INT32, 3);
+
+ entity1 = service.insertEntity(table, entity1).getEntity();
+ entity2 = service.insertEntity(table, entity2).getEntity();
+ entity2.setProperty("test", EdmType.INT32, -2);
+ service.updateEntity(table, entity2);
+
+ // Act
+ BatchOperations batchOperations = new BatchOperations();
+
+ // The entity1 still has the original etag from the first submit,
+ // so this update should fail, because another update was already made.
+ entity1.setProperty("test", EdmType.INT32, 3);
+ batchOperations.addDeleteEntity(table, entity1.getPartitionKey(), entity1.getRowKey(), entity1.getEtag());
+ batchOperations.addUpdateEntity(table, entity2);
+ batchOperations.addInsertEntity(table, entity3);
+
+ BatchResult result = service.batch(batchOperations);
+
+ // Assert
+ assertNotNull(result);
+ assertEquals(batchOperations.getOperations().size(), result.getEntries().size());
+ assertNull("First result should be null", result.getEntries().get(0));
+ assertNotNull("Second result should not be null", result.getEntries().get(1));
+ assertEquals("Second result type", com.microsoft.windowsazure.services.table.models.BatchResult.Error.class,
+ result.getEntries().get(1).getClass());
+ com.microsoft.windowsazure.services.table.models.BatchResult.Error error = (com.microsoft.windowsazure.services.table.models.BatchResult.Error) result
+ .getEntries().get(1);
+ assertEquals("Second result status code", 412, error.getError().getHttpStatusCode());
+ assertNull("Third result should be null", result.getEntries().get(2));
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriterTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriterTests.java
new file mode 100644
index 0000000000000..aa14a71f8597c
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/AtomReaderWriterTests.java
@@ -0,0 +1,80 @@
+/**
+ * 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.table.implementation;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.microsoft.windowsazure.services.blob.implementation.ISO8601DateConverter;
+import com.microsoft.windowsazure.services.core.utils.DefaultDateFactory;
+import com.microsoft.windowsazure.services.table.IntegrationTestBase;
+import com.microsoft.windowsazure.services.table.models.TableEntry;
+
+public class AtomReaderWriterTests extends IntegrationTestBase {
+ @Test
+ public void parseTableEntriesWorks() throws Exception {
+ // Arrange
+ AtomReaderWriter atom = new AtomReaderWriter(new DefaultXMLStreamFactory(), new DefaultDateFactory(),
+ new ISO8601DateConverter(), new DefaultEdmValueConterter(new ISO8601DateConverter()));
+ String feed = "\r\n"
+ + "\r\n"
+ + " Tables\r\n"
+ + " http://rpaquaytest.table.core.windows.net/Tables\r\n"
+ + " 2012-01-10T21:23:30Z\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " http://rpaquaytest.table.core.windows.net/Tables('sdktest1')\r\n"
+ + " \r\n"
+ + " 2012-01-10T21:23:30Z\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " sdktest1\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " http://rpaquaytest.table.core.windows.net/Tables('sdktest10')\r\n"
+ + " \r\n"
+ + " 2012-01-10T21:23:30Z\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n" + " \r\n"
+ + " sdktest10\r\n" + " \r\n"
+ + " \r\n" + " \r\n" + "\r\n";
+ InputStream stream = new ByteArrayInputStream(feed.getBytes("UTF-8"));
+
+ // Act
+ List entries = atom.parseTableEntries(stream);
+
+ // Assert
+ assertNotNull(entries);
+ assertEquals(2, entries.size());
+ assertEquals("sdktest1", entries.get(0).getName());
+ assertEquals("sdktest10", entries.get(1).getName());
+ }
+}
diff --git a/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/MimeMultipartTests.java b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/MimeMultipartTests.java
new file mode 100644
index 0000000000000..c01fdeaebc3cf
--- /dev/null
+++ b/microsoft-azure-api/src/test/java/com/microsoft/windowsazure/services/table/implementation/MimeMultipartTests.java
@@ -0,0 +1,336 @@
+/**
+ * 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.table.implementation;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+
+import javax.activation.DataSource;
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.MultipartDataSource;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.junit.Test;
+
+import com.microsoft.windowsazure.services.table.IntegrationTestBase;
+
+public class MimeMultipartTests extends IntegrationTestBase {
+ @Test
+ public void parseMimeWorks() throws Exception {
+ //@formatter:off
+ String s = "--batchresponse_dc0fea8c-ed83-4aa8-ac9b-bf56a2d46dfb \r\n"
+ + "Content-Type: multipart/mixed; boundary=changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977\r\n"
+ + "\r\n"
+ + "--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977\r\n"
+ + "Content-Type: application/http\r\n"
+ + "Content-Transfer-Encoding: binary\r\n"
+ + "\r\n"
+ + "HTTP/1.1 201 Created\r\n"
+ + "Content-ID: 1\r\n"
+ + "Content-Type: application/atom+xml;charset=utf-8\r\n"
+ + "Cache-Control: no-cache\r\n"
+ + "ETag: W/\"datetime'2009-04-30T20%3A44%3A09.5789464Z'\"\r\n"
+ + "Location: http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')\r\n"
+ + "DataServiceVersion: 1.0;\r\n"
+ + "\r\n"
+ + "\r\n"
+ + "\r\n"
+ + " http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='1')\r\n"
+ + " \r\n"
+ + " 2009-04-30T20:44:09Z\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " Channel_19\r\n"
+ + " 1\r\n"
+ + " 2009-04-30T20:44:09.5789464Z\r\n"
+ + " .Net...\r\n"
+ + " 9\r\n"
+ + " \r\n"
+ + " \r\n"
+ + "\r\n"
+ + "\r\n"
+ + "--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977\r\n"
+ + "Content-Type: application/http\r\n"
+ + "Content-Transfer-Encoding: binary\r\n"
+ + "\r\n"
+ + "HTTP/1.1 201 Created\r\n"
+ + "Content-ID: 2\r\n"
+ + "Content-Type: application/atom+xml;charset=utf-8\r\n"
+ + "Cache-Control: no-cache\r\n"
+ + "ETag: W/\"datetime'2009-04-30T20%3A44%3A09.5789464Z'\"\r\n"
+ + "Location: http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='2')\r\n"
+ + "DataServiceVersion: 1.0;\r\n"
+ + "\r\n"
+ + "\r\n"
+ + "\r\n"
+ + " http://myaccount.tables.core.windows.net/Blogs(PartitionKey='Channel_19',RowKey='2')\r\n"
+ + " \r\n"
+ + " 2009-04-30T20:44:09Z\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " Channel_19\r\n"
+ + " 2\r\n"
+ + " 2009-04-30T20:44:09.5789464Z\r\n"
+ + " Azure...\r\n"
+ + " 9\r\n"
+ + " \r\n"
+ + " \r\n"
+ + "\r\n"
+ + "\r\n"
+ + "--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977\r\n"
+ + "Content-Type: application/http\r\n"
+ + "Content-Transfer-Encoding: binary\r\n"
+ + "\r\n"
+ + "HTTP/1.1 204 No Content\r\n"
+ + "Content-ID: 3\r\n"
+ + "Cache-Control: no-cache\r\n"
+ + "ETag: W/\"datetime'2009-04-30T20%3A44%3A10.0019041Z'\"\r\n"
+ + "DataServiceVersion: 1.0;\r\n"
+ + "\r\n"
+ + "--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977\r\n"
+ + "Content-Type: application/http\r\n"
+ + "Content-Transfer-Encoding: binary\r\n"
+ + "\r\n"
+ + "HTTP/1.1 204 No Content\r\n"
+ + "Content-ID: 4\r\n"
+ + "Cache-Control: no-cache\r\n"
+ + "DataServiceVersion: 1.0;\r\n"
+ + "\r\n"
+ + "--changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977--\r\n"
+ + "--batchresponse_4c637ba4-b2f8-40f8-8856-c2d10d163a83--\r\n";
+ //@formatter:on
+
+ DataSource ds = new ByteArrayDataSource(s,
+ "multipart/mixed; boundary=batchresponse_dc0fea8c-ed83-4aa8-ac9b-bf56a2d46dfb");
+ MimeMultipart m = new MimeMultipart(ds);
+
+ assertEquals(1, m.getCount());
+ assertTrue(m.getBodyPart(0) instanceof MimeBodyPart);
+
+ MimeBodyPart part = (MimeBodyPart) m.getBodyPart(0);
+ String contentType = part.getHeader("Content-Type", ":");
+ assertEquals("multipart/mixed; boundary=changesetresponse_8a28b620-b4bb-458c-a177-0959fb14c977", contentType);
+
+ DataSource ds2 = new ByteArrayDataSource(part.getInputStream(), contentType);
+ MimeMultipart m2 = new MimeMultipart(ds2);
+
+ assertEquals(4, m2.getCount());
+ }
+
+ @Test
+ public void buildMimeWorks() throws Exception {
+ //@formatter:off
+ String changeset1 = "POST http://myaccount.tables.core.windows.net/Blogs HTTP/1.1\r\n" +
+ "Content-ID: 1\r\n" +
+ "Content-Type: application/atom+xml;type=entry\r\n" +
+ "Content-Length: ###\r\n" +
+ "\r\n" +
+ "\r\n" +
+ "\r\n" +
+ " \r\n" +
+ " 2009-04-30T20:45:13.7155321Z\r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " Channel_19\r\n" +
+ " 1\r\n" +
+ " 0001-01-01T00:00:00\r\n" +
+ " 9\r\n" +
+ " .NET...\r\n" +
+ " \r\n" +
+ " \r\n" +
+ "";
+ //@formatter:on
+
+ //
+ // Build inner list of change sets
+ //
+
+ MimeMultipart changeSets = new MimeMultipart(new SetBoundaryMultipartDataSource(
+ "changeset_8a28b620-b4bb-458c-a177-0959fb14c977"));
+
+ MimeBodyPart cs1 = new MimeBodyPart();
+ cs1.setContent(changeset1, "application/http");
+ changeSets.addBodyPart(cs1);
+
+ MimeBodyPart cs2 = new MimeBodyPart();
+ cs2.setContent(changeset1, "application/http");
+ changeSets.addBodyPart(cs2);
+
+ //
+ // Build outer "batch" body part
+ //
+ MimeBodyPart batchbody = new MimeBodyPart();
+ batchbody.setContent(changeSets);
+
+ //
+ // Build outer "batch" multipart
+ //
+ MimeMultipart batch = new MimeMultipart(new SetBoundaryMultipartDataSource(
+ "batch_a1e9d677-b28b-435e-a89e-87e6a768a431"));
+ batch.addBodyPart(batchbody);
+
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ batch.writeTo(stream);
+
+ String result = stream.toString("UTF-8");
+ //@formatter:off
+ String expectedResult =
+ "--batch_a1e9d677-b28b-435e-a89e-87e6a768a431\r\n" +
+ "\r\n" +
+ "--changeset_8a28b620-b4bb-458c-a177-0959fb14c977\r\n" +
+ "\r\n" +
+ "POST http://myaccount.tables.core.windows.net/Blogs HTTP/1.1\r\n" +
+ "Content-ID: 1\r\n" +
+ "Content-Type: application/atom+xml;type=entry\r\n" +
+ "Content-Length: ###\r\n" +
+ "\r\n" +
+ "\r\n" +
+ "\r\n" +
+ " \r\n" +
+ " 2009-04-30T20:45:13.7155321Z\r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " Channel_19\r\n" +
+ " 1\r\n" +
+ " 0001-01-01T00:00:00\r\n" +
+ " 9\r\n" +
+ " .NET...\r\n" +
+ " \r\n" +
+ " \r\n" +
+ "\r\n" +
+ "--changeset_8a28b620-b4bb-458c-a177-0959fb14c977\r\n" +
+ "\r\n" +
+ "POST http://myaccount.tables.core.windows.net/Blogs HTTP/1.1\r\n" +
+ "Content-ID: 1\r\n" +
+ "Content-Type: application/atom+xml;type=entry\r\n" +
+ "Content-Length: ###\r\n" +
+ "\r\n" +
+ "\r\n" +
+ "\r\n" +
+ " \r\n" +
+ " 2009-04-30T20:45:13.7155321Z\r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " \r\n" +
+ " Channel_19\r\n" +
+ " 1\r\n" +
+ " 0001-01-01T00:00:00\r\n" +
+ " 9\r\n" +
+ " .NET...\r\n" +
+ " \r\n" +
+ " \r\n" +
+ "\r\n" +
+ "--changeset_8a28b620-b4bb-458c-a177-0959fb14c977--\r\n" +
+ "\r\n" +
+ "--batch_a1e9d677-b28b-435e-a89e-87e6a768a431--\r\n";
+ //@formatter:on
+ StringReader reader1 = new StringReader(result);
+ StringReader reader2 = new StringReader(expectedResult);
+
+ for (int i = 0;; i++) {
+ int ch1 = reader1.read();
+ int ch2 = reader2.read();
+ if (ch1 == -1) {
+ assertEquals(-1, ch2);
+ break;
+ }
+ if (ch2 == -1) {
+ assertEquals(-1, ch1);
+ break;
+ }
+
+ if (ch1 != ch2) {
+ int min1 = Math.max(0, i - 20);
+ int max1 = Math.min(result.length(), i + 20);
+
+ int min2 = Math.max(0, i - 20);
+ int max2 = Math.min(expectedResult.length(), i + 20);
+
+ String closeBy1 = result.substring(min1, max1);
+ String closeBy2 = expectedResult.substring(min2, max2);
+
+ assertEquals("Message content are no equal starting at position " + i, closeBy2, closeBy1);
+ }
+ }
+ }
+
+ private class SetBoundaryMultipartDataSource implements MultipartDataSource {
+
+ private final String boundary;
+
+ public SetBoundaryMultipartDataSource(String boundary) {
+ this.boundary = boundary;
+ }
+
+ @Override
+ public String getContentType() {
+ return "multipart/mixed; boundary=" + boundary;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public int getCount() {
+ return 0;
+ }
+
+ @Override
+ public BodyPart getBodyPart(int index) throws MessagingException {
+ return null;
+ }
+ }
+}
diff --git a/microsoft-azure-api/src/test/resources/META-INF/com.microsoft.windowsazure.properties b/microsoft-azure-api/src/test/resources/META-INF/com.microsoft.windowsazure.properties
index e7bf06b034de2..7739acd3e7333 100644
--- a/microsoft-azure-api/src/test/resources/META-INF/com.microsoft.windowsazure.properties
+++ b/microsoft-azure-api/src/test/resources/META-INF/com.microsoft.windowsazure.properties
@@ -7,4 +7,7 @@ blob.accountKey=%BLOB_ACCOUNTKEY%
blob.uri=http://%BLOB_ACCOUNTNAME%.blob.core.windows.net
queue.accountName=%QUEUE_ACCOUNTNAME%
queue.accountKey=%QUEUE_ACCOUNTKEY%
-queue.uri=http://%QUEUE_ACCOUNTNAME%.queue.core.windows.net
\ No newline at end of file
+queue.uri=http://%QUEUE_ACCOUNTNAME%.queue.core.windows.net
+table.accountName=%TABLE_ACCOUNTNAME%
+table.accountKey=%TABLE_ACCOUNTKEY%
+table.uri=http://%TABLE_ACCOUNTNAME%.table.core.windows.net
\ No newline at end of file