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 — 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}