001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.aop.target;
018
019import java.io.Serializable;
020
021import org.springframework.aop.TargetSource;
022import org.springframework.util.Assert;
023
024/**
025 * {@link org.springframework.aop.TargetSource} implementation that
026 * caches a local target object, but allows the target to be swapped
027 * while the application is running.
028 *
029 * <p>If configuring an object of this class in a Spring IoC container,
030 * use constructor injection.
031 *
032 * <p>This TargetSource is serializable if the target is at the time
033 * of serialization.
034 *
035 * @author Rod Johnson
036 * @author Juergen Hoeller
037 */
038public class HotSwappableTargetSource implements TargetSource, Serializable {
039
040        /** use serialVersionUID from Spring 1.2 for interoperability. */
041        private static final long serialVersionUID = 7497929212653839187L;
042
043
044        /** The current target object. */
045        private Object target;
046
047
048        /**
049         * Create a new HotSwappableTargetSource with the given initial target object.
050         * @param initialTarget the initial target object
051         */
052        public HotSwappableTargetSource(Object initialTarget) {
053                Assert.notNull(initialTarget, "Target object must not be null");
054                this.target = initialTarget;
055        }
056
057
058        /**
059         * Return the type of the current target object.
060         * <p>The returned type should usually be constant across all target objects.
061         */
062        @Override
063        public synchronized Class<?> getTargetClass() {
064                return this.target.getClass();
065        }
066
067        @Override
068        public final boolean isStatic() {
069                return false;
070        }
071
072        @Override
073        public synchronized Object getTarget() {
074                return this.target;
075        }
076
077        @Override
078        public void releaseTarget(Object target) {
079                // nothing to do
080        }
081
082
083        /**
084         * Swap the target, returning the old target object.
085         * @param newTarget the new target object
086         * @return the old target object
087         * @throws IllegalArgumentException if the new target is invalid
088         */
089        public synchronized Object swap(Object newTarget) throws IllegalArgumentException {
090                Assert.notNull(newTarget, "Target object must not be null");
091                Object old = this.target;
092                this.target = newTarget;
093                return old;
094        }
095
096
097        /**
098         * Two HotSwappableTargetSources are equal if the current target
099         * objects are equal.
100         */
101        @Override
102        public boolean equals(Object other) {
103                return (this == other || (other instanceof HotSwappableTargetSource &&
104                                this.target.equals(((HotSwappableTargetSource) other).target)));
105        }
106
107        @Override
108        public int hashCode() {
109                return HotSwappableTargetSource.class.hashCode();
110        }
111
112        @Override
113        public String toString() {
114                return "HotSwappableTargetSource for target: " + this.target;
115        }
116
117}