5151import io .minio .messages .Item ;
5252import io .minio .messages .ListAllMyBucketsResult ;
5353import io .minio .messages .ListBucketResult ;
54+ import io .minio .messages .ListBucketResultV1 ;
5455import io .minio .messages .ListMultipartUploadsResult ;
5556import io .minio .messages .ListPartsResult ;
5657import io .minio .messages .Part ;
@@ -2089,19 +2090,222 @@ public Iterable<Result<Item>> listObjects(final String bucketName, final String
20892090 *
20902091 * @see #listObjects(String bucketName)
20912092 * @see #listObjects(String bucketName, String prefix)
2093+ * @see #listObjects(String bucketName, String prefix, boolean recursive, boolean useVersion1)
20922094 */
20932095 public Iterable <Result <Item >> listObjects (final String bucketName , final String prefix , final boolean recursive ) {
2096+ return listObjects (bucketName , prefix , recursive , false );
2097+ }
2098+
2099+
2100+ /**
2101+ * Lists object information as {@code Iterable<Result><Item>>} in given bucket, prefix, recursive flag and S3 API
2102+ * version to use.
2103+ *
2104+ * </p><b>Example:</b><br>
2105+ * <pre>{@code Iterable<Result<Item>> myObjects = minioClient.listObjects("my-bucketname", "my-object-prefix", true,
2106+ * false);
2107+ * for (Result<Item> result : myObjects) {
2108+ * Item item = result.get();
2109+ * System.out.println(item.lastModified() + ", " + item.size() + ", " + item.objectName());
2110+ * } }</pre>
2111+ *
2112+ * @param bucketName Bucket name.
2113+ * @param prefix Prefix string. List objects whose name starts with `prefix`.
2114+ * @param recursive when false, emulates a directory structure where each listing returned is either a full object
2115+ * or part of the object's key up to the first '/'. All objects wit the same prefix up to the first
2116+ * '/' will be merged into one entry.
2117+ * @param useVersion1 If set, Amazon AWS S3 List Object V1 is used, else List Object V2 is used as default.
2118+ *
2119+ * @return an iterator of Result Items.
2120+ *
2121+ * @see #listObjects(String bucketName)
2122+ * @see #listObjects(String bucketName, String prefix)
2123+ * @see #listObjects(String bucketName, String prefix, boolean recursive)
2124+ */
2125+ public Iterable <Result <Item >> listObjects (final String bucketName , final String prefix , final boolean recursive ,
2126+ final boolean useVersion1 ) {
2127+ if (useVersion1 ) {
2128+ return listObjectsV1 (bucketName , prefix , recursive );
2129+ }
2130+
2131+ return listObjectsV2 (bucketName , prefix , recursive );
2132+ }
2133+
2134+
2135+ private Iterable <Result <Item >> listObjectsV2 (final String bucketName , final String prefix , final boolean recursive ) {
20942136 return new Iterable <Result <Item >>() {
20952137 @ Override
20962138 public Iterator <Result <Item >> iterator () {
20972139 return new Iterator <Result <Item >>() {
2098- private String lastObjectName ;
20992140 private ListBucketResult listBucketResult ;
21002141 private Result <Item > error ;
21012142 private Iterator <Item > itemIterator ;
21022143 private Iterator <Prefix > prefixIterator ;
21032144 private boolean completed = false ;
21042145
2146+ private synchronized void populate () {
2147+ String delimiter = "/" ;
2148+ if (recursive ) {
2149+ delimiter = null ;
2150+ }
2151+
2152+ String continuationToken = null ;
2153+ if (this .listBucketResult != null && delimiter != null ) {
2154+ continuationToken = listBucketResult .nextContinuationToken ();
2155+ }
2156+
2157+ this .listBucketResult = null ;
2158+ this .itemIterator = null ;
2159+ this .prefixIterator = null ;
2160+
2161+ try {
2162+ this .listBucketResult = listObjectsV2 (bucketName , continuationToken , prefix , delimiter );
2163+ } catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
2164+ | InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
2165+ | InternalException e ) {
2166+ this .error = new Result <>(null , e );
2167+ } finally {
2168+ if (this .listBucketResult != null ) {
2169+ this .itemIterator = this .listBucketResult .contents ().iterator ();
2170+ this .prefixIterator = this .listBucketResult .commonPrefixes ().iterator ();
2171+ } else {
2172+ this .itemIterator = new LinkedList <Item >().iterator ();
2173+ this .prefixIterator = new LinkedList <Prefix >().iterator ();
2174+ }
2175+ }
2176+ }
2177+
2178+ @ Override
2179+ public boolean hasNext () {
2180+ if (this .completed ) {
2181+ return false ;
2182+ }
2183+
2184+ if (this .error == null && this .itemIterator == null && this .prefixIterator == null ) {
2185+ populate ();
2186+ }
2187+
2188+ if (this .error == null && !this .itemIterator .hasNext () && !this .prefixIterator .hasNext ()
2189+ && this .listBucketResult .isTruncated ()) {
2190+ populate ();
2191+ }
2192+
2193+ if (this .error != null ) {
2194+ return true ;
2195+ }
2196+
2197+ if (this .itemIterator .hasNext ()) {
2198+ return true ;
2199+ }
2200+
2201+ if (this .prefixIterator .hasNext ()) {
2202+ return true ;
2203+ }
2204+
2205+ this .completed = true ;
2206+ return false ;
2207+ }
2208+
2209+ @ Override
2210+ public Result <Item > next () {
2211+ if (this .completed ) {
2212+ throw new NoSuchElementException ();
2213+ }
2214+
2215+ if (this .error == null && this .itemIterator == null && this .prefixIterator == null ) {
2216+ populate ();
2217+ }
2218+
2219+ if (this .error == null && !this .itemIterator .hasNext () && !this .prefixIterator .hasNext ()
2220+ && this .listBucketResult .isTruncated ()) {
2221+ populate ();
2222+ }
2223+
2224+ if (this .error != null ) {
2225+ this .completed = true ;
2226+ return this .error ;
2227+ }
2228+
2229+ if (this .itemIterator .hasNext ()) {
2230+ Item item = this .itemIterator .next ();
2231+ return new Result <>(item , null );
2232+ }
2233+
2234+ if (this .prefixIterator .hasNext ()) {
2235+ Prefix prefix = this .prefixIterator .next ();
2236+ Item item ;
2237+ try {
2238+ item = new Item (prefix .prefix (), true );
2239+ } catch (XmlPullParserException e ) {
2240+ // special case: ignore the error as we can't propagate the exception in next()
2241+ item = null ;
2242+ }
2243+
2244+ return new Result <>(item , null );
2245+ }
2246+
2247+ this .completed = true ;
2248+ throw new NoSuchElementException ();
2249+ }
2250+
2251+ @ Override
2252+ public void remove () {
2253+ throw new UnsupportedOperationException ();
2254+ }
2255+ };
2256+ }
2257+ };
2258+ }
2259+
2260+
2261+ /**
2262+ * Returns {@link ListBucketResult} of given bucket, marker, prefix and delimiter.
2263+ *
2264+ * @param bucketName Bucket name.
2265+ * @param marker Marker string. List objects whose name is greater than `marker`.
2266+ * @param prefix Prefix string. List objects whose name starts with `prefix`.
2267+ * @param delimiter delimiter string. Group objects whose name contains `delimiter`.
2268+ */
2269+ private ListBucketResult listObjectsV2 (String bucketName , String continuationToken , String prefix , String delimiter )
2270+ throws InvalidBucketNameException , NoSuchAlgorithmException , InsufficientDataException , IOException ,
2271+ InvalidKeyException , NoResponseException , XmlPullParserException , ErrorResponseException ,
2272+ InternalException {
2273+ Map <String ,String > queryParamMap = new HashMap <>();
2274+ queryParamMap .put ("list-type" , "2" );
2275+
2276+ if (continuationToken != null ) {
2277+ queryParamMap .put ("continuation-token" , continuationToken );
2278+ }
2279+
2280+ if (prefix != null ) {
2281+ queryParamMap .put ("prefix" , prefix );
2282+ }
2283+
2284+ if (delimiter != null ) {
2285+ queryParamMap .put ("delimiter" , delimiter );
2286+ }
2287+
2288+ HttpResponse response = executeGet (bucketName , null , null , queryParamMap );
2289+
2290+ ListBucketResult result = new ListBucketResult ();
2291+ result .parseXml (response .body ().charStream ());
2292+ response .body ().close ();
2293+ return result ;
2294+ }
2295+
2296+
2297+ private Iterable <Result <Item >> listObjectsV1 (final String bucketName , final String prefix , final boolean recursive ) {
2298+ return new Iterable <Result <Item >>() {
2299+ @ Override
2300+ public Iterator <Result <Item >> iterator () {
2301+ return new Iterator <Result <Item >>() {
2302+ private String lastObjectName ;
2303+ private ListBucketResultV1 listBucketResult ;
2304+ private Result <Item > error ;
2305+ private Iterator <Item > itemIterator ;
2306+ private Iterator <Prefix > prefixIterator ;
2307+ private boolean completed = false ;
2308+
21052309 private synchronized void populate () {
21062310 String delimiter = "/" ;
21072311 if (recursive ) {
@@ -2122,7 +2326,7 @@ private synchronized void populate() {
21222326 this .prefixIterator = null ;
21232327
21242328 try {
2125- this .listBucketResult = listObjects (bucketName , marker , prefix , delimiter , null );
2329+ this .listBucketResult = listObjectsV1 (bucketName , marker , prefix , delimiter );
21262330 } catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
21272331 | InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
21282332 | InternalException e ) {
@@ -2223,16 +2427,15 @@ public void remove() {
22232427
22242428
22252429 /**
2226- * Returns {@link ListBucketResult } of given bucket, marker, prefix, delimiter and maxKeys .
2430+ * Returns {@link ListBucketResultV1 } of given bucket, marker, prefix and delimiter .
22272431 *
22282432 * @param bucketName Bucket name.
22292433 * @param marker Marker string. List objects whose name is greater than `marker`.
22302434 * @param prefix Prefix string. List objects whose name starts with `prefix`.
22312435 * @param delimiter delimiter string. Group objects whose name contains `delimiter`.
22322436 * @param maxKeys Maximum number of entries to be returned.
22332437 */
2234- private ListBucketResult listObjects (String bucketName , String marker , String prefix , String delimiter ,
2235- Integer maxKeys )
2438+ private ListBucketResultV1 listObjectsV1 (String bucketName , String marker , String prefix , String delimiter )
22362439 throws InvalidBucketNameException , NoSuchAlgorithmException , InsufficientDataException , IOException ,
22372440 InvalidKeyException , NoResponseException , XmlPullParserException , ErrorResponseException ,
22382441 InternalException {
@@ -2250,13 +2453,9 @@ private ListBucketResult listObjects(String bucketName, String marker, String pr
22502453 queryParamMap .put ("delimiter" , delimiter );
22512454 }
22522455
2253- if (maxKeys != null ) {
2254- queryParamMap .put ("max-keys" , maxKeys .toString ());
2255- }
2256-
22572456 HttpResponse response = executeGet (bucketName , null , null , queryParamMap );
22582457
2259- ListBucketResult result = new ListBucketResult ();
2458+ ListBucketResultV1 result = new ListBucketResultV1 ();
22602459 result .parseXml (response .body ().charStream ());
22612460 response .body ().close ();
22622461 return result ;
0 commit comments