org.omegat.core.team2.impl.HTTPRemoteRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.omegat.core.team2.impl.HTTPRemoteRepository.java

Source

/**************************************************************************
 OmegaT - Computer Assisted Translation (CAT) tool 
      with fuzzy matching, translation memory, keyword search, 
      glossaries, and translation leveraging into updated projects.
    
 Copyright (C) 2014 Alex Buloichik
           Home page: http://www.omegat.org/
           Support center: http://groups.yahoo.com/group/OmegaT/
    
 This file is part of OmegaT.
    
 OmegaT is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
 OmegaT is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************/

package org.omegat.core.team2.impl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.Properties;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;
import org.omegat.core.team2.IRemoteRepository2;
import org.omegat.core.team2.ProjectTeamSettings;
import org.omegat.util.Log;

import gen.core.project.RepositoryDefinition;
import gen.core.project.RepositoryMapping;

/**
 * HTTP/HTTPS repository connection implementation.
 * 
 * It can be used as read-only repository for retrieve sources, external TMX, glossaries, etc. Since HTTP
 * protocol doesn't support multiple files, each URL should be mapped to separate file, i.e. directory mapping
 * is not supported.
 * 
 * @author Alex Buloichik (alex73mail@gmail.com)
 */
public class HTTPRemoteRepository implements IRemoteRepository2 {
    private static final Logger LOGGER = Logger.getLogger(HTTPRemoteRepository.class.getName());

    private RepositoryDefinition config;
    private File baseDirectory;

    @Override
    public void init(RepositoryDefinition repo, File dir, ProjectTeamSettings teamSettings) throws Exception {
        Log.logDebug(LOGGER, "Initialize HTTP remote repository");
        config = repo;
        baseDirectory = dir;
    }

    /**
     * Use SHA-1 as file version.
     */
    @Override
    public String getFileVersion(String file) throws Exception {
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
        sha1.reset();

        // calculate SHA-1
        byte[] buffer = new byte[8192];
        InputStream in = new BufferedInputStream(new FileInputStream(file));
        try {
            while (true) {
                int len = in.read(buffer);
                if (len < 0) {
                    break;
                }
                sha1.update(buffer, 0, len);
            }
        } finally {
            in.close();
        }

        // out as hex
        Formatter formatter = new Formatter();
        try {
            for (byte b : sha1.digest()) {
                formatter.format("%02x", b);
            }
            return formatter.toString();
        } finally {
            formatter.close();
        }
    }

    @Override
    public void switchToVersion(String version) throws Exception {
        if (version != null) {
            throw new RuntimeException("Not supported");
        }

        Log.logDebug(LOGGER, "Update to latest");
        // retrieve all mapped files
        Properties etags = loadETags();
        for (RepositoryMapping m : config.getMapping()) {
            String url = config.getUrl() + m.getRepository();
            File out = new File(baseDirectory, m.getRepository());
            retrieve(etags, m.getRepository(), url, out);
        }
        saveETags(etags);
    }

    @Override
    public void addForCommit(String path) throws Exception {
        throw new RuntimeException("Not supported");
    }

    @Override
    public String commit(String[] onVersions, String comment) throws Exception {
        throw new RuntimeException("Not supported");
    }

    /**
     * Load all ETags.
     */
    protected Properties loadETags() throws Exception {
        Properties props = new Properties();
        File f = new File(baseDirectory, ".etags");
        if (f.exists()) {
            FileInputStream in = new FileInputStream(f);
            try {
                props.load(in);
            } finally {
                in.close();
            }
        }
        return props;
    }

    /**
     * Save all ETags.
     */
    protected void saveETags(Properties props) throws Exception {
        FileOutputStream out = new FileOutputStream(new File(baseDirectory, ".etags"));
        try {
            props.store(out, null);
        } finally {
            out.close();
        }
    }

    /**
     * Retrieve remote URL with non-modified checking by ETag. If server doesn't support ETag, file will be
     * always retrieved.
     */
    protected void retrieve(Properties etags, String file, String url, File out) throws Exception {
        String etag = etags.getProperty(file);
        Log.logDebug(LOGGER, "Retrieve " + url + " into " + out.getAbsolutePath() + " with ETag=" + etag);

        out.getParentFile().mkdirs();
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        try {
            if (etag != null) {
                // use ETag if we know it
                conn.setRequestProperty("If-None-Match", etag);
            }
            switch (conn.getResponseCode()) {
            case HttpURLConnection.HTTP_OK:
                etag = conn.getHeaderField("ETag");
                Log.logDebug(LOGGER, "Retrieve " + url + ": 200 with ETag=" + etag);
                break;
            case HttpURLConnection.HTTP_NOT_MODIFIED:
                // not modified - just return
                Log.logDebug(LOGGER, "Retrieve " + url + ": not modified");
                return;
            default:
                throw new RuntimeException("HTTP response code: " + conn.getResponseCode());
            }

            // load into .tmp file
            File temp = new File(out.getAbsolutePath() + ".tmp");
            InputStream in = conn.getInputStream();
            try {
                FileUtils.copyInputStreamToFile(in, temp);
            } finally {
                in.close();
            }

            // rename into file
            if (out.exists()) {
                if (!out.delete()) {
                    throw new IOException();
                }
            }
            if (!temp.renameTo(out)) {
                throw new IOException();
            }
            etags.setProperty(file, etag);
        } finally {
            conn.disconnect();
        }

        Log.logDebug(LOGGER, "Retrieve " + url + " finished");
    }
}