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

org.daisy.pipeline.braille.common.HyphenatorRegistry Maven / Gradle / Ivy

The newest version!
package org.daisy.pipeline.braille.common;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Supplier;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;

import org.daisy.braille.css.LanguageRange;
import org.daisy.common.file.URLs;
import org.daisy.pipeline.braille.common.Query.MutableQuery;
import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
import static org.daisy.pipeline.braille.common.Query.util.query;
import static org.daisy.pipeline.braille.common.TransformProvider.util.dispatch;
import static org.daisy.pipeline.braille.common.TransformProvider.util.logCreate;
import org.daisy.pipeline.braille.common.TransformProvider.util.Memoize;
import org.daisy.pipeline.braille.common.util.Files;
import org.daisy.pipeline.braille.common.util.Strings;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
	name = "hyphenator-registry",
	service = { HyphenatorRegistry.class }
)
public class HyphenatorRegistry extends Memoize implements HyphenatorProvider {

	public HyphenatorRegistry() {
		super(true); // memoize (id:...) lookups only
		providers = new ArrayList<>();
		dispatch = dispatch(providers);
		context = logger;
		unmodifiable = false;
	}

	private HyphenatorRegistry(TransformProvider dispatch,
	                           HyphenatorRegistry from,
	                           Logger context) {
		super(from);
		this.providers = null;
		this.dispatch = dispatch;
		this.context = context;
		this.unmodifiable = true;
	}

	private final List> providers;
	private final TransformProvider dispatch;
	private final Logger context;
	private final boolean unmodifiable;

	@Reference(
		name = "HyphenatorProvider",
		unbind = "-",
		service = HyphenatorProvider.class,
		cardinality = ReferenceCardinality.MULTIPLE,
		policy = ReferencePolicy.STATIC
	)
	/**
	 * @throws UnsupportedOperationException if this object is an unmodifiable view of another
	 * {@link BrailleTranslatorRegistry}.
	 */
	public void addProvider(HyphenatorProvider p) {
		if (unmodifiable)
			throw new UnsupportedOperationException("Unmodifiable");
		providers.add(p);
	}

	public Iterable _get(Query q) {
		if (q.containsKey("exception-words")) {
			MutableQuery baseQuery = mutableQuery(q);
			String exceptionsFilePath = baseQuery.removeOnly("exception-words").getValue().get();
			FileReader exceptionsFile;
			try {
				URI u = URLs.asURI(exceptionsFilePath);
				if ("volatile-file".equals(u.getScheme()))
					// Note that file is compiled every time regardless of whether the scheme is
					// "file" or "volatile-file" (see below).
					try {
						u = new URI("file", u.getSchemeSpecificPart(), u.getFragment());
					} catch (Exception e) {
						// should not happen
						throw new IllegalStateException(e);
					}
				File f = Files.asFile(u);
				if (!f.exists())
					throw new FileNotFoundException("File does not exist: " + f);
				exceptionsFile = new FileReader(f);
			} catch (Exception e) {
				context.debug("'exception-words' could not be resolved to a file'", e);
				return Collections.emptyList();
			}
			return Iterables.transform(
				_get(baseQuery),
				// Note that the word list is compiled again every time unless a `(id:...)' query is given.
				h -> {
					try {
						return logCreate(new HyphenatorWithExceptions(h, exceptionsFile), context);
					} catch (IOException e) {
						throw new NoSuchElementException(); // should not happen
					}
				});
		}
		if (q.containsKey("document-locale")) {
			MutableQuery fallbackQuery = mutableQuery(q);
			fallbackQuery.removeAll("document-locale");
			fallbackQuery.addAll(FALLBACK_QUERY);
			return Iterables.concat(
				dispatch.get(q),
				dispatch.get(fallbackQuery));
		} else
			return dispatch.get(q);
	}

	private final static Query FALLBACK_QUERY = query("(document-locale:und)");

	@Override
	public HyphenatorRegistry withContext(Logger context) {
		return (HyphenatorRegistry)super.withContext(context);
	}

	protected HyphenatorRegistry _withContext(Logger context) {
		if (this.context == context)
			return this;
		return new HyphenatorRegistry(dispatch.withContext(context), this, context);
	}

	/**
	 * Select {@link Hyphenator}s based on a query and a CSS style sheet possibly containing
	 * {@code @hyphenation-resource} rules.
	 *
	 * Contrary to {@link #get(Query)}, this method is not memoized, and the returned objects may
	 * not be selectable based on their identifier.
	 *
	 * @param baseURI Base URI for resolving relative paths in CSS against.
	 */
	public Iterable get(Query query, String style, URI baseURI) {
		if (style != null) {
			Map subQueries = HyphenationResourceParser.getHyphenatorQueries(style, baseURI, query);
			if (subQueries != null && !subQueries.isEmpty()) {
				Map> subHyphenators
					= Maps.transformValues(
						subQueries,
						q -> () -> HyphenatorRegistry.this.get(q).iterator().next());
				Iterable hyphenators = Iterables.transform(
					get(query),
					t -> logCreate(new CompoundHyphenator(subHyphenators, t), context));
			    if (query.isEmpty())
					hyphenators = Iterables.concat(
					    hyphenators,
						LazyValue.from(() -> logCreate(new CompoundHyphenator(subHyphenators, null), context)));
				return hyphenators;
			}
		}
		return get(query);
	}

	@Override
	public String toString() {
		return "memoize(dispatch( " + Strings.join(providers, ", ") + " ))";
	}

	private static final Logger logger = LoggerFactory.getLogger(HyphenatorRegistry.class);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy