blob: d27024cb3fd9b52c8eace18c3dffaa4529c0652f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.axis2.format;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.activation.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility class to create {@link ManagedDataSource} objects.
*/
public class ManagedDataSourceFactory {
private static class ManagedInputStream extends FilterInputStream {
private DataSourceManager manager;
public ManagedInputStream(DataSourceManager manager, InputStream parent) {
super(parent);
this.manager = manager;
}
@Override
public void close() throws IOException {
if (manager != null) {
manager.notifyStreamClosed(this);
manager = null;
}
super.close();
}
}
private static class DataSourceManager implements InvocationHandler {
private static final Log log = LogFactory.getLog(DataSourceManager.class);
private static final Method getInputStreamMethod;
private static final Method destroyMethod;
static {
try {
getInputStreamMethod = DataSource.class.getMethod("getInputStream");
destroyMethod = ManagedDataSource.class.getMethod("destroy");
} catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
}
private final DataSource dataSource;
private final List<ManagedInputStream> openStreams = Collections.synchronizedList(
new LinkedList<ManagedInputStream>());
public DataSourceManager(DataSource dataSource) {
this.dataSource = dataSource;
}
public void notifyStreamClosed(ManagedInputStream managedInputStream) {
if (!openStreams.remove(managedInputStream)) {
throw new IllegalStateException();
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (method.equals(getInputStreamMethod)) {
InputStream in = (InputStream)method.invoke(dataSource, args);
ManagedInputStream in2 = new ManagedInputStream(this, in);
openStreams.add(in2);
return in2;
} else if (method.equals(destroyMethod)) {
while (!openStreams.isEmpty()) {
try {
openStreams.get(0).close();
} catch (IOException ex) {
log.warn("Exception when closing open stream from managed data source", ex);
}
}
return null;
} else {
return method.invoke(dataSource, args);
}
} catch (InvocationTargetException ex) {
throw ex.getCause();
}
}
}
/**
* Create a {@link ManagedDataSource} proxy for an existing data source.
* This will create a dynamic proxy implementing the same interfaces as
* the original data source.
*
* @param ds the original data source
* @return a data source proxy implementing {@link ManagedDataSource}
*/
public static ManagedDataSource create(DataSource ds) {
Class<?>[] orgIfaces = ds.getClass().getInterfaces();
Class<?>[] ifaces = new Class[orgIfaces.length+1];
ifaces[0] = ManagedDataSource.class;
System.arraycopy(orgIfaces, 0, ifaces, 1, orgIfaces.length);
return (ManagedDataSource)Proxy.newProxyInstance(
ManagedDataSourceFactory.class.getClassLoader(), ifaces,
new DataSourceManager(ds));
}
}