001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.commons.crypto.utils;
019
020import java.io.File;
021import java.io.IOException;
022import java.io.InputStream;
023import java.net.URL;
024import java.security.GeneralSecurityException;
025import java.util.ArrayList;
026import java.util.Enumeration;
027import java.util.List;
028import java.util.Objects;
029import java.util.Properties;
030
031import org.apache.commons.crypto.Crypto;
032import org.apache.commons.crypto.cipher.CryptoCipher;
033import org.apache.commons.crypto.cipher.CryptoCipherFactory;
034
035/**
036 * General utility methods.
037 */
038public final class Utils {
039
040    private static class DefaultPropertiesHolder {
041        static final Properties DEFAULT_PROPERTIES = createDefaultProperties();
042
043        /**
044         * Loads system properties when configuration file of the name
045         * {@link #SYSTEM_PROPERTIES_FILE} is found.
046         *
047         * @return the default properties
048         */
049        private static Properties createDefaultProperties() {
050          // default to system
051          final Properties defaultedProps = new Properties(System.getProperties());
052          final URL url = Thread.currentThread().getContextClassLoader().getResource(SYSTEM_PROPERTIES_FILE);
053          if (url == null) {
054              // Fail early when the resource is not found which makes SpotBugs happy on Java 17.
055              return defaultedProps;
056          }
057          try {
058              final Properties fileProps = new Properties();
059              try (InputStream is = url.openStream()) {
060                  fileProps.load(is);
061              }
062              final Enumeration<?> names = fileProps.propertyNames();
063              while (names.hasMoreElements()) {
064                  final String name = (String) names.nextElement();
065                  // ensure System properties override ones in the file so one can override the file on the command line
066                  if (System.getProperty(name) == null) {
067                      defaultedProps.setProperty(name, fileProps.getProperty(name));
068                  }
069              }
070          } catch (final Exception ex) {
071              System.err.println("Could not load '" + SYSTEM_PROPERTIES_FILE + "' from classpath: " + ex.toString());
072          }
073          return defaultedProps;
074      }
075   }
076
077    /**
078     * The file name of configuration file.
079     */
080    private static final String SYSTEM_PROPERTIES_FILE = Crypto.CONF_PREFIX + "properties";
081
082    /**
083     * Ensures the truth of an expression involving one or more parameters to
084     * the calling method.
085     *
086     * @param expression a boolean expression.
087     * @throws IllegalArgumentException if expression is false.
088     */
089    public static void checkArgument(final boolean expression) {
090        if (!expression) {
091            throw new IllegalArgumentException();
092        }
093    }
094
095    /**
096     * Checks the truth of an expression.
097     *
098     * @param expression a boolean expression.
099     * @param errorMessage the exception message to use if the check fails; will
100     *        be converted to a string using <code>String
101     *                     .valueOf(Object)</code>.
102     * @throws IllegalArgumentException if expression is false.
103     */
104    public static void checkArgument(final boolean expression, final Object errorMessage) {
105        if (!expression) {
106            throw new IllegalArgumentException(String.valueOf(errorMessage));
107        }
108    }
109
110    /**
111     * Ensures that an object reference passed as a parameter to the calling
112     * method is not null.
113     *
114     * @param <T> the type of the object reference to be checked.
115     * @param reference an object reference.
116     * @return the non-null reference that was validated.
117     * @throws NullPointerException if reference is null.
118     * @deprecated Use {@link Objects#requireNonNull(Object)}.
119     */
120    @Deprecated
121    public static <T> T checkNotNull(final T reference) {
122        return Objects.requireNonNull(reference, "reference");
123    }
124
125    /**
126     * Ensures the truth of an expression involving the state of the calling
127     * instance, but not involving any parameters to the calling method.
128     *
129     * @param expression a boolean expression.
130     * @throws IllegalStateException if expression is false.
131     */
132    public static void checkState(final boolean expression) {
133        checkState(expression, null);
134    }
135
136    /**
137     * Ensures the truth of an expression involving the state of the calling
138     * instance, but not involving any parameters to the calling method.
139     *
140     * @param expression a boolean expression.
141     * @param message Error message for the exception when the expression is false.
142     * @throws IllegalStateException if expression is false.
143     */
144    public static void checkState(final boolean expression, final String message) {
145        if (!expression) {
146            throw new IllegalStateException(message);
147        }
148    }
149
150    /**
151     * Helper method to create a CryptoCipher instance and throws only
152     * IOException.
153     *
154     * @param properties The {@code Properties} class represents a set of
155     *        properties.
156     * @param transformation the name of the transformation, e.g.,
157     * <i>AES/CBC/PKCS5Padding</i>.
158     * See the Java Cryptography Architecture Standard Algorithm Name Documentation
159     * for information about standard transformation names.
160     * @return the CryptoCipher instance.
161     * @throws IOException if an I/O error occurs.
162     */
163    public static CryptoCipher getCipherInstance(final String transformation, final Properties properties) throws IOException {
164        try {
165            return CryptoCipherFactory.getCryptoCipher(transformation, properties);
166        } catch (final GeneralSecurityException e) {
167            throw new IOException(e);
168        }
169    }
170
171    /**
172     * Gets a properties instance that defaults to the System Properties
173     * plus any other properties found in the file
174     * {@link #SYSTEM_PROPERTIES_FILE}
175     * @return a Properties instance with defaults
176     */
177    public static Properties getDefaultProperties() {
178        return new Properties(DefaultPropertiesHolder.DEFAULT_PROPERTIES);
179    }
180
181    /**
182     * Gets the properties merged with default properties.
183     * @param newProp  User-defined properties
184     * @return User-defined properties with the default properties
185     */
186    public static Properties getProperties(final Properties newProp) {
187        final Properties properties = new Properties(DefaultPropertiesHolder.DEFAULT_PROPERTIES);
188        properties.putAll(newProp);
189        return properties;
190     }
191
192    /*
193     * Override the default DLL name if jni.library.path is a valid directory
194     * @param name - the default name, passed from native code
195     * @return the updated library path
196     * This method is designed for use from the DynamicLoader native code.
197     * Although it could all be implemented in native code, this hook method
198     * makes maintenance easier.
199     * The code is intended for use with macOS where SIP makes it hard to override
200     * the environment variables needed to override the DLL search path. It also
201     * works for Linux, but is not (currently) used or needed for Windows.
202     * Do not change the method name or its signature!
203     */
204    static String libraryPath(final String name) {
205        final String override = System.getProperty("jni.library.path");
206        if (override != null && new File(override).isDirectory()) {
207            return new File(override, name).getPath();
208        }
209        return name;
210    }
211
212    /**
213     * Splits class names sequence into substrings, Trim each substring into an
214     * entry,and returns an list of the entries.
215     *
216     * @param clazzNames a string consist of a list of the entries joined by a
217     *        delimiter, may be null or empty in which case an empty list is returned.
218     * @param separator a delimiter for the input string.
219     * @return a list of class entries.
220     */
221    public static List<String> splitClassNames(final String clazzNames, final String separator) {
222        final List<String> res = new ArrayList<>();
223        if (clazzNames == null || clazzNames.isEmpty()) {
224            return res;
225        }
226
227        for (String clazzName : clazzNames.split(separator)) {
228            clazzName = clazzName.trim();
229            if (!clazzName.isEmpty()) {
230                res.add(clazzName);
231            }
232        }
233        return res;
234    }
235
236    /**
237     * The private constructor of {@link Utils}.
238     */
239    private Utils() {
240    }
241
242}