/* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#refreshAvailablePlugins()
   */
  @Override
  public synchronized void refreshAvailablePlugins() {

    ProductRegisterClientRestJerseyImpl productRegisterClient =
        new ProductRegisterClientRestJerseyImpl();
    productRegisterClient.setBaseUrl(this.getPluginServerUrl());
    productRegisterClient.setUserName(this.getPluginServerUsername());
    productRegisterClient.setPassword(this.getPluginServerPassword());

    productRegisterClient.setBasePath(PRODUCT_PUB_BASE_PATH);

    ProductSpecList availablePlugins;
    try {
      availablePlugins = productRegisterClient.getList();
      pluginModelJaxb.setAvailablePlugins(availablePlugins);
      pluginModelJaxb.setAvailablePluginsLastUpdated(new Date());
      persist();
    } catch (Exception e) {
      throw new RuntimeException(
          "problem refreshing available plugins for"
              + " plugin server Url="
              + this.getPluginServerUrl()
              + ": ",
          e);
    }
  }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#getSystemId(java.lang.String)
  */
 @Override
 public synchronized String getSystemId(String karafInstance) {
   if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
   if (!pluginModelJaxb.getKarafDataMap().containsKey(karafInstance)) {
     return null;
   }
   KarafEntryJaxb karafEntry = pluginModelJaxb.getKarafDataMap().get(karafInstance);
   if (karafEntry == null) return null;
   return karafEntry.getSystemId();
 }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#getAvailablePlugins()
   */
  @Override
  public synchronized ProductSpecList getAvailablePlugins() {

    if (pluginModelJaxb.getAvailablePlugins() == null
        || pluginModelJaxb.getAvailablePlugins().getProductSpecList() == null
        || pluginModelJaxb.getAvailablePlugins().getProductSpecList().size() == 0)
      refreshAvailablePlugins();

    return pluginModelJaxb.getAvailablePlugins();
  }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#getPluginsManifest(java.lang.String)
  */
 @Override
 public synchronized ProductSpecList getPluginsManifest(String karafInstance) {
   if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
   if (!pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
     return new ProductSpecList(); // return empty list if no entry found
   }
   ProductSpecList pluginManifest =
       pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance).getPluginManifest();
   if (pluginManifest == null) return new ProductSpecList(); // return empty list if no entry found
   return pluginManifest;
 }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#setPluginManagerBasicData(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
  */
 @Override
 public synchronized void setPluginManagerBasicData(
     String pluginServerUsername,
     String pluginServerPassword,
     String pluginServerUrl,
     String licenceShoppingCartUrl) {
   pluginModelJaxb.setPluginServerUsername(pluginServerUsername);
   pluginModelJaxb.setPluginServerPassword(pluginServerPassword);
   pluginModelJaxb.setPluginServerUrl(pluginServerUrl);
   pluginModelJaxb.setLicenceShoppingCartUrl(licenceShoppingCartUrl);
   persist();
 }
  @Override
  public synchronized void deleteKarafInstance(String karafInstance) {
    if (karafInstance == null || "".equals(karafInstance))
      throw new RuntimeException("karafInstance cannot be null or empty");

    if ("localhost".equals(karafInstance))
      throw new RuntimeException("cannot delete localhost karaf instance from plugin manager");

    pluginModelJaxb.getKarafManifestEntryMap().remove(karafInstance);
    pluginModelJaxb.getKarafDataMap().remove(karafInstance);

    persist();
  }
  @Override
  public synchronized void setRemoteIsAccessible(Boolean remoteIsAccessible, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);

    if (!pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
      pluginModelJaxb.getKarafManifestEntryMap().put(karafInstance, new KarafManifestEntryJaxb());
    }
    KarafManifestEntryJaxb karafManifestEntryJaxb =
        pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance);

    karafManifestEntryJaxb.setRemoteIsAccessible(remoteIsAccessible);

    persist();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#getInstalledLicenceList(java.lang.String)
   */
  @Override
  public synchronized void updateInstalledLicenceList(
      LicenceList licenceList, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
    if (licenceList == null) throw new RuntimeException("licenceList cannot be null");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);

    if (!pluginModelJaxb.getKarafDataMap().containsKey(karafInstance)) {
      throw new RuntimeException("no karaf entry entry exists for Karaf Instance=" + karafInstance);
    }
    KarafEntryJaxb karafEntry = pluginModelJaxb.getKarafDataMap().get(karafInstance);
    karafEntry.getInstalledLicenceList().getLicenceList().clear();
    karafEntry.getInstalledLicenceList().getLicenceList().addAll(licenceList.getLicenceList());
    persist();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#addPluginToManifest(java.lang.String, java.lang.String)
   */
  @Override
  public synchronized void addPluginToManifest(String selectedProductId, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
    if (selectedProductId == null) throw new RuntimeException("selectedProductId cannot be null");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);

    ProductMetadata productMetadata = null;
    for (ProductMetadata pMetadata : pluginModelJaxb.getAvailablePlugins().getProductSpecList()) {
      if (selectedProductId.equals(pMetadata.getProductId())) {
        productMetadata = pMetadata;
        break;
      }
    }
    if (productMetadata == null)
      throw new RuntimeException("cannot install unknown available productId=" + selectedProductId);
    if (productMetadata.getFeatureRepository() == null)
      throw new RuntimeException(
          "feature repository cannot be null for productId=" + selectedProductId);

    if (!pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
      pluginModelJaxb.getKarafManifestEntryMap().put(karafInstance, new KarafManifestEntryJaxb());
    }

    ProductSpecList karafInstancePluginManifest =
        pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance).getPluginManifest();

    // remove any product metadata with duplicate productId's from the list
    String productMetadataId = productMetadata.getProductId();
    ArrayList<ProductMetadata> searchlist =
        new ArrayList<ProductMetadata>(karafInstancePluginManifest.getProductSpecList());
    for (ProductMetadata searchProductMetadata : searchlist) {
      if (productMetadataId.equals(searchProductMetadata.getProductId())) {
        karafInstancePluginManifest.getProductSpecList().remove(searchProductMetadata);
      }
    }

    karafInstancePluginManifest.getProductSpecList().add(productMetadata);

    persist();
  }
  @Override
  public synchronized Boolean getRemoteIsAccessible(String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");

    KarafManifestEntryJaxb karafManifestEntry =
        pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance);

    if (karafManifestEntry == null) return true;

    return karafManifestEntry.getRemoteIsAccessible();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#getManifestSystemId(java.lang.String)
   */
  @Override
  public synchronized String getManifestSystemId(String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");

    KarafManifestEntryJaxb karafManifestEntry =
        pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance);

    if (karafManifestEntry == null) return null;

    return karafManifestEntry.getManifestSystemId();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#removePluginFromManifest(java.lang.String, java.lang.String)
   */
  @Override
  public synchronized void removePluginFromManifest(
      String selectedProductId, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
    if (selectedProductId == null) throw new RuntimeException("selectedProductId cannot be null");

    if (pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
      List<ProductMetadata> productSpecList =
          pluginModelJaxb
              .getKarafManifestEntryMap()
              .get(karafInstance)
              .getPluginManifest()
              .getProductSpecList();
      ProductMetadata productMetadata = null;
      for (ProductMetadata pMetadata : productSpecList) {
        if (selectedProductId.equals(pMetadata.getProductId())) {
          productMetadata = pMetadata;
          break;
        }
      }
      if (productMetadata != null) productSpecList.remove(productMetadata);
      persist();
    }
  }
  @Override
  public synchronized void addNewKarafInstance(KarafManifestEntryJaxb karafManifestEntryJaxb) {
    if (karafManifestEntryJaxb == null)
      throw new RuntimeException(
          "cannot add new karaf instance -  karafManifestEntryJaxb cannot be null");

    String karafInstance = karafManifestEntryJaxb.getKarafInstanceName();
    if (karafInstance == null || "".equals(karafInstance))
      throw new RuntimeException(
          "cannot add new karaf instance - karafInstanceName in karafManifestEntryJaxb cannot be null or empty");

    if ("localhost".equals(karafInstance))
      throw new RuntimeException("cannot add localhost karaf instance to plugin manager");

    if (pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
      throw new RuntimeException(
          "cannot add new karaf instance - '"
              + karafInstance
              + "' is already defined in plugin manager");
    }

    pluginModelJaxb.getKarafManifestEntryMap().put(karafInstance, karafManifestEntryJaxb);
    persist();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#addUserDefinedPluginToManifest(org.opennms.karaf.licencemgr.metadata.jaxb.ProductMetadata, java.lang.String)
   */
  @Override
  public synchronized void addUserDefinedPluginToManifest(
      ProductMetadata newProductMetadata, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
    if (newProductMetadata == null) throw new RuntimeException("newProductMetadata cannot be null");
    if (newProductMetadata.getProductId() == null || "".equals(newProductMetadata.getProductId()))
      throw new RuntimeException("newProductMetadata productId cannot be null or empty string");
    if (newProductMetadata.getFeatureRepository() == null
        || "".equals(newProductMetadata.getFeatureRepository()))
      throw new RuntimeException(
          "newProductMetadata featureRepository cannot be null or empty string");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);

    if (!pluginModelJaxb.getKarafManifestEntryMap().containsKey(karafInstance)) {
      pluginModelJaxb.getKarafManifestEntryMap().put(karafInstance, new KarafManifestEntryJaxb());
    }

    ProductSpecList karafInstancePluginManifest =
        pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance).getPluginManifest();

    // remove any product metadata with duplicate productId's from the list
    String newProductMetadataId = newProductMetadata.getProductId();
    ArrayList<ProductMetadata> searchlist =
        new ArrayList<ProductMetadata>(karafInstancePluginManifest.getProductSpecList());
    for (ProductMetadata searchProductMetadata : searchlist) {
      if (newProductMetadataId.equals(searchProductMetadata.getProductId())) {
        karafInstancePluginManifest.getProductSpecList().remove(searchProductMetadata);
      }
    }

    karafInstancePluginManifest.getProductSpecList().add(newProductMetadata);
    persist();
  }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#getKarafInstances()
   */
  @Override
  public synchronized SortedMap<String, KarafManifestEntryJaxb> getKarafInstances() {

    SortedMap<String, KarafManifestEntryJaxb> karafInstances =
        pluginModelJaxb.getKarafManifestEntryMap();

    // creates a localhost entry if doesn't exist in karafInstances
    if (!karafInstances.containsKey(localKarafInstanceName)) {
      KarafManifestEntryJaxb localhostManifest = new KarafManifestEntryJaxb();

      localhostManifest.setKarafInstanceName(localKarafInstanceName);
      localhostManifest.setKarafInstanceUserName(localKarafInstanceUserName);
      localhostManifest.setKarafInstancePassword(localKarafInstancePassword);
      localhostManifest.setKarafInstanceUrl(localKarafInstanceUrl);
      localhostManifest.setRemoteIsAccessible(localRemoteIsAccessible);
      localhostManifest.setAllowUpdateMessages(localAllowUpdateMessages);
      karafInstances.put(localKarafInstanceName, localhostManifest);
      persist();
    }

    return karafInstances;
  }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#getLicenceShoppingCartUrl()
  */
 @Override
 public synchronized String getLicenceShoppingCartUrl() {
   return pluginModelJaxb.getLicenceShoppingCartUrl();
 }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#setPluginServerUrl(java.lang.String)
  */
 @Override
 public synchronized void setPluginServerUrl(String pluginServerUrl) {
   pluginModelJaxb.setPluginServerUrl(pluginServerUrl);
 }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#setPluginServerPassword(java.lang.String)
  */
 @Override
 public synchronized void setPluginServerPassword(String pluginServerPassword) {
   pluginModelJaxb.setPluginServerPassword(pluginServerPassword);
 }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#installPlugin(java.lang.String, java.lang.String)
   */
  @Override
  public synchronized void installPlugin(String selectedProductId, String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");
    if (selectedProductId == null) throw new RuntimeException("selectedProductId cannot be null");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);
    KarafManifestEntryJaxb karafManifest = karafInstances.get(karafInstance);
    String karafInstanceUrl = karafManifest.getKarafInstanceUrl();

    // only update remote if accessible
    if (karafManifest.getRemoteIsAccessible() == null || !karafManifest.getRemoteIsAccessible()) {
      throw new RuntimeException("karafInstance=" + karafInstance + " is not accessable remotely");
    }

    ProductMetadata productMetadata = null;

    // try manifest plugins list first
    if (pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance) != null) {
      ProductSpecList karafInstancePluginManifest =
          pluginModelJaxb.getKarafManifestEntryMap().get(karafInstance).getPluginManifest();
      if (karafInstancePluginManifest != null) {
        for (ProductMetadata pMetadata : karafInstancePluginManifest.getProductSpecList()) {
          if (selectedProductId.equals(pMetadata.getProductId())) {
            productMetadata = pMetadata;
            break;
          }
        }
      }
    }

    // then try available plugins
    if (productMetadata == null) {
      for (ProductMetadata pMetadata : pluginModelJaxb.getAvailablePlugins().getProductSpecList()) {
        if (selectedProductId.equals(pMetadata.getProductId())) {
          productMetadata = pMetadata;
          break;
        }
      }
    }

    if (productMetadata == null)
      throw new RuntimeException("cannot install unknown available productId=" + selectedProductId);
    if (productMetadata.getFeatureRepository() == null)
      throw new RuntimeException(
          "feature repository cannot be null for productId=" + selectedProductId);

    FeaturesServiceClientRestJerseyImpl featuresServiceClient =
        new FeaturesServiceClientRestJerseyImpl();
    featuresServiceClient.setBaseUrl(karafInstanceUrl);
    featuresServiceClient.setUserName(karafManifest.getKarafInstanceUserName());
    featuresServiceClient.setPassword(karafManifest.getKarafInstancePassword());
    featuresServiceClient.setBasePath(FEATURE_MGR_BASE_PATH);

    try {
      // add feature repository
      featuresServiceClient.featuresAddRepository(productMetadata.getFeatureRepository());
      // a feature id looks like name/version.
      String version = null;
      String name = null;
      if (selectedProductId.contains("/")) {
        int i = selectedProductId.indexOf('/');
        version = selectedProductId.substring(i + 1);
        name = selectedProductId.substring(0, selectedProductId.indexOf('/'));
      }
      // add feature
      featuresServiceClient.featuresInstall(name, version);
      refreshKarafEntry(karafInstance);
    } catch (Exception e) {
      throw new RuntimeException(
          "problem installing product "
              + selectedProductId
              + " for Karaf Instance="
              + karafInstance
              + " karafInstanceUrl="
              + karafInstanceUrl
              + ": ",
          e);
    }
  }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#setPluginServerUsername(java.lang.String)
  */
 @Override
 public synchronized void setPluginServerUsername(String pluginServerUsername) {
   pluginModelJaxb.setPluginServerUsername(pluginServerUsername);
 }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#setLicenceShoppingCartUrl(java.lang.String)
  */
 @Override
 public synchronized void setLicenceShoppingCartUrl(String licenceShoppingCartUrl) {
   pluginModelJaxb.setLicenceShoppingCartUrl(licenceShoppingCartUrl);
 }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#getAvailablePluginsLastUpdated()
  */
 @Override
 public synchronized Date getAvailablePluginsLastUpdated() {
   return pluginModelJaxb.getAvailablePluginsLastUpdated();
 }
  /* (non-Javadoc)
   * @see org.opennms.features.pluginmgr.PluginManager#refreshKarafEntry(java.lang.String)
   */
  @Override
  public synchronized KarafEntryJaxb refreshKarafEntry(String karafInstance) {
    if (karafInstance == null) throw new RuntimeException("karafInstance cannot be null");

    SortedMap<String, KarafManifestEntryJaxb> karafInstances = getKarafInstances();
    if (!karafInstances.containsKey(karafInstance))
      throw new RuntimeException("system does not know karafInstance=" + karafInstance);

    KarafManifestEntryJaxb karafManifest = karafInstances.get(karafInstance);
    String karafInstanceUrl = karafManifest.getKarafInstanceUrl();

    // only update remote if accessible
    // else just return current value
    if (karafManifest.getRemoteIsAccessible() == null || !karafManifest.getRemoteIsAccessible()) {
      if (!pluginModelJaxb.getKarafDataMap().containsKey(karafInstance)) {
        // if there is no entry, create an empty one
        KarafEntryJaxb karafEntryJaxb = new KarafEntryJaxb();
        pluginModelJaxb.getKarafDataMap().put(karafInstance, karafEntryJaxb);
      }
      return pluginModelJaxb.getKarafDataMap().get(karafInstance);

    } else {

      KarafEntryJaxb karafEntryJaxb = new KarafEntryJaxb();

      try {

        // getting karaf installed licences and system id
        LicenceManagerClientRestJerseyImpl licenceManagerClient =
            new LicenceManagerClientRestJerseyImpl();
        licenceManagerClient.setBaseUrl(karafInstanceUrl);
        licenceManagerClient.setUserName(karafManifest.getKarafInstanceUserName());
        licenceManagerClient.setPassword(karafManifest.getKarafInstancePassword());

        licenceManagerClient.setBasePath(LICENCE_MGR_BASE_PATH);
        LicenceList installedLicenceList;
        try {
          installedLicenceList = licenceManagerClient.getLicenceMap();
          karafEntryJaxb.setInstalledLicenceList(installedLicenceList);
          String systemId = licenceManagerClient.getSystemId();
          karafEntryJaxb.setSystemId(systemId);
          // if the remote has a system id and manifest does not, set manifest to remote value
          if (karafManifest.getManifestSystemId() == null)
            karafManifest.setManifestSystemId(systemId);
        } catch (Exception e) {
          throw new RuntimeException(
              "problem refreshing installed licences for "
                  + "karafInstance="
                  + karafInstance
                  + " karafInstanceUrl="
                  + karafInstanceUrl
                  + ": ",
              e);
        }

        // getting installed plugins
        ProductRegisterClientRestJerseyImpl productRegisterClient =
            new ProductRegisterClientRestJerseyImpl();
        productRegisterClient.setBaseUrl(karafInstanceUrl);
        productRegisterClient.setUserName(karafManifest.getKarafInstanceUserName());
        productRegisterClient.setPassword(karafManifest.getKarafInstancePassword());

        // getting karaf installed plugins
        productRegisterClient.setBasePath(PRODUCT_REG_BASE_PATH);

        ProductSpecList installedPlugins;
        try {
          installedPlugins = productRegisterClient.getList();

          List<LicenceEntry> licenceList =
              karafEntryJaxb.getInstalledLicenceList().getLicenceList();

          // tests if plugins need a licence and if the licence is authenticated
          for (ProductMetadata installedPlugin : installedPlugins.getProductSpecList()) {
            if (installedPlugin.getLicenceKeyRequired() != null
                && installedPlugin.getLicenceKeyRequired() == true) {
              // if plugin needs a licence then check if licence is already verified
              // ignores exception if no licence is installed
              Boolean licenceKeyAuthenticated = false;
              for (LicenceEntry licenceEntry : licenceList) {
                if (licenceEntry.getProductId().equals(installedPlugin.getProductId())) {
                  // only check where licence is installed
                  // note will throw exception if licence is not installed when checked
                  licenceKeyAuthenticated =
                      licenceManagerClient.isAuthenticated(installedPlugin.getProductId());
                }
              }
              installedPlugin.setLicenceKeyAuthenticated(licenceKeyAuthenticated);
            }
          }

          karafEntryJaxb.setInstalledPlugins(installedPlugins);
        } catch (Exception e) {
          throw new RuntimeException(
              "problem refreshing installed plugins for "
                  + "karafInstance="
                  + karafInstance
                  + " karafInstanceUrl="
                  + karafInstanceUrl
                  + ": ",
              e);
        }

        karafEntryJaxb.setKarafInstanceLastUpdated(new Date());

        pluginModelJaxb.getKarafDataMap().put(karafInstance, karafEntryJaxb);

        persist();

      } catch (Exception e) {
        throw new RuntimeException(
            "problem updating data from karaf Instance '" + karafInstance + "'", e);
      }

      return karafEntryJaxb;
    }
  }
 /* (non-Javadoc)
  * @see org.opennms.features.pluginmgr.PluginManager#getPluginServerUrl()
  */
 @Override
 public synchronized String getPluginServerUrl() {
   return pluginModelJaxb.getPluginServerUrl();
 }