net.sf.zekr.engine.translation.TranslationData.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.zekr.engine.translation.TranslationData.java

Source

/*
 *               In the name of Allah
 * This file is part of The Zekr Project. Use is subject to
 * license terms.
 *
 * Author:         Mohsen Saboorian
 * Start Date:     Feb 17, 2006
 */
package net.sf.zekr.engine.translation;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import net.sf.zekr.common.config.GlobalConfig;
import net.sf.zekr.common.resource.AbstractQuranText;
import net.sf.zekr.common.resource.QuranProperties;
import net.sf.zekr.common.util.CryptoUtils;
import net.sf.zekr.common.util.I18N;
import net.sf.zekr.engine.addonmgr.AddOnManagerUtils;
import net.sf.zekr.engine.addonmgr.Resource;
import net.sf.zekr.engine.common.LocalizedResource;
import net.sf.zekr.engine.common.Signable;
import net.sf.zekr.engine.log.Logger;

import org.apache.commons.lang.StringUtils;

/**
 * @author Mohsen Saboorian
 */
public class TranslationData extends AbstractQuranText implements Signable, Resource {
    private static final Logger logger = Logger.getLogger(TranslationData.class);

    /** Translation Id. */
    public String id;

    /** Translation English name */
    public String name;

    /** Translation localized name */
    public String localizedName;

    /** Language (locale) Id (e.g. en_US) */
    public Locale locale;

    /** Text direction: ltr or rtl */
    public String direction;

    /** String encoding */
    public String encoding;

    /** Line delimiter String (each line contains an aya) */
    public String delimiter;

    public File archiveFile;

    /** Text file name */
    public String file;

    private String[][] transText;
    private String[] fullTransText;

    /** signature of the text file */
    public byte[] signature;

    public boolean verified = false;
    private boolean loaded = false;

    /** descriptor version */
    public String version;

    private int verificationResult = UNKNOWN;

    private LocalizedResource localizedResource;
    private File resourceFile;

    public TranslationData() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see net.sf.zekr.common.util.IQuranText#get(int, int)
     */
    public String get(int suraNum, int ayaNum) {
        return transText[suraNum - 1][ayaNum - 1];
    }

    /*
     * (non-Javadoc)
     * 
     * @see net.sf.zekr.common.util.IQuranText#getSura(int)
     */
    public String[] getSura(int suraNum) {
        return transText[suraNum - 1];
    }

    /*
     * (non-Javadoc)
     * 
     * @see net.sf.zekr.common.util.IQuranText#getFullText()
     */
    public String[][] getFullText() {
        return transText;
    }

    public String toString() {
        return id + "(" + locale + "):(" + archiveFile.getName() + ")";
    }

    /**
     * Loads the tranalation data file, if not already loaded.
     */
    public void load() throws TranslationException {
        if (!loaded) {
            Date date1 = new Date();
            loadAndVerify();
            Date date2 = new Date();
            logger.debug("Loading translation \"" + id + "\" took " + (date2.getTime() - date1.getTime()) + " ms.");
            loaded = true;
        } else {
            logger.debug("Translation already loaded: " + id);
        }
    }

    /**
     * Unloads the content of translation in order to let Java free more memory.
     */
    public void unloadTranslationDataFile() {
        fullTransText = null;
        transText = null;
        loaded = false;
    }

    private void loadAndVerify() throws TranslationException {
        ZipFile zf = null;
        try {
            logger.info("Loading translation pack " + this + "...");
            zf = new ZipFile(archiveFile);
            ZipEntry ze = zf.getEntry(file);
            if (ze == null) {
                logger.error("Load failed. No proper entry found in \"" + archiveFile.getName() + "\".");
                return;
            }

            byte[] textBuf = new byte[(int) ze.getSize()];
            if (!verify(zf.getInputStream(ze), textBuf))
                logger.warn("Unauthorized translation data pack: " + this);
            // throw new TranslationException("INVALID_TRANSLATION_SIGNATURE", new String[] { name });

            refineText(new String(textBuf, encoding));

            logger.log("Translation pack " + this + " loaded successfully.");
        } catch (IOException e) {
            logger.error("Problem while loading translation pack " + this + ".");
            logger.log(e);
            throw new TranslationException(e);
        } finally {
            try {
                zf.close();
            } catch (Exception e) {
                // do nothing
            }
        }
    }

    /**
     * Verify the zip archive and close the zip file handle finally.
     * 
     * @return <code>true</code> if translation verified, <code>false</code> otherwise.
     * @throws IOException
     */
    public boolean verify() throws IOException {
        ZipFile zf = new ZipFile(archiveFile);
        ZipEntry ze = zf.getEntry(file);
        if (ze == null) {
            logger.error("Load failed. No proper entry found in \"" + archiveFile.getName() + "\".");
            return false;
        }

        byte[] textBuf = new byte[(int) ze.getSize()];
        boolean result;
        result = verify(zf.getInputStream(ze), textBuf);
        zf.close();
        return result;
    }

    private boolean verify(InputStream is, byte[] textBuf) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(is, 262144);
        bis.read(textBuf, 0, textBuf.length);

        logger.debug("Verifying translation text.");
        try {
            verified = CryptoUtils.verify(textBuf, signature);
        } catch (Exception e) {
            logger.warn("Error occurred during translation text verification. Text cannot be verified.", e);
        }
        if (verified) {
            logger.debug("Translation is valid");
            verificationResult = AUTHENTIC;
        } else {
            logger.debug("Translation is not valid.");
            verificationResult = NOT_AUTHENTIC;
        }
        return verified;
    }

    private void refineText(String rawText) {
        QuranProperties quranProps = QuranProperties.getInstance();
        String[] sura;
        fullTransText = rawText.split(delimiter);
        transText = new String[114][];
        int ayaTotalCount = 0;
        for (int i = 0; i < 114; i++) {
            int ayaCount = quranProps.getSura(i + 1).getAyaCount();
            sura = new String[ayaCount];
            for (int j = 0; j < ayaCount; j++) {
                sura[j] = fullTransText[ayaTotalCount + j];
            }
            transText[i] = sura;
            ayaTotalCount += ayaCount;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see net.sf.zekr.common.resource.IQuranText#get(int)
     */
    public String get(int absoluteAyaNum) {
        return fullTransText[absoluteAyaNum - 1];
    }

    public boolean isTranslation() {
        return true;
    }

    public String getLanguage() {
        return locale.getLanguage();
    }

    /**
     * This method always returns the first aya of sura 1 (Al-Fatiha).
     * 
     * @param suraNum sura number, counted from 1
     * @return sura 1, aya 1
     */
    public String getBismillah(int suraNum) {
        return get(1, 1);
    }

    public String toText() {
        return localizedName + " / " + name;
    }

    public String getDirection() {
        return direction;
    }

    public Locale getLocale() {
        return locale;
    }

    public String getId() {
        return id;
    }

    public byte[] getSignature() {
        return signature;
    }

    public int getVerificationResult() {
        return verificationResult;
    }

    public int getMode() {
        throw new UnsupportedOperationException("Method not implemented.");
    }

    public void setLocalizedResource(LocalizedResource r) {
        this.localizedResource = r;
    }

    /* Methods from the Resource interface
     * 
     */

    public LocalizedResource getLocalizedResource() {
        return localizedResource;
    }

    public String getDescription() {
        return AddOnManagerUtils.getResourceDescription(this);
    }

    public boolean isCurrent() {
        return AddOnManagerUtils.isCurrent(this);
    }

    public boolean isLoaded() {
        return AddOnManagerUtils.isLoaded(this);
    }

    @SuppressWarnings("rawtypes")
    public Class getType() {
        return this.getClass();
    }

    public File getFile() {
        return resourceFile;
    }

    public void setFile(File resourceFile) {
        this.resourceFile = resourceFile;
    }

    public Boolean isShared() {
        return AddOnManagerUtils.isResourceShared(this);
    }

    public String getInstallationFolder() {
        return AddOnManagerUtils.getInstallationFolder(this);
    }

    public void setIsShared(Boolean b) {
        throw new RuntimeException("You cannot call this method on a installed resource " + this.getDescription());
    }

    public String getName(String transNameMode, boolean rtl) {
        String s = "english".equals(transNameMode) ? name : localizedName;
        s = StringUtils.abbreviate((rtl ? I18N.RLE + "" : "") + "[" + locale.getLanguage() + "]" + " "
                + (rtl ? I18N.RLM + "" : "") + s, GlobalConfig.MAX_MENU_STRING_LENGTH);

        return s;
    }

    public String getName() {
        return name;
    }

    public String getLocalizedName() {
        return localizedName;
    }

}