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

org.daisy.pipeline.braille.liblouis.impl.LiblouisutdmlProcessBuilderImpl Maven / Gradle / Ivy

There is a newer version: 6.3.0
Show newest version
package org.daisy.pipeline.braille.liblouis.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.common.base.Function;

import static org.daisy.common.file.URLs.asURL;
import org.daisy.pipeline.braille.common.NativePath;
import static org.daisy.pipeline.braille.common.util.Files.asFile;
import static org.daisy.pipeline.braille.common.util.Files.isAbsoluteFile;
import static org.daisy.pipeline.braille.common.util.Strings.join;

import org.daisy.pipeline.braille.liblouis.LiblouisTable;
import org.daisy.pipeline.braille.liblouis.Liblouisutdml;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
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 = "org.daisy.pipeline.braille.liblouis.impl.LiblouisutdmlProcessBuilderImpl",
	service = {
		Liblouisutdml.class
	}
)
public class LiblouisutdmlProcessBuilderImpl implements Liblouisutdml {
	
	private File file2brl;
	private LiblouisTableRegistry tableRegistry;
	private LiblouisutdmlConfigRegistry configRegistry;
	
	@Activate
	protected void activate() {
		logger.debug("Loading liblouisutdml service");
	}
	
	@Deactivate
	protected void deactivate() {
		logger.debug("Unloading liblouisutdml service");
	}

	@Reference(
		name = "File2brlExecutable",
		unbind = "-",
		service = NativePath.class,
		target = "(identifier=http://www.liblouis.org/native/*)",
		cardinality = ReferenceCardinality.MANDATORY,
		policy = ReferencePolicy.STATIC
	)
	protected void bindExecutable(NativePath nativePath) {
		URI executablePath = nativePath.get("liblouisutdml/file2brl").iterator().next();
		file2brl = asFile(nativePath.resolve(executablePath));
		logger.debug("Registering file2brl executable: " + executablePath);
	}
	
	@Reference(
		name = "LiblouisTableRegistry",
		unbind = "-",
		service = LiblouisTableRegistry.class,
		cardinality = ReferenceCardinality.MANDATORY,
		policy = ReferencePolicy.STATIC
	)
	protected void bindTableRegistry(LiblouisTableRegistry tableRegistry) {
		this.tableRegistry = tableRegistry;
	}
	
	@Reference(
		name = "LiblouisutdmlConfigRegistry",
		unbind = "-",
		service = LiblouisutdmlConfigRegistry.class,
		cardinality = ReferenceCardinality.MANDATORY,
		policy = ReferencePolicy.STATIC
	)
	protected void bindConfigRegistry(LiblouisutdmlConfigRegistry configRegistry) {
		this.configRegistry = configRegistry;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void translateFile(
			List configFiles,
			List semanticFiles,
			LiblouisTable table,
			Map otherSettings,
			File input,
			File output,
			URI configPath,
			File tempDir) {
		
		try {
			
			File configPathFile = (configPath != null) ? resolveConfigPath(configPath) : tempDir;
			
			if (!Arrays.asList(configPathFile.list()).contains("liblouisutdml.ini"))
				throw new RuntimeException("liblouisutdml.ini must be placed in " + configPathFile);
			if (configFiles != null)
				configFiles.remove("liblouisutdml.ini");
			
			List command = new ArrayList();
			
			command.add(file2brl.getAbsolutePath());
			command.add("-f");
			command.add(configPathFile.getAbsolutePath() + File.separator +
					(configFiles != null ? join(configFiles, ",") : ""));
			Map settings = new HashMap();
			if (semanticFiles != null && semanticFiles.size() > 0)
				settings.put("semanticFiles", join(semanticFiles, ","));
			if (table != null) {
				String tablePath = "\"" + resolveTable(table) + "\"";
				settings.put("literaryTextTable", tablePath);
				settings.put("editTable", tablePath); }
			if (otherSettings != null)
				settings.putAll(otherSettings);
			for (String key : settings.keySet())
				command.add("-C" + key + "=" + settings.get(key));
			command.add(input.getAbsolutePath());
			command.add(output.getAbsolutePath());
			
			logger.debug("\n" + join(command, "\n\t"));
			
			ProcessBuilder builder = new ProcessBuilder(command);
			builder.directory(tempDir);
			
			// Hack to make sure tables on configPath are found
			if (!configPathFile.equals(tempDir))
				builder.environment().put("LOUIS_TABLEPATH", configPathFile.getCanonicalPath());
			
			Process process = builder.start();
			
			new StreamReaderThread(
					process.getErrorStream(),
					new Function,Void>() {
						public Void apply(List error) {
							logger.debug("\nstderr:\n\t" + join(error, "\n\t"));
							return null; }}).start();
			
			int exitValue = process.waitFor();
			logger.debug("\nexit value: " + exitValue);
			if (exitValue != 0)
				throw new RuntimeException("liblouisutdml exited with value " + exitValue); }
			
		catch (Exception e) {
			logger.error("Error during liblouisutdml conversion", e);
			throw new RuntimeException("Error during liblouisutdml conversion", e); }
	}
	
	private String resolveTable(LiblouisTable table) throws IOException {
		File[] resolved = tableRegistry.resolveLiblouisTable(table, null);
		if (resolved == null)
			throw new RuntimeException("Liblouis table " + table + " could not be resolved");
		String[] files = new String[resolved.length];
		for (int i = 0; i < resolved.length; i++)
			files[i] = resolved[i].getCanonicalPath();
		return join(files, ",");
	}
	
	private File resolveConfigPath(URI configPath) {
		URL resolvedConfigPath = isAbsoluteFile(configPath) ? asURL(configPath) : configRegistry.resolve(configPath);
		if (resolvedConfigPath == null)
			throw new RuntimeException("Liblouisutdml config path " + configPath + " could not be resolved");
		return asFile(resolvedConfigPath);
	}
	
	private static final Logger logger = LoggerFactory.getLogger(LiblouisutdmlProcessBuilderImpl.class);
	
	private static class StreamReaderThread extends Thread {
		
		private InputStream stream;
		private Function,Void> callback;
		
		public StreamReaderThread(InputStream stream, Function,Void> callback) {
			this.stream = stream;
			this.callback = callback;
		}
		
		@Override
		public void run() {
			try {
				BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
				List result = new ArrayList();
				String line = null;
				while ((line = reader.readLine()) != null) result.add(line);
				if (callback != null)
					callback.apply(result); }
			catch (IOException e) {
				throw new RuntimeException(e); }
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy