1   package com.atlassian.maven.plugins.amps.util;
2   
3   import java.io.File;
4   import java.io.FileInputStream;
5   import java.io.FileOutputStream;
6   import java.io.IOException;
7   import java.io.InputStream;
8   import java.io.OutputStream;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Properties;
12  
13  import org.apache.commons.io.FileUtils;
14  import org.apache.commons.io.IOUtils;
15  import org.apache.maven.plugin.MojoExecutionException;
16  import org.apache.maven.plugin.logging.Log;
17  
18  public class ConfigFileUtils
19  {
20      public static void replace(List<File> files, List<Replacement> replacements, boolean inverted, Log log) throws MojoExecutionException
21      {
22          for(File file : files)
23          {
24              replace(file, replacements, inverted, log);
25          }
26      }
27  
28      /**
29       * @param cfgFile the file
30       * @param replacements the list of keys to replace with values
31       * @param inverted if you want to swap values with keys. Be aware that the list is processed in order,
32       * so that if 2 keys have the same value, the first key will be chosen. The Replacement records with
33       * reversible set to false will not be reversed. Default: false.
34       */
35      public static void replace(File cfgFile, List<Replacement> replacements, boolean inverted, Log log) throws MojoExecutionException
36      {
37          if (!cfgFile.exists())
38          {
39              log.warn(replacements.size() + " replacements were attempted to be made in the following file, but the file doesn't exist: " + cfgFile.getAbsolutePath());
40              return;
41          }
42          try
43          {
44              String config = FileUtils.readFileToString(cfgFile);
45              if (!inverted)
46              {
47                  for (Replacement replacement : replacements)
48                  {
49                      config = config.replace(replacement.getKey(), replacement.getValue());
50                  }
51              }
52              else
53              {
54                  for (Replacement replacement : replacements)
55                  {
56                      if (replacement.isReversible())
57                      {
58                          config = config.replace(replacement.getValue(), replacement.getKey());
59                      }
60                  }
61              }
62              FileUtils.writeStringToFile(cfgFile, config);
63          }
64          catch (IOException ex)
65          {
66              throw new MojoExecutionException("Unable to replace " + cfgFile, ex);
67          }
68      }
69  
70      public static void replaceAll(File cfgFile, String pattern, String replacement) throws MojoExecutionException
71      {
72          if (!cfgFile.exists())
73          {
74              return;
75          }
76          try
77          {
78              String config = FileUtils.readFileToString(cfgFile);
79              config = config.replaceAll(pattern, replacement); // obeys regex
80              FileUtils.writeStringToFile(cfgFile, config);
81          }
82          catch (IOException ex)
83          {
84              throw new MojoExecutionException("Unable to replace " + cfgFile, ex);
85          }
86      }
87  
88      public static void setProperties(File propertiesFile, Map<String, String> newProperties) throws MojoExecutionException
89      {
90          InputStream in = null;
91          OutputStream out = null;
92  
93          try
94          {
95              in = new FileInputStream(propertiesFile);
96  
97              Properties props = new Properties();
98              props.load(in);
99              in.close();
100             in = null;
101 
102             for (Map.Entry<String, String> e : newProperties.entrySet())
103             {
104                 props.setProperty(e.getKey(), e.getValue());
105             }
106 
107             out = new FileOutputStream(propertiesFile);
108             props.store(out, "Processed by AMPS");
109             out.close();
110             out = null;
111         }
112         catch (IOException ioe)
113         {
114             IOUtils.closeQuietly(in);
115             IOUtils.closeQuietly(out);
116         }
117     }
118 
119     /**
120      * Represents a replacement in a configuration file or set of files.
121      */
122     public static class Replacement
123     {
124         String key;
125         String value;
126         boolean reversible = true;
127 
128         /**
129          * Represents a key to be replaced in the configuration files.
130          *
131          * <p/>
132          * <b>Important</b>: If your value is short, such as "/", "", "true", "false", please set reversible=false.
133          * When zipping a home, config files are parsed and everything is replaced back with keys, such as %PRODUCT_HOME_DIR%.
134          * If you provide a string with false positives, you may parametrise too many variables.
135          *
136          *
137          * @param key the key to be replaced. Must not be null.
138          * @param value the value to be replaced. Must not be null. <b>Important</b>: If short, such as / or "", please set reversible=false.
139          */
140         public Replacement(String key, String value)
141         {
142             // Ant-like file pattern matching could be implemented if it proves useful.
143             super();
144             if (key == null)
145             {
146                 throw new IllegalArgumentException("key must not be null");
147             }
148             if (value == null)
149             {
150                 throw new IllegalArgumentException("value must not be null");
151             }
152             this.key = key;
153             this.value = value;
154         }
155 
156         /**
157          * Represents a key to be replaced in the configuration files.
158          * @param key the key to be replaced. Must not be null.
159          * @param value the value to be replaced. Must not be null.
160          * @param reversible true if the value should be replaced with the key before
161          * preparing a snapshot. Default is true. Use false when the value is non-unique,
162          * e.g. "%BAMBOO_ENABLED% = true" should not be reversible.
163          */
164         public Replacement(String key, String value, boolean reversible)
165         {
166             this(key, value);
167             this.reversible = reversible;
168         }
169 
170         /**
171          * @return the key to be replaced. Never null.
172          */
173         public String getKey()
174         {
175             return key;
176         }
177 
178         /**
179          * @return the value. Never null.
180          */
181         public String getValue()
182         {
183             return value;
184         }
185 
186         public boolean isReversible()
187         {
188             return reversible;
189         }
190 
191         @Override
192         public String toString()
193         {
194             if (reversible)
195             {
196                 return key + " <-> " + value;
197             }
198             return key + " -> " + value;
199         }
200 
201 
202 
203     }
204 }