package permafrost.tundra.server.invoke;

import com.wm.app.b2b.server.BaseService;
import com.wm.app.b2b.server.Service;
import com.wm.app.b2b.server.invoke.ServiceStatus;
import com.wm.app.b2b.server.Package;
import com.wm.app.b2b.server.PackageManager;
import com.wm.data.IData;
import com.wm.data.IDataCursor;
import com.wm.data.IDataFactory;
import com.wm.data.IDataUtil;
import com.wm.lang.ns.NSName;
import com.wm.util.ServerException;
import permafrost.tundra.lang.IterableEnumeration;
import java.util.Iterator;
import java.util.regex.Pattern;

/**
 * Runs any uninstall services found in a package before it is uninstalled.
 */
public class PackageUninstallProcessor extends BasicInvokeChainProcessor {
    /**
     * The service used to uninstall packages, which before invocation is when any detected package uninstall services are invoked by this processor.
     */
    public static final String INTEGRATION_SERVER_PACKAGE_UNINSTALL_SERVICE = "wm.server.packages:packageDelete";
    /**
     * The default package uninstall service regular expression pattern.
     */
    public static final Pattern DEFAULT_PACKAGE_UNINSTALL_SERVICE_PATTERN = Pattern.compile("^([^\\.]+\\.)*support(\\.[^\\.]+)*:uninstall");
    /**
     * A regular expression pattern used to detect package uninstall services.
     */
    protected Pattern pattern;

    /**
     * Constructs a new PackageUninstallProcessor using the default package uninstall service pattern.
     */
    public PackageUninstallProcessor() {
        this(DEFAULT_PACKAGE_UNINSTALL_SERVICE_PATTERN);
    }

    /**
     * Constructs a new PackageUninstallProcessor using the given package uninstall service pattern.
     *
     * @param pattern A regular expression pattern used to find package uninstall services to be invoked on uninstall.
     */
    public PackageUninstallProcessor(String pattern) {
        this(pattern == null ? null : Pattern.compile(pattern));
    }

    /**
     * Constructs a new PackageUninstallProcessor using the given package uninstall service pattern.
     *
     * @param pattern A regular expression pattern used to find package uninstall services to be invoked on uninstall.
     */
    public PackageUninstallProcessor(Pattern pattern) {
        this.pattern = pattern;
    }

    /**
     * Called prior to the service invocation. Subclasses should override this method to perform work prior to an
     * invocation.
     *
     * @param iterator          Invocation chain.
     * @param baseService       The invoked service.
     * @param pipeline          The input pipeline for the service.
     * @param serviceStatus     The status of the service invocation.
     * @throws ServerException  If the service invocation fails.
     */
    @Override
    protected void processBefore(Iterator iterator, BaseService baseService, IData pipeline, ServiceStatus serviceStatus) throws ServerException {
        if (pipeline != null && baseService != null && INTEGRATION_SERVER_PACKAGE_UNINSTALL_SERVICE.equals(baseService.getNSName().getFullName())) {
            IDataCursor cursor = pipeline.getCursor();
            String packageName = IDataUtil.getString(cursor, "package");
            cursor.destroy();

            if (packageName != null) {
                Package pkg = PackageManager.getPackage(packageName);
                if (pkg != null) {
                    for (Object item : IterableEnumeration.of(pkg.getState().getLoaded())) {
                        if (item != null) {
                            String serviceName = item.toString();
                            if (pattern.matcher(serviceName).matches()) {
                                // invoke service
                                try {
                                    Service.doInvoke(NSName.create(serviceName), IDataFactory.create());
                                } catch(Exception ex) {
                                    // do nothing
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

@@ -682,13 +682,16 @@
 nds 
-Basic
+Abstract
 Invo
@@ -2297,132 +2297,112 @@
   * 
-Called prior to the service invocation. Subclasses should override this method to perform work prior to an%0A     * invocation
+Process the invocation chain; if invocation is a package uninstall, run package uninstall services prior
 .%0A  
@@ -2739,24 +2739,21 @@
 de%0A    p
-rotected
+ublic
  void pr
@@ -2761,14 +2761,8 @@
 cess
-Before
 (Ite
@@ -2888,51 +2888,8 @@
 if (
-pipeline != null && baseService != null && 
 INTE
@@ -3993,32 +3993,32 @@
 %7D%0A            %7D%0A
-
         %7D%0A    %7D%0A
@@ -4006,21 +4006,93 @@
  %7D%0A        %7D
+%0A%0A        super.process(iterator, baseService, pipeline, serviceStatus);
 %0A    %7D%0A%7D%0A

Change PackageUninstallProcessor to extend AbstractInvokeChainProcessor rather than BasicInvokeChainProcessor, and to reduce impact on service invocation performance by only performing one check per invocation to determine if it relates to a package uninstall