package gov.nih.nci.cagrid.common; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Array; import java.net.URL; import java.net.URLDecoder; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.namespace.QName; import org.apache.axis.AxisEngine; import org.apache.axis.AxisFault; import org.apache.axis.EngineConfiguration; import org.apache.axis.MessageContext; import org.apache.axis.configuration.FileProvider; import org.apache.axis.encoding.SerializationContext; import org.apache.axis.message.MessageElement; import org.apache.axis.server.AxisServer; import org.apache.axis.utils.XMLUtils; import org.globus.common.CoGProperties; import org.globus.gsi.CertificateRevocationLists; import org.globus.gsi.GlobusCredential; import org.globus.gsi.TrustedCertificates; import org.globus.gsi.proxy.ProxyPathValidator; import org.globus.gsi.proxy.ProxyPathValidatorException; import org.globus.wsrf.encoding.DeserializationException; import org.globus.wsrf.encoding.ObjectDeserializer; import org.globus.wsrf.encoding.ObjectSerializer; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class Utils { public static <T> List<T> asList(T... a) { if (a == null) { return new ArrayList<T>(); } else { return Arrays.asList(a); } } public static File getCaGridUserHome() { String userHome = System.getProperty("user.home"); File userHomeF = new File(userHome); File caGridCache = new File(userHomeF.getAbsolutePath() + File.separator + ".cagrid"); if (!caGridCache.exists()) { caGridCache.mkdirs(); } return caGridCache; } public static File getTrustedCerificatesDirectory() { String caDir = CoGProperties.getDefault().getCaCertLocations(); if (caDir != null) { return new File(caDir); } else { String userHome = System.getProperty("user.home"); File userHomeF = new File(userHome); File dir = new File(userHomeF.getAbsolutePath() + File.separator + ".globus" + File.separator + "certificates"); if (!dir.exists()) { dir.mkdirs(); } return dir; } } public static void validateGlobusCredential(GlobusCredential cred) throws ProxyPathValidatorException { validateCertificateChain(cred.getCertificateChain()); } public static void validateCertificateChain(X509Certificate[] chain) throws ProxyPathValidatorException { ProxyPathValidator validator = new ProxyPathValidator(); validator.validate(chain, TrustedCertificates.getDefaultTrustedCertificates().getCertificates(), CertificateRevocationLists.getDefaultCertificateRevocationLists()); } public static String getExceptionMessage(Throwable e) { String mess = e.getMessage(); if (e instanceof AxisFault) { AxisFault af = (AxisFault) e; if ((af.getFaultCode() != null) && (af.getFaultCode().toString() .equals("{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}General"))) { System.out.println(af.getFaultString()); if ((af.getFaultString() != null) && (af.getFaultString().equals("javax.xml.rpc.soap.SOAPFaultException"))) { mess = "An error occurred establishing a secure communication channel. The " + "problem may be that the client's credentials are NOT trusted by the server."; } else { mess = af.getFaultString(); } } else if ((af.getFaultString() != null) && (af.getFaultString().equals("java.io.EOFException"))) { mess = "An error occurred in communicating with the service. If using " + "credentials to authenticate to the service, the problem may be " + "that the credentials being used are not trusted by the server."; } else if ((af.getFaultString() != null) && (af.getFaultString().equals("java.net.SocketException: Connection reset"))) { mess = "An error occurred in communicating with the service. If using " + "credentials to authenticate to the service, the problem may be " + "that the credentials being used are not trusted by the server."; } else { mess = af.getFaultString(); } } return simplifyErrorMessage(mess); } public static String simplifyErrorMessage(String m) { if ((m == null) || (m.equalsIgnoreCase("null"))) { m = "Unknown Error"; } else if (m.indexOf("Connection refused") >= 0) { m = "Error establishing a connection to the requested service, the service may not exist or may be down."; } else if (m.indexOf("Unknown CA") >= 0) { m = "Could establish a connection with the service, the service CA is not trusted."; } return m; } public static <T> T deserializeDocument(String fileName, Class<T> objectType) throws Exception { InputStream inputStream = null; inputStream = new FileInputStream(fileName); org.w3c.dom.Document doc = XMLUtils.newDocument(inputStream); Object obj = ObjectDeserializer.toObject(doc.getDocumentElement(), objectType); inputStream.close(); return objectType.cast(obj); } public static void copyFile(File in, File out) throws IOException { File inCannon = in.getCanonicalFile(); File outCannon = out.getCanonicalFile(); // avoids copying a file to itself if (inCannon.equals(outCannon)) { return; } // ensure the output file location exists outCannon.getParentFile().mkdirs(); BufferedInputStream fis = new BufferedInputStream(new FileInputStream(inCannon)); BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(outCannon)); // a temporary buffer to read into byte[] tmpBuffer = new byte[8192]; int len = 0; while ((len = fis.read(tmpBuffer)) != -1) { // add the temp data to the output fos.write(tmpBuffer, 0, len); } // close the input stream fis.close(); // close the output stream fos.flush(); fos.close(); } // Copies all files under srcDir to dstDir. // If dstDir does not exist, it will be created. public static void copyDirectory(File srcDir, File dstDir) throws IOException { if (srcDir.isDirectory()) { if (!dstDir.exists()) { dstDir.mkdir(); } String[] children = srcDir.list(); for (int i = 0; i < children.length; i++) { copyDirectory(new File(srcDir, children[i]), new File(dstDir, children[i])); } } else { copyFile(srcDir, dstDir); } } public static boolean deleteDir(File dir) { if (dir.isDirectory()) { String[] children = dir.list(); for (int i = 0; i < children.length; i++) { boolean success = deleteDir(new File(dir, children[i])); if (!success) { System.err.println("could not remove directory: " + dir.getAbsolutePath()); return false; } } } return dir.delete(); } /** * Merges the two arrays (not necessarily creating a new array). If both are * null, null is returned. If one is null, the other is returned. * * @throws ArrayStoreException * uses System.arrarycopy and has same contract */ public static java.lang.Object concatenateArrays(Class<?> resultClass, java.lang.Object arr1, java.lang.Object arr2) throws ArrayStoreException { if (arr1 == null) { return arr2; } else if (arr2 == null) { return arr1; } java.lang.Object newArray = Array.newInstance(resultClass, Array.getLength(arr1) + Array.getLength(arr2)); System.arraycopy(arr1, 0, newArray, 0, Array.getLength(arr1)); System.arraycopy(arr2, 0, newArray, Array.getLength(arr1), Array.getLength(arr2)); return newArray; } /** * Appends to an array * * @param array * The array to append to * @param appendix * The object to append to the array * @return An array with the new item appended */ public static java.lang.Object appendToArray(java.lang.Object array, java.lang.Object appendix) { Class<?> arrayType = array.getClass().getComponentType(); java.lang.Object newArray = Array.newInstance(arrayType, Array.getLength(array) + 1); System.arraycopy(array, 0, newArray, 0, Array.getLength(array)); Array.set(newArray, Array.getLength(newArray) - 1, appendix); return newArray; } /** * Removes an object from an array. * * @param array * @param removal * @return An array with the item removed */ public static java.lang.Object removeFromArray(java.lang.Object array, java.lang.Object removal) { Class<?> arrayType = array.getClass().getComponentType(); int length = Array.getLength(array); List<Object> temp = new ArrayList<Object>(length - 1); for (int i = 0; i < length; i++) { java.lang.Object o = Array.get(array, i); if (!o.equals(removal)) { temp.add(o); } } java.lang.Object newArray = Array.newInstance(arrayType, temp.size()); System.arraycopy(temp.toArray(), 0, newArray, 0, temp.size()); return newArray; } /** * Trims an array * * @param array * @param startIndex * @param endIndex * @return */ public static java.lang.Object trimArray(java.lang.Object array, int startIndex, int endIndex) { Class<?> arrayType = array.getClass().getComponentType(); int length = endIndex - startIndex; java.lang.Object newArray = Array.newInstance(arrayType, length); System.arraycopy(array, startIndex, newArray, 0, length); return newArray; } public static StringBuffer fileToStringBuffer(File file) throws IOException { BufferedReader br = new BufferedReader(new FileReader(file)); StringBuffer sb = new StringBuffer(); try { String s = null; while ((s = br.readLine()) != null) { sb.append(s + "\n"); } } finally { br.close(); } return sb; } public static StringBuffer inputStreamToStringBuffer(InputStream stream) throws IOException { InputStreamReader reader = new InputStreamReader(stream); StringBuffer str = new StringBuffer(); char[] buff = new char[8192]; int len = 0; while ((len = reader.read(buff)) != -1) { str.append(buff, 0, len); } reader.close(); return str; } /** * Serialize an Object to XML * * @param obj * The object to be serialized * @param qname * The QName of the object * @param writer * A writer to place XML into (eg: FileWriter, StringWriter). If * a file writer is used, be sure to close it! * @param wsdd * A stream containing the WSDD configuration. This may be null. * @throws Exception */ public static void serializeObject(Object obj, QName qname, Writer writer, InputStream wsdd) throws Exception { // derive a message element for the object MessageElement element = (MessageElement) ObjectSerializer.toSOAPElement(obj, qname); AxisEngine axisEngine = null; if (wsdd != null) { // configure the axis engine to use the supplied wsdd file EngineConfiguration engineConfig = new FileProvider(wsdd); axisEngine = new AxisServer(engineConfig); } else { // no wsdd, do the default axisEngine = new AxisServer(); } MessageContext messageContext = new MessageContext(axisEngine); messageContext.setEncodingStyle(""); messageContext.setProperty(AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE); // the following two properties prevent xsd types from appearing in // every single element in the serialized XML messageContext.setProperty(AxisEngine.PROP_EMIT_ALL_TYPES, Boolean.FALSE); messageContext.setProperty(AxisEngine.PROP_SEND_XSI, Boolean.FALSE); // create a serialization context to use the new message context SerializationContext serializationContext = new SerializationContext(writer, messageContext) { public void serialize(QName elemQName, Attributes attributes, Object value) throws IOException { serialize(elemQName, attributes, value, null, Boolean.FALSE, null); } }; serializationContext.setPretty(true); // output the message element through the serialization context element.output(serializationContext); writer.write("\n"); writer.flush(); } /** * Serialize an Object to XML * * @param obj * The object to be serialized * @param qname * The QName of the object * @param writer * A writer to place XML into (eg: FileWriter, StringWriter). If * a file writer is used, be sure to close it! * @throws Exception */ public static void serializeObject(Object obj, QName qname, Writer writer) throws Exception { serializeObject(obj, qname, writer, null); } /** * Deserializes XML into an object * * @param xmlReader * The reader for the XML (eg: FileReader, StringReader, etc) * @param clazz * The class to serialize to * @param wsdd * A stream containing the WSDD configuration * @return The object deserialized from the XML * @throws SAXException * @throws DeserializationException */ public static <T> T deserializeObject(Reader xmlReader, Class<T> clazz, InputStream wsdd) throws SAXException, DeserializationException { // input source for the xml InputSource xmlSource = new InputSource(xmlReader); return ConfigurableObjectDeserializer.toObject(xmlSource, clazz, wsdd); } public static <T> T deserializeObject(Reader xmlReader, Class<T> clazz) throws Exception { org.w3c.dom.Document doc = XMLUtils.newDocument(new InputSource(xmlReader)); Object obj = ObjectDeserializer.toObject(doc.getDocumentElement(), clazz); return clazz.cast(obj); } public static void serializeDocument(String fileName, Object object, QName qname) throws Exception { FileWriter fw = null; fw = new FileWriter(fileName); ObjectSerializer.serialize(fw, object, qname); fw.close(); } public static String clean(String s) { if ((s == null) || (s.trim().length() == 0)) { return null; } else { return s; } } public static void stringBufferToFile(StringBuffer string, String fileName) throws IOException { stringBufferToFile(string, new File(fileName)); } public static void stringBufferToFile(StringBuffer string, File file) throws IOException { FileWriter fw = new FileWriter(file); fw.write(string.toString()); fw.close(); } /** * Like Object.equals, but if o1 == null && o2 == null, returns true * * @param o1 * @param o2 * @return */ public static boolean equals(Object o1, Object o2) { if (o1 == null) { return o2 == null; } return o1.equals(o2); } /** * Gets the QName that Axis has registered for the given java class * * @param clazz * @return The QName corresponding to the class registered in the Axis type * mappings */ public static QName getRegisteredQName(Class<?> clazz) { return MessageContext.getCurrentContext().getTypeMapping().getTypeQName(clazz); } /** * Gets the Class that Axis has registerd for the given QName * * @param qname * @return The class corresponding to the QName as registered in the Axis * type mappings */ public static Class<?> getRegisteredClass(QName qname) { return MessageContext.getCurrentContext().getTypeMapping().getClassForQName(qname); } public static List<File> recursiveListFiles(File baseDir, final FileFilter filter) { FileFilter dirFilter = new FileFilter() { public boolean accept(File pathname) { return pathname.isDirectory() || filter.accept(pathname); } }; File[] fileArray = baseDir.listFiles(dirFilter); List<File> files = new ArrayList<File>(fileArray.length); for (int i = 0; i < fileArray.length; i++) { if (fileArray[i].isDirectory()) { files.addAll(recursiveListFiles(fileArray[i], filter)); } else { files.add(fileArray[i]); } } return files; } /** * Gets a relative path from the source file to the destination * * @param source * The source file or location * @param destination * The file to target with the relative path * @return The relative path from the source file's directory to the * destination file */ public static String getRelativePath(File source, File destination) throws IOException { String sourceDir = null; String destDir = null; if (source.isDirectory()) { sourceDir = source.getCanonicalPath(); } else { sourceDir = source.getParentFile().getCanonicalPath(); } if (destination.isDirectory()) { destDir = destination.getCanonicalPath(); } else { destDir = destination.getParentFile().getCanonicalPath(); } // find the overlap in the source and dest paths String overlap = findOverlap(sourceDir, destDir); // strip off a training File.separator if (overlap.endsWith(File.separator)) { if (overlap.equals(File.separator)) { overlap = ""; } else { overlap = overlap.substring(0, overlap.length() - File.separator.length() - 1); } } int overlapDirs = countChars(overlap, File.separatorChar); if (overlapDirs == 0) { // no overlap at all, return full path of destination file return destination.getCanonicalPath(); } // difference is the number of path elements to back up before moving // down the tree int parentDirsNeeded = countChars(sourceDir, File.separatorChar) - overlapDirs; // difference is the number of path elements above the file to keep int parentDirsKept = countChars(destDir, File.separatorChar) - overlapDirs; // build the path StringBuffer relPath = new StringBuffer(); for (int i = 0; i < parentDirsNeeded; i++) { relPath.append("..").append(File.separatorChar); } List<String> parentPaths = new LinkedList<String>(); File parentDir = new File(destDir); for (int i = 0; i < parentDirsKept; i++) { parentPaths.add(parentDir.getName()); parentDir = parentDir.getParentFile(); } Collections.reverse(parentPaths); for (Iterator<String> i = parentPaths.iterator(); i.hasNext();) { relPath.append(i.next()).append(File.separatorChar); } if (!destination.isDirectory()) { relPath.append(destination.getName()); } return relPath.toString(); } private static String findOverlap(String s1, String s2) { // TODO: More efficient would be some kind of binary search, divide and // conquer StringBuffer overlap = new StringBuffer(); int count = Math.min(s1.length(), s2.length()); for (int i = 0; i < count; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 == c2) { overlap.append(c1); } else { break; } } return overlap.toString(); } private static int countChars(String s, char c) { int count = 0; int index = -1; while ((index = s.indexOf(c, index + 1)) != -1) { count++; } return count; } public static Object cloneBean(Object bean, QName qname) throws Exception { StringWriter writer = new StringWriter(); serializeObject(bean, qname, writer); return deserializeObject(new StringReader(writer.getBuffer().toString()), bean.getClass()); } public static String decodeUrl(URL url) throws UnsupportedEncodingException { String enc = System.getProperty("file.encoding"); String decode = URLDecoder.decode(url.getFile(), enc); return decode; } public static String encodeUrl(String url) { char[] badChars = ";?#&=+$, <>~".toCharArray(); String[] replace = {"%3B", "%3F", "%23", "%24", "%3D", "%2B", "%26", "%2C", "%20", "%3C", "%3E", "%7E"}; for (int i = 0; i < badChars.length; i++) { url = url.replace(String.valueOf(badChars[i]), replace[i]); } return url; } public static byte[] inputStreamToByteArray(InputStream is) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] temp = new byte[8192]; int len = -1; while ((len = is.read(temp)) != -1) { out.write(temp, 0, len); } out.close(); return out.toByteArray(); } }