/*
 * Copyright (C) 2005 - 2011 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package com.jaspersoft.jasperserver.irplugin.wsclient;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.activation.DataSource;

/**
 * A {@link DataSource} decorator that monitors input streams in order to close
 * the ones that are left open.
 * 
 * @author Lucian Chirita (lucianc@users.sourceforge.net)
 * @version $Id: MonitoredDataSource.java 19926 2010-12-11 15:09:26Z tmatyashovsky $
 */
public class MonitoredDataSource implements DataSource {

	private final DataSource dataSource;
	private final Map openInputStreams = new HashMap();
	
	public MonitoredDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public String getContentType() {
		return dataSource.getContentType();
	}

	public InputStream getInputStream() throws IOException {
		InputStream stream = dataSource.getInputStream();
		if (stream == null) {
			return stream;
		}
		
		synchronized (openInputStreams) {
			InputStream monitored = (InputStream) openInputStreams.get(stream);
			if (monitored == null) {
				monitored = new MonitoredInputStream(stream);
				openInputStreams.put(stream, monitored);
			}
			return monitored;
		}
	}

	public String getName() {
		return dataSource.getName();
	}

	public OutputStream getOutputStream() throws IOException {
		return dataSource.getOutputStream();
	}

	protected void closingInputStream(InputStream stream) {
		openInputStreams.remove(stream);
	}
	
	
	/**
	 * Closes all the input stream objects which were created by the decorated
	 * data source and left open.
	 */
	public void close() {
		if (!openInputStreams.isEmpty()) {
			for (Iterator it = openInputStreams.keySet().iterator(); it.hasNext();) {
				InputStream stream = (InputStream) it.next();
				try {
					stream.close();
				} catch (IOException e) {
					// ignore
				}
			}
		}
	}
	
	protected class MonitoredInputStream extends FilterInputStream {

		public MonitoredInputStream(InputStream in) {
			super(in);
		}

		public void close() throws IOException {
			closingInputStream(in);
			
			super.close();
		}
	}
	
}
