112f608f3d2089439a108788a1908941eea4277b9Puneet Lall/*
212f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Copyright (C) 2014 The Android Open Source Project
312f608f3d2089439a108788a1908941eea4277b9Puneet Lall *
412f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License");
512f608f3d2089439a108788a1908941eea4277b9Puneet Lall * you may not use this file except in compliance with the License.
612f608f3d2089439a108788a1908941eea4277b9Puneet Lall * You may obtain a copy of the License at
712f608f3d2089439a108788a1908941eea4277b9Puneet Lall *
812f608f3d2089439a108788a1908941eea4277b9Puneet Lall *      http://www.apache.org/licenses/LICENSE-2.0
912f608f3d2089439a108788a1908941eea4277b9Puneet Lall *
1012f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Unless required by applicable law or agreed to in writing, software
1112f608f3d2089439a108788a1908941eea4277b9Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS,
1212f608f3d2089439a108788a1908941eea4277b9Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1312f608f3d2089439a108788a1908941eea4277b9Puneet Lall * See the License for the specific language governing permissions and
1412f608f3d2089439a108788a1908941eea4277b9Puneet Lall * limitations under the License.
1512f608f3d2089439a108788a1908941eea4277b9Puneet Lall */
1612f608f3d2089439a108788a1908941eea4277b9Puneet Lall
1712f608f3d2089439a108788a1908941eea4277b9Puneet Lallpackage com.android.camera.async;
1812f608f3d2089439a108788a1908941eea4277b9Puneet Lall
1912f608f3d2089439a108788a1908941eea4277b9Puneet Lallimport java.util.ArrayList;
2012f608f3d2089439a108788a1908941eea4277b9Puneet Lallimport java.util.HashSet;
2112f608f3d2089439a108788a1908941eea4277b9Puneet Lallimport java.util.List;
2212f608f3d2089439a108788a1908941eea4277b9Puneet Lallimport java.util.Set;
2312f608f3d2089439a108788a1908941eea4277b9Puneet Lall
2412f608f3d2089439a108788a1908941eea4277b9Puneet Lall/**
2512f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Enables handling the shut-down of components in a structured way.
2612f608f3d2089439a108788a1908941eea4277b9Puneet Lall * <p>
2712f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Lifetimes are nestable sets of {@link SafeCloseable}s useful for guaranteeing
2812f608f3d2089439a108788a1908941eea4277b9Puneet Lall * that resources, such as threads, files, hardware devices, etc., are properly
2912f608f3d2089439a108788a1908941eea4277b9Puneet Lall * closed when necessary.
3012f608f3d2089439a108788a1908941eea4277b9Puneet Lall * <p>
3112f608f3d2089439a108788a1908941eea4277b9Puneet Lall * Child lifetimes are closed when their parent is closed, or when they are
3212f608f3d2089439a108788a1908941eea4277b9Puneet Lall * closed directly, whichever comes first. Objects added to a particular
3312f608f3d2089439a108788a1908941eea4277b9Puneet Lall * lifetime will only ever be closed once by that lifetime.
3412f608f3d2089439a108788a1908941eea4277b9Puneet Lall * </p>
3512f608f3d2089439a108788a1908941eea4277b9Puneet Lall */
3612f608f3d2089439a108788a1908941eea4277b9Puneet Lallpublic class Lifetime implements SafeCloseable {
3712f608f3d2089439a108788a1908941eea4277b9Puneet Lall    /**
3812f608f3d2089439a108788a1908941eea4277b9Puneet Lall     * The parent, or null if there is no parent lifetime.
3912f608f3d2089439a108788a1908941eea4277b9Puneet Lall     */
4012f608f3d2089439a108788a1908941eea4277b9Puneet Lall    private final Lifetime mParent;
4112f608f3d2089439a108788a1908941eea4277b9Puneet Lall    private final Object mLock;
4212f608f3d2089439a108788a1908941eea4277b9Puneet Lall    private final Set<SafeCloseable> mCloseables;
4312f608f3d2089439a108788a1908941eea4277b9Puneet Lall    private boolean mClosed;
4412f608f3d2089439a108788a1908941eea4277b9Puneet Lall
4512f608f3d2089439a108788a1908941eea4277b9Puneet Lall    public Lifetime() {
4612f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mLock = new Object();
4712f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mCloseables = new HashSet<SafeCloseable>();
4812f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mParent = null;
4912f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mClosed = false;
5012f608f3d2089439a108788a1908941eea4277b9Puneet Lall    }
5112f608f3d2089439a108788a1908941eea4277b9Puneet Lall
5212f608f3d2089439a108788a1908941eea4277b9Puneet Lall    public Lifetime(Lifetime parent) {
5312f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mLock = new Object();
5412f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mCloseables = new HashSet<SafeCloseable>();
5512f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mParent = parent;
5612f608f3d2089439a108788a1908941eea4277b9Puneet Lall        mClosed = false;
5712f608f3d2089439a108788a1908941eea4277b9Puneet Lall        parent.mCloseables.add(this);
5812f608f3d2089439a108788a1908941eea4277b9Puneet Lall    }
5912f608f3d2089439a108788a1908941eea4277b9Puneet Lall
6012f608f3d2089439a108788a1908941eea4277b9Puneet Lall    /**
6112f608f3d2089439a108788a1908941eea4277b9Puneet Lall     * Adds the given object to this lifetime and returns it.
6212f608f3d2089439a108788a1908941eea4277b9Puneet Lall     */
6312f608f3d2089439a108788a1908941eea4277b9Puneet Lall    public <T extends SafeCloseable> T add(T closeable) {
6412f608f3d2089439a108788a1908941eea4277b9Puneet Lall        boolean needToClose = false;
6512f608f3d2089439a108788a1908941eea4277b9Puneet Lall        synchronized (mLock) {
6612f608f3d2089439a108788a1908941eea4277b9Puneet Lall            if (mClosed) {
6712f608f3d2089439a108788a1908941eea4277b9Puneet Lall                needToClose = true;
6812f608f3d2089439a108788a1908941eea4277b9Puneet Lall            } else {
6912f608f3d2089439a108788a1908941eea4277b9Puneet Lall                mCloseables.add(closeable);
7012f608f3d2089439a108788a1908941eea4277b9Puneet Lall            }
7112f608f3d2089439a108788a1908941eea4277b9Puneet Lall        }
7212f608f3d2089439a108788a1908941eea4277b9Puneet Lall        if (needToClose) {
7312f608f3d2089439a108788a1908941eea4277b9Puneet Lall            closeable.close();
7412f608f3d2089439a108788a1908941eea4277b9Puneet Lall        }
7512f608f3d2089439a108788a1908941eea4277b9Puneet Lall        return closeable;
7612f608f3d2089439a108788a1908941eea4277b9Puneet Lall    }
7712f608f3d2089439a108788a1908941eea4277b9Puneet Lall
7812f608f3d2089439a108788a1908941eea4277b9Puneet Lall    @Override
7912f608f3d2089439a108788a1908941eea4277b9Puneet Lall    public void close() {
8012f608f3d2089439a108788a1908941eea4277b9Puneet Lall        List<SafeCloseable> toClose = new ArrayList<SafeCloseable>();
8112f608f3d2089439a108788a1908941eea4277b9Puneet Lall        synchronized (mLock) {
8212f608f3d2089439a108788a1908941eea4277b9Puneet Lall            if (mClosed) {
8312f608f3d2089439a108788a1908941eea4277b9Puneet Lall                return;
8412f608f3d2089439a108788a1908941eea4277b9Puneet Lall            }
8512f608f3d2089439a108788a1908941eea4277b9Puneet Lall            mClosed = true;
8612f608f3d2089439a108788a1908941eea4277b9Puneet Lall            // Remove from parent to avoid leaking memory if a long-lasting
8712f608f3d2089439a108788a1908941eea4277b9Puneet Lall            // lifetime has lots of shorter-lived lifetimes created and
8812f608f3d2089439a108788a1908941eea4277b9Puneet Lall            // destroyed repeatedly.
8912f608f3d2089439a108788a1908941eea4277b9Puneet Lall            if (mParent != null) {
9012f608f3d2089439a108788a1908941eea4277b9Puneet Lall                mParent.mCloseables.remove(this);
9112f608f3d2089439a108788a1908941eea4277b9Puneet Lall            }
9212f608f3d2089439a108788a1908941eea4277b9Puneet Lall            toClose.addAll(mCloseables);
9312f608f3d2089439a108788a1908941eea4277b9Puneet Lall            mCloseables.clear();
9412f608f3d2089439a108788a1908941eea4277b9Puneet Lall        }
9512f608f3d2089439a108788a1908941eea4277b9Puneet Lall        // Invoke close() outside the critical section
9612f608f3d2089439a108788a1908941eea4277b9Puneet Lall        for (SafeCloseable closeable : toClose) {
9712f608f3d2089439a108788a1908941eea4277b9Puneet Lall            closeable.close();
9812f608f3d2089439a108788a1908941eea4277b9Puneet Lall        }
9912f608f3d2089439a108788a1908941eea4277b9Puneet Lall    }
10012f608f3d2089439a108788a1908941eea4277b9Puneet Lall}
101