1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 import java.security.SecureRandom;
  40 import java.util.ArrayList;
  41 import java.util.List;
  42 import java.util.stream.IntStream;
  43 
  44 /**
  45  * Generates password of desired length. See {@link #usage} method for command
  46  * line arguments. This sample shows usages of:
  47  * <ol><li>
  48  * Method references (constructor reference and object method reference).</li>
  49  * <li>Lambda and bulk operations. Random double stream is mapped to chars,
  50  * limited by desired length and collected in StringBuilder as password
  51  * string.</li>
  52  * </ol>
  53  *
  54  * @author Andrey Nazarov
  55  */
  56 public class PasswordGenerator {
  57 
  58     private static void usage() {
  59         System.out.println("Usage: PasswordGenerator LENGTH");
  60         System.out.println(
  61                 "Password Generator produces password of desired LENGTH.");
  62     }
  63 
  64     private static final List<Integer> PASSWORD_CHARS = new ArrayList<>();
  65 
  66     //Valid symbols.
  67     static {
  68         IntStream.rangeClosed('0', '9').forEach(PASSWORD_CHARS::add);    // 0-9
  69         IntStream.rangeClosed('A', 'Z').forEach(PASSWORD_CHARS::add);    // A-Z
  70         IntStream.rangeClosed('a', 'z').forEach(PASSWORD_CHARS::add);    // a-z
  71     }
  72 
  73     /**
  74      * The main method for the PasswordGenerator program. Run program with empty
  75      * argument list to see possible arguments.
  76      *
  77      * @param args the argument list for PasswordGenerator.
  78      */
  79     public static void main(String[] args) {
  80 
  81         if (args.length != 1) {
  82             usage();
  83             return;
  84         }
  85 
  86         long passwordLength;
  87         try {
  88             passwordLength = Long.parseLong(args[0]);
  89             if (passwordLength < 1) {
  90                 printMessageAndUsage("Length has to be positive");
  91                 return;
  92             }
  93         } catch (NumberFormatException ex) {
  94             printMessageAndUsage("Unexpected number format" + args[0]);
  95             return;
  96         }
  97         /*
  98          * Stream of random doubles is created containing Double values
  99          * in range from 0 to 1.
 100          * Valid chars are selected by generated index.
 101          * The stream is limited by LENGTH.
 102          * Stream of chars is collected into a StringBuilder.
 103          */
 104         int passwordCharsCount = PASSWORD_CHARS.size();
 105         System.out.println(new SecureRandom().doubles()
 106                 .mapToInt(
 107                         d -> PASSWORD_CHARS.get((int) (d * passwordCharsCount)))
 108                 .limit(passwordLength)
 109                 .collect(StringBuilder::new, (sb, ch) -> sb.append((char) ch),
 110                         StringBuilder::append));
 111     }
 112 
 113     private static void printMessageAndUsage(String message) {
 114         System.out.println(message);
 115         usage();
 116     }
 117 
 118 }