Package cascading.util

Source Code of cascading.util.Util

/*
* Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved.
*
* Project and contact information: http://www.cascading.org/
*
* This file is part of the Cascading project.
*
* 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 cascading.util;

import java.beans.Expression;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;

import cascading.CascadingException;
import cascading.flow.FlowElement;
import cascading.flow.FlowException;
import cascading.flow.planner.Scope;
import cascading.operation.Operation;
import cascading.pipe.Pipe;
import cascading.scheme.Scheme;
import cascading.tap.MultiSourceTap;
import cascading.tap.Tap;
import cascading.tuple.coerce.Coercions;
import org.jgrapht.DirectedGraph;
import org.jgrapht.ext.ComponentAttributeProvider;
import org.jgrapht.ext.DOTExporter;
import org.jgrapht.ext.EdgeNameProvider;
import org.jgrapht.ext.IntegerNameProvider;
import org.jgrapht.ext.MatrixExporter;
import org.jgrapht.ext.VertexNameProvider;
import org.jgrapht.graph.SimpleDirectedGraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Class Util provides reusable operations. */
public class Util
  {
  /**
   * On OS X only, and if the graphviz dot binary is installed, when true, dot will be invoked to convert the dot file
   * to a pdf document.
   */
  public static final String CONVERT_DOT_TO_PDF = "util.dot.to.pdf.enabled";
  public static int ID_LENGTH = 32;

  private static final Logger LOG = LoggerFactory.getLogger( Util.class );
  private static final String HEXES = "0123456789ABCDEF";

  public static final boolean IS_OSX = System.getProperty( "os.name" ).toLowerCase().contains( "Mac OS X".toLowerCase() );
  public static final boolean HAS_DOT_EXEC = IS_OSX && Boolean.getBoolean( CONVERT_DOT_TO_PDF ) && hasDOT();

  public static <K, V> HashMap<K, V> createHashMap()
    {
    return new HashMap<K, V>();
    }

  public static <K, V> boolean reverseMap( Map<V, K> from, Map<K, V> to )
    {
    boolean dupes = false;

    for( Map.Entry<V, K> entry : from.entrySet() )
      dupes |= to.put( entry.getValue(), entry.getKey() ) != null;

    return dupes;
    }

  public static <V> V getFirst( Collection<V> collection )
    {
    if( collection == null || collection.isEmpty() )
      return null;

    return collection.iterator().next();
    }

  public static <N extends Number> N max( Collection<N> collection )
    {
    return new TreeSet<>( collection ).first();
    }

  public static <N extends Number> N min( Collection<N> collection )
    {
    return new TreeSet<>( collection ).last();
    }

  public static <T> Set<T> narrowSet( Class<T> type, Collection collection )
    {
    return narrowSet( type, collection.iterator() );
    }

  public static <T> Set<T> narrowSet( Class<T> type, Iterator iterator )
    {
    Set<T> set = new HashSet<>();

    while( iterator.hasNext() )
      {
      Object o = iterator.next();

      if( type.isInstance( o ) )
        set.add( (T) o );
      }

    return set;
    }

  public static synchronized String createUniqueID()
    {
    // creates a cryptographically secure random value
    String value = UUID.randomUUID().toString();
    return value.toUpperCase().replaceAll( "-", "" );
    }

  public static String createID( String rawID )
    {
    return createID( rawID.getBytes() );
    }

  /**
   * Method CreateID returns a HEX hash of the given bytes with length 32 characters long.
   *
   * @param bytes the bytes
   * @return string
   */
  public static String createID( byte[] bytes )
    {
    try
      {
      return getHex( MessageDigest.getInstance( "MD5" ).digest( bytes ) );
      }
    catch( NoSuchAlgorithmException exception )
      {
      throw new RuntimeException( "unable to digest string" );
      }
    }

  private static String getHex( byte[] bytes )
    {
    if( bytes == null )
      return null;

    final StringBuilder hex = new StringBuilder( 2 * bytes.length );

    for( final byte b : bytes )
      hex.append( HEXES.charAt( ( b & 0xF0 ) >> 4 ) ).append( HEXES.charAt( b & 0x0F ) );

    return hex.toString();
    }

  public static <T> T[] copy( T[] source )
    {
    if( source == null )
      return null;

    return Arrays.copyOf( source, source.length );
    }

  public static String unique( String value, String delim )
    {
    String[] split = value.split( delim );

    Set<String> values = new LinkedHashSet<String>();

    Collections.addAll( values, split );

    return join( values, delim );
    }

  /**
   * This method joins the values in the given list with the delim String value.
   *
   * @param list
   * @param delim
   * @return String
   */
  public static String join( int[] list, String delim )
    {
    return join( list, delim, false );
    }

  public static String join( int[] list, String delim, boolean printNull )
    {
    StringBuffer buffer = new StringBuffer();
    int count = 0;

    for( Object s : list )
      {
      if( count != 0 )
        buffer.append( delim );

      if( printNull || s != null )
        buffer.append( s );

      count++;
      }

    return buffer.toString();
    }

  public static String join( String delim, String... strings )
    {
    return join( delim, false, strings );
    }

  public static String join( String delim, boolean printNull, String... strings )
    {
    return join( strings, delim, printNull );
    }

  /**
   * This method joins the values in the given list with the delim String value.
   *
   * @param list
   * @param delim
   * @return a String
   */
  public static String join( Object[] list, String delim )
    {
    return join( list, delim, false );
    }

  public static String join( Object[] list, String delim, boolean printNull )
    {
    return join( list, delim, printNull, 0 );
    }

  public static String join( Object[] list, String delim, boolean printNull, int beginAt )
    {
    return join( list, delim, printNull, beginAt, list.length - beginAt );
    }

  public static String join( Object[] list, String delim, boolean printNull, int beginAt, int length )
    {
    StringBuffer buffer = new StringBuffer();
    int count = 0;

    for( int i = beginAt; i < beginAt + length; i++ )
      {
      Object s = list[ i ];
      if( count != 0 )
        buffer.append( delim );

      if( printNull || s != null )
        buffer.append( s );

      count++;
      }

    return buffer.toString();
    }

  public static String join( Iterable iterable, String delim, boolean printNull )
    {
    int count = 0;

    StringBuilder buffer = new StringBuilder();

    for( Object s : iterable )
      {
      if( count != 0 )
        buffer.append( delim );

      if( printNull || s != null )
        buffer.append( s );

      count++;
      }

    return buffer.toString();
    }

  /**
   * This method joins each value in the collection with a tab character as the delimiter.
   *
   * @param collection
   * @return a String
   */
  public static String join( Collection collection )
    {
    return join( collection, "\t" );
    }

  /**
   * This method joins each valuein the collection with the given delimiter.
   *
   * @param collection
   * @param delim
   * @return a String
   */
  public static String join( Collection collection, String delim )
    {
    return join( collection, delim, false );
    }

  public static String join( Collection collection, String delim, boolean printNull )
    {
    StringBuffer buffer = new StringBuffer();

    join( buffer, collection, delim, printNull );

    return buffer.toString();
    }

  /**
   * This method joins each value in the collection with the given delimiter. All results are appended to the
   * given {@link StringBuffer} instance.
   *
   * @param buffer
   * @param collection
   * @param delim
   */
  public static void join( StringBuffer buffer, Collection collection, String delim )
    {
    join( buffer, collection, delim, false );
    }

  public static void join( StringBuffer buffer, Collection collection, String delim, boolean printNull )
    {
    int count = 0;

    for( Object s : collection )
      {
      if( count != 0 )
        buffer.append( delim );

      if( printNull || s != null )
        buffer.append( s );

      count++;
      }
    }

  public static <T> List<T> split( Class<T> type, String values )
    {
    return split( type, ",", values );
    }

  public static <T> List<T> split( Class<T> type, String delim, String values )
    {
    String[] split = values.split( delim );

    List<T> results = new ArrayList<>();

    for( String value : split )
      results.add( Coercions.<T>coerce( value, type ) );

    return results;
    }

  public static String[] removeNulls( String... strings )
    {
    List<String> list = new ArrayList<String>();

    for( String string : strings )
      {
      if( string != null )
        list.add( string );
      }

    return list.toArray( new String[ list.size() ] );
    }

  public static Collection<String> quote( Collection<String> collection, String quote )
    {
    List<String> list = new ArrayList<String>();

    for( String string : collection )
      list.add( quote + string + quote );

    return list;
    }

  public static String print( Collection collection, String delim )
    {
    StringBuffer buffer = new StringBuffer();

    print( buffer, collection, delim );

    return buffer.toString();
    }

  public static void print( StringBuffer buffer, Collection collection, String delim )
    {
    int count = 0;

    for( Object s : collection )
      {
      if( count != 0 )
        buffer.append( delim );

      buffer.append( "[" );
      buffer.append( s );
      buffer.append( "]" );

      count++;
      }
    }

  /**
   * This method attempts to remove any username and password from the given url String.
   *
   * @param url
   * @return a String
   */
  public static String sanitizeUrl( String url )
    {
    if( url == null )
      return null;

    return url.replaceAll( "(?<=//).*:.*@", "" );
    }

  /**
   * This method attempts to remove duplicate consecutive forward slashes from the given url.
   *
   * @param url
   * @return a String
   */
  public static String normalizeUrl( String url )
    {
    if( url == null )
      return null;

    return url.replaceAll( "([^:]/)/{2,}", "$1/" );
    }

  /**
   * This method returns the {@link Object#toString()} of the given object, or an empty String if the object
   * is null.
   *
   * @param object
   * @return a String
   */
  public static String toNull( Object object )
    {
    if( object == null )
      return "";

    return object.toString();
    }

  /**
   * This method truncates the given String value to the given size, but appends an ellipse ("...") if the
   * String is larger than maxSize.
   *
   * @param string
   * @param maxSize
   * @return a String
   */
  public static String truncate( String string, int maxSize )
    {
    string = toNull( string );

    if( string.length() <= maxSize )
      return string;

    return String.format( "%s...", string.subSequence( 0, maxSize - 3 ) );
    }

  public static String printGraph( SimpleDirectedGraph graph )
    {
    StringWriter writer = new StringWriter();

    printGraph( writer, graph );

    return writer.toString();
    }

  public static void printGraph( PrintStream out, SimpleDirectedGraph graph )
    {
    PrintWriter printWriter = new PrintWriter( out );

    printGraph( printWriter, graph );
    }

  public static void printGraph( String filename, SimpleDirectedGraph graph )
    {
    try
      {
      new File( filename ).getParentFile().mkdirs();
      Writer writer = new FileWriter( filename );

      try
        {
        printGraph( writer, graph );
        }
      finally
        {
        writer.close();
        }
      }
    catch( IOException exception )
      {
      LOG.error( "failed printing graph to {}, with exception: {}", filename, exception );
      }
    }

  @SuppressWarnings({"unchecked"})
  private static void printGraph( Writer writer, SimpleDirectedGraph graph )
    {
    DOTExporter dot = new DOTExporter( new IntegerNameProvider(), new VertexNameProvider()
    {
    public String getVertexName( Object object )
      {
      if( object == null )
        return "none";

      return object.toString().replaceAll( "\"", "\'" );
      }
    }, new EdgeNameProvider<Object>()
    {
    public String getEdgeName( Object object )
      {
      if( object == null )
        return "none";

      return object.toString().replaceAll( "\"", "\'" );
      }
    }
    );

    dot.export( writer, graph );
    }

  public static void printMatrix( PrintStream out, SimpleDirectedGraph<FlowElement, Scope> graph )
    {
    new MatrixExporter().exportAdjacencyMatrix( new PrintWriter( out ), graph );
    }

  /**
   * This method removes all nulls from the given List.
   *
   * @param list
   */
  @SuppressWarnings({"StatementWithEmptyBody"})
  public static void removeAllNulls( List list )
    {
    while( list.remove( null ) )
      ;
    }

  /**
   * Allows for custom trace fields on Pipe, Tap, and Scheme types
   *
   * @deprecated see {@link cascading.util.TraceUtil#setTrace(Object, String)}
   */
  @Deprecated
  public static void setTrace( Object object, String trace )
    {
    TraceUtil.setTrace( object, trace );
    }

  /**
   * @deprecated see {@link cascading.util.TraceUtil#captureDebugTrace(Object)}
   */
  @Deprecated
  public static String captureDebugTrace( Class type )
    {
    return TraceUtil.captureDebugTrace( type );
    }

  public static String formatTrace( final Pipe pipe, String message )
    {
    return TraceUtil.formatTrace( pipe, message );
    }

  /**
   * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.tap.Tap, String)}
   */
  @Deprecated
  public static String formatTrace( final Tap tap, String message )
    {
    return TraceUtil.formatTrace( tap, message );
    }

  /**
   * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.scheme.Scheme, String)}
   */
  @Deprecated
  public static String formatTrace( final Scheme scheme, String message )
    {
    return TraceUtil.formatTrace( scheme, message );
    }

  /**
   * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.operation.Operation, String)}
   */
  @Deprecated
  public static String formatTrace( Operation operation, String message )
    {
    return TraceUtil.formatTrace( operation, message );
    }

  public static void writeDOT( Writer writer, DirectedGraph graph, IntegerNameProvider vertexIdProvider, VertexNameProvider vertexNameProvider, EdgeNameProvider edgeNameProvider )
    {
    new DOTExporter( vertexIdProvider, vertexNameProvider, edgeNameProvider ).export( writer, graph );
    }

  public static void writeDOT( Writer writer, DirectedGraph graph, IntegerNameProvider vertexIdProvider, VertexNameProvider vertexNameProvider, EdgeNameProvider edgeNameProvider,
                               ComponentAttributeProvider vertexAttributeProvider, ComponentAttributeProvider edgeAttributeProvider )
    {
    new DOTExporter( vertexIdProvider, vertexNameProvider, edgeNameProvider, vertexAttributeProvider, edgeAttributeProvider ).export( writer, graph );
    }

  public static boolean isEmpty( String string )
    {
    return string == null || string.isEmpty();
    }

  private static String[] findSplitName( String path )
    {
    String separator = "/";

    if( path.lastIndexOf( "/" ) < path.lastIndexOf( "\\" ) )
      separator = "\\\\";

    String[] split = path.split( separator );

    path = split[ split.length - 1 ];

    path = path.substring( 0, path.lastIndexOf( '.' ) ); // remove .jar

    return path.split( "-(?=\\d)", 2 );
    }

  public static String findVersion( String path )
    {
    if( path == null || path.isEmpty() )
      return null;

    String[] split = findSplitName( path );

    if( split.length == 2 )
      return split[ 1 ];

    return null;
    }

  public static String findName( String path )
    {
    if( path == null || path.isEmpty() )
      return null;

    String[] split = findSplitName( path );

    if( split.length == 0 )
      return null;

    return split[ 0 ];
    }

  public static long getSourceModified( Object confCopy, Iterator<Tap> values, long sinkModified ) throws IOException
    {
    long sourceModified = 0;

    while( values.hasNext() )
      {
      Tap source = values.next();

      if( source instanceof MultiSourceTap )
        return getSourceModified( confCopy, ( (MultiSourceTap) source ).getChildTaps(), sinkModified );

      sourceModified = source.getModifiedTime( confCopy );

      // source modified returns zero if does not exist
      // this should minimize number of times we touch any file meta-data server
      if( sourceModified == 0 && !source.resourceExists( confCopy ) )
        throw new FlowException( "source does not exist: " + source );

      if( sinkModified < sourceModified )
        return sourceModified;
      }

    return sourceModified;
    }

  public static long getSinkModified( Object config, Collection<Tap> sinks ) throws IOException
    {
    long sinkModified = Long.MAX_VALUE;

    for( Tap sink : sinks )
      {
      if( sink.isReplace() || sink.isUpdate() )
        sinkModified = -1L;
      else
        {
        if( !sink.resourceExists( config ) )
          sinkModified = 0L;
        else
          sinkModified = Math.min( sinkModified, sink.getModifiedTime( config ) ); // return youngest mod date
        }
      }
    return sinkModified;
    }

  public static String getTypeName( Type type )
    {
    if( type == null )
      return null;

    return type instanceof Class ? ( (Class) type ).getCanonicalName() : type.toString();
    }

  public static String getSimpleTypeName( Type type )
    {
    if( type == null )
      return null;

    return type instanceof Class ? ( (Class) type ).getSimpleName() : type.toString();
    }

  public static String[] typeNames( Type[] types )
    {
    String[] names = new String[ types.length ];

    for( int i = 0; i < types.length; i++ )
      names[ i ] = getTypeName( types[ i ] );

    return names;
    }

  public static String[] simpleTypeNames( Type[] types )
    {
    String[] names = new String[ types.length ];

    for( int i = 0; i < types.length; i++ )
      names[ i ] = getSimpleTypeName( types[ i ] );

    return names;
    }

  public static boolean containsNull( Object[] values )
    {
    for( Object value : values )
      {
      if( value == null )
        return true;
      }

    return false;
    }

  public static void safeSleep( long durationMillis )
    {
    try
      {
      Thread.sleep( durationMillis );
      }
    catch( InterruptedException exception )
      {
      // do nothing
      }
    }

  public static void writePDF( String path )
    {
    if( !HAS_DOT_EXEC )
      return;

    // dot *.dot -Tpdf -O -Nshape=box
    File file = new File( path );
    execProcess( file.getParentFile(), "dot", file.getName(), "-Tpdf", "-O" );
    }

  static boolean hasDOT()
    {
    return execProcess( null, "which", "dot" ) == 0;
    }

  public static int execProcess( File parentFile, String... command )
    {
    try
      {
      String commandLine = join( command, " " );

      LOG.debug( "command: {}", commandLine );

      Process process = Runtime.getRuntime().exec( commandLine, null, parentFile );

      int result = process.waitFor();

      BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );

      String line = reader.readLine();

      while( line != null )
        {
        LOG.warn( "{} stdout returned: {}", command[ 0 ], line );
        line = reader.readLine();
        }

      reader = new BufferedReader( new InputStreamReader( process.getErrorStream() ) );

      line = reader.readLine();

      while( line != null )
        {
        LOG.warn( "{} stderr returned: {}", command[ 0 ], line );
        line = reader.readLine();
        }

      return result;
      }
    catch( IOException exception )
      {
      LOG.warn( "unable to exec " + command[ 0 ], exception );
      }
    catch( InterruptedException exception )
      {
      LOG.warn( "interrupted exec " + command[ 0 ], exception );
      }

    return Integer.MIN_VALUE;
    }

  public static String formatDurationFromMillis( long duration )
    {
    if( duration / 1000 / 60 / 60 / 24 > 0.0 )
      return formatDurationDHMSms( duration );
    if( duration / 1000 / 60 / 60 > 0.0 )
      return formatDurationHMSms( duration );
    else
      return formatDurationMSms( duration );
    }

  public static String formatDurationMSms( long duration )
    {
    long ms = duration % 1000;
    long durationSeconds = duration / 1000;
    long seconds = durationSeconds % 60;
    long minutes = durationSeconds / 60;

    return String.format( "%02d:%02d.%03d", minutes, seconds, ms );
    }

  public static String formatDurationHMSms( long duration )
    {
    long ms = duration % 1000;
    long durationSeconds = duration / 1000;
    long seconds = durationSeconds % 60;
    long minutes = ( durationSeconds / 60 ) % 60;
    long hours = durationSeconds / 60 / 60;

    return String.format( "%02d:%02d:%02d.%03d", hours, minutes, seconds, ms );
    }

  public static String formatDurationDHMSms( long duration )
    {
    long ms = duration % 1000;
    long durationSeconds = duration / 1000;
    long seconds = durationSeconds % 60;
    long minutes = ( durationSeconds / 60 ) % 60;
    long hours = ( durationSeconds / 60 / 60 ) % 24;
    long days = durationSeconds / 60 / 60 / 24;

    return String.format( "%02d:%02d:%02d:%02d.%03d", days, hours, minutes, seconds, ms );
    }

  /**
   * Converts a given comma separated String of Exception names into a List of classes.
   * ClassNotFound exceptions are ignored if no warningMessage is given, otherwise logged as a warning.
   *
   * @param classNames A comma separated String of Exception names.
   * @return List of Exception classes.
   */
  public static Set<Class<? extends Exception>> asClasses( String classNames, String warningMessage )
    {
    Set<Class<? extends Exception>> exceptionClasses = new HashSet<Class<? extends Exception>>();
    String[] split = classNames.split( "," );

    // possibly user provided type, load from context
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

    for( String className : split )
      {
      if( className != null )
        className = className.trim();

      if( isEmpty( className ) )
        continue;

      try
        {
        Class<? extends Exception> exceptionClass = contextClassLoader.loadClass( className ).asSubclass( Exception.class );

        exceptionClasses.add( exceptionClass );
        }
      catch( ClassNotFoundException exception )
        {
        if( !Util.isEmpty( warningMessage ) )
          LOG.warn( "{}: {}", warningMessage, className );
        }
      }

    return exceptionClasses;
    }

  public interface RetryOperator<T>
    {
    T operate() throws Exception;

    boolean rethrow( Exception exception );
    }

  public static <T> T retry( Logger logger, int retries, int secondsDelay, String message, RetryOperator<T> operator ) throws Exception
    {
    Exception saved = null;

    for( int i = 0; i < retries; i++ )
      {
      try
        {
        return operator.operate();
        }
      catch( Exception exception )
        {
        if( operator.rethrow( exception ) )
          {
          logger.warn( message + ", but not retrying", exception );

          throw exception;
          }

        saved = exception;

        logger.warn( message + ", attempt: " + ( i + 1 ), exception );

        try
          {
          Thread.sleep( secondsDelay * 1000 );
          }
        catch( InterruptedException exception1 )
          {
          // do nothing
          }
        }
      }

    logger.warn( message + ", done retrying after attempts: " + retries, saved );

    throw saved;
    }

  public static Object createProtectedObject( Class type, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      Constructor constructor = type.getDeclaredConstructor( parameterTypes );

      constructor.setAccessible( true );

      return constructor.newInstance( parameters );
      }
    catch( Exception exception )
      {
      LOG.error( "unable to instantiate type: {}, with exception: {}", type.getName(), exception );

      throw new FlowException( "unable to instantiate type: " + type.getName(), exception );
      }
    }

  public static boolean hasClass( String typeString )
    {
    try
      {
      Util.class.getClassLoader().loadClass( typeString );

      return true;
      }
    catch( ClassNotFoundException exception )
      {
      return false;
      }
    }

  public static <T> T newInstance( String className, Object... parameters )
    {
    try
      {
      Class<T> type = (Class<T>) Util.class.getClassLoader().loadClass( className );

      return newInstance( type, parameters );
      }
    catch( ClassNotFoundException exception )
      {
      throw new CascadingException( "unable to load class: " + className, exception );
      }
    }

  public static <T> T newInstance( Class<T> target, Object... parameters )
    {
    // using Expression makes sure that constructors using sub-types properly work, otherwise we get a
    // NoSuchMethodException.
    Expression expr = new Expression( target, "new", parameters );

    try
      {
      return (T) expr.getValue();
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to create new instance: " + target.getName() + "(" + Arrays.toString( parameters ) + ")", exception );
      }
    }

  public static Object invokeStaticMethod( String typeString, String methodName, Object[] parameters, Class[] parameterTypes )
    {
    Class type = loadClass( typeString );

    return invokeStaticMethod( type, methodName, parameters, parameterTypes );
    }

  public static Class<?> loadClass( String typeString )
    {
    try
      {
      return Thread.currentThread().getContextClassLoader().loadClass( typeString );
      }
    catch( ClassNotFoundException exception )
      {
      throw new CascadingException( "unable to load class: " + typeString, exception );
      }
    }

  public static Object invokeStaticMethod( Class type, String methodName, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      Method method = type.getDeclaredMethod( methodName, parameterTypes );

      method.setAccessible( true );

      return method.invoke( null, parameters );
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to invoke static method: " + type.getName() + "." + methodName, exception );
      }
    }

  public static boolean hasInstanceMethod( Object target, String methodName, Class[] parameterTypes )
    {
    try
      {
      return target.getClass().getMethod( methodName, parameterTypes ) != null;
      }
    catch( NoSuchMethodException exception )
      {
      return false;
      }
    }

  public static Object invokeInstanceMethodSafe( Object target, String methodName, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      return invokeInstanceMethod( target, methodName, parameters, parameterTypes );
      }
    catch( Exception exception )
      {
      return null;
      }
    }

  public static Object invokeInstanceMethod( Object target, String methodName, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      Method method = target.getClass().getMethod( methodName, parameterTypes );

      method.setAccessible( true );

      return method.invoke( target, parameters );
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to invoke instance method: " + target.getClass().getName() + "." + methodName, exception );
      }
    }

  public static <R> R returnInstanceFieldIfExistsSafe( Object target, String fieldName )
    {
    try
      {
      return returnInstanceFieldIfExists( target, fieldName );
      }
    catch( Exception exception )
      {
      // do nothing
      return null;
      }
    }

  public static Object invokeConstructor( String className, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      Class type = Util.class.getClassLoader().loadClass( className );

      return invokeConstructor( type, parameters, parameterTypes );
      }
    catch( ClassNotFoundException exception )
      {
      throw new CascadingException( "unable to load class: " + className, exception );
      }
    }

  public static <T> T invokeConstructor( Class<T> target, Object[] parameters, Class[] parameterTypes )
    {
    try
      {
      Constructor<T> constructor = target.getConstructor( parameterTypes );

      constructor.setAccessible( true );

      return constructor.newInstance( parameters );
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to create new instance: " + target.getName() + "(" + Arrays.toString( parameters ) + ")", exception );
      }
    }

  public static <R> R returnInstanceFieldIfExists( Object target, String fieldName )
    {
    try
      {
      Class<?> type = target.getClass();
      Field field = getDeclaredField( fieldName, type );

      field.setAccessible( true );

      return (R) field.get( target );
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to get instance field: " + target.getClass().getName() + "." + fieldName, exception );
      }
    }

  public static <R> void setInstanceFieldIfExists( Object target, String fieldName, R value )
    {
    try
      {
      Class<?> type = target.getClass();
      Field field = getDeclaredField( fieldName, type );

      field.setAccessible( true );

      field.set( target, value );
      }
    catch( Exception exception )
      {
      throw new CascadingException( "unable to set instance field: " + target.getClass().getName() + "." + fieldName, exception );
      }
    }

  private static Field getDeclaredField( String fieldName, Class<?> type )
    {
    if( type == Object.class )
      {
      if( LOG.isDebugEnabled() )
        LOG.debug( "did not find {} field on {}", fieldName, type.getName() );

      return null;
      }

    try
      {
      return type.getDeclaredField( fieldName );
      }
    catch( NoSuchFieldException exception )
      {
      return getDeclaredField( fieldName, type.getSuperclass() );
      }
    }

  @Deprecated
  public static String makeTempPath( String name )
    {
    if( name == null || name.isEmpty() )
      throw new IllegalArgumentException( "name may not be null or empty " );

    name = cleansePathName( name.substring( 0, name.length() < 25 ? name.length() : 25 ) );

    return name + "/" + (int) ( Math.random() * 100000 ) + "/";
    }

  public static String makePath( String prefix, String name )
    {
    if( name == null || name.isEmpty() )
      throw new IllegalArgumentException( "name may not be null or empty " );

    if( prefix == null || prefix.isEmpty() )
      prefix = Long.toString( (long) ( Math.random() * 10000000000L ) );

    name = cleansePathName( name.substring( 0, name.length() < 25 ? name.length() : 25 ) );

    return prefix + "/" + name + "/";
    }

  public static String cleansePathName( String name )
    {
    return name.replaceAll( "\\s+|\\*|\\+|/+", "_" );
    }

  public static Class findMainClass( Class defaultType, String packageExclude )
    {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

    for( StackTraceElement stackTraceElement : stackTrace )
      {
      if( stackTraceElement.getMethodName().equals( "main" ) && !stackTraceElement.getClassName().startsWith( packageExclude ) )
        {
        try
          {
          LOG.info( "resolving application jar from found main method on: {}", stackTraceElement.getClassName() );

          return Thread.currentThread().getContextClassLoader().loadClass( stackTraceElement.getClassName() );
          }
        catch( ClassNotFoundException exception )
          {
          LOG.warn( "unable to load class while discovering application jar: {}", stackTraceElement.getClassName(), exception );
          }
        }
      }

    LOG.info( "using default application jar, may cause class not found exceptions on the cluster" );

    return defaultType;
    }

  public static String findContainingJar( Class<?> type )
    {
    ClassLoader classLoader = type.getClassLoader();

    String classFile = type.getName().replaceAll( "\\.", "/" ) + ".class";

    try
      {
      for( Enumeration<URL> iterator = classLoader.getResources( classFile ); iterator.hasMoreElements(); )
        {
        URL url = iterator.nextElement();

        if( !"jar".equals( url.getProtocol() ) )
          continue;

        String path = url.getPath();

        if( path.startsWith( "file:" ) )
          path = path.substring( "file:".length() );

        path = URLDecoder.decode( path, "UTF-8" );

        return path.replaceAll( "!.*$", "" );
        }
      }
    catch( IOException exception )
      {
      throw new CascadingException( exception );
      }

    return null;
    }
  }
TOP

Related Classes of cascading.util.Util

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.