/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package com.liferay.portal.split.packages.test; import aQute.bnd.header.OSGiHeader; import aQute.bnd.header.Parameters; import com.liferay.arquillian.extension.junit.bridge.junit.Arquillian; import com.liferay.portal.kernel.util.HashUtil; import com.liferay.portal.kernel.util.SetUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.module.framework.ModuleFrameworkUtilAdapter; import java.io.IOException; import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; /** * @author Tom Wang * @author Shuyang Zhou */ @RunWith(Arquillian.class) public class SplitPackagesTest { @Test public void testSplitPackages() throws IOException { Map<ExportPackage, Set<String>> allowedSplitPackageNames = _getAllowedSplitPackageNames(); Map<Bundle, Set<ExportPackage>> exportPackagesMap = new HashMap<>(); Bundle systemBundle = (Bundle)ModuleFrameworkUtilAdapter.getFramework(); BundleContext bundleContext = systemBundle.getBundleContext(); for (Bundle bundle : bundleContext.getBundles()) { Set<ExportPackage> exportPackages = _getExportPackages(bundle); if (exportPackages == null) { continue; } for (Map.Entry<Bundle, Set<ExportPackage>> entry : exportPackagesMap.entrySet()) { Set<ExportPackage> duplicateExportPackages = new HashSet<>( entry.getValue()); duplicateExportPackages.retainAll(exportPackages); _processSplitPackages( bundle, entry.getKey(), duplicateExportPackages, allowedSplitPackageNames); } exportPackagesMap.put(bundle, exportPackages); } } private Map<ExportPackage, Set<String>> _getAllowedSplitPackageNames() throws IOException { Map<ExportPackage, Set<String>> allowedSplitPackageNames = new HashMap<>(); for (String line : StringUtil.splitLines( StringUtil.read( SplitPackagesTest.class.getResourceAsStream( "dependencies/allowed_split_packages.txt")))) { String[] lineParts = StringUtil.split(line, StringPool.SEMICOLON); allowedSplitPackageNames.put( new ExportPackage(lineParts[0], lineParts[1]), SetUtil.fromArray(StringUtil.split(lineParts[2]))); } return allowedSplitPackageNames; } private Set<ExportPackage> _getExportPackages(Bundle bundle) { Dictionary<String, String> headers = bundle.getHeaders(); String exportPackageName = headers.get(Constants.EXPORT_PACKAGE); if (exportPackageName == null) { return null; } Set<ExportPackage> exportPackages = new HashSet<>(); Parameters parameters = OSGiHeader.parseHeader(exportPackageName); Map<String, ? extends Map<String, String>> exportPackagesMap = parameters.asMapMap(); for (Map.Entry<String, ? extends Map<String, String>> entry : exportPackagesMap.entrySet()) { Map<String, String> attributes = entry.getValue(); exportPackages.add( new ExportPackage( entry.getKey(), attributes.get(Constants.VERSION_ATTRIBUTE))); } return exportPackages; } private void _processSplitPackages( Bundle currentBundle, Bundle previousBundle, Collection<ExportPackage> duplicateExportPackages, Map<ExportPackage, Set<String>> allowedSplitPackageNames) { for (ExportPackage duplicateExportPackage : duplicateExportPackages) { boolean hasSplitPackages = false; Set<String> symbolicNames = allowedSplitPackageNames.get( duplicateExportPackage); if ((symbolicNames == null) || !symbolicNames.contains(currentBundle.getSymbolicName()) || !symbolicNames.contains(previousBundle.getSymbolicName())) { hasSplitPackages = true; } Assert.assertFalse( "Detected split packages " + duplicateExportPackage + " in " + previousBundle + " and " + currentBundle, hasSplitPackages); } } private class ExportPackage { @Override public boolean equals(Object obj) { ExportPackage exportPackage = (ExportPackage)obj; if (Objects.equals(_name, exportPackage._name) && Objects.equals(_version, exportPackage._version)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _name); return HashUtil.hash(hashCode, _version); } @Override public String toString() { StringBundler sb = new StringBundler(5); sb.append("{name="); sb.append(_name); sb.append(", version="); sb.append(_version); sb.append("}"); return sb.toString(); } private ExportPackage(String name, String version) { _name = name; _version = version; } private final String _name; private final String _version; } }