All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.vergne.translation.impl.OnDemandMap Maven / Gradle / Ivy

The newest version!
package fr.vergne.translation.impl;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import fr.vergne.translation.TranslationEntry;
import fr.vergne.translation.TranslationEntry.TranslationListener;
import fr.vergne.translation.TranslationMap;
import fr.vergne.translation.TranslationMetadata.Field;
import fr.vergne.translation.TranslationMetadata.FieldListener;
import fr.vergne.translation.util.MultiReader;
import fr.vergne.translation.util.Reader;
import fr.vergne.translation.util.Writer;

/**
 * An {@link OnDemandMap} allows to retrieve the {@link TranslationEntry}s on
 * demand, so without storing all of them. If you already have them, you may
 * prefer to use a {@link LoadedMap}.
 * 
 * @author Matthieu VERGNE 
 * 
 * @param 
 */
public class OnDemandMap> implements
		TranslationMap {

	private static final Writer> DEFAULT_SAVER = new Writer>>() {

		@Override
		public void write(OnDemandMap> map) {
			for (TranslationEntry entry : map.modifiedEntries) {
				entry.saveAll();
			}
		}
	};
	private final Reader sizeReader;
	private final MultiReader entryReader;
	private final Writer> mapSaver;
	private final Map> cache = new HashMap>();
	private final Set modifiedEntries = new HashSet();

	/**
	 * Instantiate an {@link OnDemandMap} which should manage a given number of
	 * {@link TranslationEntry}s. Each {@link TranslationEntry} is retrieved on
	 * demand through a specific {@link MultiReader}, and the overall saving
	 * strategy is dedicated to a specific {@link Writer}.
	 * 
	 * @param sizeReader
	 *            the {@link Reader} to use for {@link #size()}
	 * @param entryReader
	 *            the {@link MultiReader} to use for {@link #getEntry(int)}
	 * @param mapSaver
	 *            the {@link Writer} to use for {@link #saveAll()}
	 */
	public OnDemandMap(Reader sizeReader,
			MultiReader entryReader,
			Writer> mapSaver) {
		this.sizeReader = sizeReader;
		this.entryReader = entryReader;
		this.mapSaver = mapSaver;
	}

	/**
	 * Instantiate an {@link OnDemandMap} which should manage a given number of
	 * {@link TranslationEntry}s. Each {@link TranslationEntry} is retrieved on
	 * demand through a specific {@link MultiReader}. The overall saving
	 * strategy is a naive one: each modified {@link TranslationEntry} is saved
	 * separately. If you want a smarter saving strategy, use the most extended
	 * constructor.
	 * 
	 * @param sizeReader
	 *            the {@link Reader} to use for {@link #size()}
	 * @param entryReader
	 *            the {@link MultiReader} to use for {@link #getEntry(int)}
	 */
	public OnDemandMap(Reader sizeReader,
			MultiReader entryReader) {
		this(sizeReader, entryReader, DEFAULT_SAVER);
	}

	@Override
	public Iterator iterator() {
		return new Iterator() {

			private int index = 0;

			@Override
			public boolean hasNext() {
				return index < size();
			}

			@Override
			public Entry next() {
				Entry entry = retrieveEntry(index);
				index++;
				return entry;
			}

			@Override
			public void remove() {
				throw new RuntimeException("You cannot remove an entry.");
			}
		};
	}

	@Override
	public Entry getEntry(int index) {
		return retrieveEntry(index);
	}

	private Entry retrieveEntry(int index) {
		WeakReference reference = cache.get(index);
		if (reference == null || reference.get() == null) {
			final Entry entry = entryReader.read(index);
			entry.addTranslationListener(new TranslationListener() {

				@Override
				public void translationUpdated(String newTranslation) {
					modifiedEntries.add(entry);
				}

				@Override
				public void translationStored() {
					// ignored
				}
			});
			entry.getMetadata().addFieldListener(new FieldListener() {

				@Override
				public  void fieldUpdated(Field field, T newValue) {
					modifiedEntries.add(entry);
				}

				@Override
				public  void fieldStored(Field field) {
					// ignored
				}
			});
			cache.put(index, new WeakReference<>(entry));
			return entry;
		} else {
			return reference.get();
		}
	}

	@Override
	public int size() {
		return sizeReader.read();
	}

	@Override
	public void saveAll() {
		mapSaver.write(this);
		modifiedEntries.clear();
	}

	@Override
	public void resetAll() {
		for (Entry entry : modifiedEntries) {
			entry.resetAll();
		}
		modifiedEntries.clear();
	}

	@Override
	public String toString() {
		return "Map(" + sizeReader + " entries, " + modifiedEntries.size()
				+ " modified)";
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy