All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.virtdata.core.Bindings Maven / Gradle / Ivy

There is a newer version: 2.12.15
Show newest version
/*
 *
 *       Copyright 2015 Jonathan Shook
 *
 *   Licensed 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 io.virtdata.core;

//

import io.virtdata.api.DataMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Maps a template with named bind points and specifiers onto a set of data
 * mapping function instances. Allows for streamlined calling of mapper functions
 * as a set.
 * 

There are several ways to get generated data via this class. You must always * provide a base input value. Fields can be accessed by parameter position or name. * In some cases, you can provide an iterator stride * in order to get data in bulk. In other cases, you can have setters called * directly on your provided objects. See the detailed method docs for more information.

*/ public class Bindings { private final static Logger logger = LoggerFactory.getLogger(Bindings.class); private BindingsTemplate template; private List> dataMappers = new ArrayList>(); private ThreadLocal>> nameCache; public Bindings(BindingsTemplate template, List> dataMappers) { this.template = template; this.dataMappers = dataMappers; nameCache = ThreadLocal.withInitial(() -> new HashMap>() {{ for (int i = 0; i < template.getBindPointNames().size(); i++) { put(template.getBindPointNames().get(i), dataMappers.get(i)); } }}); } public String toString() { return template.toString() + dataMappers; } /** * Get a value from each data mapper in the bindings list * * @param input The long value which the bound data mappers will use as in input * @return An array of objects, the values yielded from each data mapper in the bindings list */ public Object[] getAll(long input) { Object[] values = new Object[dataMappers.size()]; int offset = 0; for (DataMapper dataMapper : dataMappers) { values[offset++] = dataMapper.get(input); } return values; } /** * @return {@link BindingsTemplate} associated with this set of bindings */ public BindingsTemplate getTemplate() { return this.template; } /** * @param input The input value for which the values should be generated. * @return {@link Map} of {@link String} to {@link Object} */ public Map getAllMap(long input) { Map values = new HashMap<>(); setMap(values, input); return values; } /** * Generate a list of maps over a range of inputs. *

For example, calling getIteratedMaps(5,3) with bindings named * alpha and gamma might produce something like: *

    *
  1. *
      *
    • alpha -> val1
    • *
    • gamma -> val2
    • *
    *
  2. *
  3. *
      *
    • alpha -> val3
    • *
    • gamma -> val4
    • *
    *
  4. *
  5. *
      *
    • alpha -> val5
    • *
    • gamma -> val6
    • *
    *
  6. *
* * @param input The base value for which the values should be generated. * @param count The number of iterations, starting at input, to be generated * @return {@link List} of {@link Map} of {@link String} to {@link Object} */ public List> getIteratedMaps(long input, int count) { List> listOfMaps = new ArrayList<>(count); for (int i = 0; i < count; i++) { Map suffixedMap = new HashMap<>(); setMap(suffixedMap, input + i); listOfMaps.add(suffixedMap); } return listOfMaps; } /** * Generate a map containing the results from multiple iterations, suffixing * the keys in the map with the iterations from 0 to count-1. *

For example, calling getIteratedSuffixMap(5, 3) with generators named * alpha and gamma might yield results like *

    *
  • alpha0 -> val1
  • *
  • gamma0 -> val2
  • *
  • alpha1 -> val3
  • *
  • gamma1 -> val4
  • *
  • alpha2 -> val5
  • *
  • gamma2 -> val6
  • *
* * @param input The base input value for which the values should be generated * @param count The count of maps that should be added to the final map * @return {@link Map} of {@link String} to {@link Object} */ public Map getIteratedSuffixMap(long input, int count) { Map suffixedMap = new LinkedHashMap<>(count * this.dataMappers.size()); setIteratedSuffixMap(suffixedMap, input, count); return suffixedMap; } /** * This is a version of the {@link #setIteratedSuffixMap(Map, long, int, String[])} which creates * a new map for each call. * @param input The base input value for which the values should be generated * @param count The count of maps that should be added to the final map * @param fieldNames The field names which are used to look up the functions in the binding * @return A newly created map with the generated names and values. */ public Map getIteratedSuffixMap(long input, int count, String... fieldNames) { Map suffixedMap = new LinkedHashMap<>(count * fieldNames.length); setIteratedSuffixMap(suffixedMap, input, count, fieldNames); return suffixedMap; } /** * Populate a map of values with a two-dimensional set of generated key and value names. This is a basic * traversal over all the provided field names and a range of input values from input to input+count. * The key names for the map are created by adding a numeric suffix to the field name. * * For example, with field names aleph and gamma, with input 53 and count 2, the key names will * be created as aleph0, gamma0, aleph1, gamma1, and the input values which will be used to * create the generated values for these keys will be 53, 53, and 54, 54, respectively. * * Symbolically, this does the same as the sketch below: * *
    *
  1. map{aleph0}=funcFor("aleph")(53)
  2. *
  3. map{gamma0}=funcFor("gamma")(53)
  4. *
  5. map{aleph1}=funcFor("aleph")(54)
  6. *
  7. map{gamma1}=funcFor("gamma")(54)
  8. *
* * @param suffixedMap A donor map which is to be populated. The values do not clear the map, but merely overwrite * values of the same name. * @param input The base input value for which the values should be generated * @param count The count of maps that should be added to the final map * @param fieldNames The field names which are used to look up the functions in the binding */ private void setIteratedSuffixMap(Map suffixedMap, long input, int count, String[] fieldNames) { for (int i = 0; i < count; i++) { for (String f : fieldNames) { suffixedMap.put(f+i,get(f,input+i)); } } } /** * Get a value for the data mapper in slot i * * @param i the data mapper slot, 0-indexed * @param input the long input value which the bound data mapper will use as input * @return a single object, the value yielded from the indexed data mapper in the bindings list */ public Object get(int i, long input) { return dataMappers.get(i).get(input); } /** * Get a value for the cached mapper name, using the name to mapper index cache. * @param name The field name in the data mapper * @param input the long input value which the bound data mapper will use as an input * @return a single object, the value yielded from the named and indexed data mapper in the bindings list. */ public Object get(String name, long input) { DataMapper dataMapper = nameCache.get().get(name); return dataMapper.get(input); } /** * Generate all values in the bindings template, and set each of them in * the map according to their bind point name. * * @param donorMap - a user-provided Map<String,Object> * @param cycle - the cycle for which to generate the values */ public void setMap(Map donorMap, long cycle) { Object[] all = getAll(cycle); for (int i = 0; i < all.length; i++) { donorMap.put(template.getBindPointNames().get(i), all[i]); } } /** * Set the values in a provided map, with bound names suffixed with * some value. No non-overlapping keys in the map will be affected. * * @param donorMap an existing {@link Map} of {@link String} to {@link Object} * @param cycle the cycle for which values should be generated * @param suffix a string suffix to be appended to any map keys */ public void setSuffixedMap(Map donorMap, long cycle, String suffix) { Object[] all = getAll(cycle); for (int i = 0; i < all.length; i++) { donorMap.put(template.getBindPointNames().get(i) + suffix, all[i]); } } /** * Set the values in a provided map, with the bound names suffixed with * an internal iteration value. * * @param donorMap an existing {@link Map} of {@link String} to {@link Object} * @param input the base cycle for which values should be generated * @param count the number of iterations to to generate values and keynames for */ public void setIteratedSuffixMap(Map donorMap, long input, long count) { for (int i = 0; i < count; i++) { setSuffixedMap(donorMap, input + i, String.valueOf(i)); } } /** * Generate only the values which have matching keys in the provided * map according to their bind point names, and assign them to the * map under that name. It is an error for a key name to be defined * in the map for which there is no mapper. * * @param donorMap - a user-provided Map<String,Object> * @param input - the input for which to generate the values */ public void updateMap(Map donorMap, long input) { for (String s : donorMap.keySet()) { donorMap.put(s, get(s, input)); } } /** * Generate only the values named in fieldNames, and then call the user-provided * field setter for each name and object generated. * * @param fieldSetter user-provided object that implements {@link FieldSetter}. * @param input the input for which to generate values * @param fieldName A varargs list of field names, or a String[] of names to set */ public void setNamedFields(FieldSetter fieldSetter, long input, String... fieldName) { for (String s : fieldName) { fieldSetter.setField(s, get(s, input)); } } /** * Generate all the values named in the bindings for a number of iterations, calling * a user-provided field setter for each name and object generated, with the * iteration number appended to the fieldName, but only for the named bindings. * * @param fieldSetter user-provided object that implements {@link FieldSetter} * @param input the base input value for which the objects should be generated * @param count the number of iterations to generate values and names for * @param fieldName the field names for which to generate values and names */ public void setNamedFieldsIterated(FieldSetter fieldSetter, long input, int count, String... fieldName) { for (int i = 0; i < count; i++) { for (String s : fieldName) { fieldSetter.setField(s + i, get(s, input + i)); } } } /** * Generate all the values named in the bind point names, then call the user-provided * field setter for each name and object generated. * * @param fieldSetter user-provided object that implements {@link FieldSetter} * @param input the input for which to generate values */ public void setAllFields(FieldSetter fieldSetter, long input) { Object[] all = getAll(input); for (int i = 0; i < all.length; i++) { fieldSetter.setField(template.getBindPointNames().get(i), all[i]); } } /** * Generate all the values named in the bindings for a number of iterations, calling * a user-provided field setter for each name and object generated, with the * iteration number appended to the fieldName. * * @param fieldSetter user-provided object that implements {@link FieldSetter} * @param input the base input value for which the objects should be generated * @param count the number of iterations to generate values and names for */ public void setAllFieldsIterated(FieldSetter fieldSetter, long input, int count) { for (int i = 0; i < count; i++) { Object[] all = getAll(input+i); for (int j = 0; j < all.length; j++) { fieldSetter.setField(template.getBindPointNames().get(i) + i, all[i]); } } } public LazyValuesMap getLazyMap(long input) { return new LazyValuesMap(this, input); } public static interface FieldSetter { void setField(String name, Object value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy