001 /* 002 * Copyright (c) 2007-2015 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.util; 022 023 import java.beans.Expression; 024 import java.io.FileWriter; 025 import java.io.IOException; 026 import java.io.PrintStream; 027 import java.io.PrintWriter; 028 import java.io.StringWriter; 029 import java.io.Writer; 030 import java.lang.reflect.Constructor; 031 import java.lang.reflect.Field; 032 import java.lang.reflect.Method; 033 import java.lang.reflect.Type; 034 import java.security.MessageDigest; 035 import java.security.NoSuchAlgorithmException; 036 import java.util.ArrayList; 037 import java.util.Arrays; 038 import java.util.Collection; 039 import java.util.Collections; 040 import java.util.HashSet; 041 import java.util.Iterator; 042 import java.util.LinkedHashSet; 043 import java.util.List; 044 import java.util.Set; 045 import java.util.UUID; 046 import java.util.regex.Pattern; 047 048 import cascading.CascadingException; 049 import cascading.flow.FlowElement; 050 import cascading.flow.FlowException; 051 import cascading.flow.planner.Scope; 052 import cascading.operation.Operation; 053 import cascading.pipe.Pipe; 054 import cascading.scheme.Scheme; 055 import cascading.tap.MultiSourceTap; 056 import cascading.tap.Tap; 057 import org.jgrapht.ext.DOTExporter; 058 import org.jgrapht.ext.EdgeNameProvider; 059 import org.jgrapht.ext.IntegerNameProvider; 060 import org.jgrapht.ext.MatrixExporter; 061 import org.jgrapht.ext.VertexNameProvider; 062 import org.jgrapht.graph.SimpleDirectedGraph; 063 import org.slf4j.Logger; 064 import org.slf4j.LoggerFactory; 065 066 /** Class Util provides reusable operations. */ 067 public class Util 068 { 069 public static int ID_LENGTH = 32; 070 071 private static final Logger LOG = LoggerFactory.getLogger( Util.class ); 072 private static final String HEXES = "0123456789ABCDEF"; 073 074 public static synchronized String createUniqueID() 075 { 076 // creates a cryptographically secure random value 077 String value = UUID.randomUUID().toString(); 078 return value.toUpperCase().replaceAll( "-", "" ); 079 } 080 081 public static String createID( String rawID ) 082 { 083 return createID( rawID.getBytes() ); 084 } 085 086 /** 087 * Method CreateID returns a HEX hash of the given bytes with length 32 characters long. 088 * 089 * @param bytes the bytes 090 * @return string 091 */ 092 public static String createID( byte[] bytes ) 093 { 094 try 095 { 096 return getHex( MessageDigest.getInstance( "MD5" ).digest( bytes ) ); 097 } 098 catch( NoSuchAlgorithmException exception ) 099 { 100 throw new RuntimeException( "unable to digest string" ); 101 } 102 } 103 104 private static String getHex( byte[] bytes ) 105 { 106 if( bytes == null ) 107 return null; 108 109 final StringBuilder hex = new StringBuilder( 2 * bytes.length ); 110 111 for( final byte b : bytes ) 112 hex.append( HEXES.charAt( ( b & 0xF0 ) >> 4 ) ).append( HEXES.charAt( b & 0x0F ) ); 113 114 return hex.toString(); 115 } 116 117 public static <T> T[] copy( T[] source ) 118 { 119 if( source == null ) 120 return null; 121 122 return Arrays.copyOf( source, source.length ); 123 } 124 125 public static String unique( String value, String delim ) 126 { 127 String[] split = value.split( delim ); 128 129 Set<String> values = new LinkedHashSet<String>(); 130 131 Collections.addAll( values, split ); 132 133 return join( values, delim ); 134 } 135 136 /** 137 * This method joins the values in the given list with the delim String value. 138 * 139 * @param list 140 * @param delim 141 * @return String 142 */ 143 public static String join( int[] list, String delim ) 144 { 145 return join( list, delim, false ); 146 } 147 148 public static String join( int[] list, String delim, boolean printNull ) 149 { 150 StringBuffer buffer = new StringBuffer(); 151 int count = 0; 152 153 for( Object s : list ) 154 { 155 if( count != 0 ) 156 buffer.append( delim ); 157 158 if( printNull || s != null ) 159 buffer.append( s ); 160 161 count++; 162 } 163 164 return buffer.toString(); 165 } 166 167 public static String join( String delim, String... strings ) 168 { 169 return join( delim, false, strings ); 170 } 171 172 public static String join( String delim, boolean printNull, String... strings ) 173 { 174 return join( strings, delim, printNull ); 175 } 176 177 /** 178 * This method joins the values in the given list with the delim String value. 179 * 180 * @param list 181 * @param delim 182 * @return a String 183 */ 184 public static String join( Object[] list, String delim ) 185 { 186 return join( list, delim, false ); 187 } 188 189 public static String join( Object[] list, String delim, boolean printNull ) 190 { 191 return join( list, delim, printNull, 0 ); 192 } 193 194 public static String join( Object[] list, String delim, boolean printNull, int beginAt ) 195 { 196 return join( list, delim, printNull, beginAt, list.length - beginAt ); 197 } 198 199 public static String join( Object[] list, String delim, boolean printNull, int beginAt, int length ) 200 { 201 StringBuffer buffer = new StringBuffer(); 202 int count = 0; 203 204 for( int i = beginAt; i < beginAt + length; i++ ) 205 { 206 Object s = list[ i ]; 207 if( count != 0 ) 208 buffer.append( delim ); 209 210 if( printNull || s != null ) 211 buffer.append( s ); 212 213 count++; 214 } 215 216 return buffer.toString(); 217 } 218 219 public static String join( Iterable iterable, String delim, boolean printNull ) 220 { 221 int count = 0; 222 223 StringBuilder buffer = new StringBuilder(); 224 225 for( Object s : iterable ) 226 { 227 if( count != 0 ) 228 buffer.append( delim ); 229 230 if( printNull || s != null ) 231 buffer.append( s ); 232 233 count++; 234 } 235 236 return buffer.toString(); 237 } 238 239 /** 240 * This method joins each value in the collection with a tab character as the delimiter. 241 * 242 * @param collection 243 * @return a String 244 */ 245 public static String join( Collection collection ) 246 { 247 return join( collection, "\t" ); 248 } 249 250 /** 251 * This method joins each valuein the collection with the given delimiter. 252 * 253 * @param collection 254 * @param delim 255 * @return a String 256 */ 257 public static String join( Collection collection, String delim ) 258 { 259 return join( collection, delim, false ); 260 } 261 262 public static String join( Collection collection, String delim, boolean printNull ) 263 { 264 StringBuffer buffer = new StringBuffer(); 265 266 join( buffer, collection, delim, printNull ); 267 268 return buffer.toString(); 269 } 270 271 /** 272 * This method joins each value in the collection with the given delimiter. All results are appended to the 273 * given {@link StringBuffer} instance. 274 * 275 * @param buffer 276 * @param collection 277 * @param delim 278 */ 279 public static void join( StringBuffer buffer, Collection collection, String delim ) 280 { 281 join( buffer, collection, delim, false ); 282 } 283 284 public static void join( StringBuffer buffer, Collection collection, String delim, boolean printNull ) 285 { 286 int count = 0; 287 288 for( Object s : collection ) 289 { 290 if( count != 0 ) 291 buffer.append( delim ); 292 293 if( printNull || s != null ) 294 buffer.append( s ); 295 296 count++; 297 } 298 } 299 300 public static String[] removeNulls( String... strings ) 301 { 302 List<String> list = new ArrayList<String>(); 303 304 for( String string : strings ) 305 { 306 if( string != null ) 307 list.add( string ); 308 } 309 310 return list.toArray( new String[ list.size() ] ); 311 } 312 313 public static Collection<String> quote( Collection<String> collection, String quote ) 314 { 315 List<String> list = new ArrayList<String>(); 316 317 for( String string : collection ) 318 list.add( quote + string + quote ); 319 320 return list; 321 } 322 323 public static String print( Collection collection, String delim ) 324 { 325 StringBuffer buffer = new StringBuffer(); 326 327 print( buffer, collection, delim ); 328 329 return buffer.toString(); 330 } 331 332 public static void print( StringBuffer buffer, Collection collection, String delim ) 333 { 334 int count = 0; 335 336 for( Object s : collection ) 337 { 338 if( count != 0 ) 339 buffer.append( delim ); 340 341 buffer.append( "[" ); 342 buffer.append( s ); 343 buffer.append( "]" ); 344 345 count++; 346 } 347 } 348 349 /** 350 * This method attempts to remove any username and password from the given url String. 351 * 352 * @param url 353 * @return a String 354 */ 355 public static String sanitizeUrl( String url ) 356 { 357 if( url == null ) 358 return null; 359 360 return url.replaceAll( "(?<=//).*:.*@", "" ); 361 } 362 363 /** 364 * This method attempts to remove duplicate consecutive forward slashes from the given url. 365 * 366 * @param url 367 * @return a String 368 */ 369 public static String normalizeUrl( String url ) 370 { 371 if( url == null ) 372 return null; 373 374 return url.replaceAll( "([^:]/)/{2,}", "$1/" ); 375 } 376 377 /** 378 * This method returns the {@link Object#toString()} of the given object, or an empty String if the object 379 * is null. 380 * 381 * @param object 382 * @return a String 383 */ 384 public static String toNull( Object object ) 385 { 386 if( object == null ) 387 return ""; 388 389 return object.toString(); 390 } 391 392 /** 393 * This method truncates the given String value to the given size, but appends an ellipse ("...") if the 394 * String is larger than maxSize. 395 * 396 * @param string 397 * @param maxSize 398 * @return a String 399 */ 400 public static String truncate( String string, int maxSize ) 401 { 402 string = toNull( string ); 403 404 if( string.length() <= maxSize ) 405 return string; 406 407 return String.format( "%s...", string.subSequence( 0, maxSize - 3 ) ); 408 } 409 410 public static String printGraph( SimpleDirectedGraph graph ) 411 { 412 StringWriter writer = new StringWriter(); 413 414 printGraph( writer, graph ); 415 416 return writer.toString(); 417 } 418 419 public static void printGraph( PrintStream out, SimpleDirectedGraph graph ) 420 { 421 PrintWriter printWriter = new PrintWriter( out ); 422 423 printGraph( printWriter, graph ); 424 } 425 426 public static void printGraph( String filename, SimpleDirectedGraph graph ) 427 { 428 try 429 { 430 Writer writer = new FileWriter( filename ); 431 432 try 433 { 434 printGraph( writer, graph ); 435 } 436 finally 437 { 438 writer.close(); 439 } 440 } 441 catch( IOException exception ) 442 { 443 LOG.error( "failed printing graph to {}, with exception: {}", filename, exception ); 444 } 445 } 446 447 @SuppressWarnings( {"unchecked"} ) 448 private static void printGraph( Writer writer, SimpleDirectedGraph graph ) 449 { 450 DOTExporter dot = new DOTExporter( new IntegerNameProvider(), new VertexNameProvider() 451 { 452 public String getVertexName( Object object ) 453 { 454 if( object == null ) 455 return "none"; 456 457 return object.toString().replaceAll( "\"", "\'" ); 458 } 459 }, new EdgeNameProvider<Object>() 460 { 461 public String getEdgeName( Object object ) 462 { 463 if( object == null ) 464 return "none"; 465 466 return object.toString().replaceAll( "\"", "\'" ); 467 } 468 } 469 ); 470 471 dot.export( writer, graph ); 472 } 473 474 public static void printMatrix( PrintStream out, SimpleDirectedGraph<FlowElement, Scope> graph ) 475 { 476 new MatrixExporter().exportAdjacencyMatrix( new PrintWriter( out ), graph ); 477 } 478 479 /** 480 * This method removes all nulls from the given List. 481 * 482 * @param list 483 */ 484 @SuppressWarnings( {"StatementWithEmptyBody"} ) 485 public static void removeAllNulls( List list ) 486 { 487 while( list.remove( null ) ) 488 ; 489 } 490 491 /** 492 * Allows for custom trace fields on Pipe, Tap, and Scheme types 493 * 494 * @deprecated see {@link cascading.util.TraceUtil#setTrace(Object, String)} 495 */ 496 @Deprecated 497 public static void setTrace( Object object, String trace ) 498 { 499 TraceUtil.setTrace( object, trace ); 500 } 501 502 /** 503 * @deprecated see {@link cascading.util.TraceUtil#captureDebugTrace(Object)} 504 */ 505 @Deprecated 506 public static String captureDebugTrace( Class type ) 507 { 508 return TraceUtil.captureDebugTrace( type ); 509 } 510 511 @Deprecated 512 public static String formatTrace( final Pipe pipe, String message ) 513 { 514 return TraceUtil.formatTrace( pipe, message ); 515 } 516 517 /** 518 * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.tap.Tap, String)} 519 */ 520 @Deprecated 521 public static String formatTrace( final Tap tap, String message ) 522 { 523 return TraceUtil.formatTrace( tap, message ); 524 } 525 526 /** 527 * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.scheme.Scheme, String)} 528 */ 529 @Deprecated 530 public static String formatTrace( final Scheme scheme, String message ) 531 { 532 return TraceUtil.formatTrace( scheme, message ); 533 } 534 535 /** 536 * @deprecated see {@link cascading.util.TraceUtil#formatTrace(cascading.operation.Operation, String)} 537 */ 538 @Deprecated 539 public static String formatTrace( Operation operation, String message ) 540 { 541 return TraceUtil.formatTrace( operation, message ); 542 } 543 544 public static void writeDOT( Writer writer, SimpleDirectedGraph graph, IntegerNameProvider vertexIdProvider, VertexNameProvider vertexNameProvider, EdgeNameProvider edgeNameProvider ) 545 { 546 new DOTExporter( vertexIdProvider, vertexNameProvider, edgeNameProvider ).export( writer, graph ); 547 } 548 549 public static boolean isEmpty( String string ) 550 { 551 return string == null || string.isEmpty(); 552 } 553 554 private static String[] findSplitName( String path ) 555 { 556 String separator = "/"; 557 558 if( path.lastIndexOf( "/" ) < path.lastIndexOf( "\\" ) ) 559 separator = "\\\\"; 560 561 String[] split = path.split( separator ); 562 563 path = split[ split.length - 1 ]; 564 565 path = path.substring( 0, path.lastIndexOf( '.' ) ); // remove .jar 566 567 return path.split( "-(?=\\d)", 2 ); 568 } 569 570 public static String findVersion( String path ) 571 { 572 if( path == null || path.isEmpty() ) 573 return null; 574 575 String[] split = findSplitName( path ); 576 577 if( split.length == 2 ) 578 return split[ 1 ]; 579 580 return null; 581 } 582 583 public static String findName( String path ) 584 { 585 if( path == null || path.isEmpty() ) 586 return null; 587 588 String[] split = findSplitName( path ); 589 590 if( split.length == 0 ) 591 return null; 592 593 return split[ 0 ]; 594 } 595 596 public static long getSourceModified( Object confCopy, Iterator<Tap> values, long sinkModified ) throws IOException 597 { 598 long sourceModified = 0; 599 600 while( values.hasNext() ) 601 { 602 Tap source = values.next(); 603 604 if( source instanceof MultiSourceTap ) 605 return getSourceModified( confCopy, ( (MultiSourceTap) source ).getChildTaps(), sinkModified ); 606 607 sourceModified = source.getModifiedTime( confCopy ); 608 609 // source modified returns zero if does not exist 610 // this should minimize number of times we touch any file meta-data server 611 if( sourceModified == 0 && !source.resourceExists( confCopy ) ) 612 throw new FlowException( "source does not exist: " + source ); 613 614 if( sinkModified < sourceModified ) 615 return sourceModified; 616 } 617 618 return sourceModified; 619 } 620 621 public static long getSinkModified( Object config, Collection<Tap> sinks ) throws IOException 622 { 623 long sinkModified = Long.MAX_VALUE; 624 625 for( Tap sink : sinks ) 626 { 627 if( sink.isReplace() || sink.isUpdate() ) 628 sinkModified = -1L; 629 else 630 { 631 if( !sink.resourceExists( config ) ) 632 sinkModified = 0L; 633 else 634 sinkModified = Math.min( sinkModified, sink.getModifiedTime( config ) ); // return youngest mod date 635 } 636 } 637 return sinkModified; 638 } 639 640 public static String getTypeName( Type type ) 641 { 642 if( type == null ) 643 return null; 644 645 return type instanceof Class ? ( (Class) type ).getCanonicalName() : type.toString(); 646 } 647 648 public static String getSimpleTypeName( Type type ) 649 { 650 if( type == null ) 651 return null; 652 653 return type instanceof Class ? ( (Class) type ).getSimpleName() : type.toString(); 654 } 655 656 public static String[] typeNames( Type[] types ) 657 { 658 String[] names = new String[ types.length ]; 659 660 for( int i = 0; i < types.length; i++ ) 661 names[ i ] = getTypeName( types[ i ] ); 662 663 return names; 664 } 665 666 public static String[] simpleTypeNames( Type[] types ) 667 { 668 String[] names = new String[ types.length ]; 669 670 for( int i = 0; i < types.length; i++ ) 671 names[ i ] = getSimpleTypeName( types[ i ] ); 672 673 return names; 674 } 675 676 public static boolean containsNull( Object[] values ) 677 { 678 for( Object value : values ) 679 { 680 if( value == null ) 681 return true; 682 } 683 684 return false; 685 } 686 687 public static void safeSleep( long durationMillis ) 688 { 689 try 690 { 691 Thread.sleep( durationMillis ); 692 } 693 catch( InterruptedException exception ) 694 { 695 // do nothing 696 } 697 } 698 699 /** 700 * Converts a given comma separated String of Exception names into a List of classes. 701 * ClassNotFound exceptions are ignored if no warningMessage is given, otherwise logged as a warning. 702 * 703 * @param classNames A comma separated String of Exception names. 704 * @return List of Exception classes. 705 */ 706 public static Set<Class<? extends Exception>> asClasses( String classNames, String warningMessage ) 707 { 708 Set<Class<? extends Exception>> exceptionClasses = new HashSet<Class<? extends Exception>>(); 709 String[] split = classNames.split( "," ); 710 711 // possibly user provided type, load from context 712 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 713 714 for( String className : split ) 715 { 716 if( className != null ) 717 className = className.trim(); 718 719 if( isEmpty( className ) ) 720 continue; 721 722 try 723 { 724 Class<? extends Exception> exceptionClass = contextClassLoader.loadClass( className ).asSubclass( Exception.class ); 725 726 exceptionClasses.add( exceptionClass ); 727 } 728 catch( ClassNotFoundException exception ) 729 { 730 if( !Util.isEmpty( warningMessage ) ) 731 LOG.warn( "{}: {}", warningMessage, className ); 732 } 733 } 734 735 return exceptionClasses; 736 } 737 738 public interface RetryOperator<T> 739 { 740 T operate() throws Exception; 741 742 boolean rethrow( Exception exception ); 743 } 744 745 public static <T> T retry( Logger logger, int retries, int secondsDelay, String message, RetryOperator<T> operator ) throws Exception 746 { 747 Exception saved = null; 748 749 for( int i = 0; i < retries; i++ ) 750 { 751 try 752 { 753 return operator.operate(); 754 } 755 catch( Exception exception ) 756 { 757 if( operator.rethrow( exception ) ) 758 { 759 logger.warn( message + ", but not retrying", exception ); 760 761 throw exception; 762 } 763 764 saved = exception; 765 766 logger.warn( message + ", attempt: " + ( i + 1 ), exception ); 767 768 try 769 { 770 Thread.sleep( secondsDelay * 1000 ); 771 } 772 catch( InterruptedException exception1 ) 773 { 774 // do nothing 775 } 776 } 777 } 778 779 logger.warn( message + ", done retrying after attempts: " + retries, saved ); 780 781 throw saved; 782 } 783 784 public static Object createProtectedObject( Class type, Object[] parameters, Class[] parameterTypes ) 785 { 786 try 787 { 788 Constructor constructor = type.getDeclaredConstructor( parameterTypes ); 789 790 constructor.setAccessible( true ); 791 792 return constructor.newInstance( parameters ); 793 } 794 catch( Exception exception ) 795 { 796 LOG.error( "unable to instantiate type: {}, with exception: {}", type.getName(), exception ); 797 798 throw new FlowException( "unable to instantiate type: " + type.getName(), exception ); 799 } 800 } 801 802 public static boolean hasClass( String typeString ) 803 { 804 try 805 { 806 Util.class.getClassLoader().loadClass( typeString ); 807 808 return true; 809 } 810 catch( ClassNotFoundException exception ) 811 { 812 return false; 813 } 814 } 815 816 public static <T> T newInstance( String className, Object... parameters ) 817 { 818 try 819 { 820 Class<T> type = (Class<T>) Util.class.getClassLoader().loadClass( className ); 821 822 return newInstance( type, parameters ); 823 } 824 catch( ClassNotFoundException exception ) 825 { 826 throw new CascadingException( "unable to load class: " + className, exception ); 827 } 828 } 829 830 public static <T> T newInstance( Class<T> target, Object... parameters ) 831 { 832 // using Expression makes sure that constructors using sub-types properly work, otherwise we get a 833 // NoSuchMethodException. 834 Expression expr = new Expression( target, "new", parameters ); 835 836 try 837 { 838 return (T) expr.getValue(); 839 } 840 catch( Exception exception ) 841 { 842 throw new CascadingException( "unable to create new instance: " + target.getName() + "(" + Arrays.toString( parameters ) + ")", exception ); 843 } 844 } 845 846 public static Object invokeStaticMethod( String typeString, String methodName, Object[] parameters, Class[] parameterTypes ) 847 { 848 try 849 { 850 Class type = Util.class.getClassLoader().loadClass( typeString ); 851 852 return invokeStaticMethod( type, methodName, parameters, parameterTypes ); 853 } 854 catch( ClassNotFoundException exception ) 855 { 856 throw new CascadingException( "unable to load class: " + typeString, exception ); 857 } 858 } 859 860 public static Object invokeStaticMethod( Class type, String methodName, Object[] parameters, Class[] parameterTypes ) 861 { 862 try 863 { 864 Method method = type.getDeclaredMethod( methodName, parameterTypes ); 865 866 method.setAccessible( true ); 867 868 return method.invoke( null, parameters ); 869 } 870 catch( Exception exception ) 871 { 872 throw new CascadingException( "unable to invoke static method: " + type.getName() + "." + methodName, exception ); 873 } 874 } 875 876 public static Object invokeInstanceMethod( Object target, String methodName, Object[] parameters, Class[] parameterTypes ) 877 { 878 try 879 { 880 Method method = target.getClass().getMethod( methodName, parameterTypes ); 881 882 method.setAccessible( true ); 883 884 return method.invoke( target, parameters ); 885 } 886 catch( Exception exception ) 887 { 888 throw new CascadingException( "unable to invoke instance method: " + target.getClass().getName() + "." + methodName, exception ); 889 } 890 } 891 892 public static <R> R returnInstanceFieldIfExistsSafe( Object target, String fieldName ) 893 { 894 try 895 { 896 return returnInstanceFieldIfExists( target, fieldName ); 897 } 898 catch( Exception exception ) 899 { 900 // do nothing 901 return null; 902 } 903 } 904 905 public static Object invokeConstructor( String className, Object[] parameters, Class[] parameterTypes ) 906 { 907 try 908 { 909 Class type = Util.class.getClassLoader().loadClass( className ); 910 911 return invokeConstructor( type, parameters, parameterTypes ); 912 } 913 catch( ClassNotFoundException exception ) 914 { 915 throw new CascadingException( "unable to load class: " + className, exception ); 916 } 917 } 918 919 public static <T> T invokeConstructor( Class<T> target, Object[] parameters, Class[] parameterTypes ) 920 { 921 try 922 { 923 Constructor<T> constructor = target.getConstructor( parameterTypes ); 924 925 constructor.setAccessible( true ); 926 927 return constructor.newInstance( parameters ); 928 } 929 catch( Exception exception ) 930 { 931 throw new CascadingException( "unable to create new instance: " + target.getName() + "(" + Arrays.toString( parameters ) + ")", exception ); 932 } 933 } 934 935 public static <R> R returnInstanceFieldIfExists( Object target, String fieldName ) 936 { 937 try 938 { 939 Class<?> type = target.getClass(); 940 Field field = getDeclaredField( fieldName, type ); 941 942 field.setAccessible( true ); 943 944 return (R) field.get( target ); 945 } 946 catch( Exception exception ) 947 { 948 throw new CascadingException( "unable to get instance field: " + target.getClass().getName() + "." + fieldName, exception ); 949 } 950 } 951 952 public static <R> void setInstanceFieldIfExists( Object target, String fieldName, R value ) 953 { 954 try 955 { 956 Class<?> type = target.getClass(); 957 Field field = getDeclaredField( fieldName, type ); 958 959 field.setAccessible( true ); 960 961 field.set( target, value ); 962 } 963 catch( Exception exception ) 964 { 965 throw new CascadingException( "unable to set instance field: " + target.getClass().getName() + "." + fieldName, exception ); 966 } 967 } 968 969 private static Field getDeclaredField( String fieldName, Class<?> type ) 970 { 971 if( type == Object.class ) 972 { 973 if( LOG.isDebugEnabled() ) 974 LOG.debug( "did not find {} field on {}", fieldName, type.getName() ); 975 976 return null; 977 } 978 979 try 980 { 981 return type.getDeclaredField( fieldName ); 982 } 983 catch( NoSuchFieldException exception ) 984 { 985 return getDeclaredField( fieldName, type.getSuperclass() ); 986 } 987 } 988 989 @Deprecated 990 public static String makeTempPath( String name ) 991 { 992 if( name == null || name.isEmpty() ) 993 throw new IllegalArgumentException( "name may not be null or empty " ); 994 995 name = cleansePathName( name.substring( 0, name.length() < 25 ? name.length() : 25 ) ); 996 997 return name + "/" + (int) ( Math.random() * 100000 ) + "/"; 998 } 999 1000 public static String makePath( String prefix, String name ) 1001 { 1002 if( name == null || name.isEmpty() ) 1003 throw new IllegalArgumentException( "name may not be null or empty " ); 1004 1005 if( prefix == null || prefix.isEmpty() ) 1006 prefix = Long.toString( (long) ( Math.random() * 10000000000L ) ); 1007 1008 name = cleansePathName( name.substring( 0, name.length() < 25 ? name.length() : 25 ) ); 1009 1010 return prefix + "/" + name + "/"; 1011 } 1012 1013 public static String cleansePathName( String name ) 1014 { 1015 return name.replaceAll( "\\s+|\\*|\\+|/+", "_" ); 1016 } 1017 1018 public static boolean containsWhitespace( String string ) 1019 { 1020 return Pattern.compile( "\\s" ).matcher( string ).find(); 1021 } 1022 }