IDEMPIERE-3660 Improve Packin - allow application on all tenants

This commit is contained in:
Carlos Ruiz 2018-03-16 17:49:25 -03:00
parent 0962dd0783
commit 89c00b7ada
12 changed files with 466 additions and 68 deletions

View File

@ -0,0 +1,72 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-3660 Improve Packin - allow application on all tenants
-- Mar 15, 2018 4:09:45 PM BRT
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200099,0,0,'Y',TO_DATE('2018-03-15 16:09:44','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-03-15 16:09:44','YYYY-MM-DD HH24:MI:SS'),100,'Apply Pack In from Folder','Apply all zip files from a folder following the rules and conventions of Automatic Pack In process','This process apply all the pack in files found in a folder recursively - ordered by timestamp.
The filename of the pack in files is important, it must follow the following convention:
[Timestamp]_[ClientValue][_AdditionalInformation].zip
* Timestamp: must be in the format yyyymmddHHMM
* ClientValue: case sensitive and compared against AD_Client.Value to find the tenant where the pack in must be applied
* AdditionalInformation: Any additional information to identify the zip file
NOTE that AD_Client.Value must not contain underscore in order for this process to work.
There is a special case for ClientValue, if the ClientValue is ALL-CLIENTS then the 2pack is intended to be applied in all active non-system clients.
If there is a need to apply initially in a seed tenant then the ClientValue must take the form ALL-CLIENTS-Seed.
For example:
201803151607_ALL-CLIENTS-GardenWorld_Test123.zip','N','ApplyPackInFolder','N','org.adempiere.pipo2.PackInFolder','4','D',0,0,'N','N','Y','N','670d19a4-8072-46c8-9e66-3cb3008d18f3')
;
-- Mar 15, 2018 4:10:09 PM BRT
INSERT INTO AD_Menu (AD_Menu_ID,Name,Description,Action,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsSummary,AD_Process_ID,IsSOTrx,IsReadOnly,EntityType,IsCentrallyMaintained,AD_Menu_UU) VALUES (200153,'Apply Pack In from Folder','Apply all zip files from a folder following the rules and conventions of Automatic Pack In process','P',0,0,'Y',TO_DATE('2018-03-15 16:10:09','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-03-15 16:10:09','YYYY-MM-DD HH24:MI:SS'),100,'N',200099,'Y','N','D','Y','dee67807-ff1c-45c8-94bd-5c025c3ec902')
;
-- Mar 15, 2018 4:10:09 PM BRT
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNodeMM_UU) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 200153, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200153)
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=0, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=50004
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=1, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=50006
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=2, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=50002
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=3, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=50003
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=4, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200153
;
-- Mar 15, 2018 4:12:47 PM BRT
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200226,0,0,'Y',TO_DATE('2018-03-15 16:12:46','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2018-03-15 16:12:46','YYYY-MM-DD HH24:MI:SS'),100,'Folder','Path on the server where the pack in files are located',200099,10,10,'N',1000,'Y','Folder','N','D',3012,'e0c4b099-68ba-48fe-b629-043befec7bbe','N')
;
-- Mar 15, 2018 4:43:24 PM BRT
UPDATE AD_Process SET Help='<p>This process apply all the pack in files found in a folder recursively - ordered by timestamp.<br />
The filename of the pack in files is important, it must follow the following convention:<br />
[Timestamp]_[ClientValue][_AdditionalInformation].zip</p>
<ul>
<li><strong>Timestamp:</strong> must be in the format yyyymmddHHMM</li>
<li><strong>ClientValue:</strong> case sensitive and compared against AD_Client.Value to find the tenant where the pack in must be applied</li>
<li><strong>AdditionalInformation:</strong> Any additional information to identify the zip file</li>
</ul>
<p>NOTE that AD_Client.Value must not contain underscore in order for this process to work.<br />
There is a special case for ClientValue, if the ClientValue is ALL-CLIENTS then the 2pack is intended to be applied in all active non-system clients.<br />
If there is a need to apply initially in a seed tenant then the ClientValue must take the form ALL-CLIENTS-Seed.<br />
For example:<br />
201803151607_ALL-CLIENTS-GardenWorld_Test123.zip</p>
',Updated=TO_DATE('2018-03-15 16:43:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200099
;
SELECT register_migration_script('201803151613_IDEMPIERE-3660.sql') FROM dual
;

View File

@ -0,0 +1,69 @@
-- IDEMPIERE-3660 Improve Packin - allow application on all tenants
-- Mar 15, 2018 4:09:45 PM BRT
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200099,0,0,'Y',TO_TIMESTAMP('2018-03-15 16:09:44','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-03-15 16:09:44','YYYY-MM-DD HH24:MI:SS'),100,'Apply Pack In from Folder','Apply all zip files from a folder following the rules and conventions of Automatic Pack In process','This process apply all the pack in files found in a folder recursively - ordered by timestamp.
The filename of the pack in files is important, it must follow the following convention:
[Timestamp]_[ClientValue][_AdditionalInformation].zip
* Timestamp: must be in the format yyyymmddHHMM
* ClientValue: case sensitive and compared against AD_Client.Value to find the tenant where the pack in must be applied
* AdditionalInformation: Any additional information to identify the zip file
NOTE that AD_Client.Value must not contain underscore in order for this process to work.
There is a special case for ClientValue, if the ClientValue is ALL-CLIENTS then the 2pack is intended to be applied in all active non-system clients.
If there is a need to apply initially in a seed tenant then the ClientValue must take the form ALL-CLIENTS-Seed.
For example:
201803151607_ALL-CLIENTS-GardenWorld_Test123.zip','N','ApplyPackInFolder','N','org.adempiere.pipo2.PackInFolder','4','D',0,0,'N','N','Y','N','670d19a4-8072-46c8-9e66-3cb3008d18f3')
;
-- Mar 15, 2018 4:10:09 PM BRT
INSERT INTO AD_Menu (AD_Menu_ID,Name,Description,"action",AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsSummary,AD_Process_ID,IsSOTrx,IsReadOnly,EntityType,IsCentrallyMaintained,AD_Menu_UU) VALUES (200153,'Apply Pack In from Folder','Apply all zip files from a folder following the rules and conventions of Automatic Pack In process','P',0,0,'Y',TO_TIMESTAMP('2018-03-15 16:10:09','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-03-15 16:10:09','YYYY-MM-DD HH24:MI:SS'),100,'N',200099,'Y','N','D','Y','dee67807-ff1c-45c8-94bd-5c025c3ec902')
;
-- Mar 15, 2018 4:10:09 PM BRT
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNodeMM_UU) SELECT t.AD_Client_ID, 0, 'Y', statement_timestamp(), 100, statement_timestamp(), 100,t.AD_Tree_ID, 200153, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200153)
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=0, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=50004
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=1, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=50006
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=2, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=50002
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=3, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=50003
;
-- Mar 15, 2018 4:10:13 PM BRT
UPDATE AD_TreeNodeMM SET Parent_ID=50001, SeqNo=4, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200153
;
-- Mar 15, 2018 4:12:47 PM BRT
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200226,0,0,'Y',TO_TIMESTAMP('2018-03-15 16:12:46','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2018-03-15 16:12:46','YYYY-MM-DD HH24:MI:SS'),100,'Folder','Path on the server where the pack in files are located',200099,10,10,'N',1000,'Y','Folder','N','D',3012,'e0c4b099-68ba-48fe-b629-043befec7bbe','N')
;
-- Mar 15, 2018 4:43:24 PM BRT
UPDATE AD_Process SET Help='<p>This process apply all the pack in files found in a folder recursively - ordered by timestamp.<br />
The filename of the pack in files is important, it must follow the following convention:<br />
[Timestamp]_[ClientValue][_AdditionalInformation].zip</p>
<ul>
<li><strong>Timestamp:</strong> must be in the format yyyymmddHHMM</li>
<li><strong>ClientValue:</strong> case sensitive and compared against AD_Client.Value to find the tenant where the pack in must be applied</li>
<li><strong>AdditionalInformation:</strong> Any additional information to identify the zip file</li>
</ul>
<p>NOTE that AD_Client.Value must not contain underscore in order for this process to work.<br />
There is a special case for ClientValue, if the ClientValue is ALL-CLIENTS then the 2pack is intended to be applied in all active non-system clients.<br />
If there is a need to apply initially in a seed tenant then the ClientValue must take the form ALL-CLIENTS-Seed.<br />
For example:<br />
201803151607_ALL-CLIENTS-GardenWorld_Test123.zip</p>
',Updated=TO_TIMESTAMP('2018-03-15 16:43:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200099
;
SELECT register_migration_script('201803151613_IDEMPIERE-3660.sql') FROM dual
;

View File

@ -17,6 +17,7 @@ package org.adempiere.base;
import java.io.File; import java.io.File;
import org.compiere.model.X_AD_Package_Imp_Proc;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
/** /**
@ -28,4 +29,8 @@ import org.osgi.framework.BundleContext;
*/ */
public interface IDictionaryService { public interface IDictionaryService {
void merge(BundleContext context, File packageFile) throws Exception; void merge(BundleContext context, File packageFile) throws Exception;
default public X_AD_Package_Imp_Proc getAD_Package_Imp_Proc() {
return null;
};
} }

View File

@ -35,5 +35,13 @@
class="org.adempiere.pipo2.PackRollProcess"> class="org.adempiere.pipo2.PackRollProcess">
</process> </process>
</extension> </extension>
<extension
id="org.adempiere.pipo2.PackInFolder"
name="PackIn Folder"
point="org.adempiere.base.Process">
<process
class="org.adempiere.pipo2.PackInFolder">
</process>
</extension>
</plugin> </plugin>

View File

@ -34,24 +34,28 @@ public class PipoDictionaryService implements IDictionaryService {
super(); super();
} }
X_AD_Package_Imp_Proc adPackageImp = null;
@Override @Override
public void merge(BundleContext context, File packageFile) throws Exception { public void merge(BundleContext context, File packageFile) throws Exception {
if (packageFile == null || !packageFile.exists()) { if (packageFile == null || !packageFile.exists()) {
logger.info("No PackIn Model found"); logger.info("No PackIn Model found");
return; return;
} }
String symbolicName = "org.adempiere.pipo";
if (context != null)
symbolicName = context.getBundle().getSymbolicName();
String trxName = null; String trxName = null;
X_AD_Package_Imp_Proc adPackageImp = null;
PackIn packIn = null; PackIn packIn = null;
try { try {
trxName = Trx.createTrxName("PipoDS"); trxName = Trx.createTrxName("PipoDS");
Trx.get(trxName, true).setDisplayName(getClass().getName()+"_merge"); Trx.get(trxName, true).setDisplayName(getClass().getName()+"_merge");
packIn = new PackIn(); packIn = new PackIn();
//external files must not start with "2Pack" prefix in order to work correctly //external files must not start with "2Pack" prefix in order to work correctly
if ("org.adempiere.pipo".equals(context.getBundle().getSymbolicName()) && !packageFile.getName().startsWith("2Pack")) if ("org.adempiere.pipo".equals(symbolicName) && !packageFile.getName().startsWith("2Pack"))
packIn.setPackageName(packageFile.getName()); packIn.setPackageName(packageFile.getName());
else else
packIn.setPackageName(context.getBundle().getSymbolicName()); packIn.setPackageName(symbolicName);
if (Env.getCtx().getProperty("#AD_Client_ID") == null) { if (Env.getCtx().getProperty("#AD_Client_ID") == null) {
Env.getCtx().put("#AD_Client_ID", 0); Env.getCtx().put("#AD_Client_ID", 0);
@ -70,13 +74,13 @@ public class PipoDictionaryService implements IDictionaryService {
} }
} }
//no version string from file name suffix, get it from bundle header //no version string from file name suffix, get it from bundle header
if (packageVersion == null) if (packageVersion == null && context != null)
packageVersion = (String) context.getBundle().getHeaders().get("Bundle-Version"); packageVersion = (String) context.getBundle().getHeaders().get("Bundle-Version");
packIn.setPackageVersion(packageVersion); packIn.setPackageVersion(packageVersion);
packIn.setUpdateDictionary(false); packIn.setUpdateDictionary(false);
packIn.getNotifier().setFileName(packageFile.getName()); packIn.getNotifier().setFileName(packageFile.getName());
packIn.getNotifier().setPluginName(context.getBundle().getSymbolicName() + " v" + packageVersion); packIn.getNotifier().setPluginName(symbolicName + " v" + packageVersion);
adPackageImp = new X_AD_Package_Imp_Proc(Env.getCtx(), 0, null); adPackageImp = new X_AD_Package_Imp_Proc(Env.getCtx(), 0, null);
if (logger.isLoggable(Level.INFO)) logger.info("zipFilepath->" + packageFile); if (logger.isLoggable(Level.INFO)) logger.info("zipFilepath->" + packageFile);
@ -144,4 +148,9 @@ public class PipoDictionaryService implements IDictionaryService {
return result; return result;
}*/ }*/
@Override
public X_AD_Package_Imp_Proc getAD_Package_Imp_Proc() {
return adPackageImp;
};
} }

View File

@ -0,0 +1,90 @@
/***********************************************************************
* 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 *
**********************************************************************/
package org.adempiere.pipo2;
import java.util.logging.Level;
import org.adempiere.plugin.utils.PackInApplicationActivator;
import org.compiere.process.ProcessInfoParameter;
import org.compiere.process.SvrProcess;
import org.compiere.util.AdempiereSystemError;
import org.compiere.util.Util;
/**
* Apply all zip files from a folder following the rules and conventions of Automatic Pack In process
* This process apply all the pack in files found in a folder recursively - ordered by timestamp.
* The filename of the pack in files is important, it must follow the following convention:
* [Timestamp]_[ClientValue][_AdditionalInformation].zip
* - Timestamp: must be in the format yyyymmddHHMM
* - ClientValue: case sensitive and compared against AD_Client.Value to find the tenant where the pack in must be applied
* - AdditionalInformation: Any additional information to identify the zip file
* NOTE that AD_Client.Value must not contain underscore in order for this process to work.
* There is a special case for ClientValue, if the ClientValue is ALL-CLIENTS then the 2pack is intended to be applied in all active non-system clients.
* If there is a need to apply initially in a seed tenant then the ClientValue must take the form ALL-CLIENTS-Seed.
* For example:
* 201803151607_ALL-CLIENTS-GardenWorld_Test123.zip
*
* @author Carlos Ruiz
*/
public class PackInFolder extends SvrProcess {
/** Folder to apply */
private String p_Folder;
/**
* Prepare - e.g., get Parameters.
*/
protected void prepare () {
for (ProcessInfoParameter para : getParameter()) {
String name = para.getParameterName();
if (para.getParameter() == null)
;
else if (name.equals("Folder"))
p_Folder = para.getParameterAsString();
else
log.log(Level.SEVERE, "Unknown Parameter: " + name);
}
} // prepare
/**
* Process
* @return info
* @throws Exception
*/
protected String doIt () throws Exception
{
if (Util.isEmpty(p_Folder, true))
throw new AdempiereSystemError("@Mandatory@ @Folder@");
PackInApplicationActivator piaa = new PackInApplicationActivator();
piaa.setProcessInfo(getProcessInfo());
piaa.setProcessUI(processUI);
piaa.automaticPackin(0, p_Folder, false);
String msg = getProcessInfo().getSummary();
return msg;
} // doIt
}

View File

@ -45,6 +45,7 @@ public class PackInProcess extends SvrProcess {
private String m_packageDirectory = null; private String m_packageDirectory = null;
public int p_PackIn_ID = 0; public int p_PackIn_ID = 0;
@SuppressWarnings("unused")
private String packageName = null; private String packageName = null;
private String packageVersion = null; private String packageVersion = null;
@ -130,7 +131,7 @@ public class PackInProcess extends SvrProcess {
PackIn packIn = new PackIn(); PackIn packIn = new PackIn();
packIn.setPackageDirectory(m_packageDirectory); packIn.setPackageDirectory(m_packageDirectory);
packIn.setPackageName(packageName); packIn.setPackageName(adPackageImp.getName());
packIn.setPackageVersion(packageVersion); packIn.setPackageVersion(packageVersion);
packIn.setUpdateDictionary(m_UpdateDictionary); packIn.setUpdateDictionary(m_UpdateDictionary);
packIn.getNotifier().setFileName(zipFilepath.getName()); packIn.getNotifier().setFileName(zipFilepath.getName());

View File

@ -43,6 +43,7 @@ Import-Package: org.adempiere.base,
org.compiere, org.compiere,
org.compiere.db, org.compiere.db,
org.compiere.model, org.compiere.model,
org.compiere.process,
org.compiere.util, org.compiere.util,
org.osgi.framework;version="1.5.0", org.osgi.framework;version="1.5.0",
org.osgi.util.tracker;version="1.5.0" org.osgi.util.tracker;version="1.5.0"

View File

@ -14,13 +14,19 @@
package org.adempiere.plugin.utils; package org.adempiere.plugin.utils;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.base.IDictionaryService; import org.adempiere.base.IDictionaryService;
import org.adempiere.base.Service;
import org.adempiere.util.IProcessUI;
import org.compiere.model.MClient;
import org.compiere.model.MSysConfig; import org.compiere.model.MSysConfig;
import org.compiere.model.PO; import org.compiere.model.PO;
import org.compiere.model.Query; import org.compiere.model.Query;
import org.compiere.model.X_AD_Package_Imp; import org.compiere.model.X_AD_Package_Imp;
import org.compiere.process.ProcessInfo;
import org.compiere.util.AdempiereSystemError; import org.compiere.util.AdempiereSystemError;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.DB; import org.compiere.util.DB;
@ -38,6 +44,8 @@ public abstract class AbstractActivator implements BundleActivator, ServiceTrack
protected ServiceTracker<IDictionaryService, IDictionaryService> serviceTracker; protected ServiceTracker<IDictionaryService, IDictionaryService> serviceTracker;
protected IDictionaryService service; protected IDictionaryService service;
private String trxName = ""; private String trxName = "";
private ProcessInfo m_processInfo = null;
private IProcessUI m_processUI = null;
protected boolean merge(File zipfile, String version) throws Exception { protected boolean merge(File zipfile, String version) throws Exception {
boolean success = false; boolean success = false;
@ -46,24 +54,47 @@ public abstract class AbstractActivator implements BundleActivator, ServiceTrack
service.merge(context, zipfile); service.merge(context, zipfile);
success = true; success = true;
} else { } else {
logger.log(Level.SEVERE, "The file was already installed: " + zipfile.getName()); logger.log(Level.SEVERE, "The file was previously installed: " + zipfile.getName());
}
return success;
}
protected boolean directMerge(File zipfile, String version) throws Exception {
boolean success = false;
if (!installedPackage(version)) {
List<IDictionaryService> list = Service.locator().list(IDictionaryService.class).getServices();
if (list != null) {
IDictionaryService ids = list.get(0);
ids.merge(null, zipfile);
success = true;
if (ids.getAD_Package_Imp_Proc() != null) {
MClient client = MClient.get(Env.getCtx());
addLog(Level.INFO, getName() + " in " + client.getValue() + " -> "+ ids.getAD_Package_Imp_Proc().getP_Msg());
}
} else {
addLog(Level.SEVERE, "Could not find an IDictionaryService to process the zip files");
}
} else {
addLog(Level.SEVERE, "The file was previously installed: " + zipfile.getName());
success = true;
} }
return success; return success;
} }
protected boolean installedPackage(String version) { protected boolean installedPackage(String version) {
StringBuilder where = new StringBuilder("Name=? AND PK_Status = 'Completed successfully'"); StringBuilder where = new StringBuilder("AD_Client_ID=? AND Name=? AND PK_Status='Completed successfully'");
Object[] params; List<Object> params = new ArrayList<Object>();
params.add(Env.getAD_Client_ID(Env.getCtx()));
params.add(getName());
if (version != null) { if (version != null) {
where.append(" AND PK_Version LIKE ?"); where.append(" AND PK_Version LIKE ?");
params = new Object[] { getName(), version + "%" }; params.add(version + "%");
} else {
params = new Object[] {getName()};
} }
Query q = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, Query q = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, where.toString(), null)
where.toString(), null); .setParameters(params);
q.setParameters(params);
return q.match(); return q.match();
} }
@ -105,4 +136,31 @@ public abstract class AbstractActivator implements BundleActivator, ServiceTrack
sysconfig.set_TrxName(trxName); sysconfig.set_TrxName(trxName);
return sysconfig; return sysconfig;
} }
public void setProcessInfo(ProcessInfo processInfo) {
m_processInfo = processInfo;
}
public void setProcessUI(IProcessUI processUI) {
m_processUI = processUI;
};
protected void statusUpdate(String message) {
logger.warning(message);
if (m_processUI != null)
m_processUI.statusUpdate(message);
}
public void addLog(Level level, String msg) {
logger.log(level, msg);
if (m_processInfo != null)
m_processInfo.addLog(0, null, null, msg.replaceAll("\\n", "<br>"));
}
public void setSummary(Level level, String msg) {
logger.log(level, msg);
if (m_processInfo != null)
m_processInfo.setSummary(msg);
}
} }

View File

@ -15,6 +15,7 @@ package org.adempiere.plugin.utils;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -34,6 +35,8 @@ import org.compiere.model.MSysConfig;
import org.compiere.model.Query; import org.compiere.model.Query;
import org.compiere.model.ServerStateChangeEvent; import org.compiere.model.ServerStateChangeEvent;
import org.compiere.model.ServerStateChangeListener; import org.compiere.model.ServerStateChangeListener;
import org.compiere.model.X_AD_Package_Imp;
import org.compiere.model.X_AD_Package_Imp_Proc;
import org.compiere.util.AdempiereSystemError; import org.compiere.util.AdempiereSystemError;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.Env; import org.compiere.util.Env;
@ -88,7 +91,9 @@ public class PackInApplicationActivator extends AbstractActivator {
Adempiere.getThreadPoolExecutor().execute(new Runnable() { Adempiere.getThreadPoolExecutor().execute(new Runnable() {
@Override @Override
public void run() { public void run() {
automaticPackin(); int timeout = MSysConfig.getIntValue(MSysConfig.AUTOMATIC_PACKIN_INITIAL_DELAY, 120) * 1000;
String folders = MSysConfig.getValue(MSysConfig.AUTOMATIC_PACKIN_FOLDERS);
automaticPackin(timeout, folders, true);
} }
}); });
} else { } else {
@ -96,7 +101,9 @@ public class PackInApplicationActivator extends AbstractActivator {
@Override @Override
public void stateChange(ServerStateChangeEvent event) { public void stateChange(ServerStateChangeEvent event) {
if (event.getEventType() == ServerStateChangeEvent.SERVER_START && service != null) { if (event.getEventType() == ServerStateChangeEvent.SERVER_START && service != null) {
automaticPackin(); int timeout = MSysConfig.getIntValue(MSysConfig.AUTOMATIC_PACKIN_INITIAL_DELAY, 120) * 1000;
String folders = MSysConfig.getValue(MSysConfig.AUTOMATIC_PACKIN_FOLDERS);
automaticPackin(timeout, folders, true);
} }
} }
}); });
@ -104,73 +111,90 @@ public class PackInApplicationActivator extends AbstractActivator {
return null; return null;
} }
private void automaticPackin() { public void automaticPackin(int timeout, String folders, boolean fromService) {
//Initial delay if (fromService) {
Timer t = new Timer(); //Initial delay - starting from service
t.schedule(new TimerTask() { Timer t = new Timer();
@Override t.schedule(new TimerTask() {
public void run() { @Override
ClassLoader cl = Thread.currentThread().getContextClassLoader(); public void run() {
try { ClassLoader cl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(PackInApplicationActivator.class.getClassLoader()); try {
setupPackInContext(); Thread.currentThread().setContextClassLoader(PackInApplicationActivator.class.getClassLoader());
installPackages(); setupPackInContext();
} finally { installPackages(folders);
ServerContext.dispose(); } finally {
service = null; ServerContext.dispose();
Thread.currentThread().setContextClassLoader(cl); service = null;
Thread.currentThread().setContextClassLoader(cl);
}
t.cancel();
} }
t.cancel(); }, timeout);
} else {
// No delay - starting from process
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(PackInApplicationActivator.class.getClassLoader());
setupPackInContext();
installPackages(folders);
} finally {
ServerContext.dispose();
Thread.currentThread().setContextClassLoader(cl);
} }
}, MSysConfig.getIntValue(MSysConfig.AUTOMATIC_PACKIN_INITIAL_DELAY, 120) * 1000); }
} }
private void installPackages() { private void installPackages(String folders) {
String folders = MSysConfig.getValue(MSysConfig.AUTOMATIC_PACKIN_FOLDERS);
if (Util.isEmpty(folders, true)) { if (Util.isEmpty(folders, true)) {
logger.log(Level.INFO, "Not specified folders for automatic packin"); setSummary(Level.INFO, "Not specified folders for automatic packin");
return; return;
} }
File[] fileArray = getFilesToProcess(folders); File[] fileArray = getFilesToProcess(folders);
if (fileArray.length <= 0) { if (fileArray.length <= 0) {
logger.info("No zip files to process"); setSummary(Level.INFO, "No zip files to process");
return; return;
} }
try { try {
if (getDBLock()) { if (getDBLock()) {
//Create Session to be able to create records in AD_ChangeLog //Create Session to be able to create records in AD_ChangeLog
MSession.get(Env.getCtx(), true); if (Env.getContextAsInt(Env.getCtx(), "#AD_Session_ID") <= 0)
MSession.get(Env.getCtx(), true);
for(File zipFile : fileArray) { for(File zipFile : fileArray) {
currentFile = zipFile; currentFile = zipFile;
if (!packIn(zipFile)) { if (!packIn(zipFile)) {
// stop processing further packages if one fail // stop processing further packages if one fail
addLog(Level.SEVERE, "Failed application of " + zipFile);
break; break;
} }
addLog(Level.INFO, "Successful application of " + zipFile);
filesToProcess.remove(zipFile); filesToProcess.remove(zipFile);
} }
releaseLock();
} else { } else {
logger.log(Level.SEVERE, "Could not acquire the DB lock to automatically install the packins"); addLog(Level.SEVERE, "Could not acquire the DB lock to automatically install the packins");
return;
} }
} catch (AdempiereSystemError e) { } catch (AdempiereSystemError e) {
e.printStackTrace(); e.printStackTrace();
addLog(Level.SEVERE, e.getLocalizedMessage());
} finally {
releaseLock();
} }
if (filesToProcess.size() > 0) { if (filesToProcess.size() > 0) {
logger.warning("The following packages were not applied: "); StringBuilder pending = new StringBuilder("The following packages were not applied: ");
for (File file : filesToProcess) { for (File file : filesToProcess) {
logger.warning(file.getName()); pending.append("\n").append(file.getName());
} }
addLog(Level.WARNING, pending.toString());
} }
} }
private boolean packIn(File packinFile) { private boolean packIn(File packinFile) {
if (packinFile != null && service != null) { if (packinFile != null) {
String fileName = packinFile.getName(); String fileName = packinFile.getName();
logger.warning("Installing " + fileName + " ..."); logger.warning("Installing " + fileName + " ...");
@ -178,23 +202,86 @@ public class PackInApplicationActivator extends AbstractActivator {
String [] parts = fileName.split("_"); String [] parts = fileName.split("_");
String clientValue = parts[1]; String clientValue = parts[1];
MClient client = getClient(clientValue); boolean allClients = clientValue.startsWith("ALL-CLIENTS");
if (client == null) {
logger.log(Level.SEVERE, "Client does not exist: " + clientValue);
return false;
}
Env.setContext(Env.getCtx(), "#AD_Client_ID", client.getAD_Client_ID()); int[] clientIDs;
if (allClients) {
try { int[] seedClientIDs = new int[0];
// call 2pack String seedClientValue = "";
if (!merge(packinFile, null)) if (clientValue.startsWith("ALL-CLIENTS-")) {
seedClientValue = clientValue.split("-")[2];
seedClientIDs = getClientIDs(seedClientValue);
if (seedClientIDs.length == 0) {
logger.log(Level.SEVERE, "Seed client does not exist: " + seedClientValue);
return false;
}
}
int[] allClientIDs = new Query(Env.getCtx(), MClient.Table_Name, "AD_Client_ID>0 AND Value!=?", null)
.setOnlyActiveRecords(true)
.setParameters(seedClientValue)
.setOrderBy("AD_Client_ID")
.getIDs();
// Process first the seed client, put seed in front of the array
int shift = 0;
if (seedClientIDs.length > 0)
shift = 1;
clientIDs = new int[allClientIDs.length + shift];
if (seedClientIDs.length > 0)
clientIDs[0] = seedClientIDs[0];
for (int i = 0; i < allClientIDs.length; i++) {
clientIDs[i+shift] = allClientIDs[i];
}
} else {
clientIDs = getClientIDs(clientValue);
if (clientIDs.length == 0) {
logger.log(Level.SEVERE, "Client does not exist: " + clientValue);
return false; return false;
} catch (Throwable e) { }
logger.log(Level.SEVERE, "Pack in failed.", e); }
return false;
for (int clientID : clientIDs) {
MClient client = MClient.get(Env.getCtx(), clientID);
if (allClients) {
String message = "Installing " + fileName + " in client " + client.getValue() + "/" + client.getName();
statusUpdate(message);
}
Env.setContext(Env.getCtx(), "#AD_Client_ID", client.getAD_Client_ID());
try {
// call 2pack
if (service != null) {
if (!merge(packinFile, null)) {
return false;
}
} else {
if (!directMerge(packinFile, null)) {
return false;
}
}
} catch (Throwable e) {
logger.log(Level.SEVERE, "Pack in failed.", e);
return false;
} finally {
Env.setContext(Env.getCtx(), "#AD_Client_ID", 0);
}
logger.warning(packinFile.getPath() + " installed");
}
if (allClients ) {
// when arriving here it means an ALL-CLIENTS 2pack was processed successfully
// register a record on System to avoid future reprocesses of the same file
X_AD_Package_Imp_Proc pimpr = new X_AD_Package_Imp_Proc(Env.getCtx(), 0, null);
pimpr.setName(fileName);
pimpr.setDateProcessed(new Timestamp(System.currentTimeMillis()));
pimpr.setP_Msg("This ALL-CLIENT 2Pack was applied successfully in all tenants");
pimpr.setAD_Package_Source_Type(X_AD_Package_Imp_Proc.AD_PACKAGE_SOURCE_TYPE_File);
pimpr.saveEx();
X_AD_Package_Imp pimp = new X_AD_Package_Imp(Env.getCtx(), 0, null);
pimp.setAD_Package_Imp_Proc_ID(pimpr.getAD_Package_Imp_Proc_ID());
pimp.setName(fileName);
pimp.setPK_Status("Completed successfully");
pimp.setDescription("This ALL-CLIENT 2Pack was applied successfully in all tenants");
pimp.setProcessed(true);
pimp.saveEx();
} }
logger.warning(packinFile.getPath() + " installed");
} }
return true; return true;
@ -282,14 +369,12 @@ public class PackInApplicationActivator extends AbstractActivator {
} }
} }
private MClient getClient(String clientValue) { private int[] getClientIDs(String clientValue) {
String where = "Value = ?"; String where = "Value = ?";
Query q = new Query(Env.getCtx(), MClient.Table_Name, Query q = new Query(Env.getCtx(), MClient.Table_Name, where, null)
where, null) .setParameters(clientValue)
.setParameters(new Object[] {clientValue})
.setOnlyActiveRecords(true); .setOnlyActiveRecords(true);
return q.getIDs();
return q.first();
} }
@Override @Override
@ -312,6 +397,6 @@ public class PackInApplicationActivator extends AbstractActivator {
Properties serverContext = new Properties(); Properties serverContext = new Properties();
serverContext.setProperty("#AD_Client_ID", "0"); serverContext.setProperty("#AD_Client_ID", "0");
ServerContext.setCurrentInstance(serverContext); ServerContext.setCurrentInstance(serverContext);
}; }
} }

View File

@ -314,7 +314,7 @@ public class ProcessDialog extends AbstractProcessDialog implements EventListene
layoutResultPanel (topParameterLayout); layoutResultPanel (topParameterLayout);
StringBuilder buildMsg = new StringBuilder(getInitialMessage()); StringBuilder buildMsg = new StringBuilder(getInitialMessage());
buildMsg.append("<p><font color=\"").append(pi.isError() ? "#FF0000" : "#0000FF").append("\">** ") buildMsg.append("<hr><p><font color=\"").append(pi.isError() ? "#FF0000" : "#0000FF").append("\">** ")
.append(pi.getSummary()) .append(pi.getSummary())
.append("</font></p>"); .append("</font></p>");

View File

@ -36,7 +36,7 @@ when detect side effect, fix to only apply for parameter window*/
} }
.message-paramenter{ .message-paramenter{
max-height: 150pt; max-height: 300pt;
overflow: hidden; overflow: hidden;
margin: 10px; margin: 10px;
} }