<commit_before>/*
 * Copyright 2012 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Eclipse Public License version 1.0, available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.jboss.forge.container.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.inject.Typed;

import org.jboss.forge.container.Forge;
import org.jboss.forge.container.addons.AddonId;
import org.jboss.forge.container.lock.LockManager;
import org.jboss.forge.container.lock.LockMode;
import org.jboss.forge.container.repositories.AddonDependencyEntry;
import org.jboss.forge.container.repositories.AddonRepository;
import org.jboss.forge.container.repositories.MutableAddonRepository;
import org.jboss.forge.container.util.Assert;
import org.jboss.forge.container.util.Files;
import org.jboss.forge.container.util.OperatingSystemUtils;
import org.jboss.forge.container.util.Streams;
import org.jboss.forge.container.versions.SingleVersion;
import org.jboss.forge.container.versions.Version;
import org.jboss.forge.container.versions.Versions;
import org.jboss.forge.parser.xml.Node;
import org.jboss.forge.parser.xml.XMLParser;
import org.jboss.forge.parser.xml.XMLParserException;

/**
 * Used to perform Addon installation/registration operations.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@Typed()
public final class AddonRepositoryImpl implements MutableAddonRepository
{
   private static final Logger logger = Logger.getLogger(AddonRepositoryImpl.class.getName());

   private static final String ATTR_API_VERSION = "api-version";
   private static final String ATTR_EXPORT = "export";
   private static final String ATTR_NAME = "name";
   private static final String ATTR_OPTIONAL = "optional";
   private static final String ATTR_VERSION = "version";

   private static final String DEFAULT_ADDON_DIR = ".forge/addons";
   private static final String REGISTRY_DESCRIPTOR_NAME = "installed.xml";
   private static final String ADDON_DESCRIPTOR_FILENAME = "addon.xml";

   private LockManager lock;

   public static MutableAddonRepository forDirectory(Forge forge, File dir)
   {
      return new AddonRepositoryImpl(forge.getLockManager(), dir);
   }

   public static MutableAddonRepository forDefaultDirectory(Forge forge)
   {
      return new AddonRepositoryImpl(forge.getLockManager(), new File(OperatingSystemUtils.getUserHomePath(),
               DEFAULT_ADDON_DIR));
   }

   public static String getRuntimeAPIVersion()
   {
      String version = AddonRepository.class.getPackage()
               .getImplementationVersion();
      return version;
   }

   public static boolean hasRuntimeAPIVersion()
   {
      return getRuntimeAPIVersion() != null;
   }

   public static boolean isApiCompatible(Version runtimeVersion, AddonId entry)
   {
      Assert.notNull(entry, "Addon entry must not be null.");

      return Versions.isApiCompatible(runtimeVersion, entry.getApiVersion());
   }

   private File addonDir;

   private AddonRepositoryImpl(LockManager lock, File dir)
   {
      // TODO Assert.notNull(lock, "LockManager must not be null.");
      Assert.notNull(dir, "Addon directory must not be null.");
      this.addonDir = dir;
      this.lock = lock;
   }

   @Override
   public boolean deploy(final AddonId addon, final List<AddonDependencyEntry> dependencies, final List<File> resources)
   {
      return lock.performLocked(LockMode.WRITE, new Callable<Boolean>()
      {
         @SuppressWarnings("resource")
         @Override
         public Boolean call() throws Exception
         {
            File addonSlotDir = getAddonBaseDir(addon);
            File descriptor = getAddonDescriptor(addon);
            try
            {
               if (resources != null && !resources.isEmpty())
               {
                  for (File resource : resources)
                  {
                     if (resource.isDirectory())
                     {
                        String child = addon.getName()
                                 + resource.getParentFile().getParentFile().getName();
                        child = OperatingSystemUtils.getSafeFilename(child);
                        Files.copyDirectory(resource, new File(addonSlotDir, child));
                     }
                     else
                     {
                        Files.copyFileToDirectory(resource, addonSlotDir);
                     }
                  }
               }
               /*
                * Write out the addon module dependency configuration
                */
               Node addonXml = getXmlRoot(descriptor);
               Node dependenciesNode = addonXml.createChild("dependencies");

               if (dependencies != null)
                  for (AddonDependencyEntry dependency : dependencies)
                  {
                     Node dep = dependenciesNode.createChild("dependency");
                     dep.attribute(ATTR_NAME, dependency.getId().getName());
                     dep.attribute(ATTR_VERSION, dependency.getId().getVersion());
                     dep.attribute(ATTR_EXPORT, dependency.isExported());
                     dep.attribute(ATTR_OPTIONAL, dependency.isOptional());
                  }

               FileOutputStream fos = null;
               try
               {
                  fos = new FileOutputStream(descriptor);
                  Streams.write(XMLParser.toXMLInputStream(addonXml), fos);
               }
               finally
               {
                  Streams.closeQuietly(fos);
               }
               return true;
            }
            catch (IOException io)
            {
               io.printStackTrace();
               return false;
            }
         }
      });
   }

   @Override
   public boolean disable(final AddonId addon)
   {
      return lock.performLocked(LockMode.WRITE, new Callable<Boolean>()
      {<commit_msg>Fixed scenario where <dependencies> was being written twice<commit_after>/*
 * Copyright 2012 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Eclipse Public License version 1.0, available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.jboss.forge.container.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.inject.Typed;

import org.jboss.forge.container.Forge;
import org.jboss.forge.container.addons.AddonId;
import org.jboss.forge.container.lock.LockManager;
import org.jboss.forge.container.lock.LockMode;
import org.jboss.forge.container.repositories.AddonDependencyEntry;
import org.jboss.forge.container.repositories.AddonRepository;
import org.jboss.forge.container.repositories.MutableAddonRepository;
import org.jboss.forge.container.util.Assert;
import org.jboss.forge.container.util.Files;
import org.jboss.forge.container.util.OperatingSystemUtils;
import org.jboss.forge.container.util.Streams;
import org.jboss.forge.container.versions.SingleVersion;
import org.jboss.forge.container.versions.Version;
import org.jboss.forge.container.versions.Versions;
import org.jboss.forge.parser.xml.Node;
import org.jboss.forge.parser.xml.XMLParser;
import org.jboss.forge.parser.xml.XMLParserException;

/**
 * Used to perform Addon installation/registration operations.
 *
 * @author <a href="mailto:<EMAIL>"><NAME>, III</a>
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
@Typed()
public final class AddonRepositoryImpl implements MutableAddonRepository
{
   private static final Logger logger = Logger.getLogger(AddonRepositoryImpl.class.getName());

   private static final String ATTR_API_VERSION = "api-version";
   private static final String ATTR_EXPORT = "export";
   private static final String ATTR_NAME = "name";
   private static final String ATTR_OPTIONAL = "optional";
   private static final String ATTR_VERSION = "version";

   private static final String DEFAULT_ADDON_DIR = ".forge/addons";
   private static final String REGISTRY_DESCRIPTOR_NAME = "installed.xml";
   private static final String ADDON_DESCRIPTOR_FILENAME = "addon.xml";

   private LockManager lock;

   public static MutableAddonRepository forDirectory(Forge forge, File dir)
   {
      return new AddonRepositoryImpl(forge.getLockManager(), dir);
   }

   public static MutableAddonRepository forDefaultDirectory(Forge forge)
   {
      return new AddonRepositoryImpl(forge.getLockManager(), new File(OperatingSystemUtils.getUserHomePath(),
               DEFAULT_ADDON_DIR));
   }

   public static String getRuntimeAPIVersion()
   {
      String version = AddonRepository.class.getPackage()
               .getImplementationVersion();
      return version;
   }

   public static boolean hasRuntimeAPIVersion()
   {
      return getRuntimeAPIVersion() != null;
   }

   public static boolean isApiCompatible(Version runtimeVersion, AddonId entry)
   {
      Assert.notNull(entry, "Addon entry must not be null.");

      return Versions.isApiCompatible(runtimeVersion, entry.getApiVersion());
   }

   private File addonDir;

   private AddonRepositoryImpl(LockManager lock, File dir)
   {
      // TODO Assert.notNull(lock, "LockManager must not be null.");
      Assert.notNull(dir, "Addon directory must not be null.");
      this.addonDir = dir;
      this.lock = lock;
   }

   @Override
   public boolean deploy(final AddonId addon, final List<AddonDependencyEntry> dependencies, final List<File> resources)
   {
      return lock.performLocked(LockMode.WRITE, new Callable<Boolean>()
      {
         @SuppressWarnings("resource")
         @Override
         public Boolean call() throws Exception
         {
            File addonSlotDir = getAddonBaseDir(addon);
            File descriptor = getAddonDescriptor(addon);
            try
            {
               if (resources != null && !resources.isEmpty())
               {
                  for (File resource : resources)
                  {
                     if (resource.isDirectory())
                     {
                        String child = addon.getName()
                                 + resource.getParentFile().getParentFile().getName();
                        child = OperatingSystemUtils.getSafeFilename(child);
                        Files.copyDirectory(resource, new File(addonSlotDir, child));
                     }
                     else
                     {
                        Files.copyFileToDirectory(resource, addonSlotDir);
                     }
                  }
               }
               /*
                * Write out the addon module dependency configuration
                */
               Node addonXml = getXmlRoot(descriptor);
               Node dependenciesNode = addonXml.getOrCreate("dependencies");

               // TODO: Check if dependency does not repeat
               for (AddonDependencyEntry dependency : dependencies)
               {
                  Node dep = dependenciesNode.createChild("dependency");
                  dep.attribute(ATTR_NAME, dependency.getId().getName());
                  dep.attribute(ATTR_VERSION, dependency.getId().getVersion());
                  dep.attribute(ATTR_EXPORT, dependency.isExported());
                  dep.attribute(ATTR_OPTIONAL, dependency.isOptional());
               }

               FileOutputStream fos = null;
               try
               {
                  fos = new FileOutputStream(descriptor);
                  Streams.write(XMLParser.toXMLInputStream(addonXml), fos);
               }
               finally
               {
                  Streams.closeQuietly(fos);
               }
               return true;
            }
            catch (IOException io)
            {
               io.printStackTrace();
               return false;
            }
         }
      });
   }

   @Override
   public boolean disable(final AddonId addon)
   {
      return lock.performLocked(LockMode.WRITE, new Callable<Boolean>()
      {
{'fraction_non_alphanumeric': 0.09512615577495691, 'fraction_numerical': 0.0012537219871493496, 'mean_word_length': 2.4466648663246016, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5015213', 'n_tokens_mistral': 3475, 'n_tokens_neox': 3311, 'n_words': 732}