io.fabric8.forge.ipaas.repository.NexusConnectionRepository.java Source code

Java tutorial

Introduction

Here is the source code for io.fabric8.forge.ipaas.repository.NexusConnectionRepository.java

Source

/**
 * Copyright 2005-2015 Red Hat, Inc.
 * <p>
 * Red Hat licenses this file to you 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 io.fabric8.forge.ipaas.repository;

import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.forge.ipaas.dto.ConnectionCatalogDto;
import io.fabric8.forge.ipaas.dto.NexusArtifactDto;
import io.fabric8.utils.IOHelpers;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import static io.fabric8.forge.ipaas.helper.CamelCatalogHelper.loadText;

@ApplicationScoped
public class NexusConnectionRepository implements ConnectionRepository {

    private final Set<NexusArtifactDto> indexedArtifacts = new LinkedHashSet<>();
    private final Map<NexusArtifactDto, ConnectionCatalogDto> connectors = new ConcurrentHashMap<>();
    private volatile ScheduledExecutorService executorService;
    private AtomicBoolean started = new AtomicBoolean();

    private static final String CLASSIFIER = "camel-connector";

    private Long delay = 60L; // use 60 second delay between index runs
    private String nexusUrl = "http://nexus/service/local/data_index";

    public String getNexusUrl() {
        return nexusUrl;
    }

    public void setNexusUrl(String nexusUrl) {
        this.nexusUrl = nexusUrl;
    }

    public Long getDelay() {
        return delay;
    }

    public void setDelay(Long delay) {
        this.delay = delay;
    }

    // we want to eager start ourselves
    public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
        start();
    }

    @PostConstruct
    public void start() {
        if (started.compareAndSet(false, true)) {
            System.out.println("NexusConnectionRepository is already started");
            return;
        }

        System.out.println("Starting NexusConnectionRepository");

        if (nexusUrl == null || nexusUrl.isEmpty()) {
            System.out.println("Nexus service not found. Indexing Nexus is not enabled!");
            return;
        }

        System.out.println("Indexing Nexus every " + delay + " seconds interval");
        executorService = Executors.newScheduledThreadPool(1);

        executorService.scheduleWithFixedDelay(() -> {
            try {
                System.out.println("Indexing Nexus " + nexusUrl + " +++ start +++");
                indexNexus();
            } catch (Throwable e) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                e.printStackTrace(pw);

                if (sw.toString().contains("UnknownHostException")) {
                    // less noise if its unknown host
                    System.err
                            .println("Error indexing Nexus " + nexusUrl + " due unknown hosts: " + e.getMessage());
                } else {
                    System.err.println(
                            "Error indexing Nexus " + nexusUrl + " due " + e.getMessage() + "\n" + sw.toString());
                }
            } finally {
                System.out.println("Indexing Nexus " + nexusUrl + " +++ end +++");
            }
        }, 10, delay, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void stop() {
        if (executorService != null) {
            executorService.shutdownNow();
        }
        started.set(false);
    }

    @Override
    public List<ConnectionCatalogDto> search(String filter, boolean latestVersionOnly) {
        List<ConnectionCatalogDto> answer = new ArrayList<>();

        if (filter == null || filter.isEmpty()) {
            // return all of them
            answer.addAll(connectors.values());
        } else {
            // search ignore case
            filter = filter.toLowerCase(Locale.US);
            for (ConnectionCatalogDto dto : connectors.values()) {
                if (dto.getName().toLowerCase(Locale.US).contains(filter)) {
                    answer.add(dto);
                } else if (dto.getDescription().toLowerCase(Locale.US).contains(filter)) {
                    answer.add(dto);
                } else if (dto.getGroupId().toLowerCase(Locale.US).contains(filter)) {
                    answer.add(dto);
                } else if (dto.getArtifactId().toLowerCase(Locale.US).contains(filter)) {
                    answer.add(dto);
                } else if (dto.getVersion().toLowerCase(Locale.US).contains(filter)) {
                    answer.add(dto);
                } else {
                    String[] labels = dto.getLabels();
                    if (labels != null && labels.length > 0) {
                        for (String lab : labels) {
                            lab = lab.toLowerCase(Locale.US);
                            if (lab.contains(filter)) {
                                answer.add(dto);
                                break;
                            }
                        }
                    }
                }
            }
        }

        // filter only latest version
        if (latestVersionOnly && answer.size() > 1) {
            // sort first
            Collections.sort(answer, (o1, o2) -> o1.getMavenGav().compareTo(o2.getMavenGav()));

            // keep only latest in each group
            List<ConnectionCatalogDto> unique = new ArrayList<>();
            ConnectionCatalogDto prev = null;

            for (ConnectionCatalogDto dto : answer) {
                if (prev == null || (prev.getGroupId().equals(dto.getGroupId())
                        && prev.getArtifactId().equals(dto.getArtifactId()))) {
                    prev = dto;
                } else {
                    unique.add(prev);
                    prev = dto;
                }
            }
            if (prev != null) {
                // special for last element
                unique.add(prev);
            }

            answer = unique;
        }

        return answer;
    }

    protected void indexNexus() throws Exception {
        // must have q parameter so use connector to find all connectors
        String query = nexusUrl + "?q=connector";
        URL url = new URL(query);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setIgnoringElementContentWhitespace(true);
        factory.setIgnoringComments(true);

        DocumentBuilder documentBuilder = factory.newDocumentBuilder();

        InputStream is = url.openStream();
        Document dom = documentBuilder.parse(is);

        XPathFactory xpFactory = XPathFactory.newInstance();
        XPath exp = xpFactory.newXPath();
        NodeList list = (NodeList) exp.evaluate("//classifier[text() = '" + CLASSIFIER + "']", dom,
                XPathConstants.NODESET);

        Set<NexusArtifactDto> newArtifacts = new LinkedHashSet<>();
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);
            Node parent = node.getParentNode();

            String g = getNodeText(parent.getChildNodes(), "groupId");
            String a = getNodeText(parent.getChildNodes(), "artifactId");
            String v = getNodeText(parent.getChildNodes(), "version");
            String l = getNodeText(parent.getChildNodes(), "artifactLink");

            if (g != null & a != null & v != null & l != null) {
                NexusArtifactDto dto = new NexusArtifactDto();
                dto.setGroupId(g);
                dto.setArtifactId(a);
                dto.setVersion(v);
                dto.setArtifactLink(l);

                System.out.println("Found connector: " + dto.getGroupId() + ":" + dto.getArtifactId() + ":"
                        + dto.getVersion());

                // is it a new artifact
                boolean newArtifact = true;
                for (NexusArtifactDto existing : indexedArtifacts) {
                    if (existing.getGroupId().equals(dto.getGroupId())
                            && existing.getArtifactId().equals(dto.getArtifactId())
                            && existing.getVersion().equals(dto.getVersion())) {
                        newArtifact = false;
                        break;
                    }
                }
                if (newArtifact) {
                    newArtifacts.add(dto);
                }
            }
        }

        // now download the new artifact JARs and look inside to find more details
        for (NexusArtifactDto dto : newArtifacts) {
            try {
                // download using url classloader reader
                URL jarUrl = new URL(dto.getArtifactLink());
                String json = loadCamelConnectorJSonSchema(jarUrl);

                ObjectMapper mapper = new ObjectMapper();
                ConnectionCatalogDto cat = mapper.readerFor(ConnectionCatalogDto.class).readValue(json);

                indexedArtifacts.add(dto);
                connectors.putIfAbsent(dto, cat);
                System.out.println("Added connector: " + dto.getGroupId() + ":" + dto.getArtifactId() + ":"
                        + dto.getVersion());
            } catch (Exception e) {
                System.err.println("Error downloading connector JAR " + dto.getArtifactLink()
                        + ". This exception is ignored. " + e.getMessage());
            }
        }

        IOHelpers.close(is);
    }

    private static String loadCamelConnectorJSonSchema(URL url) {
        try {
            // is it a JAR file
            URLClassLoader child = new URLClassLoader(new URL[] { url });
            InputStream is = child.getResourceAsStream("camel-connector.json");
            if (is != null) {
                return loadText(is);
            }
            IOHelpers.close(is);
        } catch (Throwable e) {
            e.printStackTrace();
            // ignore
        }

        return null;
    }

    private static String getNodeText(NodeList list, String name) {
        for (int i = 0; i < list.getLength(); i++) {
            Node child = list.item(i);
            if (name.equals(child.getNodeName())) {
                return child.getTextContent();
            }
        }
        return null;
    }
}