001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.repository; 017 018import java.util.List; 019import java.util.NoSuchElementException; 020import java.util.stream.Collectors; 021 022/** 023 * Implementation of a {@link AmetysObjectIterable} based on a list of others {@link AmetysObjectIterable}. 024 * @param <A> the actual type of {@link AmetysObject}s. 025 */ 026public class ChainedAmetysObjectIterable<A extends AmetysObject> implements AmetysObjectIterable<A> 027{ 028 long _size; 029 private List<AmetysObjectIterable<A>> _iterables; 030 private boolean _sizeComputed; 031 032 /** 033 * Creates a {@link ChainedAmetysObjectIterable}. 034 * @param iterables a list of {@link AmetysObjectIterable}. 035 */ 036 public ChainedAmetysObjectIterable(List<AmetysObjectIterable<A>> iterables) 037 { 038 _iterables = iterables; 039 } 040 041 public long getSize() 042 { 043 if (!_sizeComputed) 044 { 045 _size = _computeSize(); 046 } 047 048 return _size; 049 } 050 051 private long _computeSize() 052 { 053 _sizeComputed = true; 054 055 long size = 0; 056 057 for (AmetysObjectIterable it : _iterables) 058 { 059 long s = it.getSize(); 060 061 if (s == -1) 062 { 063 return -1; 064 } 065 066 size += s; 067 } 068 069 return size; 070 } 071 072 public AmetysObjectIterator<A> iterator() 073 { 074 List<AmetysObjectIterator<A>> its = _iterables.stream().map(it -> it.iterator()).collect(Collectors.toList()); 075 return new ChainedIterator(its); 076 } 077 078 public void close() 079 { 080 for (AmetysObjectIterable<A> it : _iterables) 081 { 082 it.close(); 083 } 084 } 085 086 class ChainedIterator implements AmetysObjectIterator<A> 087 { 088 private long _position; 089 private int _currentIterator; 090 private List<AmetysObjectIterator<A>> _its; 091 092 public ChainedIterator(List<AmetysObjectIterator<A>> its) 093 { 094 _its = its; 095 } 096 097 public long getPosition() 098 { 099 return _position; 100 } 101 102 public long getSize() 103 { 104 return ChainedAmetysObjectIterable.this.getSize(); 105 } 106 107 public void skip(long skipNum) 108 { 109 if (skipNum == 0) 110 { 111 return; 112 } 113 114 if (skipNum < 0) 115 { 116 throw new AmetysRepositoryException("Cannot skip with a negative number"); 117 } 118 119 for (long i = skipNum; i > 0; i--) 120 { 121 if (!hasNext()) 122 { 123 throw new NoSuchElementException(); 124 } 125 126 _position++; 127 _its.get(_currentIterator).skip(1); 128 } 129 } 130 131 public boolean hasNext() 132 { 133 while (_currentIterator < _its.size() && !_its.get(_currentIterator).hasNext()) 134 { 135 _currentIterator++; 136 } 137 138 return _currentIterator < _its.size() && _its.get(_currentIterator).hasNext(); 139 } 140 141 public A next() 142 { 143 if (!hasNext()) 144 { 145 throw new NoSuchElementException(); 146 } 147 148 _position++; 149 return _its.get(_currentIterator).next(); 150 } 151 } 152}