package org.dcache.gplazma.loader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
/**
* The Utf8DataClassLoader is a {@link ClassLoader} that provides access to
* zero or more resources at some fixed location.
* <p>
* The class initially has zero resources at that location and additional
* resources may be added by calling the {@link #addResource} method. The
* resources are added as strings and made available as a UTF-8 encoded
* byte-stream of the supplied String's data.
*/
public class Utf8DataClassLoader extends ClassLoader {
private static final String URL_SCHEMA = "test";
private static final String URL_HOSTNAME = "ignored-host.invalid";
private static final int URL_DEFAULT_PORT = -1;
private final URLStreamHandler _handler = new TestURLStreamHandler();
private final List<String> _resourceData = new ArrayList<>();
private final String _path;
public Utf8DataClassLoader( String path) {
this(path, getSystemClassLoader());
}
public Utf8DataClassLoader( String path, ClassLoader parent) {
super(parent);
_path = path;
}
public void addResource( PluginXmlGenerator xmlData) {
_resourceData.add( xmlData.toString());
}
public void addResource( String xmlData) {
_resourceData.add( xmlData);
}
@Override
protected URL findResource( String name) {
if( name.equals( _path) && !_resourceData.isEmpty()) {
return newUrlForIndex( 0);
} else {
return null;
}
}
private URL newUrlForIndex( int index) {
URL result;
String filename = _path + "?" + index;
try {
result =
new URL( URL_SCHEMA, URL_HOSTNAME, URL_DEFAULT_PORT,
filename, _handler);
} catch (MalformedURLException e) {
throw new RuntimeException( "Failed to create local URL", e);
}
return result;
}
@Override
protected Enumeration<URL> findResources( String name) throws IOException {
Vector<URL> results = new Vector<>();
if( name.equals( _path)) {
for( int i = 0; i < _resourceData.size(); i++) {
URL resourceUrl = newUrlForIndex( i);
results.add( resourceUrl);
}
}
return results.elements();
}
/**
* A custom handler to allow reading of a "test" URL
*/
public class TestURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection( URL url) throws IOException {
return new TestURLConnection( url);
}
}
/**
* A custom URLConnection that allows reading of String data as a UTF-8
* encoded sequence of bytes.
*/
public class TestURLConnection extends URLConnection {
private static final String CHARSET_NAME_UTF_8 = "UTF-8";
private byte[] _rawData;
public TestURLConnection( URL url) {
super( url);
String queryPart = url.getQuery();
int index = Integer.valueOf( queryPart);
String data = _resourceData.get( index);
_rawData = getByteContent( data);
}
@Override
public void connect() throws IOException {
// nothing needs to be done as data is local
}
@Override
public InputStream getInputStream() throws IOException {
InputStream is = new ByteArrayInputStream( _rawData);
return is;
}
private byte[] getByteContent( String content) {
Charset utf8 = Charset.forName( CHARSET_NAME_UTF_8);
return content.getBytes( utf8);
}
}
}