001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.inject;
018
019/**
020 * Opaque handle for a single pushed overlay frame on a {@link WritableBeanStore}.
021 *
022 * <p>
023 * A {@code Snapshot} is returned by {@link WritableBeanStore#pushOverlay(BeanStore)} and must be passed back to
024 * {@link WritableBeanStore#popOverlay(Snapshot)} to remove the corresponding frame.  The type intentionally exposes
025 * no public state: tests treat it as a token, the implementation uses it to enforce LIFO discipline and reject
026 * cross-store pops.
027 *
028 * <p>
029 * Instances cannot be constructed externally &mdash; only {@code pushOverlay(...)} produces them.  Equality is
030 * identity-based; two distinct push operations always produce distinct snapshots, even when the overlay and the
031 * owning store are the same.
032 *
033 * <h5 class='section'>Example:</h5>
034 * <p class='bjava'>
035 *    WritableBeanStore <jv>store</jv> = ...;
036 *    BeanStore <jv>overlay</jv> = <jk>new</jk> BasicBeanStore().addBean(MyService.<jk>class</jk>, <jv>mock</jv>);
037 *
038 *    Snapshot <jv>snap</jv> = <jv>store</jv>.pushOverlay(<jv>overlay</jv>);
039 *    <jk>try</jk> {
040 *       <jc>// overlay active here</jc>
041 *    } <jk>finally</jk> {
042 *       <jv>store</jv>.popOverlay(<jv>snap</jv>);
043 *    }
044 * </p>
045 *
046 * <h5 class='section'>See Also:</h5><ul>
047 *    <li class='jc'>{@link WritableBeanStore} - The interface that produces and consumes {@code Snapshot} instances.
048 *    <li class='jc'>{@link StackOverlay} - The underlying stack-overlay primitive {@code BasicBeanStore} composes with.
049 * </ul>
050 *
051 * @since 10.0.0
052 */
053@SuppressWarnings({
054   "resource" // owner and frame are not owned by Snapshot; their lifecycle is managed externally.
055})
056public final class Snapshot {
057
058   private final WritableBeanStore owner;
059   private final BeanStore frame;
060
061   /**
062    * Package-private constructor.
063    *
064    * <p>
065    * Only {@link BasicBeanStore#pushOverlay(BeanStore)} (and other {@code WritableBeanStore} implementations sharing
066    * the same package) may construct {@code Snapshot} instances.  External code receives them as opaque handles.
067    *
068    * @param owner The store that produced this snapshot.  Must not be <jk>null</jk>.
069    * @param frame The overlay frame this snapshot identifies.  Must not be <jk>null</jk>.
070    */
071   Snapshot(WritableBeanStore owner, BeanStore frame) {
072      this.owner = owner;
073      this.frame = frame;
074   }
075
076   /**
077    * Returns the {@link WritableBeanStore} that produced this snapshot.
078    *
079    * <p>
080    * Used by the producing store to reject {@link WritableBeanStore#popOverlay(Snapshot)} calls invoked on a
081    * different store instance (i.e. foreign-snapshot pops).
082    *
083    * @return The owning store.  Never <jk>null</jk>.
084    */
085   WritableBeanStore owner() {
086      return owner;
087   }
088
089   /**
090    * Returns the overlay frame this snapshot identifies.
091    *
092    * <p>
093    * Used by the producing store to verify the snapshot matches the current top-of-stack frame before popping.
094    *
095    * @return The overlay frame.  Never <jk>null</jk>.
096    */
097   BeanStore frame() {
098      return frame;
099   }
100
101   @Override /* Overridden from Object */
102   public String toString() {
103      return "Snapshot[owner=" + Integer.toHexString(System.identityHashCode(owner))
104         + ", frame=" + Integer.toHexString(System.identityHashCode(frame)) + "]";
105   }
106}