com.eva.properties.DataSource Maven / Gradle / Ivy
/*
* $Id: DataSource.java 23 2007-02-16 07:44:41Z max $
*
* Copyright (c) 2006-2007 Maximilian Antoni. All rights reserved.
*
* This software is licensed as described in the file LICENSE.txt, which you
* should have received as part of this distribution. The terms are also
* available at http://www.maxantoni.de/projects/eva-properties/license.txt.
*/
package com.eva.properties;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Pattern;
/**
* provides access to files and URLs in a unified way.
*
* @author Max Antoni
* @version $Revision: 23 $
*/
public class DataSource {
/**
* defines a delegate for data retrieval.
*/
private interface Delegate {
abstract Object getBase();
abstract Reader getReader() throws IOException;
}
/**
* retrieves data from a file.
*/
private static class FileDelegate implements Delegate {
private File file;
FileDelegate(File inFile) {
super();
file = inFile;
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj == null || getClass() != obj.getClass()) {
return false;
}
return file.equals(((FileDelegate) obj).file);
}
/*
* @see com.eva.properties.DataSource.Delegate#getBase()
*/
public Object getBase() {
try {
return new File(file.getParent()).getCanonicalFile();
}
catch(IOException e) {
Log.INSTANCE.warning("Cannot resolve canonical form of \""
+ file.getParent() + "\": " + e.getMessage());
return new File(file.getParent());
}
}
/*
* @see com.eva.properties.DataSource.Delegate#getReader()
*/
public Reader getReader() throws IOException {
return new FileReader(file);
}
/*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 17 + 5 * file.hashCode();
}
/*
* @see java.lang.Object#toString()
*/
public String toString() {
return "\"file://" + file.getAbsolutePath() + "\"";
}
}
/**
* retrieves data from a URL.
*/
private static class URLDelegate implements Delegate {
private URL url;
URLDelegate(URL inUrl) {
super();
url = inUrl;
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj == null || getClass() != obj.getClass()) {
return false;
}
return url.equals(((URLDelegate) obj).url);
}
/*
* @see com.eva.properties.DataSource.Delegate#getBase()
*/
public Object getBase() {
String base = url.getFile();
base = base.substring(base.lastIndexOf('/'));
try {
return new URL(url.getProtocol(), url.getHost(), url.getPort(),
base);
}
catch(MalformedURLException e) {
throw new RuntimeException(e.getMessage());
}
}
/*
* @see com.eva.properties.DataSource.Delegate#getReader()
*/
public Reader getReader() throws IOException {
return new InputStreamReader(url.openStream());
}
/*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 31 + url.hashCode();
}
/*
* @see java.lang.Object#toString()
*/
public String toString() {
return "\"" + url.toString() + "\"";
}
}
private static final String CLASSPATH = "classpath://";
private static final Pattern URL_PATTERN = Pattern
.compile("^[a-z]{3,}\\:\\/\\/.*");
private ClassLoader classLoader;
private Delegate delegate;
/**
*
* creates a data source with a class loader and a path. The path argument
* can point to different types of resources:
*
* - If the path starts with "classpath://" it specifies a
* classpath resource.
* - If the path matches the URL pattern, witch is the case if it starts
* with at least 3 lowercase characters in the range [a-z], followed by the
* sequence "://", the path specifies a URL resosurce.
* - Otherwise the path specifies a file resource.
*
* If non of the above is the case, a FileNotFoundException
* is thrown.
*
*
* If you don't rely on a special class loader, use
* {@link #DataSource(String)}.
*
*
* @param inClassLoader the class loader.
* @param inPath the path.
* @throws FileNotFoundException if the resource specified by
* inPath
cannot be found.
* @see #DataSource(String)
*/
public DataSource(ClassLoader inClassLoader, String inPath)
throws FileNotFoundException {
super();
if(inPath == null) {
throw new NullPointerException("Path cannot be null.");
}
classLoader = inClassLoader; // null permitted, see DataSource(String)
if(inPath.startsWith(CLASSPATH)) {
initWithClassPath(inPath);
}
else if(inPath.startsWith("file://")) {
File file = new File(inPath.substring(7).replace('/',
File.separatorChar));
if(!file.exists()) {
throw new FileNotFoundException("File not found: "
+ file.getAbsolutePath());
}
delegate = new FileDelegate(file);
}
else if(URL_PATTERN.matcher(inPath).matches()) {
try {
delegate = new URLDelegate(new URL(inPath));
}
catch(MalformedURLException e) {
throw new FileNotFoundException("Malformed URL: " + inPath);
}
}
else {
File file = new File(inPath.replace('/', File.separatorChar));
if(!file.exists()) {
throw new FileNotFoundException("File not found: "
+ file.getAbsolutePath());
}
delegate = new FileDelegate(file);
}
}
/**
* creates a data source from a file.
*
* @param inFile the file.
* @throws NullPointerException if inFile
is null
.
* @throws FileNotFoundException if the file was not found.
*/
public DataSource(File inFile) throws FileNotFoundException {
super();
if(inFile == null) {
throw new NullPointerException();
}
if(!inFile.exists()) {
throw new FileNotFoundException(inFile.getAbsolutePath());
}
delegate = new FileDelegate(inFile);
}
/**
* creates a data source from a path. This convenience constructor behaves
* like DataSource(null, inPath)
.
*
* @param inPath in path.
* @throws FileNotFoundException
* @see #DataSource(ClassLoader, String)
*/
public DataSource(String inPath) throws FileNotFoundException {
this(null, inPath);
}
/*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object inObject) {
if(this == inObject) {
return true;
}
if(inObject == null || getClass() != inObject.getClass()) {
return false;
}
return delegate.equals(((DataSource) inObject).delegate);
}
/**
* returns the delegate-base for this DataSource.
*
* @return the delegate-base.
*/
public Object getDelegateBase() {
return delegate.getBase();
}
/**
* returns the reader for this data source.
*
* @return the reader.
* @throws IOException if the reader cannot be resolved.
*/
public Reader getReader() throws IOException {
return delegate.getReader();
}
/*
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return 31 + delegate.hashCode();
}
/*
* @see java.lang.Object#toString()
*/
public String toString() {
return delegate.toString();
}
/**
* returns the ClassLoader for this DataSource.
*
* @return the ClassLoader.
*/
ClassLoader getClassLoader() {
return classLoader;
}
/**
* helper method for initializing this DataSource with a path starting with
* "classpath".
*
* @param inPath the path.
* @throws FileNotFoundException
*/
private void initWithClassPath(String inPath) throws FileNotFoundException {
String classpathResource = inPath.substring(CLASSPATH.length());
URL resource;
if(classLoader == null) {
resource = Thread.currentThread().getContextClassLoader()
.getResource(classpathResource);
}
else {
resource = classLoader.getResource(classpathResource);
}
if(resource == null) {
throw new FileNotFoundException("Resource not found in classpath: "
+ classpathResource);
}
delegate = new URLDelegate(resource);
}
}