/*
* Copyright 2009 Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net.
*
* 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.
* under the License.
*/
package de.timefinder.data.util;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* @author Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net
*/
public class Helper {
// 01234567890 12345678
private static final String utcDateTimeFormatString = "yyyy-MM-dd'T'HH:mm:ssZ";
private static final String localDateTimeFormatString = "yyyy-MM-dd'T'HH:mm:ss";
private final static int readBlockSize = 1024;
private final static Log logger = LogFactory.getLog(Helper.class);
/**
* I cannot find such a nice solution like for known compoundTypes.
* List<String> list = ...;
* String[] stringList = convert(list.toArray());
*
* @see convertStringList
*/
public static <T> T[] convert(Class<T> componentType, Collection<T> list) {
@SuppressWarnings("unchecked")
T[] res = (T[]) Array.newInstance(componentType, list.size());
list.toArray(res);
return res;
}
public static String[] convertStringList(Collection<String> list) {
return list.toArray(new String[list.size()]);
}
public static <T> Constructor<T> getConstructor(Class<T> aClass) throws NoSuchMethodException {
Constructor constr = aClass.getDeclaredConstructor();
try {
constr.setAccessible(true);
return constr;
} catch (Exception ex) {
return aClass.getConstructor();
}
}
/**
* Returns a DOM parser
*/
public static DocumentBuilder newDocumentBuilder()
throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder;
}
public static Document getAsDocument(String xmlString) throws SAXException,
IOException, ParserConfigurationException {
return newDocumentBuilder().parse(
new ByteArrayInputStream(xmlString.getBytes()));
}
public static Document parse(InputStream is) throws SAXException,
IOException, ParserConfigurationException {
return newDocumentBuilder().parse(is);
}
public static String getDocumentAsString(Document doc)
throws TransformerException {
StringWriter writer = new StringWriter();
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString();
}
public static String getFromFile(File file, int blockSize)
throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
char character[] = new char[blockSize];
StringBuilder sb = new StringBuilder(character.length);
int ret;
while ((ret = reader.read(character)) != -1) {
sb.append(character, 0, ret);
}
return sb.toString();
}
public static String getAsString(InputStream is, int blockSize)
throws IOException {
if (is == null)
throw new NullPointerException("InputStream cannot be null!");
BufferedInputStream reader = new BufferedInputStream(is);
byte bytes[] = new byte[blockSize];
StringBuilder sb = new StringBuilder(bytes.length);
int ret;
while ((ret = reader.read(bytes)) != -1) {
sb.append(new String(bytes, 0, ret));
}
return sb.toString();
}
/**
* This method counts the number of matches in the specified pattern in the
* string str.
*/
public static int countPattern(String str, String pattern) {
int counter = 0;
int index = 0;
while ((index = str.indexOf(pattern, index)) > -1) {
counter++;
index++;
}
return counter;
}
public static String beautifyXML(String s) {
return s.replace(">", ">\n");
}
/**
* This method is useful to convert xml to java code.
*/
public static String createJavaStringFromXMLString(String xml) {
StringBuilder sb = new StringBuilder();
// convert " into \"
xml = xml.replaceAll("\"", "\\\\\"");
// put every line into " -> "LINE"
for (String line : xml.split("\n")) {
sb.append("\"");
sb.append(line);
// fill until 80 character -> this is useful to format the String
// via CTRL+SHIFT
for (int i = line.length(); i < 80; i++) {
sb.append(' ');
}
sb.append("\"+\n");
}
return sb.toString();
}
public static void readStreamIntoWriter(InputStream iStream, Writer writer)
throws IOException {
byte bytes[] = new byte[readBlockSize];
int len;
while ((len = iStream.read(bytes)) != -1) {
writer.write(new String(bytes, 0, len));
}
writer.close();
iStream.close();
}
/**
* This method creates a Date object from the specified string.
* The string has to be in the form of XML schema type 'xsd:dateTime'
*
* WARNING: "localdateandtime-offset" <br /> means: localdateandtime == GMT - offset
* @see http://www.w3.org/TR/NOTE-datetime
*/
public static Date fromDateTime(String dateAsString) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat(utcDateTimeFormatString);
if (dateAsString.length() == 19)
// without Z, assume UTC
dateAsString += "+0000";
else if (dateAsString.indexOf(':', 20) > -1)
//xsd:dateTime
//Java parser couldn't process hh:mm => copy to hhmm
dateAsString = dateAsString.substring(0, 22) + dateAsString.substring(23);
else if (dateAsString.indexOf('Z', 19) > -1)
//xsd:dateTime
//Java parser couldn't process the chars if they end with Z
//-> no offset to UTC
dateAsString = dateAsString.substring(0, 19) + "+0000";
else if (dateAsString.length() < 19)
throw new IllegalArgumentException(
"DateTime has to be in the following format:" + utcDateTimeFormatString);
return df.parse(dateAsString);
}
/**
* This method reads the specified string as date.
* The info about the time zone will be neglected (e.g. -07:00).
*/
public static Date fromLocalDateTime(String dateAsString)
throws ParseException {
SimpleDateFormat df = new SimpleDateFormat(localDateTimeFormatString);
if (dateAsString.length() >= 19)
dateAsString = dateAsString.substring(0, 19);
return df.parse(dateAsString);
}
/**
* This method returns a char from the specified date.
*
* @return string of Fdate in local time.
*/
public static String toLocalDateTime(Date date) {
return new SimpleDateFormat(localDateTimeFormatString).format(date);
}
public static Element getFirstElement(NodeList list) {
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).getNodeType() == Node.ELEMENT_NODE)
return (Element) list.item(i);
}
return null;
}
/**
* Utility method used to delete the profile directory when run as
* a stand-alone application.
* @param file The file to recursively delete.
**/
public static void deleteFileOrDir(File file) {
if (file.isDirectory()) {
File[] childs = file.listFiles();
for (int i = 0; i < childs.length; i++) {
deleteFileOrDir(childs[i]);
}
}
file.delete();
}
/**
* Invoke the specified Runnable always within the EDT.
*/
public static void swingInvoke(Runnable runner) {
if (SwingUtilities.isEventDispatchThread()) {
runner.run();
return;
}
try {
SwingUtilities.invokeAndWait(runner);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// getName => name; setName => name; isSth => sth
public static String getPropertyFromJavaMethod(String name, boolean bool) {
if (bool) {
//is/set
if (name.charAt(0) == 'i' && name.charAt(1) == 's' && name.length() > 2)
return Character.toLowerCase(name.charAt(2)) + name.substring(3);
}
//get/set
if ((name.charAt(0) == 'g' || name.charAt(0) == 's') && name.charAt(1) == 'e' && name.charAt(2) == 't' && name.length() > 3)
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
return null;
}
public static boolean isSetter(Method method) {
return method.getName().startsWith("set") && method.getReturnType() == void.class && method.getParameterTypes().length == 1;
}
public static boolean isGetter(Method method) {
return (method.getName().startsWith("is") || method.getName().startsWith("get"))
&& method.getReturnType() != void.class && method.getParameterTypes().length == 0;
}
public static void fillSettersAndGetters(Class clazz, Map<String, Method> setterMethods,
Map<String, Method> getterMethods) {
for (Method method : clazz.getMethods()) {
String propertyName = getPropertyFromJavaMethod(method.getName(), method.getReturnType() == boolean.class);
if (propertyName != null) {
method.setAccessible(true);
if (setterMethods != null && isSetter(method)) {
setterMethods.put(propertyName, method);
} else if (getterMethods != null && isGetter(method)) {
if (!method.getReturnType().equals(Class.class))
getterMethods.put(propertyName, method);
}
}
}
}
/**
* Copies all properties present via getters in class of obj into the
* specified newObj if there are setters available
*/
public static void copyProperties(Object obj, Object newObj) {
// ensure that always the same order of method calls will be applied
// => use TreeMap not HashMap
Map<String, Method> getterMapping = new TreeMap();
Map<String, Method> setterMapping = new TreeMap();
fillSettersAndGetters(obj.getClass(), setterMapping, getterMapping);
getterMapping.keySet().retainAll(setterMapping.keySet());
for (Entry<String, Method> getter : getterMapping.entrySet()) {
Method setter = setterMapping.get(getter.getKey());
// getter object should be castable to setter type:
if (!setter.getParameterTypes()[0].isAssignableFrom(
getter.getValue().getReturnType()))
continue;
try {
Object param = getter.getValue().invoke(obj);
if (getter.getValue().getReturnType().isArray()) {
param = ((Object[]) param).clone();
} else if (Collection.class.isAssignableFrom(getter.getValue().getReturnType())) {
param = new HashSet((Collection) param);
} else if (Map.class.isAssignableFrom(getter.getValue().getReturnType())) {
param = new HashMap((Map) param);
}
setter.invoke(newObj, param);
} catch (Exception ex) {
logger.fatal("Cannot set:" + getter.getKey(), ex);
}
}
}
static final String[] browsers = {"google-chrome", "firefox", "opera",
"konqueror", "epiphany", "seamonkey", "galeon", "kazehakase", "mozilla"};
public static void openURL(URI url) {
openURL(url.toString());
}
// taken from http://www.centerkey.com/java/browser/ which is public domain
// solves http://stackoverflow.com/questions/2329718/open-html-in-browser-from-java-bug-if-browser-is-not-started
public static void openURL(String url) {
try {
String osName = System.getProperty("os.name");
if (osName.startsWith("Mac OS")) {
Class.forName("com.apple.eio.FileManager").getDeclaredMethod(
"openURL", new Class[]{String.class}).invoke(null,
new Object[]{url});
} else if (osName.startsWith("Windows")) {
Runtime.getRuntime().exec(
"rundll32 url.dll,FileProtocolHandler " + url);
} else { //assume Unix or Linux
boolean found = false;
for (String browser : browsers) {
if (!found) {
found = Runtime.getRuntime().exec(
new String[]{"which", browser}).waitFor() == 0;
if (found)
Runtime.getRuntime().exec(new String[]{browser, url});
}
}
if (!found)
throw new Exception(Arrays.toString(browsers));
}
} catch (Exception ex1) {
try {
// java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
Class<?> d = Class.forName("java.awt.Desktop");
d.getDeclaredMethod("browse", new Class[]{java.net.URI.class}).invoke(
d.getDeclaredMethod("getDesktop").invoke(null),
new Object[]{java.net.URI.create(url)});
} catch (Exception ex2) {
ex1.printStackTrace();
ex2.printStackTrace();
JOptionPane.showMessageDialog(null, "Error attempting to launch web browser\n"
+ ex2.toString() + " " + ex1.getMessage());
}
}
}
public static Map<String, Method> findGetterMethods(Class clazz) {
Map<String, Method> getterMethods = new HashMap();
for (Method method : clazz.getMethods()) {
String element = getPropertyFromJavaMethod(method.getName(),
method.getReturnType() == boolean.class);
if (element != null) {
method.setAccessible(true);
if (Helper.isGetter(method)) {
if (!method.getReturnType().equals(Class.class))
getterMethods.put(element, method);
}
}
}
return getterMethods;
}
public static Map<String, Method> findSetterMethods(Class clazz) {
Map<String, Method> setterMethods = new HashMap();
for (Method method : clazz.getMethods()) {
String element = getPropertyFromJavaMethod(method.getName(),
method.getReturnType() == boolean.class);
if (element != null) {
method.setAccessible(true);
if (Helper.isSetter(method)) {
setterMethods.put(element, method);
}
}
}
return setterMethods;
}
}