10 changed files with 63 additions and 544 deletions
@ -1,50 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.core; |
|
||||||
|
|
||||||
/** |
|
||||||
* Exception thrown when the {@link Constants} class is asked for |
|
||||||
* an invalid constant name. |
|
||||||
* |
|
||||||
* @author Rod Johnson |
|
||||||
* @since 28.04.2003 |
|
||||||
* @see org.springframework.core.Constants |
|
||||||
*/ |
|
||||||
@SuppressWarnings("serial") |
|
||||||
public class ConstantException extends IllegalArgumentException { |
|
||||||
|
|
||||||
/** |
|
||||||
* Thrown when an invalid constant name is requested. |
|
||||||
* @param className name of the class containing the constant definitions |
|
||||||
* @param field invalid constant name |
|
||||||
* @param message description of the problem |
|
||||||
*/ |
|
||||||
public ConstantException(String className, String field, String message) { |
|
||||||
super("Field '" + field + "' " + message + " in class [" + className + "]"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Thrown when an invalid constant value is looked up. |
|
||||||
* @param className name of the class containing the constant definitions |
|
||||||
* @param namePrefix prefix of the searched constant names |
|
||||||
* @param value the looked up constant value |
|
||||||
*/ |
|
||||||
public ConstantException(String className, String namePrefix, Object value) { |
|
||||||
super("No '" + namePrefix + "' field with value '" + value + "' found in class [" + className + "]"); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,50 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.core; |
|
||||||
|
|
||||||
/** |
|
||||||
* Interface to be implemented by objects that can return information about |
|
||||||
* the current call stack. Useful in AOP (as in AspectJ cflow concept) |
|
||||||
* but not AOP-specific. |
|
||||||
* |
|
||||||
* @author Rod Johnson |
|
||||||
* @since 02.02.2004 |
|
||||||
*/ |
|
||||||
public interface ControlFlow { |
|
||||||
|
|
||||||
/** |
|
||||||
* Detect whether we're under the given class, |
|
||||||
* according to the current stack trace. |
|
||||||
* @param clazz the clazz to look for |
|
||||||
*/ |
|
||||||
boolean under(Class<?> clazz); |
|
||||||
|
|
||||||
/** |
|
||||||
* Detect whether we're under the given class and method, |
|
||||||
* according to the current stack trace. |
|
||||||
* @param clazz the clazz to look for |
|
||||||
* @param methodName the name of the method to look for |
|
||||||
*/ |
|
||||||
boolean under(Class<?> clazz, String methodName); |
|
||||||
|
|
||||||
/** |
|
||||||
* Detect whether the current stack trace contains the given token. |
|
||||||
* @param token the token to look for |
|
||||||
*/ |
|
||||||
boolean underToken(String token); |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,122 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.core; |
|
||||||
|
|
||||||
import java.io.PrintWriter; |
|
||||||
import java.io.StringWriter; |
|
||||||
|
|
||||||
import org.springframework.util.Assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Static factory to conceal the automatic choice of the ControlFlow |
|
||||||
* implementation class. |
|
||||||
* |
|
||||||
* <p>This implementation always uses the efficient Java 1.4 StackTraceElement |
|
||||||
* mechanism for analyzing control flows. |
|
||||||
* |
|
||||||
* @author Rod Johnson |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 02.02.2004 |
|
||||||
*/ |
|
||||||
public abstract class ControlFlowFactory { |
|
||||||
|
|
||||||
/** |
|
||||||
* Return an appropriate {@link ControlFlow} instance. |
|
||||||
*/ |
|
||||||
public static ControlFlow createControlFlow() { |
|
||||||
return new Jdk14ControlFlow(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Utilities for cflow-style pointcuts. Note that such pointcuts are |
|
||||||
* 5-10 times more expensive to evaluate than other pointcuts, as they require |
|
||||||
* analysis of the stack trace (through constructing a new throwable). |
|
||||||
* However, they are useful in some cases. |
|
||||||
* <p>This implementation uses the StackTraceElement class introduced in Java 1.4. |
|
||||||
* @see java.lang.StackTraceElement |
|
||||||
*/ |
|
||||||
static class Jdk14ControlFlow implements ControlFlow { |
|
||||||
|
|
||||||
private StackTraceElement[] stack; |
|
||||||
|
|
||||||
public Jdk14ControlFlow() { |
|
||||||
this.stack = new Throwable().getStackTrace(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Searches for class name match in a StackTraceElement. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public boolean under(Class<?> clazz) { |
|
||||||
Assert.notNull(clazz, "Class must not be null"); |
|
||||||
String className = clazz.getName(); |
|
||||||
for (int i = 0; i < stack.length; i++) { |
|
||||||
if (this.stack[i].getClassName().equals(className)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Searches for class name match plus method name match |
|
||||||
* in a StackTraceElement. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public boolean under(Class<?> clazz, String methodName) { |
|
||||||
Assert.notNull(clazz, "Class must not be null"); |
|
||||||
Assert.notNull(methodName, "Method name must not be null"); |
|
||||||
String className = clazz.getName(); |
|
||||||
for (int i = 0; i < this.stack.length; i++) { |
|
||||||
if (this.stack[i].getClassName().equals(className) && |
|
||||||
this.stack[i].getMethodName().equals(methodName)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Leave it up to the caller to decide what matches. |
|
||||||
* Caller must understand stack trace format, so there's less abstraction. |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public boolean underToken(String token) { |
|
||||||
if (token == null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
StringWriter sw = new StringWriter(); |
|
||||||
new Throwable().printStackTrace(new PrintWriter(sw)); |
|
||||||
String stackTrace = sw.toString(); |
|
||||||
return stackTrace.indexOf(token) != -1; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
StringBuilder sb = new StringBuilder("Jdk14ControlFlow: "); |
|
||||||
for (int i = 0; i < this.stack.length; i++) { |
|
||||||
if (i > 0) { |
|
||||||
sb.append("\n\t@"); |
|
||||||
} |
|
||||||
sb.append(this.stack[i]); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,39 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2012 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.core; |
|
||||||
|
|
||||||
/** |
|
||||||
* Interface that can be implemented by exceptions etc that are error coded. |
|
||||||
* The error code is a String, rather than a number, so it can be given |
|
||||||
* user-readable values, such as "object.failureDescription". |
|
||||||
* |
|
||||||
* <p>An error code can be resolved by a MessageSource, for example. |
|
||||||
* |
|
||||||
* @author Rod Johnson |
|
||||||
* @see org.springframework.context.MessageSource |
|
||||||
*/ |
|
||||||
public interface ErrorCoded { |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the error code associated with this failure. |
|
||||||
* The GUI can render this any way it pleases, allowing for localization etc. |
|
||||||
* @return a String error code associated with this failure, |
|
||||||
* or {@code null} if not error-coded |
|
||||||
*/ |
|
||||||
String getErrorCode(); |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,179 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2016 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.util; |
|
||||||
|
|
||||||
import java.lang.ref.Reference; |
|
||||||
import java.lang.ref.ReferenceQueue; |
|
||||||
import java.lang.ref.WeakReference; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import org.apache.commons.logging.Log; |
|
||||||
import org.apache.commons.logging.LogFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* Track references to arbitrary objects using proxy and weak references. To |
|
||||||
* monitor a handle, one should call {@link #monitor(Object, ReleaseListener)}, |
|
||||||
* with the given handle object usually being a holder that uses the target |
|
||||||
* object underneath, and the release listener performing cleanup of the |
|
||||||
* target object once the handle is not strongly referenced anymore. |
|
||||||
* |
|
||||||
* <p>When a given handle becomes weakly reachable, the specified listener |
|
||||||
* will be called by a background thread. This thread will only be started |
|
||||||
* lazily and will be stopped once no handles are registered for monitoring |
|
||||||
* anymore, to be restarted if further handles are added. |
|
||||||
* |
|
||||||
* <p>Thanks to Tomasz Wysocki for the suggestion and the original |
|
||||||
* implementation of this class! |
|
||||||
* |
|
||||||
* @author Colin Sampaleanu |
|
||||||
* @author Juergen Hoeller |
|
||||||
* @since 1.2 |
|
||||||
* @see #monitor |
|
||||||
*/ |
|
||||||
public class WeakReferenceMonitor { |
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(WeakReferenceMonitor.class); |
|
||||||
|
|
||||||
// Queue receiving reachability events
|
|
||||||
private static final ReferenceQueue<Object> handleQueue = new ReferenceQueue<>(); |
|
||||||
|
|
||||||
// All tracked entries (WeakReference => ReleaseListener)
|
|
||||||
private static final Map<Reference<?>, ReleaseListener> trackedEntries = new HashMap<>(); |
|
||||||
|
|
||||||
// Thread polling handleQueue, lazy initialized
|
|
||||||
private static Thread monitoringThread = null; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Start to monitor given handle object for becoming weakly reachable. |
|
||||||
* When the handle isn't used anymore, the given listener will be called. |
|
||||||
* @param handle the object that will be monitored |
|
||||||
* @param listener the listener that will be called upon release of the handle |
|
||||||
*/ |
|
||||||
public static void monitor(Object handle, ReleaseListener listener) { |
|
||||||
if (logger.isDebugEnabled()) { |
|
||||||
logger.debug("Monitoring handle [" + handle + "] with release listener [" + listener + "]"); |
|
||||||
} |
|
||||||
|
|
||||||
// Make weak reference to this handle, so we can say when
|
|
||||||
// handle is not used any more by polling on handleQueue.
|
|
||||||
WeakReference<Object> weakRef = new WeakReference<>(handle, handleQueue); |
|
||||||
|
|
||||||
// Add monitored entry to internal map of all monitored entries.
|
|
||||||
addEntry(weakRef, listener); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Add entry to internal map of tracked entries. |
|
||||||
* Internal monitoring thread is started if not already running. |
|
||||||
* @param ref reference to tracked handle |
|
||||||
* @param entry the associated entry |
|
||||||
*/ |
|
||||||
private static void addEntry(Reference<?> ref, ReleaseListener entry) { |
|
||||||
synchronized (WeakReferenceMonitor.class) { |
|
||||||
// Add entry, the key is given reference.
|
|
||||||
trackedEntries.put(ref, entry); |
|
||||||
|
|
||||||
// Start monitoring thread lazily.
|
|
||||||
if (monitoringThread == null) { |
|
||||||
monitoringThread = new Thread(new MonitoringProcess(), WeakReferenceMonitor.class.getName()); |
|
||||||
monitoringThread.setDaemon(true); |
|
||||||
monitoringThread.start(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Remove entry from internal map of tracked entries. |
|
||||||
* @param reference the reference that should be removed |
|
||||||
* @return entry object associated with given reference |
|
||||||
*/ |
|
||||||
private static ReleaseListener removeEntry(Reference<?> reference) { |
|
||||||
synchronized (WeakReferenceMonitor.class) { |
|
||||||
return trackedEntries.remove(reference); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Check whether to keep the monitoring thread alive, |
|
||||||
* i.e. whether there are still entries being tracked. |
|
||||||
*/ |
|
||||||
private static boolean keepMonitoringThreadAlive() { |
|
||||||
synchronized (WeakReferenceMonitor.class) { |
|
||||||
if (!trackedEntries.isEmpty()) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
else { |
|
||||||
logger.debug("No entries left to track - stopping reference monitor thread"); |
|
||||||
monitoringThread = null; |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Thread implementation that performs the actual monitoring. |
|
||||||
*/ |
|
||||||
private static class MonitoringProcess implements Runnable { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void run() { |
|
||||||
logger.debug("Starting reference monitor thread"); |
|
||||||
// Check if there are any tracked entries left.
|
|
||||||
while (keepMonitoringThreadAlive()) { |
|
||||||
try { |
|
||||||
Reference<?> reference = handleQueue.remove(); |
|
||||||
// Stop tracking this reference.
|
|
||||||
ReleaseListener entry = removeEntry(reference); |
|
||||||
if (entry != null) { |
|
||||||
// Invoke listener callback.
|
|
||||||
try { |
|
||||||
entry.released(); |
|
||||||
} |
|
||||||
catch (Throwable ex) { |
|
||||||
logger.warn("Reference release listener threw exception", ex); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
catch (InterruptedException ex) { |
|
||||||
synchronized (WeakReferenceMonitor.class) { |
|
||||||
monitoringThread = null; |
|
||||||
} |
|
||||||
logger.debug("Reference monitor thread interrupted", ex); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Listener that is notified when the handle is being released. |
|
||||||
* To be implemented by users of this reference monitor. |
|
||||||
*/ |
|
||||||
public static interface ReleaseListener { |
|
||||||
|
|
||||||
/** |
|
||||||
* This callback method is invoked once the associated handle has been released, |
|
||||||
* i.e. once there are no monitored strong references to the handle anymore. |
|
||||||
*/ |
|
||||||
void released(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,76 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2002-2014 the original author or authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.springframework.core; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Rod Johnson |
|
||||||
* @author Sam Brannen |
|
||||||
*/ |
|
||||||
public class ControlFlowTests { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void underClassAndMethod() { |
|
||||||
new One().test(); |
|
||||||
new Two().testing(); |
|
||||||
new Three().test(); |
|
||||||
} |
|
||||||
|
|
||||||
static class One { |
|
||||||
|
|
||||||
void test() { |
|
||||||
ControlFlow cflow = ControlFlowFactory.createControlFlow(); |
|
||||||
assertTrue(cflow.under(One.class)); |
|
||||||
assertTrue(cflow.under(ControlFlowTests.class)); |
|
||||||
assertFalse(cflow.under(Two.class)); |
|
||||||
assertTrue(cflow.under(One.class, "test")); |
|
||||||
assertFalse(cflow.under(One.class, "hashCode")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static class Two { |
|
||||||
|
|
||||||
void testing() { |
|
||||||
ControlFlow cflow = ControlFlowFactory.createControlFlow(); |
|
||||||
assertTrue(cflow.under(Two.class)); |
|
||||||
assertTrue(cflow.under(ControlFlowTests.class)); |
|
||||||
assertFalse(cflow.under(One.class)); |
|
||||||
assertFalse(cflow.under(Two.class, "test")); |
|
||||||
assertTrue(cflow.under(Two.class, "testing")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static class Three { |
|
||||||
|
|
||||||
void test() { |
|
||||||
testing(); |
|
||||||
} |
|
||||||
|
|
||||||
private void testing() { |
|
||||||
ControlFlow cflow = ControlFlowFactory.createControlFlow(); |
|
||||||
assertTrue(cflow.under(Three.class)); |
|
||||||
assertTrue(cflow.under(ControlFlowTests.class)); |
|
||||||
assertFalse(cflow.under(One.class)); |
|
||||||
assertTrue(cflow.under(Three.class, "test")); |
|
||||||
assertTrue(cflow.under(Three.class, "testing")); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
Loading…
Reference in new issue