From 005419e6b3b9b58c362cfc4d7919d7c0f2b4115a Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Wed, 17 May 2017 17:52:09 +0800 Subject: [PATCH] IDEMPIERE-2771 1007609 Incremental 2Pack to apply ALL-unapplied instead of NEW --- .../pipo/srv/PipoDictionaryService.java | 4 +- .../utils/Incremental2PackActivator.java | 143 +++++---- .../plugin/utils/Version2PackActivator.java | 303 ++++++++++++++++++ 3 files changed, 391 insertions(+), 59 deletions(-) create mode 100644 org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Version2PackActivator.java diff --git a/org.adempiere.pipo/src/org/adempiere/pipo/srv/PipoDictionaryService.java b/org.adempiere.pipo/src/org/adempiere/pipo/srv/PipoDictionaryService.java index e92e2f0032..7dd856774d 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo/srv/PipoDictionaryService.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo/srv/PipoDictionaryService.java @@ -65,11 +65,11 @@ public class PipoDictionaryService implements IDictionaryService { //get package version from file name suffix or bundle header String packageVersion = null; String fileName = packageFile.getName(); - int versionSeparatorPos = fileName.lastIndexOf("_"); + int versionSeparatorPos = fileName.lastIndexOf("2Pack_"); if (versionSeparatorPos > 0) { int dotPos = fileName.lastIndexOf("."); if (dotPos > 0 && dotPos > versionSeparatorPos) { - String version = fileName.substring(versionSeparatorPos+1, dotPos); + String version = fileName.substring(versionSeparatorPos+"2Pack_".length(), dotPos); if (version.split("[.]").length == 3) { packageVersion = version; } diff --git a/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Incremental2PackActivator.java b/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Incremental2PackActivator.java index a168bd9877..cdf2906590 100644 --- a/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Incremental2PackActivator.java +++ b/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Incremental2PackActivator.java @@ -34,7 +34,7 @@ import org.compiere.model.ServerStateChangeListener; import org.compiere.model.X_AD_Package_Imp; import org.compiere.util.CLogger; import org.compiere.util.Env; -import org.compiere.util.Util; +import org.compiere.util.Trx; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -87,38 +87,24 @@ public class Incremental2PackActivator implements BundleActivator, ServiceTracke } private void installPackage() { - // e.g. 1.0.0.qualifier, check only the "1.0.0" part - String bundleVersionPart = getVersion(); - String installedVersionPart = null; - String where = "Name=? AND PK_Status = 'Completed successfully'"; - Query q = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, - where.toString(), null); - q.setParameters(new Object[] { getName() }); - List pkgs = q.list(); - if (pkgs != null && !pkgs.isEmpty()) { - for(X_AD_Package_Imp pkg : pkgs) { - String packageVersionPart = pkg.getPK_Version(); - String[] part = packageVersionPart.split("[.]"); - if (installedVersionPart == null) { - if (part.length > 3) { - installedVersionPart = part[0]+"."+part[1]+"."+part[2]; - } else { - installedVersionPart = packageVersionPart; - } - } else { - Version installedVersion = new Version(installedVersionPart); - if (part.length > 3) { - packageVersionPart = part[0]+"."+part[1]+"."+part[2]; - } - Version packageVersion = new Version(packageVersionPart); - if (packageVersion.compareTo(installedVersion) > 0) { - installedVersionPart = packageVersionPart; - } - } + String where = "Name=? AND PK_Status = 'Completed successfully'"; + Query q = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, + where.toString(), null); + q.setParameters(new Object[] { getName() }); + List pkgs = q.list(); + List installedVersions = new ArrayList(); + if (pkgs != null && !pkgs.isEmpty()) { + for(X_AD_Package_Imp pkg : pkgs) { + String packageVersionPart = pkg.getPK_Version(); + String[] part = packageVersionPart.split("[.]"); + if (part.length > 3 && (packageVersionPart.indexOf(".v") > 0 || packageVersionPart.indexOf(".qualifier") > 0)) { + packageVersionPart = part[0]+"."+part[1]+"."+part[2]; } + installedVersions.add(packageVersionPart); } - packIn(installedVersionPart, bundleVersionPart); - afterPackIn(); + } + packIn(installedVersions); + afterPackIn(); } private static class TwoPackEntry { @@ -130,31 +116,72 @@ public class Incremental2PackActivator implements BundleActivator, ServiceTracke } } - protected void packIn(String installedVersionPart, String bundleVersionPart) { + protected void packIn(List installedVersions) { List list = new ArrayList(); //2Pack_1.0.0.zip, 2Pack_1.0.1.zip, etc Enumeration urls = context.getBundle().findEntries("/META-INF", "2Pack_*.zip", false); - Version bundleVersion = new Version(bundleVersionPart); - if (!Util.isEmpty(installedVersionPart)) { - Version installedVersion = new Version(installedVersionPart); - while(urls.hasMoreElements()) { - URL u = urls.nextElement(); - String version = extractVersionString(u); - Version packageVersion = new Version(version); - if (packageVersion.compareTo(bundleVersion) <= 0 && packageVersion.compareTo(installedVersion) > 0) - list.add(new TwoPackEntry(u, version)); - } - } else { - while(urls.hasMoreElements()) { - URL u = urls.nextElement(); - String version = extractVersionString(u); - Version packageVersion = new Version(version); - if (packageVersion.compareTo(bundleVersion) <= 0) - list.add(new TwoPackEntry(u, version)); - } + while(urls.hasMoreElements()) { + URL u = urls.nextElement(); + String version = extractVersionString(u); + list.add(new TwoPackEntry(u, version)); } + X_AD_Package_Imp firstImp = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, "Name=? AND PK_Version=? AND PK_Status=?", null) + .setParameters(getName(), "0.0.0", "Completed successfully") + .setClient_ID() + .first(); + if (firstImp == null) { + Trx trx = Trx.get(Trx.createTrxName(), true); + try { + Env.getCtx().put("#AD_Client_ID", 0); + + firstImp = new X_AD_Package_Imp(Env.getCtx(), 0, trx.getTrxName()); + firstImp.setName(getName()); + firstImp.setPK_Version("0.0.0"); + firstImp.setPK_Status("Completed successfully"); + firstImp.setProcessed(true); + firstImp.saveEx(); + + if (list.size() > 0 && installedVersions.size() > 0) { + List newList = new ArrayList(); + for(TwoPackEntry entry : list) { + boolean patch = false; + for(String v : installedVersions) { + Version v1 = new Version(entry.version); + Version v2 = new Version(v); + int c = v2.compareTo(v1); + if (c == 0) { + patch = false; + break; + } else if (c > 0) { + patch = true; + } + } + if (patch) { + System.out.println("Patch Meta Data for " + getName() + " " + entry.version + " ..."); + + X_AD_Package_Imp pi = new X_AD_Package_Imp(Env.getCtx(), 0, trx.getTrxName()); + pi.setName(getName()); + pi.setPK_Version(entry.version); + pi.setPK_Status("Completed successfully"); + pi.setProcessed(true); + pi.saveEx(); + + } else { + newList.add(entry); + } + } + list = newList; + } + trx.commit(true); + } catch (Exception e) { + trx.rollback(); + logger.log(Level.SEVERE, e.getLocalizedMessage(), e); + } finally { + trx.close(); + } + } Collections.sort(list, new Comparator() { @Override public int compare(TwoPackEntry o1, TwoPackEntry o2) { @@ -163,31 +190,33 @@ public class Incremental2PackActivator implements BundleActivator, ServiceTracke }); for(TwoPackEntry entry : list) { - if (!packIn(entry.url)) { - // stop processing further packages if one fail - break; + if (!installedVersions.contains(entry.version)) { + if (!packIn(entry.url)) { + // stop processing further packages if one fail + break; + } } } } private String extractVersionString(URL u) { String p = u.getPath(); - int upos=p.lastIndexOf("_"); + int upos=p.lastIndexOf("2Pack_"); int dpos=p.lastIndexOf("."); - String v = p.substring(upos+1, dpos); + String v = p.substring(upos+"2Pack_".length(), dpos); return v; } protected boolean packIn(URL packout) { if (packout != null && service != null) { String path = packout.getPath(); - String suffix = path.substring(path.lastIndexOf("_")); + String suffix = "_"+path.substring(path.lastIndexOf("2Pack_")); System.out.println("Installing " + getName() + " " + path + " ..."); FileOutputStream zipstream = null; try { // copy the resource to a temporary file to process it with 2pack InputStream stream = packout.openStream(); - File zipfile = File.createTempFile(getName(), suffix); + File zipfile = File.createTempFile(getName()+"_", suffix); zipstream = new FileOutputStream(zipfile); byte[] buffer = new byte[1024]; int read; diff --git a/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Version2PackActivator.java b/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Version2PackActivator.java new file mode 100644 index 0000000000..1544d317a3 --- /dev/null +++ b/org.adempiere.plugin.utils/src/org/adempiere/plugin/utils/Version2PackActivator.java @@ -0,0 +1,303 @@ +/****************************************************************************** + * Copyright (C) 2013 Heng Sin Low * + * Copyright (C) 2013 Trek Global * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.adempiere.plugin.utils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; + +import org.adempiere.base.IDictionaryService; +import org.adempiere.util.ServerContext; +import org.compiere.Adempiere; +import org.compiere.model.Query; +import org.compiere.model.ServerStateChangeEvent; +import org.compiere.model.ServerStateChangeListener; +import org.compiere.model.X_AD_Package_Imp; +import org.compiere.util.CLogger; +import org.compiere.util.Env; +import org.compiere.util.Util; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * + * @author hengsin + * + */ +public class Version2PackActivator implements BundleActivator, ServiceTrackerCustomizer { + + protected final static CLogger logger = CLogger.getCLogger(Version2PackActivator.class.getName()); + private BundleContext context; + private ServiceTracker serviceTracker; + private IDictionaryService service; + + @Override + public void start(BundleContext context) throws Exception { + this.context = context; + if (logger.isLoggable(Level.INFO)) logger.info(getName() + " " + getVersion() + " starting..."); + serviceTracker = new ServiceTracker(context, IDictionaryService.class.getName(), this); + serviceTracker.open(); + start(); + if (logger.isLoggable(Level.INFO)) logger.info(getName() + " " + getVersion() + " ready."); + } + + public String getName() { + return context.getBundle().getSymbolicName(); + } + + public String getVersion() { + String version = (String) context.getBundle().getHeaders().get("Bundle-Version"); + // e.g. 1.0.0.qualifier, check only the "1.0.0" part + String[] components = version.split("[.]"); + StringBuilder versionBuilder = new StringBuilder(components[0]); + if (components.length >= 3) { + versionBuilder.append(".").append(components[1]).append(".").append(components[2]); + } else if (components.length == 2) { + versionBuilder.append(".").append(components[1]).append(".0"); + } else { + versionBuilder.append(".0.0"); + } + return versionBuilder.toString(); + } + + public String getDescription() { + return getName(); + } + + private void installPackage() { + // e.g. 1.0.0.qualifier, check only the "1.0.0" part + String bundleVersionPart = getVersion(); + String installedVersionPart = null; + String where = "Name=? AND PK_Status = 'Completed successfully'"; + Query q = new Query(Env.getCtx(), X_AD_Package_Imp.Table_Name, + where.toString(), null); + q.setParameters(new Object[] { getName() }); + List pkgs = q.list(); + if (pkgs != null && !pkgs.isEmpty()) { + for(X_AD_Package_Imp pkg : pkgs) { + String packageVersionPart = pkg.getPK_Version(); + String[] part = packageVersionPart.split("[.]"); + if (installedVersionPart == null) { + if (part.length > 3) { + installedVersionPart = part[0]+"."+part[1]+"."+part[2]; + } else { + installedVersionPart = packageVersionPart; + } + } else { + Version installedVersion = new Version(installedVersionPart); + if (part.length > 3) { + packageVersionPart = part[0]+"."+part[1]+"."+part[2]; + } + Version packageVersion = new Version(packageVersionPart); + if (packageVersion.compareTo(installedVersion) > 0) { + installedVersionPart = packageVersionPart; + } + } + } + } + packIn(installedVersionPart, bundleVersionPart); + afterPackIn(); + } + + private static class TwoPackEntry { + private URL url; + private String version; + private TwoPackEntry(URL url, String version) { + this.url=url; + this.version = version; + } + } + + protected void packIn(String installedVersionPart, String bundleVersionPart) { + List list = new ArrayList(); + + //2Pack_1.0.0.zip, 2Pack_1.0.1.zip, etc + Enumeration urls = context.getBundle().findEntries("/META-INF", "2Pack_*.zip", false); + Version bundleVersion = new Version(bundleVersionPart); + if (!Util.isEmpty(installedVersionPart)) { + Version installedVersion = new Version(installedVersionPart); + while(urls.hasMoreElements()) { + URL u = urls.nextElement(); + String version = extractVersionString(u); + Version packageVersion = new Version(version); + if (packageVersion.compareTo(bundleVersion) <= 0 && packageVersion.compareTo(installedVersion) > 0) + list.add(new TwoPackEntry(u, version)); + } + } else { + while(urls.hasMoreElements()) { + URL u = urls.nextElement(); + String version = extractVersionString(u); + Version packageVersion = new Version(version); + if (packageVersion.compareTo(bundleVersion) <= 0) + list.add(new TwoPackEntry(u, version)); + } + } + + Collections.sort(list, new Comparator() { + @Override + public int compare(TwoPackEntry o1, TwoPackEntry o2) { + return new Version(o1.version).compareTo(new Version(o2.version)); + } + }); + + for(TwoPackEntry entry : list) { + if (!packIn(entry.url)) { + // stop processing further packages if one fail + break; + } + } + } + + private String extractVersionString(URL u) { + String p = u.getPath(); + int upos=p.lastIndexOf("_"); + int dpos=p.lastIndexOf("."); + String v = p.substring(upos+1, dpos); + return v; + } + + protected boolean packIn(URL packout) { + if (packout != null && service != null) { + String path = packout.getPath(); + String suffix = "_"+path.substring(path.lastIndexOf("2Pack_")); + System.out.println("Installing " + getName() + " " + path + " ..."); + FileOutputStream zipstream = null; + try { + // copy the resource to a temporary file to process it with 2pack + InputStream stream = packout.openStream(); + File zipfile = File.createTempFile(getName()+"_", suffix); + zipstream = new FileOutputStream(zipfile); + byte[] buffer = new byte[1024]; + int read; + while((read = stream.read(buffer)) != -1){ + zipstream.write(buffer, 0, read); + } + // call 2pack + service.merge(context, zipfile); + } catch (Throwable e) { + logger.log(Level.SEVERE, "Pack in failed.", e); + return false; + } finally{ + if (zipstream != null) { + try { + zipstream.close(); + } catch (Exception e2) {} + } + } + System.out.println(getName() + " " + packout.getPath() + " installed"); + } + return true; + } + + protected BundleContext getContext() { + return context; + } + + protected void setContext(BundleContext context) { + this.context = context; + } + + @Override + public void stop(BundleContext context) throws Exception { + stop(); + serviceTracker.close(); + this.context = null; + if (logger.isLoggable(Level.INFO)) logger.info(context.getBundle().getSymbolicName() + " " + + context.getBundle().getHeaders().get("Bundle-Version") + + " stopped."); + } + + protected void afterPackIn() { + }; + + /** + * call when bundle have been started ( after this.context have been set ) + */ + protected void start() { + }; + + /** + * call when bundle is stop ( before this.context is set to null ) + */ + protected void stop() { + } + + @Override + public IDictionaryService addingService( + ServiceReference reference) { + service = context.getService(reference); + if (Adempiere.getThreadPoolExecutor() != null) { + Adempiere.getThreadPoolExecutor().execute(new Runnable() { + @Override + public void run() { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(Version2PackActivator.class.getClassLoader()); + setupPackInContext(); + installPackage(); + } finally { + ServerContext.dispose(); + service = null; + Thread.currentThread().setContextClassLoader(cl); + } + } + }); + } else { + Adempiere.addServerStateChangeListener(new ServerStateChangeListener() { + @Override + public void stateChange(ServerStateChangeEvent event) { + if (event.getEventType() == ServerStateChangeEvent.SERVER_START && service != null) { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(Version2PackActivator.class.getClassLoader()); + setupPackInContext(); + installPackage(); + } finally { + ServerContext.dispose(); + service = null; + Thread.currentThread().setContextClassLoader(cl); + } + } + } + }); + } + return null; + } + + @Override + public void modifiedService(ServiceReference reference, + IDictionaryService service) { + } + + @Override + public void removedService(ServiceReference reference, + IDictionaryService service) { + } + + protected void setupPackInContext() { + Properties serverContext = new Properties(); + ServerContext.setCurrentInstance(serverContext); + }; +}