001package org.apache.maven.extension.internal;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import com.google.common.collect.ImmutableSet;
023import org.apache.maven.project.ExtensionDescriptor;
024import org.apache.maven.project.ExtensionDescriptorBuilder;
025import org.codehaus.plexus.classworlds.realm.ClassRealm;
026
027import java.io.File;
028import java.io.IOException;
029import java.io.InputStream;
030import java.net.URL;
031import java.util.Collection;
032import java.util.Enumeration;
033import java.util.LinkedHashSet;
034import java.util.Set;
035
036/**
037 * Provides information about artifacts (identified by groupId:artifactId string key) and classpath elements exported by
038 * Maven core itself or a Maven core extension.
039 *
040 * @since 3.3.0
041 */
042public class CoreExtensionEntry
043{
044    private final ClassRealm realm;
045
046    private final Set<String> artifacts;
047
048    private final Set<String> packages;
049
050    public CoreExtensionEntry( ClassRealm realm, Collection<String> artifacts, Collection<String> packages )
051    {
052        this.realm = realm;
053        this.artifacts = ImmutableSet.copyOf( artifacts );
054        this.packages = ImmutableSet.copyOf( packages );
055    }
056
057    /**
058     * Returns ClassLoader used to load extension classes.
059     */
060    public ClassRealm getClassRealm()
061    {
062        return realm;
063    }
064
065    /**
066     * Returns artifacts exported by the extension, identified by groupId:artifactId string key.
067     */
068    public Set<String> getExportedArtifacts()
069    {
070        return artifacts;
071    }
072
073    /**
074     * Returns classpath elements exported by the extension.
075     */
076    public Set<String> getExportedPackages()
077    {
078        return packages;
079    }
080
081    private static final ExtensionDescriptorBuilder builder = new ExtensionDescriptorBuilder();
082
083    public static CoreExtensionEntry discoverFrom( ClassRealm loader )
084    {
085        Set<String> artifacts = new LinkedHashSet<>();
086        Set<String> packages = new LinkedHashSet<>();
087
088        try
089        {
090            Enumeration<URL> urls = loader.getResources( builder.getExtensionDescriptorLocation() );
091            while ( urls.hasMoreElements() )
092            {
093
094                try ( InputStream is = urls.nextElement().openStream() )
095                {
096                    ExtensionDescriptor descriptor = builder.build( is );
097                    artifacts.addAll( descriptor.getExportedArtifacts() );
098                    packages.addAll( descriptor.getExportedPackages() );
099                }
100            }
101        }
102        catch ( IOException ignored )
103        {
104            // exports descriptors are entirely optional
105        }
106
107        return new CoreExtensionEntry( loader, artifacts, packages );
108    }
109
110    public static CoreExtensionEntry discoverFrom( ClassRealm loader, Collection<File> classpath )
111    {
112        Set<String> artifacts = new LinkedHashSet<>();
113        Set<String> packages = new LinkedHashSet<>();
114
115        try
116        {
117            for ( File entry : classpath )
118            {
119                ExtensionDescriptor descriptor = builder.build( entry );
120                if ( descriptor != null )
121                {
122                    artifacts.addAll( descriptor.getExportedArtifacts() );
123                    packages.addAll( descriptor.getExportedPackages() );
124                }
125            }
126        }
127        catch ( IOException ignored )
128        {
129            // exports descriptors are entirely optional
130        }
131
132        return new CoreExtensionEntry( loader, artifacts, packages );
133    }
134
135}