/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.workbench.common.services.backend.builder.core;
import java.net.URLClassLoader;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.guvnor.common.services.backend.cache.LRUCache;
import org.kie.api.builder.KieModule;
import org.kie.scanner.KieModuleMetaData;
import org.kie.workbench.common.services.backend.builder.service.BuildInfoService;
import org.kie.workbench.common.services.shared.project.KieProject;
@ApplicationScoped
@Named("LRUProjectDependenciesClassLoaderCache")
public class LRUProjectDependenciesClassLoaderCache extends LRUCache<KieProject, ClassLoader> {
private BuildInfoService buildInfoService;
public LRUProjectDependenciesClassLoaderCache( ) {
}
@Inject
public LRUProjectDependenciesClassLoaderCache( BuildInfoService buildInfoService ) {
this.buildInfoService = buildInfoService;
}
protected void setBuildInfoService( final BuildInfoService buildInfoService ) {
this.buildInfoService = buildInfoService;
}
public synchronized ClassLoader assertDependenciesClassLoader(final KieProject project) {
ClassLoader classLoader = getEntry(project);
if (classLoader == null) {
classLoader = buildClassLoader(project);
setEntry(project,
classLoader);
}
return classLoader;
}
public synchronized void setDependenciesClassLoader(final KieProject project,
ClassLoader classLoader) {
setEntry(project,
classLoader);
}
private ClassLoader buildClassLoader(final KieProject project) {
final KieModule module = buildInfoService.getBuildInfo(project).getKieModuleIgnoringErrors();
return buildClassLoader(project,
KieModuleMetaData.Factory.newKieModuleMetaData(module));
}
/**
* This method and the subsequent caching was added for performance reasons, since the dependencies calculation and
* project class loader calculation tends to be time consuming when we manage project with transitives dependencies.
* Since the project ClassLoader may change with ever incremental build it's better to store in the cache the
* ClassLoader part that has the project dependencies. And the project ClassLoader can be easily calculated using
* this ClassLoader as parent. Since current project classes are quickly calculated on each incremental build, etc.
*/
public static ClassLoader buildClassLoader(final KieProject project,
final KieModuleMetaData kieModuleMetaData) {
//By construction the parent class loader for the KieModuleMetadata.getClassLoader() is an URLClass loader
//that has the project dependencies. So this implementation relies on this. BUT can easily be changed to
//calculate this URL class loader given that we have the pom.xml and we can use maven libraries classes
//to calculate project maven dependencies. This is basically what the KieModuleMetaData already does. The
//optimization was added to avoid the maven transitive calculation on complex projects.
final ClassLoader classLoader = kieModuleMetaData.getClassLoader().getParent();
if (classLoader instanceof URLClassLoader) {
return classLoader;
} else {
//this case should never happen. But if ProjectClassLoader calculation for KieModuleMetadata changes at
//the error will be notified for implementation review.
throw new RuntimeException("It was not posible to calculate project dependencies class loader for project: "
+ project.getKModuleXMLPath());
}
}
}