001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util;
018
019import java.io.Closeable;
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Scanner;
025
026import org.apache.camel.CamelContext;
027import org.apache.camel.Exchange;
028
029/**
030 * Group based {@link Iterator} which groups the given {@link Iterator} a number of times
031 * and then return a combined response as a <tt>List</tt>.
032 * <p/>
033 * This implementation uses a internal array list, to combine the response.
034 *
035 * @see GroupTokenIterator
036 */
037public final class GroupIterator implements Iterator<Object>, Closeable {
038
039    private final CamelContext camelContext;
040    private final Exchange exchange;
041    private final Iterator<?> it;
042    private final int group;
043    private final boolean skipFirst;
044    private boolean closed;
045
046    /**
047     * Creates a new group iterator
048     *
049     * @param exchange  the exchange used to create this group iterator
050     * @param it            the iterator to group
051     * @param group         number of parts to group together
052     * @throws IllegalArgumentException is thrown if group is not a positive number
053     */
054    public GroupIterator(Exchange exchange, Iterator<?> it, int group) {
055        this(exchange, it, group, false);
056    }
057
058    /**
059     * Creates a new group iterator
060     *
061     * @param exchange  the exchange used to create this group iterator
062     * @param it            the iterator to group
063     * @param group         number of parts to group together
064     * @throws IllegalArgumentException is thrown if group is not a positive number
065     */
066    public GroupIterator(Exchange exchange, Iterator<?> it, int group, boolean skipFirst) {
067        this.exchange = exchange;
068        this.camelContext = exchange.getContext();
069        this.it = it;
070        this.group = group;
071        if (group <= 0) {
072            throw new IllegalArgumentException("Group must be a positive number, was: " + group);
073        }
074        this.skipFirst = skipFirst;
075    }
076
077    @Override
078    public void close() throws IOException {
079        try {
080            if (it instanceof Scanner) {
081                // special for Scanner which implement the Closeable since JDK7 
082                Scanner scanner = (Scanner) it;
083                scanner.close();
084                IOException ioException = scanner.ioException();
085                if (ioException != null) {
086                    throw ioException;
087                }
088            } else if (it instanceof Closeable) {
089                IOHelper.closeWithException((Closeable) it);
090            }
091        } finally {
092            // we are now closed
093            closed = true;
094        }
095    }
096
097    @Override
098    public boolean hasNext() {
099        if (closed) {
100            return false;
101        }
102
103        boolean answer = it.hasNext();
104        if (!answer) {
105            // auto close
106            try {
107                close();
108            } catch (IOException e) {
109                // ignore
110            }
111        }
112        return answer;
113    }
114
115    @Override
116    public Object next() {
117        try {
118            return doNext();
119        } catch (Exception e) {
120            throw ObjectHelper.wrapRuntimeCamelException(e);
121        }
122    }
123
124    private Object doNext() throws IOException {
125        List<Object> list = new ArrayList<Object>();
126        int count = 0;
127        while (count < group && it.hasNext()) {
128            Object data = it.next();
129            list.add(data);
130            count++;
131        }
132
133        return list;
134    }
135
136    @Override
137    public void remove() {
138        it.remove();
139    }
140}