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 */
018
019package org.apache.oozie.util;
020
021import com.google.common.base.Preconditions;
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.mapreduce.MRJobConfig;
024import org.apache.oozie.client.OozieClient;
025import org.apache.oozie.service.ConfigurationService;
026import org.apache.oozie.service.StatusTransitService;
027import org.apache.oozie.servlet.ServicesLoader;
028
029/**
030 *
031 */
032public class ConfigUtils {
033    private final static XLog LOG = XLog.getLog(ConfigUtils.class);
034
035    public static boolean BOOLEAN_DEFAULT = false;
036    public static String STRING_DEFAULT = "";
037    public static int INT_DEFAULT = 0;
038    public static float FLOAT_DEFAULT = 0f;
039    public static long LONG_DEFAULT = 0l;
040
041    /**
042     * Fetches a property using both a deprecated name and the new name. The deprecated property
043     * has precedence over the new name. If the deprecated name is used a warning is written to
044     * the log.
045     *
046     * @param conf configuration object.
047     * @param newName new property name.
048     * @param oldName deprecated property name.
049     * @param defaultValue default value.
050     * @return the property value, or the default value if not found under the deprecated name and the new name.
051     */
052    public static String getWithDeprecatedCheck(Configuration conf, String newName, String oldName,
053                                                String defaultValue) {
054        String value = conf.get(oldName, null);
055        if (value == null) {
056            value = conf.get(newName, defaultValue);
057        }
058        else {
059            LOG.warn("Using a deprecated configuration property [{0}], should use [{1}].  " +
060                     "Please delete the deprecated property in order for the new property to take effect.",
061                     oldName, newName);
062        }
063        return value;
064    }
065
066    /**
067     * Fetches a property using both a deprecated name and the new name. The deprecated property
068     * has precedence over the new name. If the deprecated name is used a warning is written to
069     * the log.
070     *
071     * @param conf configuration object.
072     * @param newName new property name.
073     * @param oldName deprecated property name.
074     * @param defaultValue default value.
075     * @return the property value, or the default value if not found under the deprecated name and the new name.
076     */
077    public static boolean getWithDeprecatedCheck(Configuration conf, String newName, String oldName,
078                                                 boolean defaultValue) {
079        String value = getWithDeprecatedCheck(conf, newName, oldName, Boolean.toString(defaultValue));
080        return Boolean.parseBoolean(value);
081    }
082
083    /**
084     * Returns the HTTP or HTTPS URL for this Oozie server
085     * (http://HOSTNAME:HTTP_PORT/oozie or https://HOSTNAME:HTTPS_PORT/oozie)
086     *
087     * @param secure true to return the HTTPS URL or false to return the HTTP URL
088     * @return the HTTP or HTTPS URL for this Oozie server
089     */
090    public static String getOozieURL(boolean secure) {
091        StringBuilder sb = new StringBuilder();
092        if (secure) {
093            sb.append("https://");
094        }
095        else {
096            sb.append("http://");
097        }
098        sb.append(ConfigurationService.get("oozie.http.hostname"));
099        sb.append(":");
100        if (secure) {
101            sb.append(ConfigurationService.get("oozie.https.port"));
102        }
103        else {
104            sb.append(ConfigurationService.get("oozie.http.port"));
105        }
106        sb.append("/oozie");
107        return sb.toString();
108    }
109
110    /**
111     * Returns the HTTP or HTTPS URL for this Oozie server depending on which is actually configured
112     *
113     * @return the HTTP or HTTPS URL for this Oozie server
114     */
115    public static String getOozieEffectiveUrl() {
116        return getOozieURL(ServicesLoader.isSSLEnabled());
117    }
118
119    public static boolean isBackwardSupportForCoordStatus() {
120        return ConfigurationService.getBoolean(StatusTransitService.CONF_BACKWARD_SUPPORT_FOR_COORD_STATUS);
121    }
122
123    /**
124     * Check {@link Configuration} whether it contains disallowed properties. Given configuration property values of
125     * {@code oozie-site.xml#oozie.configuration.check-and-set.DISALLOWED.PROPERTY_KEY}, {@code newValue} and {@code performWrite}
126     * values, one of the following will happen:
127     * <ul>
128     *     <li>{@code base} doesn't contain any disallowed property: NOP</li>
129     *     <li>{@code base} contains a disallowed property but its value is the same as {@code newValue}: NOP</li>
130     *     <li>{@code base} contains a conflicting disallowed property and configuration tells we should also set, but
131     *     {@code performWrite=false}: NOP</li>
132     *     <li>{@code base} contains a conflicting disallowed property and configuration tells we should also set, and
133     *     {@code performWrite=true}: {@code base} will be overwritten by {@code key=newValue}</li>
134     *     <li>{@code base} contains a conflicting disallowed property and configuration tells we should not set:
135     *     {@code Exception toThrow} is thrown</li>
136     * </ul>
137     * @param base the {@link Configuration} to check
138     * @param newValue the new value to assign if {@code performWrite=true} and if configuration value
139     * {@code oozie.configuration.check-and-set.*} is set
140     * @param toThrow the {@link Exception} to throw when {@code oozie.configuration.check-and-set.*} is unset
141     * @param performWrite
142     * @param <E> {@link Exception} type
143     * @throws E the {@link Exception} to throw when {@code oozie.configuration.check-and-set.*} is unset
144     */
145    public static <E extends Exception> void checkAndSetDisallowedProperties(final Configuration base,
146                                                                             final String newValue,
147                                                                             final E toThrow,
148                                                                             final boolean performWrite) throws E {
149        Preconditions.checkNotNull(base, "base");
150        Preconditions.checkNotNull(newValue, "newValue");
151        Preconditions.checkNotNull(toThrow, "toThrow");
152
153        for (final String defaultDisallowedProperty : PropertiesUtils.DEFAULT_DISALLOWED_PROPERTIES) {
154            checkAndSetConfigValue(base, defaultDisallowedProperty, newValue, toThrow, performWrite);
155        }
156    }
157
158    private static <E extends Exception> void checkAndSetConfigValue(final Configuration base,
159                                                                     final String key,
160                                                                     final String newValue,
161                                                                     final E toThrow,
162                                                                     final boolean performWrite) throws E {
163        final boolean shouldCheckAndSet = ConfigurationService.getBoolean("oozie.configuration.check-and-set." + key, false);
164        final boolean isPresent = base.get(key) != null;
165        if (isPresent && !base.get(key).equals(newValue)) {
166            LOG.trace("Base configuration contains config property [{0}={1}] that is different from new value [{2}]",
167                    key,
168                    base.get(key),
169                    newValue);
170            if (shouldCheckAndSet && performWrite) {
171                LOG.trace("Setting [{0}] to [{1}]", key, newValue);
172                base.set(key, newValue);
173            }
174            else if (!shouldCheckAndSet) {
175                LOG.error("Cannot set [{0}] to [{1}]. {2}", key, newValue, toThrow.getMessage());
176                throw toThrow;
177            }
178        }
179    }
180}