/*
* ====================================================================
*
* This code is subject to the freebxml License, Version 1.1
*
* Copyright (c) 2001 - 2003 freebxml.org. All rights reserved.
*
* $Header: /cvsroot/ebxmlrr/omar/src/java/org/freebxml/omar/common/Utility.java,v 1.40 2007/05/18 18:58:59 psterk Exp $
* ====================================================================
*/
package org.openhealthtools.openxds.repository;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import org.openhealthtools.openxds.repository.api.XdsRepositoryItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Class Declaration.
* @see
* @author Farrukh S. Najmi
* @author Adrian Chong
* @version 1.2, 05/02/00
*/
public class Utility {
private static final Log log = LogFactory.getLog(Utility.class);
public static final int MAX_REGISTRY_ID_LENGTH = 256;
private static HashMap tableNameMap = new HashMap();
public static final String FILE_SEPARATOR = System.getProperty(
"file.separator");
/*
* See http://www.digit-life.com/articles/ntfs/
*/
public static final int MAX_FILE_LENGTH = 255;
/**
* 128-bit buffer for use with secRand
*/
private final byte[] secRandBuf16 = new byte[16];
/**
* 64-bit buffer for use with secRand
*/
private final byte[] secRandBuf8 = new byte[8];
/**
* random number generator for UUID generation
*/
private final SecureRandom secRand = new SecureRandom();
static {
tableNameMap.put("user", "user_");
tableNameMap.put("name", "name_");
tableNameMap.put("classificationscheme", "ClassScheme");
tableNameMap.put("concept", "ClassificationNode");
}
private static HashMap columnNameMap = new HashMap();
static {
columnNameMap.put("number", "number_");
columnNameMap.put("name", "name_");
columnNameMap.put("user", "user_");
columnNameMap.put("timestamp", "timestamp_");
}
/**
* @link
* @shapeType PatternLink
* @pattern Singleton
* @supplierRole Singleton factory
*/
/* # private Utility _utility; */
private static Utility instance = null;
/**
* Class Constructor.
*
*
* @see
*/
protected Utility() {
}
/**
* Converts an InputStream to a String.
*
* @param is the InputStream content to convert to String
*/
public String unmarshalInputStreamToString(InputStream is)
throws IOException {
int buflen = 1024;
byte[] bytes = new byte[buflen + 1];
BufferedInputStream bis = new BufferedInputStream(is);
int bytesRead = 0;
StringBuffer strBuf = new StringBuffer();
while ((bytesRead = bis.read(bytes, 0, buflen)) != -1) {
strBuf.append(new String(bytes, 0, bytesRead, "utf-8"));
}
return strBuf.toString();
}
/**
* Create a temporary file with the specified content.
*
* @param content contents of the created RepositoryItem
* @param deleteOnExit deletes the temporary file upon exiting the VM if true.
*
* @return the File instance representing the temporary file
*/
public static File createTempFile(String content, boolean deleteOnExit) throws IOException {
// Write to temp file
byte[] bytes = content.getBytes("utf-8");
File temp = createTempFile(bytes, "omar", ".txt", deleteOnExit);
return temp;
}
public static File createTempFile(byte[] bytes, String prefix, String extension, boolean deleteOnExit) throws IOException {
File temp = File.createTempFile(prefix, extension);
// Delete temp file when program exits.
if (deleteOnExit) {
temp.deleteOnExit();
}
// Write to temp file
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(temp));
out.write(bytes, 0, bytes.length);
out.close();
return temp;
}
/**
* Create a RepositoryItem containing provided content.
*
* @param id the id of the created ExtrinsicObject created for the RepositoryItem
* @param content contents of the created RepositoryItem
*
* @return a <code>RepositoryItem</code> value
* @throws IOException encountered during IO operations
*/
public XdsRepositoryItem createRepositoryItem(String id, String content) throws IOException {
File file = createTempFile(content, true);
DataHandler dh = new DataHandler(new FileDataSource(file));
XdsRepositoryItem ri = new XdsRepositoryItemImpl(id, dh);
return ri;
}
/**
* Create a valid registry id.
*/
public String createId() {
String id = "urn:uuid:" + getNewUUID();
return id;
}
/**
* Strip urn:uuid: part from start of registry
* object id. If id is null or doesn't start with
* urn:uuid: then the id is returned without modification.
*/
public String stripId(String id) {
if (id != null) {
if (id.startsWith("urn:uuid:")) {
id = id.substring(9).trim();
} else {
// id is urn
id = id.replaceAll(":", "_");
}
}
return id;
}
/**
* Validates URIs according to Registry specs.
*
* From Registry specs: "If the URI is a URL then a registry MUST validate the
* URL to be resolvable at the time of submission before accepting an
* ExternalLink submission to the registry."
*
* Any non-Http URLs and other types of URIs will not be checked. If the http
* response code is smaller than 200 or bigger than 299, the http URL is
* considered invalid.
*/
public boolean isValidURI(String uRI) {
if (uRI == null) {
return false;
}
try {
java.net.URI _uri = new java.net.URI(uRI);
} catch (java.net.URISyntaxException e) {
// Not an URI. return false
return false;
}
// Quoting Doug: "URLs are resolvable URIs"!
// Try to resolve the URLs here, if it is URL
try {
java.net.URL uRL = new java.net.URL(uRI);
if (uRI.startsWith("http:")) {
java.net.HttpURLConnection httpUrlConn = (java.net.HttpURLConnection) uRL.openConnection();
int responseCode = httpUrlConn.getResponseCode();
if ((responseCode < 200) || (responseCode > 299)) {
return false;
} else {
return true;
}
} else {
URLConnection conn = uRL.openConnection();
}
} catch (java.net.MalformedURLException e) {
// Not an URL, will not try to resolve. Valid URI
} catch (IOException e) {
return false;
}
return true;
}
public static String fixIdentifier(String inputId) {
String outputId = inputId.replace(':', '_');
outputId = outputId.replace('.', '_');
outputId = outputId.replace('$', '_');
return outputId;
}
/**
* Fixes an input URN to comply with URN syntax by replacing invalid chars with '_'
*/
public static String fixURN(String inputId) {
String outputId = inputId.replace(FILE_SEPARATOR.charAt( 0 ), ':');
if (!(outputId.startsWith("urn:"))) {
outputId = "urn:" + outputId;
}
outputId = outputId.replaceAll("[^a-zA-Z_0-9:_]", "_");
return outputId;
}
/*
* Gets the path suitable for the path component of a URL based upon the specified URI.
*/
public static String getURLPathFromURI(String uri) throws URISyntaxException {
String path = null;
try {
URL url = new URL(uri);
path = url.getPath();
} catch (MalformedURLException e) {
//Not a URL. Convert to URN
String urn = fixURN(uri);
path = getURLPathFromURN(urn);
}
return path;
}
public static String getURLPathFromURN(String urn) throws URISyntaxException {
String path = null;
URI uri = new java.net.URI(urn);
path = urn.replaceAll("[:]", "/");
return path;
}
public static ZipOutputStream createZipOutputStream(String baseDir, String[] relativeFilePaths, OutputStream os) throws FileNotFoundException, IOException {
if (baseDir.startsWith("file:/")) {
baseDir = baseDir.substring(5);
}
ZipOutputStream zipoutputstream = new ZipOutputStream(os);
zipoutputstream.setMethod(ZipOutputStream.STORED);
for (int i = 0; i < relativeFilePaths.length; i++) {
File file = new File(baseDir + FILE_SEPARATOR + relativeFilePaths[i]);
byte [] buffer = new byte [1000];
int n;
FileInputStream fis;
// Calculate the CRC-32 value. This isn't strictly necessary
// for deflated entries, but it doesn't hurt.
CRC32 crc32 = new CRC32();
fis = new FileInputStream(file);
while ((n = fis.read(buffer)) > -1) {
crc32.update(buffer, 0, n);
}
fis.close();
// Create a zip entry.
ZipEntry zipEntry = new ZipEntry(relativeFilePaths[i]);
zipEntry.setSize(file.length());
zipEntry.setTime(file.lastModified());
zipEntry.setCrc(crc32.getValue());
// Add the zip entry and associated data.
zipoutputstream.putNextEntry(zipEntry);
fis = new FileInputStream(file);
while ((n = fis.read(buffer)) > -1) {
zipoutputstream.write(buffer, 0, n);
}
fis.close();
zipoutputstream.closeEntry();
}
return zipoutputstream;
}
/**
*
* Extracts Zip file contents relative to baseDir
* @return An ArrayList containing the File instances for each unzipped file
*/
public static ArrayList unZip(String baseDir, InputStream is) throws IOException {
ArrayList files = new ArrayList();
ZipInputStream zis = new ZipInputStream(is);
while (true) {
// Get the next zip entry. Break out of the loop if there are
// no more.
ZipEntry zipEntry = zis.getNextEntry();
if (zipEntry == null) break;
String entryName = zipEntry.getName();
if (FILE_SEPARATOR.equalsIgnoreCase("\\")) {
// Convert '/' to Windows file separator
entryName = entryName.replaceAll("/", "\\\\");
}
String fileName = baseDir + FILE_SEPARATOR + entryName;
//Make sure that directory exists.
String dirName = fileName.substring(0, fileName.lastIndexOf(FILE_SEPARATOR));
File dir = new File(dirName);
dir.mkdirs();
//Entry could be a directory
if (!(zipEntry.isDirectory())) {
//Entry is a file not a directory.
//Write out the content of of entry to file
File file = new File(fileName);
files.add(file);
FileOutputStream fos = new FileOutputStream(file);
// Read data from the zip entry. The read() method will return
// -1 when there is no more data to read.
byte [] buffer = new byte [1000];
int n;
while ((n = zis.read(buffer)) > -1) {
// In real life, you'd probably write the data to a file.
fos.write(buffer, 0, n);
}
zis.closeEntry();
fos.close();
} else {
zis.closeEntry();
}
}
zis.close();
return files;
}
/* public String mapTableName(RegistryObjectType ro) {
Class clazz = ro.getClass();
String className = clazz.getName();
className = className.substring(className.lastIndexOf(".") + 1);
if (className.endsWith("Impl")) {
className = className.substring(0, className.length() - 4);
}
return mapTableName(className);
}*/
public String mapTableName(String name) {
String newName = (String) tableNameMap.get(name.toLowerCase().trim());
if (newName == null) {
newName = name;
}
return newName;
}
public String mapColumnName(String name) {
String newName = (String) columnNameMap.get(name.toLowerCase().trim());
if (newName == null) {
newName = name;
}
return newName;
}
public String getClassNameNoPackage(Object obj) {
Class clazz = obj.getClass();
return getClassNameNoPackage(clazz);
}
public String getClassNameNoPackage(Class clazz) {
String className = clazz.getName();
//Make sure className is not package qualified
int index = className.lastIndexOf('.');
if (index >=0 ) {
className = className.substring(index+1, className.length());
}
return className;
}
public static boolean containsWhiteSpacesOnly(String str) {
boolean whiteSpaceOnly = false;
String[] strArr = str.split("[^\\s]");
if ((str == null) || (str.length() == 0) || ((str.split("[^\\s]")).length <= 1)) {
whiteSpaceOnly = true;
}
return whiteSpaceOnly;
}
public static String absolutize(String name) {
// absolutize all the system IDs in the input,
// so that we can map system IDs to DOM trees.
try {
URL baseURL = new File(".").getCanonicalFile().toURL();
return new URL(baseURL, name).toExternalForm();
} catch( IOException e ) {
; // ignore
}
return name;
}
public static String getFileOrURLName(String fileOrURL) {
try{
try {
return escapeSpace(new URL(fileOrURL).toExternalForm());
} catch (MalformedURLException e) {
return new File(fileOrURL).getCanonicalFile().toURL().toExternalForm();
}
} catch (Exception e) {
// try it as an URL
return fileOrURL;
}
}
private static String escapeSpace( String url ) {
// URLEncoder didn't work.
StringBuffer buf = new StringBuffer();
for (int i = 0; i < url.length(); i++) {
// TODO: not sure if this is the only character that needs to be escaped.
if (url.charAt(i) == ' ')
buf.append("%20");
else
buf.append(url.charAt(i));
}
return buf.toString();
}
/**
* Method Declaration.
*
*
* @return
*
* @see
*/
public synchronized static Utility getInstance() {
if (instance == null) {
instance = new Utility();
}
return instance;
}
/**
* This method is used to retrieve a QName prefix
*
* @arg qName
* A String containing the QName from which to retrieve the prefix.
* @return
* A String containing the prefix
*/
public static String getPrefix(String qName) {
int i = qName.indexOf(':');
if (i == -1) {
return null;
}
return qName.substring(0, i);
}
/**
* This method is used to retrieve the local part of a QName
*
* @arg qName
* A String containing the QName from which to retrieve the local part.
* @return
* A String containing the local part
*/
public static String getLocalPart(String qName) {
int i = qName.lastIndexOf(':');
if (i == -1) {
return qName;
}
return qName.substring(i + 1);
}
/**
* Replaces a JDK 1.5 Pattern.quote method to allow use with JDK 1.4
*
* Returns a literal pattern <code>String</code> for the specified
* <code>String</code>.
*
* <p>This method produces a <code>String</code> that can be used to
* create a <code>Pattern</code> that would match the string
* <code>s</code> as if it were a literal pattern.</p> Metacharacters
* or escape sequences in the input sequence will be given no special
* meaning.
*
* @param s The string to be literalized
* @return A literal string replacement
* @since 1.5
*/
public static String quote(String s) {
int slashEIndex = s.indexOf("\\E");
if (slashEIndex == -1)
return "\\Q" + s + "\\E";
StringBuffer sb = new StringBuffer(s.length() * 2);
sb.append("\\Q");
slashEIndex = 0;
int current = 0;
while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
sb.append(s.substring(current, slashEIndex));
current = slashEIndex + 2;
sb.append("\\E\\\\E\\Q");
}
sb.append(s.substring(current, s.length()));
sb.append("\\E");
return sb.toString();
}
/**
* This method takes a fileName and verifies that it is a valid filename
* @param fileName
* A String that contains the file name to validate
* @return
* A String that contains a validated file name
*/
public static String makeValidFileName(String fileName) {
// First check to see if fileName is > MAX_FILE_LENGTH
// If it is, truncate.
String validFileName = new String(fileName);
int fileNameLength = validFileName.length();
if (fileNameLength > MAX_FILE_LENGTH) {
validFileName = validFileName.substring(0, MAX_FILE_LENGTH-1);
}
// Replace illegal characters with a '-'
validFileName = validFileName.replaceAll("[:*?\"<>]", "-");
return validFileName;
}
public UUID getNewUUID() {
secRand.nextBytes(secRandBuf16);
secRandBuf16[6] &= 0x0f;
secRandBuf16[6] |= 0x40; /* version 4 */
secRandBuf16[8] &= 0x3f;
secRandBuf16[8] |= 0x80; /* IETF variant */
secRandBuf16[10] |= 0x80; /* multicast bit */
long mostSig = 0;
for (int i = 0; i < 8; i++) {
mostSig = (mostSig << 8) | (secRandBuf16[i] & 0xff);
}
long leastSig = 0;
for (int i = 8; i < 16; i++) {
leastSig = (leastSig << 8) | (secRandBuf16[i] & 0xff);
}
return new UUID(mostSig, leastSig);
}
}