/* Copyright 2015 The jeo project. All rights reserved.
*
* Licensed 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 io.jeo.util;
import io.jeo.data.Disposable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Tracks resources that must be closed later.
* <p>
* Objects are tracked by calling {@link #open(Object)}. Objects are thrown onto
* a stack and later closed when this objects {@link #close()} method is called.
* Objects are closed in the reverse order they are opened.
* </p>
* <p>
* This class handles the following types of objects.
* <ul>
* <li>{@link java.lang.AutoCloseable}</li>
* <li>{@link java.io.Closeable}</li>
* <li>{@link Disposable}</li>
* </ul>
* The {@link #closeObject(Object)} can be overridden to handle additional types.
* </p>
* <p>
* Exceptions thrown by an objects close() method are always caught.
* </p>
*/
public class Disposer implements Disposable {
static final Logger LOG = LoggerFactory.getLogger(Disposer.class);
/**
* objects to close
*/
Deque<Object> toClose = new ArrayDeque<Object>();
/**
* Tracks a new object to be closed.
*/
public <T> T open(T obj) {
if (obj != null) {
toClose.push(obj);
}
return obj;
}
@Override
public void close() {
while(!toClose.isEmpty()) {
Object obj = toClose.pop();
try {
closeObject(obj);
}
catch(Exception e) {
if (LOG.isTraceEnabled()) {
LOG.trace("Error closing object: " + obj, e);
}
}
}
}
/**
* Closes the object.
* @param obj
* @throws Exception
*/
protected void closeObject(Object obj) throws Exception {
if (obj instanceof Closeable) {
((Closeable) obj).close();
}
else if (obj instanceof AutoCloseable) {
((AutoCloseable) obj).close();
}
else if (obj instanceof Disposable) {
((Disposable) obj).close();
}
}
}