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.hadoop.hbase.chaos.factories;
019
020import java.lang.reflect.Constructor;
021import java.util.function.Function;
022import org.apache.hadoop.hbase.TableName;
023import org.apache.hadoop.hbase.chaos.actions.Action;
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027public class ConfigurableSlowDeterministicMonkeyFactory extends SlowDeterministicMonkeyFactory {
028
029  private static final Logger LOG =
030    LoggerFactory.getLogger(ConfigurableSlowDeterministicMonkeyFactory.class);
031
032  final static String HEAVY_ACTIONS = "heavy.actions";
033  final static String TABLE_PARAM = "\\$table_name";
034
035  public enum SupportedTypes {
036    FLOAT(p -> Float.parseFloat(p)),
037    LONG(p -> Long.parseLong(p)),
038    INT(p -> Integer.parseInt(p)),
039    TABLENAME(p -> TableName.valueOf(p));
040
041    final Function<String, Object> converter;
042
043    SupportedTypes(Function<String, Object> converter) {
044      this.converter = converter;
045    }
046
047    Object convert(String param) {
048      return converter.apply(param);
049    }
050  }
051
052  @Override
053  protected Action[] getHeavyWeightedActions() {
054    String actions = this.properties.getProperty(HEAVY_ACTIONS);
055    if (actions == null || actions.isEmpty()) {
056      return super.getHeavyWeightedActions();
057    } else {
058      try {
059        String[] actionClasses = actions.split(";");
060        Action[] heavyActions = new Action[actionClasses.length];
061        for (int i = 0; i < actionClasses.length; i++) {
062          heavyActions[i] = instantiateAction(actionClasses[i]);
063        }
064        LOG.info("Created actions {}", heavyActions);
065        return heavyActions;
066      } catch (Exception e) {
067        LOG.error("Error trying to instantiate heavy actions. Returning null array.", e);
068      }
069      return null;
070    }
071  }
072
073  private Action instantiateAction(String actionString) throws Exception {
074    final String packageName = "org.apache.hadoop.hbase.chaos.actions";
075    String[] classAndParams = actionString.split("\\)")[0].split("\\(");
076    String className = packageName + "." + classAndParams[0];
077    String[] params =
078      classAndParams[1].replaceAll(TABLE_PARAM, tableName.getNameAsString()).split(",");
079    LOG.info("About to instantiate action class: {}; With constructor params: {}", className,
080      params);
081    Class<? extends Action> actionClass = (Class<? extends Action>) Class.forName(className);
082    Constructor<? extends Action>[] constructors =
083      (Constructor<? extends Action>[]) actionClass.getDeclaredConstructors();
084    for (Constructor<? extends Action> c : constructors) {
085      if (c.getParameterCount() != params.length) {
086        continue;
087      }
088      Class[] paramTypes = c.getParameterTypes();
089      Object[] constructorParams = new Object[paramTypes.length];
090      for (int i = 0; i < paramTypes.length; i++) {
091        constructorParams[i] =
092          SupportedTypes.valueOf(paramTypes[i].getSimpleName().toUpperCase()).convert(params[i]);
093      }
094      return c.newInstance(constructorParams);
095    }
096    throw new IllegalArgumentException(
097      "Couldn't find any matching constructor for: " + actionString);
098  }
099}