Skip to content

Commit

Permalink
Issue # 55 CloudTableClient should use Iterator instead of Iterable.
Browse files Browse the repository at this point in the history
Signed-off-by: Joe Giardino <joegiard@microsoft.com>
  • Loading branch information
Joe Giardino committed May 1, 2012
1 parent fad32f6 commit 0f84dbb
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import com.microsoft.windowsazure.services.core.storage.utils.PathUtility;
import com.microsoft.windowsazure.services.core.storage.utils.Utility;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ExecutionEngine;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterator;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterable;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ListingContext;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.SegmentedStorageOperation;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.StorageOperation;
Expand Down Expand Up @@ -534,7 +534,7 @@ public ResultSegment<CloudBlobContainer> execute(final CloudBlobClient client, f
}
};

return new LazySegmentedIterator<CloudBlobClient, Void, CloudBlobContainer>(impl, this, null,
return new LazySegmentedIterable<CloudBlobClient, Void, CloudBlobContainer>(impl, this, null,
options.getRetryPolicyFactory(), opContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import com.microsoft.windowsazure.services.core.storage.utils.UriQueryBuilder;
import com.microsoft.windowsazure.services.core.storage.utils.Utility;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ExecutionEngine;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterator;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterable;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.SegmentedStorageOperation;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.StorageOperation;

Expand Down Expand Up @@ -1273,7 +1273,7 @@ public ResultSegment<ListBlobItem> execute(final CloudBlobClient client,
}
};

return new LazySegmentedIterator<CloudBlobClient, CloudBlobContainer, ListBlobItem>(impl,
return new LazySegmentedIterable<CloudBlobClient, CloudBlobContainer, ListBlobItem>(impl,
this.blobServiceClient, this, options.getRetryPolicyFactory(), opContext);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* 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.core.storage.utils.implementation;

import java.util.Iterator;

import com.microsoft.windowsazure.services.core.storage.OperationContext;
import com.microsoft.windowsazure.services.core.storage.ResultSegment;
import com.microsoft.windowsazure.services.core.storage.RetryPolicyFactory;

/**
* RESERVED FOR INTERNAL USE. Provides a lazy iterator which will retrieve the next segment of a result as the iterator
* is consumed
*
* @param <CLIENT_TYPE>
* The service client type
* @param <PARENT_TYPE>
* The type of the parent object, i.e. CloudBlobClient for ListContainers etc.
* @param <ENTITY_TYPE>
* The type of the objects the resulting iterable objects
*/
public final class LazySegmentedIterable<CLIENT_TYPE, PARENT_TYPE, ENTITY_TYPE> implements Iterable<ENTITY_TYPE> {
/**
* Holds the service client associated with the operations.
*/
private final CLIENT_TYPE client;

/**
* Holds a reference to the parent object, i.e. CloudBlobContainer for list blobs.
*/
private final PARENT_TYPE parentObject;

/**
* Holds the reference to the RetryPolicyFactory object.
*/
private final RetryPolicyFactory policyFactory;

/**
* Holds the SegmentedStorageOperation which is used to retrieve the next segment of results.
*/
private final SegmentedStorageOperation<CLIENT_TYPE, PARENT_TYPE, ResultSegment<ENTITY_TYPE>> segmentGenerator;

/**
* Holds an object used to track the execution of the operation
*/
private final OperationContext opContext;

public LazySegmentedIterable(
final SegmentedStorageOperation<CLIENT_TYPE, PARENT_TYPE, ResultSegment<ENTITY_TYPE>> segmentGenerator,
final CLIENT_TYPE client, final PARENT_TYPE parent, final RetryPolicyFactory policyFactory,
final OperationContext opContext) {
this.segmentGenerator = segmentGenerator;
this.parentObject = parent;
this.opContext = opContext;
this.policyFactory = policyFactory;
this.client = client;
}

@Override
public Iterator<ENTITY_TYPE> iterator() {
return new LazySegmentedIterator<CLIENT_TYPE, PARENT_TYPE, ENTITY_TYPE>(this.segmentGenerator, this.client,
this.parentObject, this.policyFactory, this.opContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
* @param <ENTITY_TYPE>
* The type of the objects the resulting iterable objects
*/
public final class LazySegmentedIterator<CLIENT_TYPE, PARENT_TYPE, ENTITY_TYPE> implements Iterator<ENTITY_TYPE>,
Iterable<ENTITY_TYPE> {
public final class LazySegmentedIterator<CLIENT_TYPE, PARENT_TYPE, ENTITY_TYPE> implements Iterator<ENTITY_TYPE> {

/**
* Holds the current segment of results.
Expand Down Expand Up @@ -126,14 +125,6 @@ public boolean hasNext() {
return this.currentSegmentIterator.hasNext();
}

/**
* Gets a reference to the iterator.
*/
@Override
public Iterator<ENTITY_TYPE> iterator() {
return this;
}

/**
* Returns the next element.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import com.microsoft.windowsazure.services.core.storage.StorageException;
import com.microsoft.windowsazure.services.core.storage.utils.Utility;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ExecutionEngine;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterator;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterable;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ListingContext;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.SegmentedStorageOperation;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.StorageOperation;
Expand Down Expand Up @@ -164,7 +164,7 @@ public ResultSegment<CloudQueue> execute(final CloudQueueClient client, final Vo
}
};

return new LazySegmentedIterator<CloudQueueClient, Void, CloudQueue>(impl, this, null,
return new LazySegmentedIterable<CloudQueueClient, Void, CloudQueue>(impl, this, null,
options.getRetryPolicyFactory(), opContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import com.microsoft.windowsazure.services.core.storage.StorageException;
import com.microsoft.windowsazure.services.core.storage.utils.Utility;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.ExecutionEngine;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterator;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.LazySegmentedIterable;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.SegmentedStorageOperation;
import com.microsoft.windowsazure.services.core.storage.utils.implementation.StorageOperation;

Expand Down Expand Up @@ -1328,7 +1328,7 @@ public ResultSegment<T> execute(final CloudTableClient client, final TableQuery<
}
};

return new LazySegmentedIterator<CloudTableClient, TableQuery<T>, T>(impl, this, queryRef,
return new LazySegmentedIterable<CloudTableClient, TableQuery<T>, T>(impl, this, queryRef,
options.getRetryPolicyFactory(), opContext);
}
else {
Expand All @@ -1352,7 +1352,7 @@ public ResultSegment<R> execute(final CloudTableClient client, final TableQuery<
return result;
}
};
return new LazySegmentedIterator<CloudTableClient, TableQuery<T>, R>(impl, this, queryRef,
return new LazySegmentedIterable<CloudTableClient, TableQuery<T>, R>(impl, this, queryRef,
options.getRetryPolicyFactory(), opContext);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,35 @@ public void listTablesWithIterator() throws IOException, URISyntaxException, Sto
try {
// With prefix
int currTable = 0;
for (String s : tClient.listTables(tableBaseName, null, null)) {
Iterable<String> listTables = tClient.listTables(tableBaseName, null, null);
for (String s : listTables) {
Assert.assertEquals(s,
String.format("%s%s", tableBaseName, new DecimalFormat("#0000").format(currTable)));
currTable++;
}

Assert.assertEquals(20, currTable);
// Second Iteration
currTable = 0;
for (String s : listTables) {
Assert.assertEquals(s,
String.format("%s%s", tableBaseName, new DecimalFormat("#0000").format(currTable)));
currTable++;
}
Assert.assertEquals(20, currTable);

// Without prefix
currTable = 0;
for (String s : tClient.listTables()) {
Iterable<String> listTablesNoPrefix = tClient.listTables();
for (String s : listTablesNoPrefix) {
if (s.startsWith(tableBaseName)) {
currTable++;
}
}

Assert.assertEquals(20, currTable);
currTable = 0;
for (String s : listTablesNoPrefix) {
if (s.startsWith(tableBaseName)) {
currTable++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
Expand Down Expand Up @@ -59,6 +60,54 @@ public static void setup() throws URISyntaxException, StorageException, InvalidK
}
}

@Test
public void tableQueryIterateTwice() {
// Create entity to check against
class1 randEnt = TableTestBase.generateRandomEnitity(null);

final Iterable<DynamicTableEntity> result = tClient.execute(TableQuery.from(testSuiteTableName,
DynamicTableEntity.class).take(50));

ArrayList<DynamicTableEntity> firstIteration = new ArrayList<DynamicTableEntity>();
ArrayList<DynamicTableEntity> secondIteration = new ArrayList<DynamicTableEntity>();

// Validate results
for (DynamicTableEntity ent : result) {
Assert.assertEquals(ent.getProperties().size(), 4);
Assert.assertEquals(ent.getProperties().get("A").getValueAsString(), randEnt.getA());
Assert.assertEquals(ent.getProperties().get("B").getValueAsString(), randEnt.getB());
Assert.assertEquals(ent.getProperties().get("C").getValueAsString(), randEnt.getC());
Assert.assertTrue(Arrays.equals(ent.getProperties().get("D").getValueAsByteArray(), randEnt.getD()));
firstIteration.add(ent);
}

// Validate results
for (DynamicTableEntity ent : result) {
Assert.assertEquals(ent.getProperties().size(), 4);
Assert.assertEquals(ent.getProperties().get("A").getValueAsString(), randEnt.getA());
Assert.assertEquals(ent.getProperties().get("B").getValueAsString(), randEnt.getB());
Assert.assertEquals(ent.getProperties().get("C").getValueAsString(), randEnt.getC());
Assert.assertTrue(Arrays.equals(ent.getProperties().get("D").getValueAsByteArray(), randEnt.getD()));
secondIteration.add(ent);
}

Assert.assertEquals(firstIteration.size(), secondIteration.size());
for (int m = 0; m < firstIteration.size(); m++) {
Assert.assertEquals(firstIteration.get(m).getPartitionKey(), secondIteration.get(m).getPartitionKey());
Assert.assertEquals(firstIteration.get(m).getRowKey(), secondIteration.get(m).getRowKey());
Assert.assertEquals(firstIteration.get(m).getProperties().size(), secondIteration.get(m).getProperties()
.size());
Assert.assertEquals(firstIteration.get(m).getProperties().get("A").getValueAsString(),
secondIteration.get(m).getProperties().get("A").getValueAsString());
Assert.assertEquals(firstIteration.get(m).getProperties().get("B").getValueAsString(),
secondIteration.get(m).getProperties().get("B").getValueAsString());
Assert.assertEquals(firstIteration.get(m).getProperties().get("C").getValueAsString(),
secondIteration.get(m).getProperties().get("C").getValueAsString());
Assert.assertTrue(Arrays.equals(firstIteration.get(m).getProperties().get("D").getValueAsByteArray(),
secondIteration.get(m).getProperties().get("D").getValueAsByteArray()));
}
}

@Test
public void tableQueryWithDynamicEntity() {
// Create entity to check against
Expand Down

0 comments on commit 0f84dbb

Please sign in to comment.