/* * Copyright (c) 2015, SRI International * All rights reserved. * Licensed under the The BSD 3-Clause License; * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://opensource.org/licenses/BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the aic-praise nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.sri.ai.praise.lang.translate.impl; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.nio.file.Files; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Base64; import java.util.List; import com.google.common.annotations.Beta; import com.sri.ai.praise.lang.translate.Translator; import com.sri.ai.praise.lang.translate.TranslatorOptions; /** * Abstract Translator class to handle common functionality (e.g. caching). * * @author oreilly * */ @Beta public abstract class AbstractTranslator implements Translator { // // START-Translator @Override public void translate(String inputIdentifier, Reader[] inputModelReaders, PrintWriter[] translatedOutputs, TranslatorOptions options) throws Exception { if (options.isCacheTranslations()) { String cacheIdentifier = computeCacheIdentifier(inputIdentifier); List<File> cachedOutputs = new ArrayList<>(translatedOutputs.length); for (int i = 0; i < translatedOutputs.length; i++) { cachedOutputs.add(new File(options.getCacheDirectory(), getSource().getCode() + "-to-" + getTarget().getCode() + "-" + i + "-" + cacheIdentifier + ".cached")); } // Ensure we have cached already if (!cachedOutputs.stream().allMatch(File::isFile)) { // No cached outputs so must generate them // Ensure all the files are new cachedOutputs.stream().forEach(cacheFile -> { try { cacheFile.delete(); cacheFile.createNewFile(); } catch (IOException ioe) { throw new RuntimeException(ioe); } }); // We don't have the cached translation information, so must // perform the translation, first into the cached files PrintWriter[] cachedWriters = new PrintWriter[cachedOutputs.size()]; for (int i = 0; i < cachedWriters.length; i++) { cachedWriters[i] = new PrintWriter(cachedOutputs.get(i)); } translate(inputIdentifier, inputModelReaders, cachedWriters); for (int i = 0; i < cachedWriters.length; i++) { cachedWriters[i].flush(); cachedWriters[i].close(); } } // We now know we have cached files, now take these and feed them to // the translatedOutputs for (int i = 0; i < cachedOutputs.size(); i++) { BufferedReader br = Files.newBufferedReader(cachedOutputs.get(i).toPath()); final PrintWriter translatedOutputI = translatedOutputs[i]; br.lines().forEach(line -> translatedOutputI.println(line)); translatedOutputI.flush(); } } else { translate(inputIdentifier, inputModelReaders, translatedOutputs); } } // END-Translator // // // PROTECTED protected abstract void translate(String inputIdentifier, Reader[] inputModelReaders, PrintWriter[] translatedOutputs) throws Exception; protected String computeCacheIdentifier(String... identifyingInputs) { String result; try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); for (int i = 0; i < identifyingInputs.length; i++) { messageDigest.update(identifyingInputs[i].getBytes()); } // NOTE: Use replace calls to ensure only legal filenames are // generated from the BASE64 alphabet result = Base64.getEncoder().encodeToString(messageDigest.digest()).replace('+', '-').replace('/', '_'); } catch (NoSuchAlgorithmException nsae) { throw new RuntimeException("Unexpected exception", nsae); } return result; } }