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