package org.jboss.windup.config.metadata;
import org.jboss.windup.config.RuleProvider;
import org.jboss.windup.config.loader.RuleLoader;
import org.jboss.windup.config.loader.RuleLoaderContext;
import org.jboss.windup.util.PathUtil;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
*/
@Singleton
public class RuleProviderRegistryCacheImpl implements RuleProviderRegistryCache
{
private static final Logger LOG = Logger.getLogger(RuleProviderRegistryCache.class.getSimpleName());
private static final long MAX_CACHE_AGE = 1000L * 60L * 1L;
/**
* This value is a hack to allow us to only print a load error to the console once, even
* if we are called multiple times.
*
* Each incident will still be logged to the detailed log file.
*/
private static boolean loadErrorPrinted = false;
@Inject
private RuleLoader ruleLoader;
private Set<Path> userRulesPaths = new LinkedHashSet<>();
private List<TechnologyReferenceTransformer> cachedTransformers;
private RuleProviderRegistry cachedRegistry;
private long cacheRefreshTime;
@Override
public void addUserRulesPath(Path path)
{
this.cachedRegistry = null;
this.cachedTransformers = null;
userRulesPaths.add(path);
}
@Override
public Set<String> getAvailableTags()
{
Set<String> tags = new HashSet<>();
RuleProviderRegistry registry = getRuleProviderRegistry();
if (registry == null)
return Collections.emptySet();
for (RuleProvider provider : registry.getProviders())
{
tags.addAll(provider.getMetadata().getTags());
}
return tags;
}
@Override
public Set<String> getAvailableSourceTechnologies()
{
Set<TechnologyReference> sourceOptions = new HashSet<>();
RuleProviderRegistry registry = getRuleProviderRegistry();
if (registry == null)
return Collections.emptySet();
for (RuleProvider provider : registry.getProviders())
{
for (TechnologyReference technologyReference : provider.getMetadata().getSourceTechnologies())
{
sourceOptions.add(technologyReference);
}
}
addTransformers(sourceOptions);
return sourceOptions.stream().map(TechnologyReference::getId).collect(Collectors.toSet());
}
@Override
public Set<String> getAvailableTargetTechnologies()
{
Set<TechnologyReference> targetOptions = new HashSet<>();
RuleProviderRegistry registry = getRuleProviderRegistry();
if (registry == null)
return Collections.emptySet();
for (RuleProvider provider : registry.getProviders())
{
for (TechnologyReference technologyReference : provider.getMetadata().getTargetTechnologies())
{
targetOptions.add(technologyReference);
}
}
addTransformers(targetOptions);
return targetOptions.stream().map(TechnologyReference::getId).collect(Collectors.toSet());
}
private void addTransformers(Set<TechnologyReference> techs)
{
techs.addAll(getTechnologyTransformers()
.stream()
// Only include it if the target of the transformation will match one of the items
// already in the list.
.filter(transformer -> {
for (TechnologyReference originalTech : techs)
{
if (originalTech.matches(transformer.getTarget()))
{
return true;
}
}
return false;
})
.map(TechnologyReferenceTransformer::getOriginal)
.collect(Collectors.toList()));
}
@Override
public RuleProviderRegistry getRuleProviderRegistry()
{
if (cacheValid())
{
return cachedRegistry;
}
else
{
this.cachedRegistry = null;
try
{
Set<Path> defaultRulePaths = new HashSet<>();
defaultRulePaths.add(PathUtil.getWindupRulesDir());
defaultRulePaths.add(PathUtil.getUserRulesDir());
defaultRulePaths.addAll(this.userRulesPaths);
RuleLoaderContext ruleLoaderContext = new RuleLoaderContext(defaultRulePaths, null);
getRuleProviderRegistry(ruleLoaderContext);
}
catch (Exception e)
{
if (!loadErrorPrinted)
{
System.err.println("Failed to load rule information due to: " + e.getMessage());
loadErrorPrinted = true;
}
LOG.log(Level.WARNING, "Failed to load rule information due to: " + e.getMessage(), e);
}
return cachedRegistry;
}
}
@Override
public RuleProviderRegistry getRuleProviderRegistry(RuleLoaderContext ruleLoaderContext)
{
initCaches(ruleLoaderContext);
return this.cachedRegistry;
}
private List<TechnologyReferenceTransformer> getTechnologyTransformers()
{
return this.cachedTransformers;
}
private void initCaches(RuleLoaderContext ruleLoaderContext)
{
this.cachedRegistry = ruleLoader.loadConfiguration(ruleLoaderContext);
this.cachedTransformers = TechnologyReferenceTransformer.getTransformers(ruleLoaderContext);
this.cacheRefreshTime = System.currentTimeMillis();
}
private boolean cacheValid()
{
if (cachedRegistry == null)
return false;
long cacheAge = System.currentTimeMillis() - this.cacheRefreshTime;
return cacheAge < MAX_CACHE_AGE;
}
}