package com.panopset;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;
import javax.swing.text.JTextComponent;
import com.panopset.io.PropertiesFile;
/**
* General static utilities.
*
* @author Karl Dinwiddie
*/
public final class Util {
/**
* 1000 milliseconds.
*/
public static final long ONE_SECOND = 1000;
/**
* ONE_SECOND * 60.
*/
public static final long ONE_MINUTE = ONE_SECOND * 60;
/**
* ONE_MINUTE * 60.
*/
public static final long ONE_HOUR = ONE_MINUTE * 60;
/**
* ONE_HOUR * 24.
*/
public static final long ONE_DAY = ONE_HOUR * 24;
/**
* ONE_DAY * 7.
*/
public static final long ONE_WEEK = ONE_DAY * 7;
/**
* Timestamp up to seconds <b>yyyy-MM-dd HH:mm:ss</b>.
*/
public static final SimpleDateFormat TIMESTAMP_SECONDS
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* <b>MMMMMMMMMMM dd, yyyy</b>.
*/
public static final SimpleDateFormat TIMESTAMP_FORMAT
= new SimpleDateFormat("MMMMMMMMMMM d, yyyy");
/**
* <b>HH:mm:ss MMMMMMMMMMM dd, yyyy</b>.
*/
public static final SimpleDateFormat VERSION_FORMAT
= new SimpleDateFormat("yyyyMMdd");
/**
* <b>EEEE, MMMM dd, yyyy, h:mm a(zz)</b>.
*/
public static final SimpleDateFormat LAST_MODIFIED_FORMAT
= new SimpleDateFormat("EEEE, MMMM dd, yyyy, h:mm a(zz)");
/**
* <b>yyyy-MM-dd'T'HH:mmZ</b>.
* From <a href="http://code.google.com/p/sitemapgen4j"> sitemapgen4j</a>.
*/
public static final SimpleDateFormat SITEMAP_FORMAT
= new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
/**
* Clear all text components, including those in parent containers.
*
* @param c
* Container to have all editable text fields cleared for.
*/
public static void clearAllTextComponents(final Container c) {
if (c == null) {
return;
}
Container p = c.getParent();
while (p != null && p != c) {
clearAllTextComponents(p);
return;
}
clearAllSubText(c);
}
/**
* Get source name.
*
* Reference:
*
* http://www.exampledepot.com/egs/java.lang/ClassOrigin.html
*
* @param clazz
* Class to get source name from.
* @return Name of source as URL toString.
* @throws Exception
* Exception.
*/
public static String getSourceName(final Class<?> clazz) throws Exception {
ProtectionDomain pDomain = clazz.getProtectionDomain();
CodeSource cSource = pDomain.getCodeSource();
URL loc = cSource.getLocation();
return loc.toString();
}
/**
* Clear all text components in a container.
*
* @param c
* Container for which all text components are to be cleared.
*/
public static void clearAllSubText(final Container c) {
for (Component s : c.getComponents()) {
if (s instanceof JTextComponent) {
JTextComponent t = (JTextComponent) s;
if (t.isEditable()) {
t.setText("");
}
} else if (s instanceof Container) {
clearAllSubText((Container) s);
}
}
}
/**
* @return true if verbose messages flag is true, default is false.
*/
public static boolean isVerbose() {
return verbose;
}
/**
* Sets logging to verbose.
*/
public static void setVerbose() {
verbose = true;
}
/**
* Used by vlog, iff true, vlog will log a message.
*/
private static boolean verbose = false;
/**
* Log only if verbose set to true.
*
* @param msg
* Message.
*/
public static void vlog(final String msg) {
if (verbose) {
log(msg);
}
}
/**
* Exit JVM for debugging purposes.
*/
public static void exit() {
System.exit(0);
}
/**
* Convert a List<String> to a String array.
*
* @param list
* List.
* @return array Array.
*/
public static String[] toArray(final List<String> list) {
String[] rtn = new String[list.size()];
int i = 0;
for (String s : list) {
rtn[i++] = s;
}
return rtn;
}
/**
* Copy one String map to another.
*
* @param fromMap
* Map to copy from.
* @param toMap
* Map to copy to. Existing entries are kept or written over.
* @return toMap if toMap is null, a new map will be created.
*/
public static Map<String, String> copyMap(
final Map<String, String> fromMap,
final Map<String, String> toMap) {
Map<String, String> rtn = toMap;
if (rtn == null) {
rtn = new HashMap<String, String>();
}
if (fromMap != null) {
for (Entry<String, String> entry : fromMap.entrySet()) {
rtn.put(entry.getKey(), entry.getValue());
}
}
return rtn;
}
/**
* Verbose log.
*
* @param msg
* Message to log if verbose is true.
*/
public static void logv(final String msg) {
if (verbose) {
log(msg);
}
}
/**
* Log writer.
*/
private static final StringWriter LOG_WRITER = new StringWriter();
/**
* @return Log.
*/
public static String getLog() {
return LOG_WRITER.toString();
}
/**
* Log a String.
*
* @param msg
* Message to log.
*/
public static void log(final String msg) {
Alert.green(Strings.getFirstLine(msg));
LOG_WRITER.append(msg).append(Strings.getEol());
}
/**
* Log a String.
*
* @param msg
* Message to log.
*/
public static void logError(final String msg) {
Alert.red(Strings.getFirstLine(msg));
LOG_WRITER.append(msg).append(Strings.getEol());
System.out.println(msg);
}
/**
* Log a Throwable stack trace.
*
* @param t
* Throwable
*/
public static void log(final Throwable t) {
logError(getFullStackTrace(t));
}
/**
* Display a message.
*
* @param msg
* Message to display.
*/
public static void dspmsg(final String msg) {
Alert.green(msg);
}
/**
* Stub class for future Nation Language System use, doesn't do anything.
*
* @param s
* String to translate.
* @return s Translated string.
*/
public static String x(final String s) {
return s;
}
/**
* Generic dump. Collections and dumps are nicely formatted.
*
* @param o
* Object to be given a clean dump for.
* @return String representation of given Object.
*/
@SuppressWarnings("unchecked")
public static String dump(final Object o) {
StringWriter sw = new StringWriter();
if (o == null) {
return x("Can not dump null object") + ".";
}
if (o instanceof Object[]) {
for (Object s : (Object[]) o) {
sw.append(dump(s));
}
} else if (o instanceof Map) {
Map<Object, Object> m = (Map<Object, Object>) o;
for (Entry<Object, Object> entry : m.entrySet()) {
sw.append(entry.getKey().toString());
sw.append(Strings.getEol());
Object v = entry.getValue();
if (v == null) {
sw.append("null");
} else {
sw.append(v.toString());
}
sw.append(Strings.getEol());
sw.append(Strings.getEol());
}
} else if (o instanceof Collection) {
for (Object e : (Collection<?>) o) {
sw.append(dump(e));
}
} else {
sw.append(o.toString());
sw.append(Strings.getEol());
}
return sw.toString();
}
/**
* Invoke a static method.
* <ul>
* <li>It must return a String</li>
* </ul>
*
* @param classMethodAndParms Example:
*
* <pre>
* com.panopset.Strings.capitalize(foo)
*
* </pre>
*
* @param classMethodAndParms
* Class method and params.
* @return String result of method invocation.
* @throws Exception
* Exception.
*/
public static String invokeStaticStringMethod(
final String classMethodAndParms) throws Exception {
return invokeStaticStringMethod(classMethodAndParms, null);
}
/**
* Invoke a static method.
* <ul>
* <li>It must return a String</li>
* <li>The parameters are keys to a map.</li>
* </ul>
*
* <pre>
* @param classMethodAndParms
* Example:
* com.panopset.Strings.capitalize(foo)
* Note that if foo is not in the map, the value passed will be foo
* itself.
* </pre>
*
* @param classMethodAndParms
* Class method and params.
* @param mapProvider
* Can be null if there are no parameters.
* @return String result of invoking method.
* @throws Exception
* Exception.
*/
public static String invokeStaticStringMethod(
final String classMethodAndParms, final MapProvider mapProvider)
throws Exception {
return new ReflectionInvoker.Builder()
.classMethodAndParms(classMethodAndParms)
.mapProvider(mapProvider).construct().exec();
}
/**
* Load Properties from a file.
*
* @param f
* File to load property values from.
* @return new Properties object.
*/
public static Map<String, String> loadPropsFromFile(final File f) {
Properties p = new Properties();
loadProperties(p, f);
return loadMapFromProperties(p);
}
/**
* Load Map<String, String> from Properties.
*
* @param p
* Properties to load Map<String, String> from.
* @return Map<String, String>
*/
public static Map<String, String> loadMapFromProperties(
final Properties p) {
final Map<String, String> rtn = new HashMap<String, String>();
for (Object key : p.keySet()) {
rtn.put(key.toString(), p.getProperty(key.toString()));
}
return rtn;
}
/**
* Wrapper for java.io.File.getCanonicalPath method, to handle IOException.
* If an IOException is caught, the exception is logged by the log function,
* and the results of the Exception.getMessage function are returned.
*
* @param f
* File to get canonical path of.
* @return result of java.io.File.getCanonicalPath
*/
public static String getCanonicalPath(final File f) {
try {
if (f == null) {
return "";
}
return f.getCanonicalPath();
} catch (IOException e) {
log(e);
return e.getMessage();
}
}
/**
* Get the parent directory, fully qualified even if the file is based on a
* relative path.
*
* @param f
* File.
* @return Parent directory.
*/
public static String getParentDirectory(final File f) {
if (f.exists()) {
File fullFile = new File(getCanonicalPath(f));
return getCanonicalPath(fullFile.getParentFile());
}
return getCanonicalPath(f.getParentFile());
}
/**
* Load properties from a file.
*
* @param p
* Properties to load values in to.
* @param f
* File to load properties from.
*/
public static void loadProperties(final Properties p, final File f) {
if (!f.exists()) {
log(x("Skipping properties load, file")
+ " " + getCanonicalPath(f));
return;
}
try {
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
p.load(br);
br.close();
fr.close();
} catch (IOException e) {
log(e);
}
}
/**
* Save properties to a file.
*
* @param p
* Properties to save to file.
* @param f
* File to store properties.
*/
public static void saveProperties(final Properties p, final File f) {
try {
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos);
p.store(bos, new Date().toString());
bos.flush();
bos.close();
fos.close();
} catch (ClassCastException e) {
dump(p);
log(e);
} catch (IOException e) {
log(e);
}
}
/**
* Sort a set.
*
* @param set
* Set to sort.
* @return Sorted set.
*/
public static SortedSet<Object> sort(final Set<Object> set) {
SortedSet<Object> ss = Collections
.synchronizedSortedSet(new TreeSet<Object>());
for (Object o : set) {
ss.add(o);
}
return ss;
}
/**
* This is a good example of how the <b>e</b> exec command is useful.
* Anywhere that <%e getCurrentDateTime%> appears, the output will be
* replaced with a nice time stamp. Useful for automatically putting a
* "last modified" time on your HTML page.
*
* @see com.panopset.flywheel.CommandExecute
* @see com.panopset.Util#TIMESTAMP_SECONDS
* @return String the nicely formatted time stamp.
*/
public static String getCurrentDateTime() {
return TIMESTAMP_SECONDS.format(new Date());
}
/**
* This is a another good example of how the <b>e</b> exec command is
* useful. Use this to set the last-modified header meta tag.
*
* @see com.panopset.flywheel.CommandExecute
* @see com.panopset.Util#LAST_MODIFIED_FORMAT
* @return String current date formatted for html meta tag last-modified.
*/
public static String getLastModifiedDate() {
return LAST_MODIFIED_FORMAT.format(new Date());
}
/**
* sitemap.xml formatted date.
*
* @return yyyy-MM-dd'T'HH:mmZ formatted date.
*/
public static String getSitemapDate() {
return SITEMAP_FORMAT.format(new Date());
}
/**
* Get current date.
*
* @see com.panopset.flywheel.CommandExecute
* @see com.panopset.Util#TIMESTAMP_FORMAT
* @return Current date in timestamp format.
*/
public static String getCurrentDate() {
return TIMESTAMP_FORMAT.format(new Date());
}
/**
* Check for match, useful in menu generation.
*
* If s1 is equal to s2, return r1, otherwise return r2.
*
* @param s1
* String 1.
* @param s2
* String 2.
* @param r1
* Result 1, to return if s1 = s2.
* @param r2
* Result 2, to return if s1 <> s2.
* @return String r1 if s1 = s2, r2 if s1 <> s2.
*/
public static String check4match(final String s1, final String s2,
final String r1, final String r2) {
if (s1 == null || s2 == null || r1 == null || r2 == null) {
return "";
}
if (s1.equals(s2)) {
return r1;
}
return r2;
}
/**
* Fill String to a given length with a given String.
*
* @param str
* String to fill.
* @param length
* Length to fill to.
* @param filler
* String to fill left.
* @return Adjusted String.
*/
public static String fillStringLeft(final String str, final int length,
final String filler) {
StringBuilder sb = new StringBuilder();
int m = str.length();
while (m++ < length) {
sb.append(filler);
}
sb.append(str);
return sb.toString();
}
/**
* Pad a String with a given character. If str param is longer than width,
* str will be returned un-changed.
*
* @param str
* String to be padded
* @param fill
* char to pad the String with
* @param width
* How wide the result String is to be
* @param left
* Pad left if true, right if false
* @return String padded left or right with fill char
*/
public static String pad(final String str, final char fill,
final int width, final boolean left) {
StringBuilder sb = new StringBuilder();
String s = "";
if (str != null) {
s = str;
}
int l = s.length();
if (l > (width - 1)) {
return s;
}
synchronized (sb) {
if (!left) {
sb.append(s);
}
for (int i = l; i < width; i++) {
sb.append(fill);
}
if (left) {
sb.append(s);
}
}
return sb.toString();
}
/**
* centerInScreen returns a point that can be used in a window setLocation
* call to place the window in the center of the screen.
*
* @param d
* For example, the Dimension of the window from a getSize()
* call.
* @return Point Returns upper left corner point that would place the window
* in the center.
*/
public static Point centerInScreen(final Dimension d) {
final Dimension s = Toolkit.getDefaultToolkit().getScreenSize();
return new Point(((s.width - d.width) / 2),
((s.height - d.height) / 2));
}
/**
* Center a Dimension in a Rectangle.
*
* @param d
* Dimension to center
* @param r
* Rectangle to center Dimension in
* @return center of r
*/
public static Point centerInRect(final Dimension d, final Rectangle r) {
return new Point(r.x + ((int) (r.width - d.width) / 2), r.y
+ ((int) (r.height - d.height) / 2));
}
/**
* Check to see if a point is in a rectangle.
*
* @param p
* Point to check.
* @param r
* Rectangle to check.
* @return True iff p is contained within r.
*/
public static boolean pointInRect(final Point p, final Rectangle r) {
return pointInRect(p.x, p.y, r.x, r.y, r.width, r.height);
}
/**
* Check to see if a point is in a rectangle.
*
* @param px
* Point x.
* @param py
* Point y.
* @param rx
* Rectangle x.
* @param ry
* Rectangle y.
* @param rw
* Rectangle width.
* @param rh
* Rectangle height.
* @return True iff p is contained within r.
*/
public static boolean pointInRect(final int px, final int py, final int rx,
final int ry, final int rw, final int rh) {
return pointInBounds(px, py, rx, ry, rx + rw, ry + rh);
}
/**
* Check to see if a point is in a boundry.
*
* @param px
* Point x.
* @param py
* Point y.
* @param bx1
* Bounds point 1 x.
* @param by1
* Bounds point 1 y.
* @param bx2
* Bounds point 2 x.
* @param by2
* Bounds point 2 y.
* @return True iff p is contained within r.
*/
public static boolean pointInBounds(final int px, final int py,
final int bx1, final int by1, final int bx2, final int by2) {
if ((px < bx1 && px < bx2) || (px > bx1 && px > bx2)
|| (py < by1 && py < by2) || (py > by1 && py > by2)) {
return false;
}
return true;
}
/**
* Copy a JVM path resource to a file.
*
* @param resourcePath
* ie com/company/favicon.png
* @param targetPath
* ie html/images/icon16x16.png. If called from Flywheel, the
* targetPath is relative to the target directory.
* @throws IOException
* IO Exception.
*/
public static void copyLibraryResource(final String resourcePath,
final String targetPath) throws IOException {
copyLibraryResource(resourcePath, new File(targetPath));
}
/**
* Copy a JVM path resource to a file.
*
* @param resourcePath
* Resource path.
* @param targetFile
* Target file.
* @throws IOException
* IO Exception.
*/
public static void copyLibraryResource(final String resourcePath,
final File targetFile) throws IOException {
UtilIO.copyLibraryResource(resourcePath, targetFile);
}
/**
* Get the URL for an application package resource.
*
* @param clazz
* Class that resides in the package the the resource is from.
* @param resourceName
* Simple name of the resource.
* @return URL for resource.
*/
public static URL getPackageURL(final Class<?> clazz,
final String resourceName) {
return clazz.getResource(convertPackageToURLsyntax(clazz.getPackage()
.getName()) + "/" + resourceName);
}
/**
* Get the text of a file in the same package of a given file.
*
* @param clazz
* Class in same package where file resides.
* @param name
* file name.
* @return Text contents of file.
*/
public static String getPackageText(final Class<?> clazz,
final String name) {
URL url = getPackageURL(clazz, name);
if (url == null) {
return x("Not found: ") + clazz.getCanonicalName() + name;
}
return getTextFromURL(url);
}
/**
* Get text from POST.
*
* @param url
* Base url.
* @param dta
* Data to post.
* @return Result from HTTP stream.
*/
public static String getTextFromURLPost(final String url,
final String dta) {
return new HttpPOSTclient(url).getTextFromPost(dta);
}
/**
* Get the text from a file represented by a URL.
*
* @param url
* Location of text file.
* @return Text contents of file.
*/
public static String getTextFromURL(final URL url) {
return new HttpGETclient(url).getResponse();
}
/** Match period. */
public static final Pattern REGEX_PATTERN_JAVA_PACKAGE = Pattern
.compile("\\.");
/**
* Convert package to URL syntax.
*
* @param s
* Dot separated package name.
* @return Forward slash separated path.
*/
public static String convertPackageToURLsyntax(final String s) {
return "/" + REGEX_PATTERN_JAVA_PACKAGE.matcher(s).replaceAll("/");
}
/**
* Get an Integer from a property file, using the given key.
*
* @param p
* Properties file.
* @param key
* Key.
* @return null if property not found or not convertable to an int,
* otherwise the int value.
*/
public static Integer getIntegerFromProperty(final Properties p,
final String key) {
if (p == null) {
return null;
}
if (key == null) {
return null;
}
Object o = p.get(key);
if (o == null) {
return null;
}
String s = o.toString();
return parseInt(s);
}
/**
* Parse integer from PropertiesFile.
*
* @param propsFile
* Properties file.
* @param key
* Key.
* @return Integer or 0.
*/
public static Integer parseInt(final PropertiesFile propsFile,
final String key) {
if (propsFile == null) {
return 0;
}
if (key == null) {
return 0;
}
return parseInt(propsFile.get(key));
}
/**
* Parse integer.
*
* @param s
* String to parse.
* @return Integer from s. Logs an error and returns 0 if Integer can not be
* parsed from the String.
*/
public static Integer parseInt(final String s) {
if (s == null) {
return 0;
}
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return 0;
}
}
/**
* @param t
* Throwable to get the stack trace from.
* @return Stack trace.
*/
public static String getStackTrace(final Throwable t) {
StringWriter sw = new StringWriter();
try {
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.flush();
pw.close();
sw.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return sw.toString();
}
/**
* @param t
* Throwable to get the stack trace from.
* @return Full stack trace, including causes.
*/
public static String getFullStackTrace(final Throwable t) {
StringWriter sw = new StringWriter();
sw.append(x("See log"));
sw.append(": ");
sw.append(t.getMessage());
sw.append(Strings.getEol());
sw.append("*************************");
sw.append(Strings.getEol());
sw.append(getStackTrace(t));
sw.append(Strings.getEol());
Throwable cause = t.getCause();
while (cause != null) {
sw.append("*************************");
sw.append(Strings.getEol());
sw.append(getStackTrace(cause));
sw.append(Strings.getEol());
cause = cause.getCause();
}
return sw.toString();
}
/**
* Get the String page source of an http page.
*
* @param urlStr
* URL String.
* @return page source String.
* @throws Exception
* Exception.
*/
public static String httpGet(final String urlStr) throws Exception {
return new HttpGETclient(urlStr).getResponse();
}
/**
* Default connect timeout is 300000 (5 minutes).
*/
private static final Integer CONNECT_TIMEOUT_DEFAULT = 300000;
/**
* Connect timeout.
*/
private static Integer connectTimeout = CONNECT_TIMEOUT_DEFAULT;
/**
* Get connection timeout. Default is 25000 (25 seconds).
*
* @return timeout, in milliseconds.
*/
public static Integer getConnectTimeout() {
return connectTimeout;
}
/**
* Set the connection timeout.
*
* @param value
* in milliseconds.
*/
public static void setConnectTimeout(final int value) {
connectTimeout = value;
connectTimeoutString = null;
}
/**
* Connection timeout.
*/
private static String connectTimeoutString;
/**
* getConnectionTimeout as a String.
*
* @return String representation of getConnectTimeout.
*/
public static String getConnectTimeoutString() {
if (connectTimeoutString == null) {
connectTimeoutString = "" + getConnectTimeout();
}
return connectTimeoutString;
}
/**
* If you know how much memory is required for an operation, pass that
* amount in bytes to this method.
*
* @param needed
* How much memory is needed.
* @return true iff enough memory is available.
*/
public static boolean checkMemory(final long needed) {
long fm = getFreeMemory();
if (needed > fm) {
int length = maxWidth(fm, needed);
log(x("Available memory: ") + fillStringLeft("" + fm, length, "0"));
log(x("Memory needed : ")
+ fillStringLeft("" + needed, length, "0"));
dspmsg(x("Not enough memory, try increasing memory, for example:"));
dspmsg("-Xms256m -Xmx1024m");
return false;
}
return true;
}
/**
* Returns the maximum length of two objects, after conversion to String.
* Primitives may be passed in due to the Java 5 autoboxing feature. If both
* are null, -1 is returned.
*
* @param o0
* Object 0
* @param o1
* Object 1
* @return Width of o0 or o1, depending on which is longer.
*/
public static int maxWidth(final Object o0, final Object o1) {
if (o0 == null && o1 == null) {
return -1;
}
if (o0 == null) {
return ("" + o1).length();
}
if (o1 == null) {
return ("" + o0).length();
}
return Math.max(("" + o0).length(), ("" + o1).length());
}
/**
* @return Free memory, in bytes.
*/
public static long getFreeMemory() {
return Runtime.getRuntime().freeMemory();
}
/**
* @return Total memory, in bytes.
*/
public static long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
/**
* @return Maximum memory, in bytes.
*/
public static long getMaxMemory() {
return Runtime.getRuntime().maxMemory();
}
/**
* Prevent instantiation.
*/
private Util() {
}
}
|