/*********************************************************************** * This file is part of iDempiere ERP Open Source * * http://www.idempiere.org * * * * Copyright (C) Contributors * * * * This program 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 2 * * of the License, or (at your option) any later version. * * * * This program 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, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301, USA. * * * * Contributors: * * - Carlos Ruiz - globalqss * **********************************************************************/ package org.idempiere.process; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.Enumeration; import java.util.List; import java.util.logging.Level; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.adempiere.exceptions.AdempiereException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Target; import org.apache.tools.ant.taskdefs.Zip; import org.compiere.install.Translation; import org.compiere.model.MProcessPara; import org.compiere.model.MTable; import org.compiere.model.Query; import org.compiere.process.ProcessInfoParameter; import org.compiere.process.SvrProcess; import org.compiere.tools.FileUtil; import org.compiere.util.AdempiereSystemError; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; /** * Process to import or export translations */ @org.adempiere.base.annotation.Process public class TranslationImpExp extends SvrProcess { private String p_ImportOrExport; private int p_AD_Client_ID; // Client private String p_AD_Language; private int p_AD_Table_ID; private boolean p_IsOnlyCentralizedData; private String p_Folder; private String p_FileName; @Override protected void prepare() { for (ProcessInfoParameter para : getParameter()) { String name = para.getParameterName(); if ("ImportOrExport".equals(name)) { p_ImportOrExport = para.getParameterAsString(); } else if ("AD_AllClients_V_ID".equals(name)) { p_AD_Client_ID = para.getParameterAsInt(); } else if ("AD_Language".equals(name)) { p_AD_Language = para.getParameterAsString(); } else if ("AD_Table_ID".equals(name)) { p_AD_Table_ID = para.getParameterAsInt(); } else if ("IsOnlyCentralizedData".equals(name)) { p_IsOnlyCentralizedData = para.getParameterAsBoolean(); } else if ("Folder".equals(name)) { p_Folder = para.getParameterAsString(); } else if ("FileName".equals(name)) { p_FileName = para.getParameterAsString(); } else { MProcessPara.validateUnknownParameter(getProcessInfo().getAD_Process_ID(), para); } } } @Override protected String doIt() throws Exception { // validate parameters if (Util.isEmpty(p_AD_Language, true)) throw new AdempiereSystemError("@Mandatory@ @AD_Language@"); if ("import".equals(p_ImportOrExport) && Util.isEmpty(p_Folder, true) && Util.isEmpty(p_FileName, true)) throw new AdempiereSystemError("@Mandatory@ @Folder@ / @FileName@"); File tempFolder = null; try { if (! Util.isEmpty(p_FileName, true) && "import".equals(p_ImportOrExport)) { if (p_FileName.startsWith("http://") || p_FileName.startsWith("https://")) { String tmpZip = null; FileOutputStream fos = null; try { URL website = new URL(p_FileName); ReadableByteChannel rbc = Channels.newChannel(website.openStream()); tmpZip = FileUtil.getTempMailName(p_AD_Language, ".zip"); fos = new FileOutputStream(tmpZip); fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); p_FileName = tmpZip; } catch (Exception e) { throw new AdempiereSystemError("Could not download " + p_FileName + " -> " + e.getLocalizedMessage()); } finally { fos.close(); } } else { if (! p_FileName.toLowerCase().endsWith(".zip")) { throw new AdempiereSystemError("@FileMustBeZIP@"); } } tempFolder = createTempFolder(p_AD_Language); unZipLangFile(p_FileName, p_AD_Language, tempFolder); p_Folder = tempFolder.getAbsolutePath(); } else { if (Util.isEmpty(p_Folder)) { tempFolder = createTempFolder(p_AD_Language); p_Folder = tempFolder.getAbsolutePath(); } } Translation translation = new Translation(Env.getCtx()); String msg = translation.validateLanguage(p_AD_Language, get_TrxName()); if (msg.length() > 0) throw new AdempiereSystemError(msg); StringBuilder whereClause = new StringBuilder("TableName LIKE '%_Trl' AND TableName<>'AD_Column_Trl'"); if (p_AD_Table_ID > 0) whereClause.append(" AND AD_Table_ID=?"); Query query = new Query(getCtx(), MTable.Table_Name, whereClause.toString(), get_TrxName()) .setOnlyActiveRecords(true) .setOrderBy("TableName"); if (p_AD_Table_ID > 0) query.setParameters(p_AD_Table_ID); List tables = query.list(); for (MTable table : tables) { String msgProc; String tableName = table.getTableName(); if ("import".equals(p_ImportOrExport)) { statusUpdate(Msg.parseTranslation(getCtx(), "@Import@ " + tableName + " ...")); msgProc = translation.importTrl(p_Folder, p_AD_Client_ID, p_AD_Language, tableName, get_TrxName()); } else { statusUpdate(Msg.parseTranslation(getCtx(), "@Export@ " + tableName + " ...")); msgProc = translation.exportTrl(p_Folder, p_AD_Client_ID, p_AD_Language, tableName, p_IsOnlyCentralizedData); } addLog(tableName + " " + msgProc); } if (!"import".equals(p_ImportOrExport) && tempFolder != null) { // exporting to zip, now zip the exported files File destZipFile = null; try { destZipFile = File.createTempFile(p_AD_Language + "_trlExport_", ".zip"); } catch (Throwable e) { throw new AdempiereException("Unable to create temp file", e); } destZipFile.delete(); Zip zipper = new Zip(); zipper.setDestFile(destZipFile); zipper.setBasedir(tempFolder); zipper.setUpdate(false); zipper.setCompress(true); zipper.setCaseSensitive(false); zipper.setFilesonly(true); zipper.setTaskName("zip"); zipper.setTaskType("zip"); zipper.setProject(new Project()); zipper.setOwningTarget(new Target()); zipper.execute(); processUI.download(destZipFile); } } finally { // Cleanup when temp folder if (tempFolder != null) { try { FileUtil.deleteFolderRecursive(tempFolder); } catch (IOException e) {} } } return "@OK@"; } private File createTempFolder(String language) { // create temp folder File tmpFolder; try { tmpFolder = File.createTempFile(language, ".trl"); tmpFolder.delete(); tmpFolder.mkdir(); } catch (IOException e1) { throw new AdempiereException("Problem creating temp folder", e1); } return tmpFolder; } /** * Unzip the fileName into a temp folder and return the folder name * @param file Name * @return folder Name * @throws AdempiereException */ private void unZipLangFile(String fileName, String language, File folder) throws AdempiereException { String suffix = "_" + language + ".xml"; ZipFile zipFile = null; boolean validfile = false; try { zipFile = new ZipFile(fileName); Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry)entries.nextElement(); if (entry.isDirectory()) { // ignore folders addLog("Imported zip must not contain folders, ignored folder" + entry.getName()); continue; } if (! entry.getName().endsWith(suffix)) { // not valid file addLog("Ignored file " + entry.getName()); continue; } String outName = entry.getName(); String prefixFolderLang = language + File.separator; // allow files in the language folder (in case the zip was created including the folder) if (outName.startsWith(prefixFolderLang)) { outName = outName.substring(prefixFolderLang.length()); } File outFile = new File(folder.getPath(), outName); if (!outFile.toPath().normalize().startsWith(folder.toPath())) { log.severe("Bad zip entry: " + entry.getName()); addLog("Bad zip entry: " + entry.getName()); continue; } if (log.isLoggable(Level.INFO)) log.info("Extracting file: " + entry.getName()); copyInputStream(zipFile.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(outFile))); validfile = true; } } catch (Throwable e) { throw new AdempiereException("Uncompress zip failed", e); } finally { if (zipFile != null) try { zipFile.close(); } catch (IOException e) {} } if (!validfile) { throw new AdempiereException("ZIP file invalid, doesn't contain *" + suffix + " files"); } } public static final void copyInputStream(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; int len; while((len = in.read(buffer)) >= 0) out.write(buffer, 0, len); in.close(); out.close(); } }