View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.context.task;
21  
22  import org.apache.commons.cli.CommandLine;
23  import org.apache.commons.cli.CommandLineParser;
24  import org.apache.commons.cli.DefaultParser;
25  import org.apache.commons.cli.HelpFormatter;
26  import org.apache.commons.cli.Option;
27  import org.apache.commons.cli.Options;
28  import org.apache.commons.cli.ParseException;
29  import org.waarp.common.logging.WaarpLogger;
30  import org.waarp.common.logging.WaarpLoggerFactory;
31  import org.waarp.common.utility.ParametersChecker;
32  import org.waarp.openr66.s3.taskfactory.S3TaskFactory;
33  
34  import java.io.File;
35  import java.net.MalformedURLException;
36  import java.net.URL;
37  import java.util.Arrays;
38  import java.util.HashMap;
39  import java.util.HashSet;
40  import java.util.Map;
41  import java.util.Set;
42  
43  /**
44   * S3 GET Task<br>
45   * <p>
46   * Result of arguments will be as a S3 GET command.<br>
47   * Format is the following:<br>
48   * "-URL url of S3 service <br>
49   * -accessKey access Key for S3 service <br>
50   * -secretKey secret Key for S3 service <br>
51   * -bucketName bucket Name where to retrieve the object <br>
52   * -sourceName source Name from the bucket to select the final Object <br>
53   * -file final File path (absolute or relative from IN path) <br>
54   * [-getTags [* or list of tag names comma separated without space]]" <br>
55   * -targetName source Name from the bucket to select the final Object <br>
56   * [-setTags 'name:value,...' without space]" <br>
57   */
58  public class S3TaskArgs {
59    private static final WaarpLogger logger =
60        WaarpLoggerFactory.getLogger(S3TaskArgs.class);
61  
62    public static final String ARG_URL = "URL";
63    public static final String ARG_ACCESS_KEY = "accessKey";
64    public static final String ARG_SECRET_KEY = "secretKey";
65    public static final String ARG_BUCKET_NAME = "bucketName";
66    public static final String ARG_SOURCE_NAME = "sourceName";
67    public static final String ARG_TARGET_NAME = "targetName";
68    public static final String ARG_FILE = "file";
69    public static final String ARG_GET_TAGS = "getTags";
70    public static final String ARG_SET_TAGS = "setTags";
71  
72    private static final Option OPTION_URL =
73        Option.builder(ARG_URL).required(true).hasArg(true)
74              .desc("Specify the URL to operate on").build();
75    private static final Option OPTION_ACCESS_KEY =
76        Option.builder(ARG_ACCESS_KEY).required(true).hasArg(true)
77              .desc("Specify the Access Key to operate with").build();
78    private static final Option OPTION_SECRET_KEY =
79        Option.builder(ARG_SECRET_KEY).required(true).hasArg(true)
80              .desc("Specify the Secret Key to operate with").build();
81    private static final Option OPTION_BUCKET_NAME =
82        Option.builder(ARG_BUCKET_NAME).required(true).hasArg(true)
83              .desc("Specify the Bucket Name to operate with").build();
84    private static final Option OPTION_SOURCE_NAME =
85        Option.builder(ARG_SOURCE_NAME).required(true).hasArg(true)
86              .desc("Specify the Source Name to operate on").build();
87    private static final Option OPTION_TARGET_NAME =
88        Option.builder(ARG_TARGET_NAME).required(true).hasArg(true)
89              .desc("Specify the Target Name to operate on").build();
90    private static final Option OPTION_FILE =
91        Option.builder(ARG_FILE).required(true).hasArg(true)
92              .desc("Specify the File to operate on").build();
93    private static final Option OPTION_GET_TAGS =
94        Option.builder(ARG_GET_TAGS).required(false).hasArg(true).desc(
95                  "Specify the Tags to retrieve: * or comma separated list without space")
96              .build();
97    private static final Option OPTION_SET_TAGS =
98        Option.builder(ARG_SET_TAGS).required(false).hasArg(true).desc(
99                  "Specify the Tags to set: key1:value1,key2:value2 comma separated list without space")
100             .build();
101 
102   private static final Options S3_GET_OPTIONS =
103       new Options().addOption(OPTION_URL).addOption(OPTION_ACCESS_KEY)
104                    .addOption(OPTION_SECRET_KEY).addOption(OPTION_BUCKET_NAME)
105                    .addOption(OPTION_SOURCE_NAME).addOption(OPTION_FILE)
106                    .addOption(OPTION_GET_TAGS);
107   private static final Options S3_PUT_OPTIONS =
108       new Options().addOption(OPTION_URL).addOption(OPTION_ACCESS_KEY)
109                    .addOption(OPTION_SECRET_KEY).addOption(OPTION_BUCKET_NAME)
110                    .addOption(OPTION_TARGET_NAME).addOption(OPTION_SET_TAGS);
111   private static final Options S3_DELETE_OPTIONS =
112       new Options().addOption(OPTION_URL).addOption(OPTION_ACCESS_KEY)
113                    .addOption(OPTION_SECRET_KEY).addOption(OPTION_BUCKET_NAME)
114                    .addOption(OPTION_SOURCE_NAME);
115   protected static final String EMPTY_STRING_NOT_ALLOWED =
116       "Empty String not allowed";
117 
118   /**
119    * Print to standard output the help of this command
120    */
121   public static void printHelp(final S3TaskFactory.S3TaskType type,
122                                final Options options) {
123     final HelpFormatter formatter = new HelpFormatter();
124     formatter.printHelp(type.name(), options);
125   }
126 
127   public static S3TaskArgs getS3Params(final S3TaskFactory.S3TaskType type,
128                                        final int rank, final String[] args) {
129     if (args == null || args.length == 0) {
130       logger.error("Arguments cannot be empty or null");
131       return null;
132     }
133     final String[] realArgs = getRealArgs(rank, args);
134     final CommandLineParser parser = new DefaultParser();
135     final Options options;
136     switch (type) {
137       case S3GET:
138       case S3GETDELETE:
139         options = S3_GET_OPTIONS;
140         break;
141       case S3PUT:
142       case S3PUTR66DELETE:
143         options = S3_PUT_OPTIONS;
144         break;
145       case S3DELETE:
146         options = S3_DELETE_OPTIONS;
147         break;
148       default:
149         logger.error("Unknown Task {}", type);
150         return null;
151     }
152     try {
153       final CommandLine cmd = parser.parse(options, realArgs, true);
154       final String surl = cmd.getOptionValue(ARG_URL);
155       final URL url = new URL(surl);
156       final String accessKey = cmd.getOptionValue(ARG_ACCESS_KEY);
157       final String secretKey = cmd.getOptionValue(ARG_SECRET_KEY);
158       final String bucketName =
159           cmd.getOptionValue(ARG_BUCKET_NAME).toLowerCase();
160       final String sourceName =
161           cmd.hasOption(ARG_SOURCE_NAME)? cmd.getOptionValue(ARG_SOURCE_NAME) :
162               null;
163       final String targetName =
164           cmd.hasOption(ARG_TARGET_NAME)? cmd.getOptionValue(ARG_TARGET_NAME) :
165               null;
166       final String sfile =
167           cmd.hasOption(ARG_FILE)? cmd.getOptionValue(ARG_FILE) : null;
168       final File file;
169       if (sfile != null) {
170         file = new File(sfile);
171       } else {
172         file = null;
173       }
174       final String sgetTags =
175           cmd.hasOption(ARG_GET_TAGS)? cmd.getOptionValue(ARG_GET_TAGS) : null;
176       Set<String> getTags = null;
177       if (ParametersChecker.isNotEmpty(sgetTags)) {
178         getTags = new HashSet<>();
179         final String[] keys = sgetTags.split(","); // NOSONAR
180         boolean star = false;
181         for (final String key : keys) {
182           if (key.equalsIgnoreCase("*")) {
183             star = true;
184             break;
185           }
186           if (key.isEmpty()) {
187             printHelp(type, options);
188             logger.error("Arguments GetTags are incorrect: {}", sgetTags);
189             return null;
190           }
191           getTags.add(key);
192         }
193         if (star) {
194           getTags.clear();
195         }
196       }
197       final String ssetTags =
198           cmd.hasOption(ARG_SET_TAGS)? cmd.getOptionValue(ARG_SET_TAGS) : null;
199       Map<String, String> setTags = null;
200       if (ParametersChecker.isNotEmpty(ssetTags)) {
201         setTags = new HashMap<>();
202         final String[] keyvalues = ssetTags.split(","); // NOSONAR
203         for (final String key : keyvalues) {
204           if (key.isEmpty()) {
205             printHelp(type, options);
206             logger.error("Arguments SetTags are incorrect: {}", ssetTags);
207             return null;
208           }
209           final String[] dual = key.split(":");
210           if (dual.length != 2 || dual[0].isEmpty() || dual[1].isEmpty()) {
211             printHelp(type, options);
212             logger.error("Arguments SetTags are incorrect: {}", ssetTags);
213             return null;
214           }
215           setTags.put(dual[0], dual[1]);
216         }
217       }
218       return new S3TaskArgs(type, url, accessKey, secretKey, bucketName,
219                             sourceName, targetName, file, getTags, setTags);
220     } catch (final ParseException | MalformedURLException e) {
221       printHelp(type, options);
222       logger.error("Arguments are incorrect: {}", e.getMessage());
223       return null;
224     }
225   }
226 
227   /**
228    * Finalize the real arguments to parse
229    *
230    * @param rank
231    * @param args
232    *
233    * @return the real arguments
234    */
235   private static String[] getRealArgs(final int rank, final String[] args) {
236     return rank == 0? args : Arrays.copyOfRange(args, rank, args.length);
237   }
238 
239   private final URL url;
240   private final String accessKey;
241   private final String secretKey;
242   private final String bucketName;
243   private final String sourceName;
244   private final String targetName;
245   private final File file;
246   private final Set<String> getTags;
247   private final boolean getTag;
248   private final Map<String, String> setTags;
249 
250 
251   public S3TaskArgs(final S3TaskFactory.S3TaskType type, final URL url,
252                     final String accessKey, final String secretKey,
253                     final String bucketName, final String sourceName,
254                     final String targetName, final File file,
255                     final Set<String> getTags,
256                     final Map<String, String> setTags) {
257     ParametersChecker.checkParameter(EMPTY_STRING_NOT_ALLOWED, accessKey,
258                                      secretKey, bucketName);
259     if ((type == S3TaskFactory.S3TaskType.S3GET ||
260          type == S3TaskFactory.S3TaskType.S3GETDELETE ||
261          type == S3TaskFactory.S3TaskType.S3DELETE) &&
262         ParametersChecker.isEmpty(sourceName) && file == null) {
263       throw new IllegalArgumentException(EMPTY_STRING_NOT_ALLOWED);
264     }
265     if ((type == S3TaskFactory.S3TaskType.S3PUT ||
266          type == S3TaskFactory.S3TaskType.S3PUTR66DELETE) &&
267         ParametersChecker.isEmpty(targetName)) {
268       throw new IllegalArgumentException(EMPTY_STRING_NOT_ALLOWED);
269     }
270     this.url = url;
271     this.accessKey = accessKey;
272     this.secretKey = secretKey;
273     this.bucketName = bucketName;
274     this.sourceName = sourceName;
275     this.targetName = targetName;
276     this.file = file;
277     this.getTags = getTags;
278     this.setTags = setTags;
279     this.getTag = getTags != null;
280   }
281 
282   public final URL getUrl() {
283     return url;
284   }
285 
286   public final String getAccessKey() {
287     return accessKey;
288   }
289 
290   public final String getSecretKey() {
291     return secretKey;
292   }
293 
294   public final String getBucketName() {
295     return bucketName;
296   }
297 
298   public final String getSourceName() {
299     return sourceName;
300   }
301 
302   public final String getTargetName() {
303     return targetName;
304   }
305 
306   public final File getFile() {
307     return file;
308   }
309 
310   public final Set<String> getGetTags() {
311     return getTags;
312   }
313 
314   public final boolean getGetTag() {
315     return getTag;
316   }
317 
318   public final Map<String, String> getSetTags() {
319     return setTags;
320   }
321 }