/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.container.internal;
import static org.apache.commons.lang3.builder.ToStringBuilder.reflectionToString;
import static org.apache.commons.lang3.builder.ToStringStyle.MULTI_LINE_STYLE;
import org.mule.runtime.container.api.MuleModule;
import org.mule.runtime.module.artifact.classloader.DefaultArtifactClassLoaderFilter;
import org.mule.runtime.module.artifact.classloader.ArtifactClassLoaderFilter;
import org.mule.runtime.module.artifact.classloader.ClassLoaderFilter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Creates a {@link ClassLoaderFilter} for the container filter what is exposed to Mule artifacts.
* <p/>
* Filter is constructed searching for {code}mule-module.properties{code} files in the classpath and then merging the
* corresponding packages and resources in a new filter.
*/
public class ContainerClassLoaderFilterFactory {
private static final String EMPTY_PACKAGE = "";
private static final char RESOURCE_SEPARATOR = '/';
public ClassLoaderFilter create(Set<String> bootPackages, List<MuleModule> muleModules) {
final Set<String> resources = getExportedResourcePaths(muleModules);
final Set<String> packages = getModuleExportedPackages(muleModules);
final ArtifactClassLoaderFilter artifactClassLoaderFilter = new DefaultArtifactClassLoaderFilter(packages, resources);
return new ContainerClassLoaderFilter(artifactClassLoaderFilter, bootPackages);
}
private Set<String> getExportedResourcePaths(List<MuleModule> muleModules) {
Set<String> resources = new HashSet<>();
for (MuleModule muleModule : muleModules) {
resources.addAll(muleModule.getExportedPaths());
}
return resources;
}
private Set<String> getModuleExportedPackages(List<MuleModule> muleModules) {
Set<String> packages = new HashSet<>();
for (MuleModule muleModule : muleModules) {
packages.addAll(muleModule.getExportedPackages());
}
return packages;
}
public static class ContainerClassLoaderFilter implements ClassLoaderFilter {
public static final String CLASS_PACKAGE_SPLIT_REGEX = "\\.";
public static final String RESOURCE_PACKAGE_SPLIT_REGEX = "/";
private final ClassLoaderFilter moduleClassLoaderFilter;
private final Set<String> bootPackages;
public ContainerClassLoaderFilter(ClassLoaderFilter moduleClassLoaderFilter, Set<String> bootPackages) {
this.moduleClassLoaderFilter = moduleClassLoaderFilter;
this.bootPackages = bootPackages;
}
@Override
public boolean exportsClass(String name) {
boolean exported = moduleClassLoaderFilter.exportsClass(name);
if (!exported) {
exported = isExportedBooPackage(name, CLASS_PACKAGE_SPLIT_REGEX);
}
return exported;
}
@Override
public boolean exportsResource(String name) {
boolean exported = moduleClassLoaderFilter.exportsResource(name);
if (!exported) {
final String resourceFolder = getResourceFolder(name);
exported = moduleClassLoaderFilter.exportsResource(resourceFolder);
if (!exported) {
exported = isExportedBooPackage(name, RESOURCE_PACKAGE_SPLIT_REGEX);
}
}
return exported;
}
private String getResourceFolder(String resourceName) {
String resourceFolder = "";
if (resourceName.length() > 0) {
resourceFolder = (resourceName.charAt(0) == RESOURCE_SEPARATOR) ? resourceName.substring(1) : resourceName;
resourceFolder = (resourceFolder.lastIndexOf(RESOURCE_SEPARATOR) < 0) ? EMPTY_PACKAGE
: resourceFolder.substring(0, resourceFolder.lastIndexOf(RESOURCE_SEPARATOR));
}
return resourceFolder;
}
private boolean isExportedBooPackage(String name, String splitRegex) {
boolean exported = false;
final String[] splitName = name.split(splitRegex);
final String[] packages = Arrays.copyOf(splitName, splitName.length - 1);
String candidatePackage = "";
for (String currentPackage : packages) {
if (candidatePackage.length() != 0) {
candidatePackage += ".";
}
candidatePackage += currentPackage;
if (bootPackages.contains(candidatePackage)) {
exported = true;
break;
}
}
return exported;
}
@Override
public String toString() {
return reflectionToString(this, MULTI_LINE_STYLE);
}
}
}