// Copyright (C) 2011-2012 CRS4. // // This file is part of Seal. // // Seal is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // Seal is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with Seal. If not, see <http://www.gnu.org/licenses/>. package it.crs4.seal.common; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.List; import java.util.Iterator; import org.apache.hadoop.io.Writable; public class TestContext<K,V> implements IMRContext<K,V> { private static class CounterStore { private HashMap<String, HashMap<String, Long> > counters; public CounterStore() { counters = new HashMap<String, HashMap<String, Long> >(5); } public long getValue(String group, String name) { HashMap<String, Long> map = counters.get(group); if (map != null) { Long value = map.get(name); if (value != null) return value; } return 0; } public void setValue(String group, String name, long value) { HashMap<String, Long> map = counters.get(group); if (map == null) { map = new HashMap<String, Long>(); counters.put(group, map); } map.put(name, value); } } public static class Tuple<K,V> { public K key; public V value; public Tuple(K k, V v) { key = k; value = v; } public K getKey() { return key; } public V getValue() { return value; } } protected ArrayList< Tuple<K,V> > output; protected int progressCalled; protected String lastStatus; protected CounterStore counters; public TestContext() { output = new ArrayList< Tuple<K,V> >(30); progressCalled = 0; counters = new CounterStore(); } public void progress() { progressCalled += 1; } public boolean getProgressCalled() { return progressCalled > 0; } public int getNumProgressCalls() { return progressCalled; } public void setStatus(String msg) { lastStatus = msg; } public String getLastStatus() { return lastStatus; } @SuppressWarnings("unchecked") public void write(K key, V value) throws java.io.IOException, InterruptedException { // If possible, duplicate the objects we store to sever dependencies to the mapper or reducer objects, // like the real Hadoop context does when values are trasferred between map and reduce phases. if (key instanceof Writable && value instanceof Writable) output.add( new Tuple<K,V>((K)duplicateWritable(key), (V)duplicateWritable(value)) ); // unchecked casts that generate warnings else output.add( new Tuple<K,V>(key, value) ); } public Set<K> getKeys() { Set<K> set = new HashSet<K>(); for (Tuple<K,V> pair: output) set.add(pair.key); return set; } public List<V> getValuesForKey(K key) { List<V> list = new ArrayList<V>(); for (Tuple<K,V> pair: output) { if (key == pair.key || key != null && key.equals(pair.key)) list.add(pair.value); } return list; } public List<V> getAllValues() { List<V> list = new ArrayList<V>(); for (Tuple<K,V> pair: output) list.add(pair.value); return list; } public Iterator< Tuple<K,V> > iterator() { return output.iterator(); } public int getNumWrites() { return output.size(); } public void increment(Enum<?> counter, long value) { increment(counter.getClass().getName(), counter.name(), value); } public void increment(String groupName, String counterName, long value) { long currentValue = counters.getValue(groupName, counterName); counters.setValue(groupName, counterName, currentValue + value); } public long getCounterValue(String groupName, String counterName) { return counters.getValue(groupName, counterName); } /** * Duplicate Writable object by by serializing and then unserializing it. */ private Object duplicateWritable(Object oldItem) throws java.io.IOException { if (oldItem == null) return null; Writable w = (Writable) oldItem; // duplicate the key by serializing and then unserializing it ByteArrayOutputStream obytes = new ByteArrayOutputStream(); DataOutputStream ostream = new DataOutputStream(obytes); w.write(ostream); ostream.close(); Object newItem; try { newItem = oldItem.getClass().newInstance(); } catch (Exception e) { throw new RuntimeException("error instantiating duplicate key or value. Message: " + e.getMessage()); } ByteArrayInputStream ibytes = new ByteArrayInputStream(obytes.toByteArray()); DataInputStream istream = new DataInputStream(ibytes); ((Writable)newItem).readFields(istream); return newItem; } }