10 changed files with 63 additions and 544 deletions
@ -1,50 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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