A cyclic iterator

Sometimes, a cyclic iterator can be useful to supply an endless supply of deterministic data. Here’s an simple implementation that I wrote today.


import java.util.Iterator;

/**
 * This class iterates across an iterable object with the option to recycle amongst the elements infinitely.
 * In case the recycle option is not set, the original data is iterated upon once, and all subsequent calls to
 * next() will return the defaultDataValue
 *
 * @param <T>
 */
public class CyclicIterator<T>
 implements Iterator<T> {
 final private Iterable<T> data;
 final private boolean recycleData;
 final private T defaultDataValue;
 private Iterator<T> dataIterator;

public CyclicIterator(Iterable<T> data, boolean recycle, T defaultDataValue) {
 this.data = data;
 this.recycleData = recycle;
 this.defaultDataValue = defaultDataValue;
 resetDataIterator();
 }

private void resetDataIterator() {
 this.dataIterator = this.data.iterator();
 }

@Override
 public boolean hasNext() {
 return true;
 }

@Override
 public T next() {
 //if the iterator is done, check whether to reset or not
 if (!dataIterator.hasNext()) {
 if (recycleData) {
 resetDataIterator();
 } else {
 return defaultDataValue;
 }
 }

//at this point, next should be valid
 return dataIterator.next();
 }

@Override
 public void remove() {
 //NO-OP
 }
}

BerkeleyDb QuickStart

Here’s a basic set of methods I wrote while trying to familizrize myself with some of BerkeleyDb‘s API methods. Interesting to see how it can be used as an object store and the use of a hashmap facade to query. FWIW, we didn’t want to annotate the POJOs with @Entity, hence we used serial entity binding.

Ze maven dependencies

    <dependencies>
        <dependency>
            <groupId>berkeleydb</groupId>
            <artifactId>je</artifactId>
            <version>3.2.76</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.3</version>
        </dependency>
    </dependencies>

Ze code …

import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.tuple.LongBinding;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.je.*;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.Serializable;
import java.util.*;

public class DbApp {


    private static final String CLASS_CATALOG_DB = "ClassCatalog_Db";
    private EnvironmentConfig envConfig_ = null;
    private Environment env_ = null;
    private DatabaseConfig dbConfig_ = null;
    private Database dataDb_ = null;
    private Database classCatalogDb_ = null;


    private final File envHome_;
    private final String dbName;
    private StoredClassCatalog classCatalog_;
    private SerialBinding myDataBinding;
    private EntryBinding keyBinding;
    private SortedMap <Long, MyData> map;


    public DbApp(String envLocation, String dbName) throws Exception {
        envHome_ = new File(envLocation);
        if (envHome_.exists()) {
            FileUtils.cleanDirectory(envHome_);
        } else {
            FileUtils.forceMkdir(envHome_);
        }
        this.dbName = dbName;
        createEnv();
        createDbHandle();
        createClassCatalogAndBindings();
    }

    private void createEnv() throws Exception {
            final EnvironmentConfig envConfig_ = new EnvironmentConfig();
            envConfig_.setTransactional(false);
            envConfig_.setAllowCreate(true);
            envConfig_.setLocking(true);
            this.env_ = new Environment(envHome_, envConfig_);
    }


    private void createDbHandle() throws Exception {
        dbConfig_ = new DatabaseConfig();
        dbConfig_.setTransactional(false);
        dbConfig_.setAllowCreate(true);
        dbConfig_.setDeferredWrite(true);
        dataDb_ = env_.openDatabase(null, dbName, dbConfig_);
    }

    private void createClassCatalogAndBindings() throws DatabaseException {
        classCatalogDb_ = env_.openDatabase(null, CLASS_CATALOG_DB, dbConfig_);
        classCatalog_ = new StoredClassCatalog(classCatalogDb_);
        myDataBinding = new SerialBinding(classCatalog_, MyData.class);
        keyBinding = TupleBinding.getPrimitiveBinding(Long.class);
        map = new StoredSortedMap(dataDb_, keyBinding, myDataBinding, true);

    }

    public void store(MyData mydata) throws Exception {
        final DatabaseEntry key = new DatabaseEntry();
        final DatabaseEntry data = new DatabaseEntry();
        LongBinding.longToEntry(mydata.getSsn(), key);
        myDataBinding.objectToEntry(mydata, data);
        dataDb_.put(null, key, data);
    }

    public List<MyData> getAll() throws Exception {
        List<MyData> dataList = new ArrayList<MyData>();
        final DatabaseEntry key = new DatabaseEntry();
        final DatabaseEntry data = new DatabaseEntry();
        final Cursor cursor = dataDb_.openCursor(null, null);
        try {
            while (cursor.getNext(key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
                MyData mydata = (MyData) (myDataBinding.entryToObject(data));
                dataList.add(mydata);
            }
            return dataList;
        } finally {
            cursor.close();
        }
    }

    public MyData getHead() throws Exception {
        final DatabaseEntry key = new DatabaseEntry();
        final DatabaseEntry data = new DatabaseEntry();
        final Cursor cursor = dataDb_.openCursor(null, null);
        MyData myData = null;
        try {
            cursor.getFirst(key, data, LockMode.RMW);
            if (data.getData() == null) {
                return null;
            }
            myData = (MyData) (myDataBinding.entryToObject(data));
        } finally {
            cursor.close();
        }
        return myData;
    }


    public MyData query(Long keyData) throws Exception {  
        return map.get(keyData);
    }

    public MyData poll() throws Exception {

        final DatabaseEntry key = new DatabaseEntry();
        final DatabaseEntry data = new DatabaseEntry();


        final Cursor cursor = dataDb_.openCursor(null, null);
        MyData myData = null;
        try {
            cursor.getFirst(key, data, LockMode.RMW);
            if (data.getData() == null) {
                return null;
            }
            myData = (MyData) (myDataBinding.entryToObject(data));
        } finally {
            cursor.close();
        }
        return myData;

    }

    public static void main(String[] args) throws Exception {

        DbApp app = new DbApp("/home/vinayb/junk/abc/bdb_env", "mydata_db");
        MyData data1 = new MyData(1, "me", 21, "121 some street");
        MyData data2 = new MyData(2, "he", 22, "122 some street");
        MyData data3 = new MyData(3, "she", 23, "123 some street");

        app.store(data1);
        app.store(data2);
        app.store(data3);

        List<MyData> dataList = app.getAll();
        for (MyData data : dataList) {
            System.out.println(data);
        }
        System.out.println("app.poll() = " + app.poll());
        MyData data2Retrieved = app.query(2L);
        System.err.println("id = 2: data: " +  data2Retrieved);
    }


    private static class MyData implements Serializable {
        private long ssn;
        private String name;
        private int age;
        private String address;

        private MyData(long ssn, String name, int age, String address) {
            this.ssn = ssn;
            this.name = name;
            this.age = age;
            this.address = address;
        }

        public long getSsn() {
            return ssn;
        }

        public void setSsn(long ssn) {
            this.ssn = ssn;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        @Override
        public String toString() {
            return "MyData{" +
                    "ssn=" + ssn +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", address='" + address + '\'' +
                    '}';
        }
    }

}

Basic Chunked List Iterator

Here’s a simple chunked iterator I wrote up that makes it easy to provide list data in chunks. This is useful when there is a need to break up and process large lists in pieces/chunks

    private static class ChunkList
            implements Iterable<List> {
        private final List list;
        private final int chunkSize;
        int cur;
        boolean hasNext = true;

        public ChunkList(List list, int chunkSize) {
            this.list = list;
            this.chunkSize = chunkSize;
            this.cur = 0;
        }

        @Override
        public Iterator<List> iterator() {
            return new Iterator<List>() {
                @Override
                public boolean hasNext() {
                    return hasNext;
                }

                @Override
                public List next() {
                    int start = cur;
                    int end = cur+chunkSize;
                    if (cur+chunkSize >= list.size()) {
                        end = list.size();
                        hasNext = false;
                    }

                    List subList =  list.subList(start, end);
                    cur = end;

                    return subList;
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException("Chunk Removal not supported");
                }
            };
        }
    }

Test driver

    public static void main(String arg[]) {
        List list = new ArrayList();
        for (int i = 1; i             list.add(i);
        }

        ChunkList chunkList = new ChunkList(list, 10);

        Iterator<List> iter = chunkList.iterator();

        while (iter.hasNext()) {
            List chunk = iter.next();
            System.err.println("#### " + chunk);
        }
    }

Results

#### [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#### [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
#### [21, 22, 23, 24]

Another (perhaps cleaner) alternative would have been to use a list iterator to “collect” elements withing the next() methods instead of employing sublist(…).

Enjoy.