org.kantega.revoc.source.MavenSourceArtifactSourceSource.java Source code

Java tutorial

Introduction

Here is the source code for org.kantega.revoc.source.MavenSourceArtifactSourceSource.java

Source

/*
 * Copyright 2012 Kantega AS
 *
 * 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.kantega.revoc.source;

import org.kantega.revoc.config.Config;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

/**
 *
 */
public class MavenSourceArtifactSourceSource implements SourceSource {

    private final Map<String, MavenSourceInfo> mavenInfoMap = new HashMap<String, MavenSourceInfo>();
    private final Map<String, JarFile> sourceFileMap = new HashMap<String, JarFile>();
    private File mavenDownloads;
    private String mavenRepo;

    public MavenSourceArtifactSourceSource() {
        String mavenDownloadsEnv = Config.getProperty("REVOC_MAVEN_DOWNLOAD");
        String mavenRepo = Config.getProperty("REVOC_MAVEN_REPO");

        if (mavenDownloadsEnv != null && mavenRepo != null) {
            File mavenDir = new File(mavenDownloadsEnv);
            mavenDir.mkdirs();
            this.mavenDownloads = mavenDir;
            if (!mavenRepo.endsWith("/")) {
                mavenRepo += "/";
            }
            this.mavenRepo = mavenRepo;

        }

    }

    public String[] getSource(String className, ClassLoader classLoader) {

        URL resource = classLoader.getResource(className + ".class");

        String filePath = getFilePath(resource);

        if (filePath == null) {
            return null;
        }

        try {

            MavenSourceInfo info;

            synchronized (mavenInfoMap) {

                if (!mavenInfoMap.containsKey(filePath)) {
                    mavenInfoMap.put(filePath, parseInfo(filePath, resource));
                }
                info = mavenInfoMap.get(filePath);
            }

            JarFile sourceFile;
            synchronized (sourceFileMap) {
                if (!sourceFileMap.containsKey(filePath)) {
                    sourceFileMap.put(filePath, getSourceFile(filePath, info));
                }
                sourceFile = sourceFileMap.get(filePath);
            }

            if (sourceFile == null) {
                return null;
            }
            String sourcePath = className.replace('.', '/') + ".java";
            ZipEntry entry = sourceFile.getEntry(sourcePath);
            if (entry == null) {
                return null;
            }
            InputStream inputStream = sourceFile.getInputStream(entry);
            List<String> lines = IOUtils.readLines(inputStream);
            return lines.toArray(new String[lines.size()]);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private JarFile getSourceFile(String filePath, MavenSourceInfo info) throws IOException {
        if (!filePath.endsWith(".jar")) {
            return null;
        }
        File sourceJar;
        if (info == null) {
            sourceJar = new File(filePath.substring(0, filePath.lastIndexOf(".jar")) + "-sources.jar");
        } else {
            File m2Repo = new File(System.getProperty("user.home"), ".m2/repository");
            sourceJar = new File(m2Repo, getSourceFileMavenPath(info));
            if (!sourceJar.exists()) {
                sourceJar = new File(new File(filePath).getParentFile(), getSourceArtifactName(info));
            }
        }
        if (!sourceJar.exists()) {
            if (mavenDownloads != null && info != null) {
                File downLoad = downloadMavenSource(info);
                if (downLoad != null) {
                    sourceJar = downLoad;
                }

            }
            if (!sourceJar.exists()) {
                return null;
            }
        }

        return new JarFile(sourceJar);
    }

    private File downloadMavenSource(MavenSourceInfo info) {
        File downloadFile = new File(mavenDownloads, getSourceFileMavenPath(info));
        if (info.getVersion().contains("-SNAPSHOT")) {
            downloadFile.delete();
        }
        if (downloadFile.exists()) {
            return downloadFile;
        }
        downloadFile.getParentFile().mkdirs();
        File tempFile = new File(downloadFile.getParentFile(), "_tmp" + downloadFile.getName());

        try {
            URL remoteSourceURL = new URL(this.mavenRepo + getSourceFileDownloadMavenPath(info));

            InputStream stream = remoteSourceURL.openStream();
            FileOutputStream output = new FileOutputStream(tempFile);
            IOUtils.copy(stream, output);
            output.close();
            tempFile.renameTo(downloadFile);
            return downloadFile;
        } catch (MalformedURLException e) {
            return null;
        } catch (IOException e) {
            return null;
        }
    }

    private String getSourceFileMavenPath(MavenSourceInfo info) {
        StringBuilder sb = new StringBuilder();
        appendArtifactDirectory(info, sb);
        sb.append(getSourceArtifactName(info));
        return sb.toString();
    }

    private String getSourceFileDownloadMavenPath(MavenSourceInfo info) {

        StringBuilder sb = new StringBuilder();
        appendArtifactDirectory(info, sb);
        if (info.getVersion().contains("SNAPSHOT")) {
            sb.append(resolveSnapshotFileName(info, sb.toString()));
        } else {
            sb.append(getSourceArtifactName(info));
        }
        return sb.toString();
    }

    private void appendArtifactDirectory(MavenSourceInfo info, StringBuilder sb) {
        sb.append(info.getGroupId().replace('.', '/')).append("/");
        sb.append(info.getArtifactId()).append("/");
        sb.append(info.getVersion()).append("/");
    }

    private String resolveSnapshotFileName(MavenSourceInfo info, String artifactUrl) {

        try {
            URL url = new URL(this.mavenRepo + artifactUrl + "maven-metadata.xml");

            final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.addRequestProperty("Cache-Control", "max-age=0");
            urlConnection.addRequestProperty("User-Agent", "Apache-Maven/3.0");
            InputStream inputStream = urlConnection.getInputStream();
            final Document doc = builder.parse(inputStream);
            inputStream.close();

            Element versioning = (Element) doc.getDocumentElement().getElementsByTagName("versioning").item(0);
            Element snapshotVersions = (Element) versioning.getElementsByTagName("snapshotVersions").item(0);
            NodeList snapshotVersion = snapshotVersions.getElementsByTagName("snapshotVersion");
            for (int i = 0; i < snapshotVersion.getLength(); i++) {
                final Element versioningElement = (Element) snapshotVersion.item(i);

                String value = getText((Element) versioningElement.getElementsByTagName("value").item(0));

                return info.getArtifactId() + "-" + value + "-sources.jar";

            }

            return null;

        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String getText(Element versionNode) {
        StringBuilder text = new StringBuilder();

        for (int t = 0; t < versionNode.getChildNodes().getLength(); t++) {
            final Node node = versionNode.getChildNodes().item(t);
            if (node instanceof Text) {
                text.append(((Text) node).getData());
            }

        }
        return text.toString();
    }

    private String getSourceArtifactName(MavenSourceInfo info) {
        StringBuilder sb = new StringBuilder();
        sb.append(info.getArtifactId()).append("-").append(info.getVersion()).append("-sources.jar");
        return sb.toString();
    }

    private String getFilePath(URL resource) {
        if (resource == null) {
            return null;
        }
        if (!resource.getProtocol().equals("jar")) {
            return null;
        }
        String filePath = resource.getPath();
        if (!filePath.startsWith("file:") || !filePath.contains("!")) {
            return null;
        }
        filePath = filePath.substring("file:".length());
        return URLDecoder.decode(filePath.substring(0, filePath.indexOf("!")));
    }

    private MavenSourceInfo parseInfo(String filePath, URL resource) {

        File file = new File(filePath);

        JarFile jarFile = null;
        boolean isNewFile = false;
        try {
            URLConnection urlConnection = resource.openConnection();
            if (urlConnection instanceof JarURLConnection) {
                jarFile = ((JarURLConnection) urlConnection).getJarFile();
            } else {
                jarFile = new JarFile(file);
                isNewFile = true;
            }
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String prefix = "META-INF/maven/";
                String propSuffix = "/pom.properties";

                if (entry.getName().startsWith(prefix) && entry.getName().endsWith(propSuffix)) {
                    Properties props = new Properties();
                    InputStream inputStream = jarFile.getInputStream(entry);
                    props.load(inputStream);
                    inputStream.close();
                    String groupId = props.getProperty("groupId");
                    String artifactId = props.getProperty("artifactId");
                    String version = props.getProperty("version");

                    if (file.getName().startsWith(artifactId + "-" + version)) {
                        return new MavenSourceInfo(groupId, artifactId, version);
                    }

                }
            }
            return null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (isNewFile) {
                if (jarFile != null) {
                    try {
                        jarFile.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    private class MavenSourceInfo {

        private final String groupId;
        private final String artifactId;
        private final String version;
        private JarFile sourceFile;

        public MavenSourceInfo(String groupId, String artifactId, String version) {
            this.groupId = groupId;
            this.artifactId = artifactId;
            this.version = version;
        }

        public String getArtifactId() {
            return artifactId;
        }

        public String getGroupId() {
            return groupId;
        }

        public String getVersion() {
            return version;
        }

        public void setSourceFile(JarFile sourceFile) {
            this.sourceFile = sourceFile;
        }

        public JarFile getSourceFile() {
            return sourceFile;
        }
    }

    public static void main(String[] args) throws IOException {
        URL url = new URL(
                "http://nexus.kantega.lan/content/repositories/snapshots/no/kantega/davexchange/1.6.16-SNAPSHOT/maven-metadata.xml");
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.addRequestProperty("Cache-Control", "max-age=0");
        urlConnection.addRequestProperty("User-Agent", "Apache-Maven/3.0");
        InputStream inputStream = urlConnection.getInputStream();

        String content = IOUtils.toString(inputStream);

        System.out.println(content);
    }
}