/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * 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. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.admin.application.service.impl; import java.io.Serializable; import java.net.URI; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.apache.karaf.features.BundleInfo; import org.apache.karaf.features.Feature; import org.apache.karaf.features.Repository; import org.codice.ddf.admin.application.service.Application; import org.codice.ddf.admin.application.service.ApplicationServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of the application interface. This class exposes a karaf-based * repository (identified inside of a feature) as a DDF application. */ public class ApplicationImpl implements Application, Comparable<Application> { private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationImpl.class); private Set<Feature> features = new HashSet<>(); private Set<Feature> autoInstallFeatures = new HashSet<>(); private Feature mainFeature; private String name; private String version; private String description; private URI location; /** * Creates a new instance of application. * * @param repo Creates the application from a Karaf Feature Repository * object. */ public ApplicationImpl(Repository repo) { String repoName = null; try { repoName = repo.getName(); features.addAll(Arrays.asList(repo.getFeatures())); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } setRepoNameAndVersion(repoName); location = repo.getURI(); if (features.size() == 1) { autoInstallFeatures.add(features.iterator() .next()); } else { autoInstallFeatures.addAll(features.stream() .filter(curFeature -> StringUtils.equalsIgnoreCase(Feature.DEFAULT_INSTALL_MODE, curFeature.getInstall())) .collect(Collectors.toList())); } // Determine mainFeature if (autoInstallFeatures.size() == 1) { mainFeature = autoInstallFeatures.iterator() .next(); name = mainFeature.getName(); version = mainFeature.getVersion(); description = mainFeature.getDescription(); } else { Optional<Feature> first = autoInstallFeatures.stream() .filter(f -> name.equals(f.getName())) .findFirst(); if (first.isPresent()) { mainFeature = first.get(); name = mainFeature.getName(); version = mainFeature.getVersion(); description = mainFeature.getDescription(); } } if (mainFeature == null) { LOGGER.debug("Could not determine main feature in {}, using defaults. Each application " + "should have 1 feature with the same name as the repository or 1 auto" + " install feature. This Application will take no action when started" + " or stopped.", name); } } private void setRepoNameAndVersion(String repoName) { String[] repoNameParts; int numberOfParts; // DDF-2596 repoNameParts = repoName.split("-(?=[0-9])", 2); numberOfParts = repoNameParts.length; switch (numberOfParts) { case 1: name = repoName; version = "0.0.0"; break; case 2: name = repoNameParts[0]; version = repoNameParts[1]; break; default: LOGGER.error("Could not tokenize repository name of '%s'", repoName); } } @Override public String getName() { return name; } @Override public String getVersion() { return version; } @Override public String getDescription() { return description; } @Override public Set<Feature> getFeatures() throws ApplicationServiceException { if (features != null) { return Collections.unmodifiableSet(features); } else { throw new ApplicationServiceException("No features found in application " + name + " check the feature definition and log for errors."); } } public Set<Feature> getAutoInstallFeatures() { return autoInstallFeatures; } @Override public Feature getMainFeature() { return mainFeature; } @Override public Set<BundleInfo> getBundles() throws ApplicationServiceException { Set<BundleInfo> bundles = new TreeSet<>(new BundleInfoComparator()); for (Feature curFeature : getFeatures()) { bundles.addAll(curFeature.getBundles()); } return bundles; } @Override public String toString() { return name + " - " + version; } @Override public int hashCode() { return name.concat(version) .hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } else if (obj == this) { return true; } else if (!(obj instanceof Application)) { return false; } Application otherApp = (Application) obj; return name.equals(otherApp.getName()) && version.equals(otherApp.getVersion()); } @Override public int compareTo(Application otherApp) { int nameCompare = name.compareTo(otherApp.getName()); if (nameCompare == 0) { return version.compareTo(otherApp.getVersion()); } else { return nameCompare; } } @Override public URI getURI() { return location; } private static class BundleInfoComparator implements Comparator<BundleInfo>, Serializable { private static final long serialVersionUID = 1L; @Override public int compare(BundleInfo bundle1, BundleInfo bundle2) { return bundle1.getLocation() .compareTo(bundle2.getLocation()); } } }