/* * The MIT License (MIT) * * Copyright (c) 2015 Lachlan Dowding * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package permafrost.tundra.server; import com.wm.app.b2b.server.Manifest; import com.wm.app.b2b.server.Package; import com.wm.app.b2b.server.PackageManager; import com.wm.app.b2b.server.PackageState; import com.wm.app.b2b.server.PackageStore; import com.wm.app.b2b.server.ServerAPI; import com.wm.app.b2b.server.ns.NSDependencyManager; import com.wm.app.b2b.server.ns.Namespace; 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.DependencyManager; import com.wm.lang.ns.NSNode; import com.wm.lang.ns.NSService; import permafrost.tundra.data.IDataMap; import permafrost.tundra.io.FileHelper; import permafrost.tundra.lang.BooleanHelper; import permafrost.tundra.lang.IterableEnumeration; import permafrost.tundra.math.IntegerHelper; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; /** * A collection of convenience methods for working with webMethods Integration Server packages. */ public final class PackageHelper { /** * Disallow instantiation of this class. */ private PackageHelper() {} /** * Returns true if a package with the given name exists on this Integration Server. * * @param packageName The name of the package to check existence of. * @return True if a package with the given name exists. */ public static boolean exists(String packageName) { return getPackage(packageName) != null; } /** * Returns the package with the given name if it exists on this Integration Server. * * @param packageName The name of the package. * @return The package with the given name, or null if no package with the given name exists. */ public static Package getPackage(String packageName) { if (packageName == null) return null; return PackageManager.getPackage(packageName); } /** * Returns the invoking package. * * @return The invoking package. */ public static Package self() { NSService service = ServiceHelper.self(); if (service != null) { return getPackage(service.getPackage().getName()); } return null; } /** * Returns true if the package with the given name is enabled on this Integration Server. * * @param packageName The name of the package. * @return True if the package with the given name is enabled. */ public static boolean isEnabled(String packageName) { Package pkg = getPackage(packageName); return pkg != null && pkg.isEnabled(); } /** * Returns a list of packages on this Integration Server. * * @return A list of packages on this Integration Server. */ public static Package[] list() { return list(false); } /** * Returns a list of packages on this Integration Server. * * @param enabledOnly If true, only returns enabled packages. * @return A list of packages on this Integration Server. */ public static Package[] list(boolean enabledOnly) { Package[] packages = PackageManager.getAllPackages(); SortedSet<Package> packageSet = new TreeSet<Package>(PackageNameComparator.getInstance()); if (packages != null) { for (Package item : packages) { if (item != null && (!enabledOnly || item.isEnabled())) packageSet.add(item); } } return packageSet.toArray(new Package[packageSet.size()]); } /** * Reloads the package with the given name. * * @param packageName The name of the package to be reloaded. */ public static void reload(String packageName) { PackageManager.loadPackage(packageName, true); } /** * Returns the list of elements referenced by given the services in the given package. * * @param packageName The package to get references for. * @return The list of references for the given package. */ public static IData getReferences(String packageName) { return getReferences(getPackage(packageName)); } /** * Returns the list of elements referenced by given the services in the given package. * * @param pkg The package to get references for. * @return The list of references for the given package. */ public static IData getReferences(Package pkg) { String[] services = toStringArray(IterableEnumeration.of(pkg.getLoaded())); DependencyManager manager = NSDependencyManager.current(); Namespace namespace = Namespace.current(); SortedSet<String> packages = new TreeSet<String>(); SortedMap<String, IData> resolved = new TreeMap<String, IData>(); SortedSet<String> unresolved = new TreeSet<String>(); for (String service : services) { if (service != null) { NSNode node = namespace.getNode(service); IData results = manager.getReferenced(node, null); if (results != null) { IDataCursor resultsCursor = results.getCursor(); IData[] references = IDataUtil.getIDataArray(resultsCursor, "reference"); resultsCursor.destroy(); if (references != null) { for (IData reference : references) { if (reference != null) { IDataCursor referenceCursor = reference.getCursor(); String name = IDataUtil.getString(referenceCursor, "name"); String status = IDataUtil.getString(referenceCursor, "status"); referenceCursor.destroy(); if (status.equals("unresolved")) { unresolved.add(name); } else { String[] parts = name.split("\\/"); if (parts.length > 1) { if (!pkg.getName().equals(parts[0])) { IData result = IDataFactory.create(); IDataCursor resultCursor = result.getCursor(); IDataUtil.put(resultCursor, "package", parts[0]); IDataUtil.put(resultCursor, "node", parts[1]); resultCursor.destroy(); packages.add(parts[0]); resolved.put(name, result); } } } } } } } } } IData output = IDataFactory.create(); IDataCursor cursor = output.getCursor(); IDataUtil.put(cursor, "packages", packages.toArray(new String[packages.size()])); IDataUtil.put(cursor, "packages.length", IntegerHelper.emit(packages.size())); IDataUtil.put(cursor, "nodes", resolved.values().toArray(new IData[resolved.size()])); IDataUtil.put(cursor, "nodes.length", IntegerHelper.emit(resolved.size())); IDataUtil.put(cursor, "unresolved", unresolved.toArray(new String[unresolved.size()])); IDataUtil.put(cursor, "unresolved.length", IntegerHelper.emit(unresolved.size())); cursor.destroy(); return output; } /** * Returns the list of services that are dependent on the services in the given package. * * @param packageName The package to get dependents for. * @return The list of dependents for the given package. */ private static IData getDependents(String packageName) { return getDependents(getPackage(packageName)); } /** * Returns the list of services that are dependent on the services in the given package. * * @param pkg The package to get dependents for. * @return The list of dependents for the given package. */ private static IData getDependents(Package pkg) { String[] services = toStringArray(IterableEnumeration.of(pkg.getLoaded())); DependencyManager manager = NSDependencyManager.current(); Namespace namespace = Namespace.current(); SortedSet<String> packages = new TreeSet<String>(); SortedMap<String, IData> nodes = new TreeMap<String, IData>(); for (String service : services) { if (service != null) { NSNode node = namespace.getNode(service); if (node != null) { IData results = manager.getDependent(node, null); if (results != null) { IDataCursor resultsCursor = results.getCursor(); IData[] referencedBy = IDataUtil.getIDataArray(resultsCursor, "referencedBy"); resultsCursor.destroy(); if (referencedBy != null) { for (IData dependent : referencedBy) { if (dependent != null) { IDataCursor dependentCursor = dependent.getCursor(); String name = IDataUtil.getString(dependentCursor, "name"); dependentCursor.destroy(); String[] parts = name.split("\\/"); if (parts.length > 1) { if (!pkg.getName().equals(parts[0])) { IData result = IDataFactory.create(); IDataCursor resultCursor = result.getCursor(); IDataUtil.put(resultCursor, "package", parts[0]); IDataUtil.put(resultCursor, "node", parts[1]); resultCursor.destroy(); packages.add(parts[0]); nodes.put(name, result); } } } } } } } } } IData output = IDataFactory.create(); IDataCursor cursor = output.getCursor(); IDataUtil.put(cursor, "packages", packages.toArray(new String[packages.size()])); IDataUtil.put(cursor, "packages.length", IntegerHelper.emit(packages.size())); IDataUtil.put(cursor, "nodes", nodes.values().toArray(new IData[nodes.size()])); IDataUtil.put(cursor, "nodes.length", IntegerHelper.emit(nodes.size())); cursor.destroy(); return output; } /** * Converts the given Package to an IData document. * * @param pkg The package to be converted. * @return An IData representation of the given package. */ public static IData toIData(Package pkg) { if (pkg == null) return null; IDataMap map = new IDataMap(); map.put("name", pkg.getName()); map.merge(toIData(pkg.getManifest())); IDataMap services = IDataMap.of((IData)map.get("services")); services.merge(toIData(pkg.getState())); map.put("services", services); IDataMap directories = new IDataMap(); directories.merge(toIData(pkg.getStore())); directories.put("config", FileHelper.normalize(ServerAPI.getPackageConfigDir(pkg.getName()))); map.put("directories", directories); map.put("references", getReferences(pkg)); return map; } /** * Converts the given list of packages to an IData[]. * * @param packages The list of packages to convert. * @return The IData[] representation of the packages. */ public static IData[] toIDataArray(Package... packages) { if (packages == null) return new IData[0]; IData[] output = new IData[packages.length]; for (int i = 0; i < packages.length; i++) { output[i] = toIData(packages[i]); } return output; } /** * Converts an Package[] to a String[] by calling getName on each package in the list. * * @param packages The list of packages to convert. * @return The String[] representation of the list. */ private static String[] toStringArray(Package... packages) { if (packages == null) return new String[0]; List<String> output = new ArrayList<String>(packages.length); for (Package item : packages) { if (item != null) output.add(item.getName()); } return output.toArray(new String[output.size()]); } /** * Converts an Iterable object to a String[] by calling toString on each object returned by the iterator. * * @param iterable The object to convert. * @return The String[] representation of the object. */ private static String[] toStringArray(Iterable iterable) { if (iterable == null) return new String[0]; List<String> output = new ArrayList<String>(); for (Object item : iterable) { output.add(item == null ? null : item.toString()); } return output.toArray(new String[output.size()]); } /** * Converts the given Manifest object to an IData document representation. * * @param manifest The object to be converted. * @return An IData representation of the object. */ @SuppressWarnings("unchecked") private static IData toIData(Manifest manifest) { if (manifest == null) return null; IDataMap map = new IDataMap(); map.put("version", manifest.getVersion()); map.put("enabled?", BooleanHelper.emit(manifest.isEnabled())); map.put("system?", BooleanHelper.emit(manifest.isSystemPkg())); IData[] packageDependencies = toIDataArray(manifest.getRequires()); map.put("dependencies", packageDependencies); map.put("dependencies.length", "" + packageDependencies.length); IDataMap services = new IDataMap(); String[] startupServices = toStringArray(manifest.getStartupServices()); services.put("startup", startupServices); services.put("startup.length", "" + startupServices.length); String[] shutdownServices = toStringArray(manifest.getShutdownServices()); services.put("shutdown", shutdownServices); services.put("shutdown.length", "" + shutdownServices.length); String[] replicationServices = toStringArray(manifest.getReplicationServices()); services.put("replication", replicationServices); services.put("replication.length", "" + replicationServices.length); map.put("services", services); return map; } /** * Convert the given list of package dependencies to an IData[]. * * @param packageDependencies The object to convert. * @return The IData[] representation of the object. */ private static IData[] toIDataArray(Iterable<Manifest.Requires> packageDependencies) { if (packageDependencies == null) return new IData[0]; List<IData> output = new ArrayList<IData>(); for (Manifest.Requires packageDependency : packageDependencies) { IDataMap map = new IDataMap(); map.put("package", packageDependency.getPackage()); map.put("version", packageDependency.getVersion()); output.add(map); } return output.toArray(new IData[output.size()]); } /** * Converts the given PackageState object to an IData document representation. * * @param packageState The object to be converted. * @return An IData representation of the object. */ private static IData toIData(PackageState packageState) { if (packageState == null) return null; IDataMap map = new IDataMap(); String[] loadedServices = toStringArray(IterableEnumeration.of(packageState.getLoaded())); map.put("loaded", loadedServices); map.put("loaded.length", IntegerHelper.emit(loadedServices.length)); return map; } /** * Converts the given PackageStore object to an IData document representation. * * @param packageStore The object to be converted. * @return An IData representation of the object. */ private static IData toIData(PackageStore packageStore) { if (packageStore == null) return null; IDataMap map = new IDataMap(); map.put("root", FileHelper.normalize(packageStore.getPackageDir())); map.put("ns", FileHelper.normalize(packageStore.getNSDir())); map.put("pub", FileHelper.normalize(packageStore.getPubDir())); map.put("template", FileHelper.normalize(packageStore.getTemplateDir())); map.put("web", FileHelper.normalize(packageStore.getWebDir())); return map; } }