src.main.java.com.eva.properties.ProtocolFactory Maven / Gradle / Ivy
/*
* $Id: ProtocolFactory.java 37 2007-02-27 11:42:55Z 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.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* creates objects for protocol-style strings.
*
* @author Max Antoni
* @version $Revision: 37 $
*/
abstract class ProtocolFactory {
/**
* protocol name for classpath URLs.
*/
private static final String PROTOCOL_CLASSPATH = "classpath";
/**
* protocol name for {@link DataSource datasources}.
*/
private static final String PROTOCOL_DATASOURCE = "datasource";
/**
* protocol name for files.
*/
private static final String PROTOCOL_FILE = "file";
/**
* protocol name for URLs.
*/
private static final String PROTOCOL_URL = "url";
/**
* protocol name for Java classes.
*/
private static final String PROTOCOL_CLASS = "class";
/**
* protocol name for static instances.
*/
private static final String PROTOCOL_STATIC = "static";
/**
* protocol name for strings that start with a protocol.
*/
private static final String PROTOCOL_STRING = "string";
private static final String COLON_SLASH_SLASH = "://";
private static final Map PROTOCOL_FACTORIES;
private static final Pattern PROTOCOL_PATTERN = Pattern.compile(
"^([a-z]{3,})\\:\\/\\/.*");
static {
PROTOCOL_FACTORIES = new HashMap();
PROTOCOL_FACTORIES.put(PROTOCOL_STRING, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath) {
return removePrefix(inPath);
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_CLASS, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath) {
return inContext.loadClass(removePrefix(inPath));
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_STATIC, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath) {
String path = removePrefix(inPath);
int p = path.indexOf('#');
if(p == -1) {
throw new IllegalArgumentException("No hash found in "
+ inPath);
}
Class clazz = inContext.loadClass(path.substring(0, p));
String instance = path.substring(p + 1);
Field field;
try {
field = clazz.getField(instance);
}
catch(SecurityException e) {
throw new RuntimeException(e);
}
catch(NoSuchFieldException e) {
throw new RuntimeException(e);
}
if(Modifier.isStatic(field.getModifiers())) {
try {
return field.get(null);
}
catch(IllegalArgumentException e) {
throw new RuntimeException(e);
}
catch(IllegalAccessException e) {
throw new RuntimeException(e);
}
}
throw new IllegalArgumentException(clazz.getName() + "#"
+ instance + " is not static.");
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_URL, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath)
throws FileNotFoundException {
try {
return new URL(removePrefix(inPath));
}
catch(MalformedURLException e) {
throw new FileNotFoundException(e.getMessage());
}
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_FILE, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath) {
return new File(removePrefix(inPath).replace('/',
File.separatorChar));
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_DATASOURCE, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath)
throws FileNotFoundException, PropertiesException {
return new DataSource((ClassLoader) inContext
.lookup("classloader"), removePrefix(inPath));
}
});
PROTOCOL_FACTORIES.put(PROTOCOL_CLASSPATH, new ProtocolFactory() {
/*
* @see com.eva.properties.ProtocolFactory#build(
* com.eva.properties.Context, java.lang.String)
*/
Object build(Context inContext, String inPath)
throws FileNotFoundException, PropertiesException {
return new DataSource((ClassLoader) inContext
.lookup("classloader"), inPath);
}
});
}
/**
*
* returns an object for a string. If the string starts with a protocol, the
* replacement for that specific protocol will be returned. If the protocol
* references any kind of file, but the file is not found, null
* is returned. If an exception is catched during the creation of the
* object, it will be wrapped in a {@link PropertiesException}.
*
*
* If the given string does not match a protocol, the sting itself is
* returned.
*
*
* @param inContext the context.
* @param inString the string to be replaced.
* @return the replaced object, the string argument or null
.
* @throws PropertiesException if an exception was thrown while creating the
* object.
*/
static Object forString(Context inContext, String inString)
throws PropertiesException {
Matcher matcher = PROTOCOL_PATTERN.matcher(inString);
if(matcher.matches()) {
ProtocolFactory factory = (ProtocolFactory) PROTOCOL_FACTORIES.get(
matcher.group(1));
if(factory == null) {
try {
return new URL(inString);
}
catch(MalformedURLException e) {
throw new PropertiesException(e);
}
}
try {
return factory.build(inContext, inString);
}
catch(FileNotFoundException e) {
if(Log.INSTANCE.isLoggable(Level.FINE)) {
Log.INSTANCE.fine("Properties: File not found, "
+ e.getMessage());
}
return null; // Try next if in switch
}
}
return inString; // not a URL
}
/**
* standard constructor.
*/
ProtocolFactory() {
super();
}
/**
* creates an object for a path.
*
* @param inContext the context.
* @param inPath the path.
* @return the object.
* @throws FileNotFoundException if the object is a file that cannot be
* found.
* @throws PropertiesException if any unexpected exception accours that
* cannot be handled properly by throwing a
* FileNotFoundException
.
*/
abstract Object build(Context inContext, String inPath)
throws FileNotFoundException, PropertiesException;
/**
* helper method that removes the protocol prefix from a url.
*
* @param inUrl the url.
* @return the url without the prefix.
*/
String removePrefix(String inUrl) {
return inUrl.substring(inUrl.indexOf(COLON_SLASH_SLASH)
+ COLON_SLASH_SLASH.length());
}
}