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

org.apache.solr.client.solrj.io.stream.expr.StreamFactory Maven / Gradle / Ivy

There is a newer version: 9.5.0
Show newest version
/*
 * 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.solr.client.solrj.io.stream.expr;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.solr.client.solrj.io.comp.ComparatorOrder;
import org.apache.solr.client.solrj.io.comp.MultipleFieldComparator;
import org.apache.solr.client.solrj.io.comp.StreamComparator;
import org.apache.solr.client.solrj.io.eq.MultipleFieldEqualitor;
import org.apache.solr.client.solrj.io.eq.StreamEqualitor;
import org.apache.solr.client.solrj.io.ops.StreamOperation;
import org.apache.solr.client.solrj.io.stream.TupleStream;
import org.apache.solr.client.solrj.io.stream.metrics.Metric;

/**
 * Used to convert strings into stream expressions
 */
public class StreamFactory implements Serializable {
  
  private transient HashMap collectionZkHosts;
  private transient HashMap functionNames;
  private transient String defaultZkHost;
  
  public StreamFactory(){
    collectionZkHosts = new HashMap();
    functionNames = new HashMap();
  }
  
  public StreamFactory withCollectionZkHost(String collectionName, String zkHost){
    this.collectionZkHosts.put(collectionName, zkHost);
    return this;
  }

  public StreamFactory withDefaultZkHost(String zkHost) {
    this.defaultZkHost = zkHost;
    return this;
  }

  public String getDefaultZkHost() {
    return this.defaultZkHost;
  }

  public String getCollectionZkHost(String collectionName){
    if(this.collectionZkHosts.containsKey(collectionName)){
      return this.collectionZkHosts.get(collectionName);
    }
    return null;
  }
  
  public Map getFunctionNames(){
    return functionNames;
  }
  public StreamFactory withFunctionName(String functionName, Class clazz){
    this.functionNames.put(functionName, clazz);
    return this;
  }
  
  public StreamExpressionParameter getOperand(StreamExpression expression, int parameterIndex){
    if(null == expression.getParameters() || parameterIndex >= expression.getParameters().size()){
      return null;
    }
    
    return expression.getParameters().get(parameterIndex);
  }
  
  /** Given an expression, will return the value parameter at the given index, or null if doesn't exist */
  public String getValueOperand(StreamExpression expression, int parameterIndex){
    StreamExpressionParameter parameter = getOperand(expression, parameterIndex);
    if(null != parameter){ 
      if(parameter instanceof StreamExpressionValue){
        return ((StreamExpressionValue)parameter).getValue();
      }
    }
    
    return null;
  }
  
  public List getNamedOperands(StreamExpression expression){
    List namedParameters = new ArrayList();
    for(StreamExpressionParameter parameter : getOperandsOfType(expression, StreamExpressionNamedParameter.class)){
      namedParameters.add((StreamExpressionNamedParameter)parameter);
    }
    
    return namedParameters;
  }
  public StreamExpressionNamedParameter getNamedOperand(StreamExpression expression, String name){
    List namedParameters = getNamedOperands(expression);
    for(StreamExpressionNamedParameter param : namedParameters){
      if(param.getName().equals(name)){
        return param;
      }
    }
    
    return null;
  }
  
  public List getExpressionOperands(StreamExpression expression){
    List namedParameters = new ArrayList();
    for(StreamExpressionParameter parameter : getOperandsOfType(expression, StreamExpression.class)){
      namedParameters.add((StreamExpression)parameter);
    }
    
    return namedParameters;
  }
  public List getExpressionOperands(StreamExpression expression, String functionName){
    List namedParameters = new ArrayList();
    for(StreamExpressionParameter parameter : getOperandsOfType(expression, StreamExpression.class)){
      StreamExpression expressionOperand = (StreamExpression)parameter;
      if(expressionOperand.getFunctionName().equals(functionName)){
        namedParameters.add(expressionOperand);
      }
    }
    
    return namedParameters;
  }
  public List getOperandsOfType(StreamExpression expression, Class ... clazzes){
    List parameters = new ArrayList();
    
    parameterLoop:
     for(StreamExpressionParameter parameter : expression.getParameters()){
      for(Class clazz : clazzes){
        if(!clazz.isAssignableFrom(parameter.getClass())){
          continue parameterLoop; // go to the next parameter since this parameter cannot be assigned to at least one of the classes
        }
      }
      
      parameters.add(parameter);
    }
    
    return parameters;
  }
  
  public List getExpressionOperandsRepresentingTypes(StreamExpression expression, Class ... clazzes){
    List matchingStreamExpressions = new ArrayList();
    List allStreamExpressions = getExpressionOperands(expression);
    
    parameterLoop:
    for(StreamExpression streamExpression : allStreamExpressions){
      if(functionNames.containsKey(streamExpression.getFunctionName())){
        for(Class clazz : clazzes){
          if(!clazz.isAssignableFrom(functionNames.get(streamExpression.getFunctionName()))){
            continue parameterLoop;
          }
        }
        
        matchingStreamExpressions.add(streamExpression);
      }
    }
    
    return matchingStreamExpressions;   
  }
  
  public TupleStream constructStream(String expressionClause) throws IOException {
    return constructStream(StreamExpressionParser.parse(expressionClause));
  }
  public TupleStream constructStream(StreamExpression expression) throws IOException{
    String function = expression.getFunctionName();
    if(functionNames.containsKey(function)){
      Class clazz = functionNames.get(function);
      if(Expressible.class.isAssignableFrom(clazz) && TupleStream.class.isAssignableFrom(clazz)){
        TupleStream stream = (TupleStream)createInstance(functionNames.get(function), new Class[]{ StreamExpression.class, StreamFactory.class }, new Object[]{ expression, this});
        return stream;
      }
    }
    
    throw new IOException(String.format(Locale.ROOT,"Invalid stream expression %s - function '%s' is unknown (not mapped to a valid TupleStream)", expression, expression.getFunctionName()));
  }
  
  public Metric constructMetric(String expressionClause) throws IOException {
    return constructMetric(StreamExpressionParser.parse(expressionClause));
  }
  public Metric constructMetric(StreamExpression expression) throws IOException{
    String function = expression.getFunctionName();
    if(functionNames.containsKey(function)){
      Class clazz = functionNames.get(function);
      if(Expressible.class.isAssignableFrom(clazz) && Metric.class.isAssignableFrom(clazz)){
        Metric metric = (Metric)createInstance(functionNames.get(function), new Class[]{ StreamExpression.class, StreamFactory.class }, new Object[]{ expression, this});
        return metric;
      }
    }
    
    throw new IOException(String.format(Locale.ROOT,"Invalid metric expression %s - function '%s' is unknown (not mapped to a valid Metric)", expression, expression.getFunctionName()));
  }

  public StreamComparator constructComparator(String comparatorString, Class comparatorType) throws IOException {
    if(comparatorString.contains(",")){
      String[] parts = comparatorString.split(",");
      StreamComparator[] comps = new StreamComparator[parts.length];
      for(int idx = 0; idx < parts.length; ++idx){
        comps[idx] = constructComparator(parts[idx].trim(), comparatorType);
      }
      return new MultipleFieldComparator(comps);
    }
    else if(comparatorString.contains("=")){
      // expected format is "left=right order"
      String[] parts = comparatorString.split("[ =]");
      
      if(parts.length < 3){
        throw new IOException(String.format(Locale.ROOT,"Invalid comparator expression %s - expecting 'left=right order'",comparatorString));
      }
      
      String leftFieldName = null;
      String rightFieldName = null;
      String order = null;
      for(String part : parts){
        // skip empty
        if(null == part || 0 == part.trim().length()){ continue; }
        
        // assign each in order
        if(null == leftFieldName){ 
          leftFieldName = part.trim(); 
        }
        else if(null == rightFieldName){ 
          rightFieldName = part.trim(); 
        }
        else if(null == order){ 
          order = part.trim();
          break; // we're done, stop looping
        }
      }
      
      if(null == leftFieldName || null == rightFieldName || null == order){
        throw new IOException(String.format(Locale.ROOT,"Invalid comparator expression %s - expecting 'left=right order'",comparatorString));
      }
      
      return (StreamComparator)createInstance(comparatorType, new Class[]{ String.class, String.class, ComparatorOrder.class }, new Object[]{ leftFieldName, rightFieldName, ComparatorOrder.fromString(order) });
    }
    else{
      // expected format is "field order"
      String[] parts = comparatorString.split(" ");
      if(2 != parts.length){
        throw new IOException(String.format(Locale.ROOT,"Invalid comparator expression %s - expecting 'field order'",comparatorString));
      }
      
      String fieldName = parts[0].trim();
      String order = parts[1].trim();
      
      return (StreamComparator)createInstance(comparatorType, new Class[]{ String.class, ComparatorOrder.class }, new Object[]{ fieldName, ComparatorOrder.fromString(order) });
    }
  }
    
  public StreamEqualitor constructEqualitor(String equalitorString, Class equalitorType) throws IOException {
    if(equalitorString.contains(",")){
      String[] parts = equalitorString.split(",");
      StreamEqualitor[] eqs = new StreamEqualitor[parts.length];
      for(int idx = 0; idx < parts.length; ++idx){
        eqs[idx] = constructEqualitor(parts[idx].trim(), equalitorType);
      }
      return new MultipleFieldEqualitor(eqs);
    }
    else{
      String leftFieldName;
      String rightFieldName;
      
      if(equalitorString.contains("=")){
        String[] parts = equalitorString.split("=");
        if(2 != parts.length){
          throw new IOException(String.format(Locale.ROOT,"Invalid equalitor expression %s - expecting fieldName=fieldName",equalitorString));
        }
        
        leftFieldName = parts[0].trim();
        rightFieldName = parts[1].trim();
      }
      else{
        leftFieldName = rightFieldName = equalitorString.trim();
      }
      
      return (StreamEqualitor)createInstance(equalitorType, new Class[]{ String.class, String.class }, new Object[]{ leftFieldName, rightFieldName });
    }
  }
  
  public Metric constructOperation(String expressionClause) throws IOException {
    return constructMetric(StreamExpressionParser.parse(expressionClause));
  }
  public StreamOperation constructOperation(StreamExpression expression) throws IOException{
    String function = expression.getFunctionName();
    if(functionNames.containsKey(function)){
      Class clazz = functionNames.get(function);
      if(Expressible.class.isAssignableFrom(clazz) && StreamOperation.class.isAssignableFrom(clazz)){
        return (StreamOperation)createInstance(functionNames.get(function), new Class[]{ StreamExpression.class, StreamFactory.class }, new Object[]{ expression, this});
      }
    }
    
    throw new IOException(String.format(Locale.ROOT,"Invalid operation expression %s - function '%s' is unknown (not mapped to a valid StreamOperation)", expression, expression.getFunctionName()));
  }


  public  T createInstance(Class clazz, Class[] paramTypes, Object[] params) throws IOException{
    Constructor ctor;
    try {
      ctor = clazz.getConstructor(paramTypes);
      return ctor.newInstance(params);
      
    } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      if(null != e.getMessage()){
        throw new IOException(String.format(Locale.ROOT,"Unable to construct instance of %s caused by %s", clazz.getName(), e.getMessage()),e);
      }
      else{
        throw new IOException(String.format(Locale.ROOT,"Unable to construct instance of %s", clazz.getName()),e);
      }
    }
  }
  
  public String getFunctionName(Class clazz) throws IOException{
    for(Entry entry : functionNames.entrySet()){
      if(entry.getValue() == clazz){
        return entry.getKey();
      }
    }
    
    throw new IOException(String.format(Locale.ROOT, "Unable to find function name for class '%s'", clazz.getName()));
  }
  
  public Object constructPrimitiveObject(String original){
    String lower = original.trim().toLowerCase(Locale.ROOT);
    
    if("null".equals(lower)){ return null; }
    if("true".equals(lower) || "false".equals(lower)){ return Boolean.parseBoolean(lower); }
    try{ return Long.valueOf(original); } catch(Exception e){};
    try{ if (original.matches(".{1,8}")){ return Float.valueOf(original); }} catch(Exception e){};
    try{ if (original.matches(".{1,17}")){ return Double.valueOf(original); }} catch(Exception e){};
    
    // is a string
    return original;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy