Java tutorial
/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.metron.profiler.client.stellar; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.metron.common.dsl.Context; import org.apache.metron.common.dsl.ParseException; import org.apache.metron.common.dsl.Stellar; import org.apache.metron.common.dsl.StellarFunction; import org.apache.metron.common.utils.ConversionUtils; import org.apache.metron.hbase.HTableProvider; import org.apache.metron.hbase.TableProvider; import org.apache.metron.profiler.client.HBaseProfilerClient; import org.apache.metron.profiler.client.ProfilerClient; import org.apache.metron.profiler.hbase.ColumnBuilder; import org.apache.metron.profiler.hbase.RowKeyBuilder; import org.apache.metron.profiler.hbase.SaltyRowKeyBuilder; import org.apache.metron.profiler.hbase.ValueOnlyColumnBuilder; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; import static java.lang.String.format; import static org.apache.metron.common.dsl.Context.Capabilities.GLOBAL_CONFIG; /** * A Stellar function that can retrieve data contained within a Profile. * * PROFILE_GET * * Retrieve all values for 'entity1' from 'profile1' over the past 4 hours. * * <code>PROFILE_GET('profile1', 'entity1', 4, 'HOURS')</code> * * Retrieve all values for 'entity1' from 'profile1' over the past 2 days. * * <code>PROFILE_GET('profile1', 'entity1', 2, 'DAYS')</code> * * Retrieve all values for 'entity1' from 'profile1' that occurred on 'weekdays' over the past month. * * <code>PROFILE_GET('profile1', 'entity1', 1, 'MONTHS', 'weekdays')</code> * */ @Stellar(namespace = "PROFILE", name = "GET", description = "Retrieves a series of values from a stored profile.", params = { "profile - The name of the profile.", "entity - The name of the entity.", "durationAgo - How long ago should values be retrieved from?", "units - The units of 'durationAgo'.", "groups - Optional - The groups used to sort the profile." }, returns = "The profile measurements.") public class GetProfile implements StellarFunction { /** * A global property that defines the name of the HBase table storing profile definitions. */ public static final String PROFILER_HBASE_TABLE = "profiler.hbase.table"; /** * A global property that defines the name of the column family used to store profile data. */ public static final String PROFILER_COLUMN_FAMILY = "profiler.column.family"; /** * A global property that defines the name of the HBaseTableProvider implementation class. */ public static final String PROFILER_HBASE_TABLE_PROVIDER = "profiler.hbase.table.provider"; /** * A client that can retrieve profile values. */ private ProfilerClient client; /** * Initialization. */ @Override public void initialize(Context context) { // ensure the required capabilities are defined Context.Capabilities[] required = { GLOBAL_CONFIG }; validateCapabilities(context, required); Map<String, Object> global = (Map<String, Object>) context.getCapability(GLOBAL_CONFIG).get(); // create the profiler client ColumnBuilder columnBuilder = getColumnBuilder(global); RowKeyBuilder rowKeyBuilder = getRowKeyBuilder(global); HTableInterface table = getTable(global); client = new HBaseProfilerClient(table, rowKeyBuilder, columnBuilder); } /** * Is the function initialized? */ @Override public boolean isInitialized() { return client != null; } /** * Apply the function. * @param args The function arguments. * @param context */ @Override public Object apply(List<Object> args, Context context) throws ParseException { String profile = getArg(0, String.class, args); String entity = getArg(1, String.class, args); long durationAgo = getArg(2, Long.class, args); String unitsName = getArg(3, String.class, args); TimeUnit units = TimeUnit.valueOf(unitsName); List<Object> groups = getGroupsArg(4, args); return client.fetch(Object.class, profile, entity, groups, durationAgo, units); } /** * Get the groups defined by the user. * * The user can specify 0 or more groups. All arguments from the specified position * on are assumed to be groups. If there is no argument in the specified position, * then it is assumed the user did not specify any groups. * * @param startIndex The starting index of groups within the function argument list. * @param args The function arguments. * @return The groups. */ private List<Object> getGroupsArg(int startIndex, List<Object> args) { List<Object> groups = new ArrayList<>(); for (int i = startIndex; i < args.size(); i++) { String group = getArg(i, String.class, args); groups.add(group); } return groups; } /** * Ensure that the required capabilities are defined. * @param context The context to validate. * @param required The required capabilities. * @throws IllegalStateException if all of the required capabilities are not present in the Context. */ private void validateCapabilities(Context context, Context.Capabilities[] required) throws IllegalStateException { // collect the name of each missing capability String missing = Stream.of(required).filter(c -> !context.getCapability(c).isPresent()) .map(c -> c.toString()).collect(Collectors.joining(", ")); if (StringUtils.isNotBlank(missing) || context == null) { throw new IllegalStateException("missing required context: " + missing); } } /** * Get an argument from a list of arguments. * @param index The index within the list of arguments. * @param clazz The type expected. * @param args All of the arguments. * @param <T> The type of the argument expected. */ private <T> T getArg(int index, Class<T> clazz, List<Object> args) { if (index >= args.size()) { throw new IllegalArgumentException( format("expected at least %d argument(s), found %d", index + 1, args.size())); } return ConversionUtils.convert(args.get(index), clazz); } /** * Creates the ColumnBuilder to use in accessing the profile data. * @param global The global configuration. */ private ColumnBuilder getColumnBuilder(Map<String, Object> global) { // the builder is not currently configurable - but should be made so ColumnBuilder columnBuilder; if (global.containsKey(PROFILER_COLUMN_FAMILY)) { String columnFamily = (String) global.get(PROFILER_COLUMN_FAMILY); columnBuilder = new ValueOnlyColumnBuilder(columnFamily); } else { columnBuilder = new ValueOnlyColumnBuilder(); } return columnBuilder; } /** * Creates the ColumnBuilder to use in accessing the profile data. * @param global The global configuration. */ private RowKeyBuilder getRowKeyBuilder(Map<String, Object> global) { // the builder is not currently configurable - but should be made so return new SaltyRowKeyBuilder(); } /** * Create an HBase table used when accessing HBase. * @param global The global configuration. * @return */ private HTableInterface getTable(Map<String, Object> global) { String tableName = (String) global.getOrDefault(PROFILER_HBASE_TABLE, "profiler"); TableProvider provider = getTableProvider(global); try { return provider.getTable(HBaseConfiguration.create(), tableName); } catch (IOException e) { throw new IllegalArgumentException(String.format("Unable to access table: %s", tableName)); } } /** * Create the TableProvider to use when accessing HBase. * @param global The global configuration. */ private TableProvider getTableProvider(Map<String, Object> global) { String clazzName = (String) global.getOrDefault(PROFILER_HBASE_TABLE_PROVIDER, HTableProvider.class.getName()); TableProvider provider; try { Class<? extends TableProvider> clazz = (Class<? extends TableProvider>) Class.forName(clazzName); provider = clazz.newInstance(); } catch (Exception e) { provider = new HTableProvider(); } return provider; } }