001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.aop.target.dynamic;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021:
022: import org.springframework.aop.TargetSource;
023:
024: /**
025: * Abstract {@link org.springframework.aop.TargetSource} implementation that
026: * wraps a refreshable target object. Subclasses can determine whether a
027: * refresh is required, and need to provide fresh target objects.
028: *
029: * <p>Implements the {@link Refreshable} interface in order to allow for
030: * explicit control over the refresh status.
031: *
032: * @author Rod Johnson
033: * @author Rob Harrop
034: * @author Juergen Hoeller
035: * @since 2.0
036: * @see #requiresRefresh()
037: * @see #freshTarget()
038: */
039: public abstract class AbstractRefreshableTargetSource implements
040: TargetSource, Refreshable {
041:
042: /** Logger available to subclasses */
043: protected Log logger = LogFactory.getLog(getClass());
044:
045: protected Object targetObject;
046:
047: private long refreshCheckDelay = -1;
048:
049: private long lastRefreshCheck = -1;
050:
051: private long lastRefreshTime = -1;
052:
053: private long refreshCount = 0;
054:
055: /**
056: * Set the delay between refresh checks, in milliseconds.
057: * Default is -1, indicating no refresh checks at all.
058: * <p>Note that an actual refresh will only happen when
059: * {@link #requiresRefresh()} returns <code>true</code>.
060: */
061: public void setRefreshCheckDelay(long refreshCheckDelay) {
062: this .refreshCheckDelay = refreshCheckDelay;
063: }
064:
065: public synchronized Class getTargetClass() {
066: if (this .targetObject == null) {
067: refresh();
068: }
069: return this .targetObject.getClass();
070: }
071:
072: /**
073: * Not static.
074: */
075: public boolean isStatic() {
076: return false;
077: }
078:
079: public final synchronized Object getTarget() {
080: if ((refreshCheckDelayElapsed() && requiresRefresh())
081: || this .targetObject == null) {
082: refresh();
083: }
084: return this .targetObject;
085: }
086:
087: /**
088: * No need to release target.
089: */
090: public void releaseTarget(Object object) {
091: }
092:
093: public final synchronized void refresh() {
094: logger.debug("Attempting to refresh target");
095:
096: this .targetObject = freshTarget();
097: this .refreshCount++;
098: this .lastRefreshTime = System.currentTimeMillis();
099:
100: logger.debug("Target refreshed successfully");
101: }
102:
103: public long getRefreshCount() {
104: return this .refreshCount;
105: }
106:
107: public long getLastRefreshTime() {
108: return this .lastRefreshTime;
109: }
110:
111: private boolean refreshCheckDelayElapsed() {
112: if (this .refreshCheckDelay < 0) {
113: return false;
114: }
115:
116: long currentTimeMillis = System.currentTimeMillis();
117:
118: if (this .lastRefreshCheck < 0
119: || currentTimeMillis - this .lastRefreshCheck > this .refreshCheckDelay) {
120: // Going to perform a refresh check - update the time.
121: this .lastRefreshCheck = currentTimeMillis;
122: logger
123: .debug("Refresh check delay elapsed - checking whether refresh is required");
124: return true;
125: }
126:
127: return false;
128: }
129:
130: /**
131: * Determine whether a refresh is required.
132: * Invoked for each refresh check, after the refresh check delay has elapsed.
133: * <p>The default implementation always returns <code>true</code>, triggering
134: * a refresh every time the delay has elapsed. To be overridden by subclasses
135: * with an appropriate check of the underlying target resource.
136: * @return whether a refresh is required
137: */
138: protected boolean requiresRefresh() {
139: return true;
140: }
141:
142: /**
143: * Obtain a fresh target object.
144: * <p>Only invoked if a refresh check has found that a refresh is required
145: * (that is, {@link #requiresRefresh()} has returned <code>true</code>).
146: * @return the fresh target object
147: */
148: protected abstract Object freshTarget();
149:
150: }
|