/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.hibernate.gradle.testing.database; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ivy.Ivy; import org.apache.ivy.core.cache.DefaultRepositoryCacheManager; import org.apache.ivy.core.cache.RepositoryCacheManager; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.report.ResolveReport; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.gradle.api.Project; import org.gradle.api.internal.artifacts.IvyService; import org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer; import org.gradle.api.internal.artifacts.configurations.ResolverProvider; import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency; import org.gradle.api.internal.artifacts.ivyservice.DefaultIvyService; import org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingIvyService; import org.gradle.api.internal.artifacts.ivyservice.IvyFactory; import org.gradle.api.internal.artifacts.ivyservice.SettingsConverter; import org.gradle.api.internal.artifacts.ivyservice.ShortcircuitEmptyConfigsIvyService; import org.gradle.api.internal.artifacts.repositories.InternalRepository; import org.gradle.api.internal.file.AbstractFileCollection; import org.gradle.invocation.DefaultGradle; import org.hibernate.gradle.util.BuildException; import org.hibernate.gradle.util.ResolutionException; /** * TODO : javadoc * * @author Steve Ebersole */ public class IvyXmlDependency extends DefaultSelfResolvingDependency { private final String name; public IvyXmlDependency(Project project, File ivyXmlFile) { super( new IvyXmlDependencyFileCollection( project, ivyXmlFile ) ); this.name = ivyXmlFile.getParentFile().getName() + '/' + ivyXmlFile.getName(); } @Override public String getName() { return name; } @Override public IvyXmlDependencyFileCollection getSource() { return (IvyXmlDependencyFileCollection) super.getSource(); } private static class IvyXmlDependencyFileCollection extends AbstractFileCollection { private final Project project; private final File ivyXmlFile; private Set<File> resolvedDependencyFiles; private IvyXmlDependencyFileCollection(Project project, File ivyXmlFile) { this.project = project; this.ivyXmlFile = ivyXmlFile; } public File getIvyXmlFile() { return ivyXmlFile; } @Override public String getDisplayName() { return ivyXmlFile.getAbsolutePath(); } public Set<File> getFiles() { if ( resolvedDependencyFiles == null ) { resolvedDependencyFiles = resolveDependencyFiles(); } return resolvedDependencyFiles; } private Set<File> resolveDependencyFiles() { DefaultIvyService ivyService = unwrap( ( (DefaultConfigurationContainer) project.getConfigurations() ).getIvyService() ); final ModuleDescriptor moduleDescriptor = resolveIvyXml( ivyService ); DefaultRepositoryCacheManager repositoryCacheManager = null; final ResolverProvider resolverProvider = ivyService.getResolverProvider(); for ( DependencyResolver resolver : resolverProvider.getResolvers() ) { RepositoryCacheManager potentialRepositoryCacheManager = resolver.getRepositoryCacheManager(); if ( DefaultRepositoryCacheManager.class.isInstance( potentialRepositoryCacheManager ) ) { repositoryCacheManager = (DefaultRepositoryCacheManager) potentialRepositoryCacheManager; } } if ( repositoryCacheManager == null ) { throw buildResolutionException( moduleDescriptor.getModuleRevisionId(), "Unable to locate proper dependency cache manager" ); } HashSet<File> dependencyFiles = new HashSet<File>(); for ( DependencyDescriptor dependencyDescriptor : moduleDescriptor.getDependencies() ) { final ModuleRevisionId info = dependencyDescriptor.getDynamicConstraintDependencyRevisionId(); dependencyFiles.add( repositoryCacheManager.getIvyFileInCache( info ) ); } return dependencyFiles; } private DefaultIvyService unwrap(IvyService ivyService) { if ( DefaultIvyService.class.isInstance( ivyService ) ) { return (DefaultIvyService) ivyService; } if ( ErrorHandlingIvyService.class.isInstance( ivyService ) ) { return unwrap( ( (ErrorHandlingIvyService) ivyService ).getIvyService() ); } if ( ShortcircuitEmptyConfigsIvyService.class.isInstance( ivyService ) ) { return unwrap( ( (ShortcircuitEmptyConfigsIvyService) ivyService ).getIvyService() ); } throw new BuildException( "Do not know how to extract needed ivy config from ivy service of type " + ivyService.getClass().getName() ); } private ModuleDescriptor resolveIvyXml(DefaultIvyService ivyService) { Ivy ivy = locateIvyService( ivyService ); ResolveReport resolveReport = performResolve( ivy, ivyXmlFile ); return resolveReport.getModuleDescriptor(); } @SuppressWarnings({ "unchecked" }) private ResolveReport performResolve(Ivy ivy, File ivyXmlFile) { try { ResolveReport resolveReport = ivy.resolve( ivyXmlFile ); if ( resolveReport.hasError() ) { throw buildResolutionException( resolveReport.getModuleDescriptor().getModuleRevisionId(), resolveReport.getAllProblemMessages() ); } return resolveReport; } catch ( ParseException e ) { throw new BuildException( "Malformed ivy dependency file [" + ivyXmlFile.getName() + "]", e ); } catch ( IOException e ) { throw new BuildException( "Problem reading ivy dependency file [" + ivyXmlFile.getName() + "]", e ); } } private Ivy locateIvyService(DefaultIvyService ivyService) { final IvyFactory ivyFactory = ivyService.getIvyFactory(); final SettingsConverter settingsConverter = ivyService.getSettingsConverter(); final ResolverProvider resolverProvider = ivyService.getResolverProvider(); // Ugh, can absolutely find no way to access this other than a bunch of recursive reflection calls to // locate the build's org.gradle.api.internal.project.TopLevelBuildServiceRegistry and access its // private org.gradle.api.internal.project.TopLevelBuildServiceRegistry.clientModuleRegistry field. // // Not sure if it is critical to reuse that map instance or not. seems to work without, but i have no // idea about the ramifications. Map<String, ModuleDescriptor> clientModuleRegistry = new HashMap<String, ModuleDescriptor>(); // this part is mainly DefaultIvyService#ivyForResolve IvySettings ivySettings = settingsConverter.convertForResolve( resolverProvider.getResolvers(), project.getGradle().getGradleUserHomeDir(), getGradeService( InternalRepository.class ), clientModuleRegistry ); return ivyFactory.createIvy( ivySettings ); } protected <T> T getGradeService(Class<T> type) { return ( (DefaultGradle) project.getGradle() ).getServices().get( type ); } } private static ResolutionException buildResolutionException(ModuleRevisionId descriptor, List<String> messages) { return new ResolutionException( descriptor.toString(), messages ); } private static ResolutionException buildResolutionException(ModuleRevisionId descriptor, String... messages) { return buildResolutionException( descriptor, Arrays.asList( messages ) ); } }