blob: 39cf13c95a003067e3517124d623141aae092fad [file] [log] [blame]
/*
* 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.codehaus.groovy.runtime;
import groovy.lang.Closure;
import org.codehaus.groovy.reflection.ReflectionUtils;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
/**
* This class defines all the new static groovy methods which appear on normal
* JDK classes inside the Groovy environment. Static methods are used with the
* first parameter as the destination class.
*/
public class DefaultGroovyStaticMethods {
/**
* Start a Thread with the given closure as a Runnable instance.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param closure the Runnable closure
* @return the started thread
* @since 1.0
*/
public static Thread start(Thread self, Closure closure) {
return createThread(null, false, closure);
}
/**
* Start a Thread with a given name and the given closure
* as a Runnable instance.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param name the name to give the thread
* @param closure the Runnable closure
* @return the started thread
* @since 1.6
*/
public static Thread start(Thread self, String name, Closure closure) {
return createThread(name, false, closure);
}
/**
* Start a daemon Thread with the given closure as a Runnable instance.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param closure the Runnable closure
* @return the started thread
* @since 1.0
*/
public static Thread startDaemon(Thread self, Closure closure) {
return createThread(null, true, closure);
}
/**
* Start a daemon Thread with a given name and the given closure as
* a Runnable instance.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param name the name to give the thread
* @param closure the Runnable closure
* @return the started thread
* @since 1.6
*/
public static Thread startDaemon(Thread self, String name, Closure closure) {
return createThread(name, true, closure);
}
private static Thread createThread(String name, boolean daemon, Closure closure) {
Thread thread = name != null ? new Thread(closure, name) : new Thread(closure);
if (daemon) thread.setDaemon(true);
thread.start();
return thread;
}
/**
* Dump the thread dump of all threads
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @return the thread dump of all threads
* @since 3.0.0
*/
public static String dumpAll(Thread self){
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
return Arrays.stream(threadMxBean.dumpAllThreads(true, true))
.map(ThreadInfo::toString)
.collect(Collectors.joining(""));
}
/**
* Get the last hidden matcher that the system used to do a match.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @return the last regex matcher
* @since 1.0
*/
public static Matcher getLastMatcher(Matcher self) {
return RegexSupport.getLastMatcher();
}
/**
* This method is used by both sleep() methods to implement sleeping
* for the given time even if interrupted
*
* @param millis the number of milliseconds to sleep
* @param closure optional closure called when interrupted
* as long as the closure returns false the sleep continues
*/
private static void sleepImpl(long millis, Closure closure) {
long start = System.currentTimeMillis();
long rest = millis;
long current;
while (rest > 0) {
try {
Thread.sleep(rest);
rest = 0;
} catch (InterruptedException e) {
if (closure != null) {
if (DefaultTypeTransformation.castToBoolean(closure.call(e))) {
return;
}
}
current = System.currentTimeMillis(); // compensate for closure's time
rest = millis + start - current;
}
}
}
/**
* Sleep for so many milliseconds, even if interrupted.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param milliseconds the number of milliseconds to sleep
* @since 1.0
*/
public static void sleep(Object self, long milliseconds) {
sleepImpl(milliseconds, null);
}
/**
* Sleep for so many milliseconds, using a given closure for interrupt processing.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param milliseconds the number of milliseconds to sleep
* @param onInterrupt interrupt handler, InterruptedException is passed to the Closure
* as long as it returns false, the sleep continues
* @since 1.0
*/
public static void sleep(Object self, long milliseconds, Closure onInterrupt) {
sleepImpl(milliseconds, onInterrupt);
}
@Deprecated
public static Date parse(Date self, String format, String input) throws ParseException {
return new SimpleDateFormat(format).parse(input);
}
@Deprecated
public static Date parse(Date self, String format, String input, TimeZone zone) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(zone);
return sdf.parse(input);
}
@Deprecated
public static Date parseToStringDate(Date self, String dateToString) throws ParseException {
return new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse(dateToString);
}
/**
* Works exactly like ResourceBundle.getBundle(String). This is needed
* because the java method depends on a particular stack configuration that
* is not guaranteed in Groovy when calling the Java method.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param bundleName the name of the bundle.
* @return the resource bundle
* @see java.util.ResourceBundle#getBundle(java.lang.String)
* @since 1.6.0
*/
public static ResourceBundle getBundle(ResourceBundle self, String bundleName) {
return getBundle(self, bundleName, Locale.getDefault());
}
/**
* Works exactly like ResourceBundle.getBundle(String, Locale). This is needed
* because the java method depends on a particular stack configuration that
* is not guaranteed in Groovy when calling the Java method.
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @param bundleName the name of the bundle.
* @param locale the specific locale
* @return the resource bundle
* @see java.util.ResourceBundle#getBundle(java.lang.String, java.util.Locale)
* @since 1.6.0
*/
public static ResourceBundle getBundle(ResourceBundle self, String bundleName, Locale locale) {
Class c = ReflectionUtils.getCallingClass();
ClassLoader targetCL = c != null ? c.getClassLoader() : null;
if (targetCL == null) targetCL = ClassLoader.getSystemClassLoader();
return ResourceBundle.getBundle(bundleName, locale, targetCL);
}
public static File createTempDir(File self) throws IOException {
return createTempDir(self, "groovy-generated-", "-tmpdir");
}
public static File createTempDir(File self, final String prefix, final String suffix) throws IOException {
final int MAXTRIES = 3;
int accessDeniedCounter = 0;
File tempFile=null;
for (int i=0; i<MAXTRIES; i++) {
try {
tempFile = File.createTempFile(prefix, suffix);
tempFile.delete();
tempFile.mkdirs();
break;
} catch (IOException ioe) {
if (ioe.getMessage().startsWith("Access is denied")) {
accessDeniedCounter++;
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
if (i==MAXTRIES-1) {
if (accessDeniedCounter==MAXTRIES) {
String msg =
"Access is denied.\nWe tried " +
+ accessDeniedCounter+
" times to create a temporary directory"+
" and failed each time. If you are on Windows"+
" you are possibly victim to"+
" http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6325169. "+
" this is no bug in Groovy.";
throw new IOException(msg);
} else {
throw ioe;
}
}
}
}
return tempFile;
}
/**
* Get the current time in seconds
*
* @param self placeholder variable used by Groovy categories; ignored for default static methods
* @return the difference, measured in seconds, between
* the current time and midnight, January 1, 1970 UTC.
* @see System#currentTimeMillis()
*/
public static long currentTimeSeconds(System self){
return System.currentTimeMillis() / 1000;
}
}