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

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

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

import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
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;
import fr.vergne.translation.TranslationMetadata.Field;
import fr.vergne.translation.TranslationMetadata.FieldListener;
import fr.vergne.translation.TranslationProject;
import fr.vergne.translation.util.EntryFilter;
import fr.vergne.translation.util.Feature;
import fr.vergne.translation.util.MapNamer;
import fr.vergne.translation.util.MultiReader;
import fr.vergne.translation.util.Writer;

/**
 * An {@link OnDemandProject} aims at accessing to the resources of a
 * {@link TranslationProject} on demand, thus retrieving each
 * {@link TranslationMap} only when requested.
 * 
 * @author Matthieu VERGNE 
 * 
 * @param 
 * @param 
 */
public class OnDemandProject, TMapID, TMap extends TranslationMap>
		implements TranslationProject {

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

		@Override
		public void write(
				OnDemandProject> project) {
			for (TranslationMap map : project.modifiedMaps) {
				map.saveAll();
			}
		}
	};
	private final Set ids;
	private final MultiReader mapReader;
	private final Writer> projectSaver;
	private final Map> cache = new HashMap>();
	private final Set modifiedMaps = new HashSet<>();

	/**
	 * Instantiate an {@link OnDemandProject} for a given set of
	 * {@link TranslationMap}s. Only the IDs of the {@link TranslationMap}s are
	 * stored, the {@link TranslationMap}s themselves are retrieved on demand.
	 * The overall saving strategy is provided by a custom {@link Writer}.
	 * 
	 * @param ids
	 *            the {@link TranslationMap} IDs of this
	 *            {@link TranslationProject}
	 * @param mapReader
	 *            the {@link MultiReader} to use for {@link #getMap(Object)}
	 * @param projectSaver
	 *            the {@link Writer} to use for {@link #saveAll()}
	 */
	public OnDemandProject(Collection ids,
			MultiReader mapReader,
			Writer> projectSaver) {
		this.ids = Collections.unmodifiableSet(new LinkedHashSet<>(ids));
		this.mapReader = mapReader;
		this.projectSaver = projectSaver;
	}

	/**
	 * Instantiate an {@link OnDemandProject} for a given set of
	 * {@link TranslationMap}s. Only the IDs of the {@link TranslationMap}s are
	 * stored, the {@link TranslationMap}s themselves are retrieved on demand.
	 * For saving the project, a naive strategy is used: each modified
	 * {@link TranslationMap} is saved separately. If you want a smarter
	 * strategy, use the most extended constructor.
	 * 
	 * @param ids
	 *            the {@link TranslationMap} IDs of this
	 *            {@link TranslationProject}
	 * @param mapReader
	 *            the {@link MultiReader} to use for {@link #getMap(Object)}
	 */
	public OnDemandProject(Collection ids,
			MultiReader reader) {
		this(ids, reader, DEFAULT_SAVER);
	}

	@Override
	public Iterator iterator() {
		return ids.iterator();
	}

	@Override
	public TMap getMap(TMapID id) {
		WeakReference reference = cache.get(id);
		if (reference == null || reference.get() == null) {
			final TMap map = mapReader.read(id);
			TranslationListener translationListener = new TranslationListener() {

				@Override
				public void translationUpdated(String newTranslation) {
					modifiedMaps.add(map);
				}

				@Override
				public void translationStored() {
					// ignored
				}
			};
			FieldListener metadataListener = new FieldListener() {

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

				@Override
				public  void fieldStored(Field field) {
					// ignored
				}
			};
			for (TranslationEntry entry : map) {
				entry.addTranslationListener(translationListener);
				entry.getMetadata().addFieldListener(metadataListener);
			}
			cache.put(id, new WeakReference(map));
			return map;
		} else {
			return reference.get();
		}
	}

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

	@Override
	public void saveAll() {
		projectSaver.write(this);
		modifiedMaps.clear();
	}

	@Override
	public void resetAll() {
		for (TMap map : modifiedMaps) {
			map.resetAll();
		}
		modifiedMaps.clear();
	}

	private final Collection> mapNamers = new LinkedHashSet<>();

	@Override
	public Collection> getMapNamers() {
		return mapNamers;
	}

	public void addMapNamer(MapNamer namer) {
		mapNamers.add(namer);
	}

	private final Collection features = new LinkedHashSet<>();

	@Override
	public Collection getFeatures() {
		return features;
	}

	public void addFeature(Feature feature) {
		features.add(feature);
	}

	private final Collection> filters = new HashSet>();

	@Override
	public Collection> getEntryFilters() {
		return filters;
	}

	public void addEntryFilter(EntryFilter filter) {
		filters.add(filter);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy