Index: 3rdParty_sources/.project
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/.project,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/.project 17 Aug 2012 15:17:21 -0000 1.1
@@ -0,0 +1,11 @@
+
+
+ 3rdParty_sources
+
+
+
+
+
+
+
+
Index: 3rdParty_sources/versions.txt
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/versions.txt,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/versions.txt 17 Aug 2012 15:17:21 -0000 1.1
@@ -0,0 +1,46 @@
+In this project are located source files for 3rd party libraries used in LAMS.
+This project helps in development and is optional to download. LAMS will build without it.
+If you update a library version in lams_build/lib or anywhere else in LAMS,
+check if you should also update source code here.
+
+This project contains following versions:
+
+aspirin 0.8.03.201003071132
+
+CKEditor 3.6.2
+
+Hibernate Core 3.3.1 GA
+
+jbosscache 3.1.0.CR1
+
+JBoss Web 2.1.3
+embedded in JBoss 5.1.0.GA; based on Tomcat 6.0; contains Servlet API 2.5; contains JSP API 2.1
+
+Jexcelapi 2.6
+
+jgroups 2.6.10
+
+Joda Time 0.98
+
+Joid 1.1
+
+lucene 2.4.0
+contains lucene-snowball 2.4.0
+
+MySQL Connector/J 5.0.8
+
+opencsv 1.8
+
+opensaml 2.5.2
+
+openws 1.4.3
+
+Quartz 1.5.2
+
+Spring 2.5.6
+
+Struts 1.2.9
+
+Strutstest 2.1.3
+
+xmltooling 1.3.3
\ No newline at end of file
Index: 3rdParty_sources/spring/org/springframework/jms/IllegalStateException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/IllegalStateException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/IllegalStateException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS IllegalStateException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.IllegalStateException
+ */
+public class IllegalStateException extends JmsException {
+
+ public IllegalStateException(javax.jms.IllegalStateException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/InvalidClientIDException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/InvalidClientIDException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/InvalidClientIDException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS InvalidClientIDException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.InvalidClientIDException
+ */
+public class InvalidClientIDException extends JmsException {
+
+ public InvalidClientIDException(javax.jms.InvalidClientIDException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/InvalidDestinationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/InvalidDestinationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/InvalidDestinationException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS InvalidDestinationException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.InvalidDestinationException
+ */
+public class InvalidDestinationException extends JmsException {
+
+ public InvalidDestinationException(javax.jms.InvalidDestinationException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/InvalidSelectorException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/InvalidSelectorException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/InvalidSelectorException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS InvalidSelectorException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.InvalidSelectorException
+ */
+public class InvalidSelectorException extends JmsException {
+
+ public InvalidSelectorException(javax.jms.InvalidSelectorException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/JmsException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/JmsException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/JmsException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2002-2008 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.jms;
+
+import javax.jms.JMSException;
+
+import org.springframework.core.NestedRuntimeException;
+
+/**
+ * Base class for exception thrown by the framework whenever it
+ * encounters a problem related to JMS.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ */
+public abstract class JmsException extends NestedRuntimeException {
+
+ /**
+ * Constructor that takes a message.
+ * @param msg the detail message
+ */
+ public JmsException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor that takes a message and a root cause.
+ * @param msg the detail message
+ * @param cause the cause of the exception. This argument is generally
+ * expected to be a proper subclass of {@link javax.jms.JMSException},
+ * but can also be a JNDI NamingException or the like.
+ */
+ public JmsException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructor that takes a plain root cause, intended for
+ * subclasses mirroring corresponding javax.jms exceptions.
+ * @param cause the cause of the exception. This argument is generally
+ * expected to be a proper subclass of {@link javax.jms.JMSException}.
+ */
+ public JmsException(Throwable cause) {
+ super(cause != null ? cause.getMessage() : null, cause);
+ }
+
+
+ /**
+ * Convenience method to get the vendor specific error code if
+ * the root cause was an instance of JMSException.
+ * @return a string specifying the vendor-specific error code if the
+ * root cause is an instance of JMSException, or null
+ */
+ public String getErrorCode() {
+ Throwable cause = getCause();
+ if (cause instanceof JMSException) {
+ return ((JMSException) cause).getErrorCode();
+ }
+ return null;
+ }
+
+ /**
+ * Return the detail message, including the message from the linked exception
+ * if there is one.
+ * @see javax.jms.JMSException#getLinkedException()
+ */
+ public String getMessage() {
+ String message = super.getMessage();
+ Throwable cause = getCause();
+ if (cause instanceof JMSException) {
+ Exception linkedEx = ((JMSException) cause).getLinkedException();
+ if (linkedEx != null && cause.getMessage().indexOf(linkedEx.getMessage()) == -1) {
+ message = message + "; nested exception is " + linkedEx;
+ }
+ }
+ return message;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/JmsSecurityException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/JmsSecurityException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/JmsSecurityException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS JMSSecurityException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.JMSSecurityException
+ */
+public class JmsSecurityException extends JmsException {
+
+ public JmsSecurityException(javax.jms.JMSSecurityException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/MessageEOFException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/MessageEOFException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/MessageEOFException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS MessageEOFException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.MessageEOFException
+ */
+public class MessageEOFException extends JmsException {
+
+ public MessageEOFException(javax.jms.MessageEOFException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/MessageFormatException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/MessageFormatException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/MessageFormatException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS MessageFormatException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.MessageFormatException
+ */
+public class MessageFormatException extends JmsException {
+
+ public MessageFormatException(javax.jms.MessageFormatException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/MessageNotReadableException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/MessageNotReadableException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/MessageNotReadableException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS MessageNotReadableException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.MessageNotReadableException
+ */
+public class MessageNotReadableException extends JmsException {
+
+ public MessageNotReadableException(javax.jms.MessageNotReadableException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/MessageNotWriteableException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/MessageNotWriteableException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/MessageNotWriteableException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS MessageNotWriteableException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.MessageNotWriteableException
+ */
+public class MessageNotWriteableException extends JmsException {
+
+ public MessageNotWriteableException(javax.jms.MessageNotWriteableException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/ResourceAllocationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/ResourceAllocationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/ResourceAllocationException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS ResourceAllocationException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.ResourceAllocationException
+ */
+public class ResourceAllocationException extends JmsException {
+
+ public ResourceAllocationException(javax.jms.ResourceAllocationException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/TransactionInProgressException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/TransactionInProgressException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/TransactionInProgressException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS TransactionInProgressException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.TransactionInProgressException
+ */
+public class TransactionInProgressException extends JmsException {
+
+ public TransactionInProgressException(javax.jms.TransactionInProgressException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/TransactionRolledBackException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/TransactionRolledBackException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/TransactionRolledBackException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * Runtime exception mirroring the JMS TransactionRolledBackException.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see javax.jms.TransactionRolledBackException
+ */
+public class TransactionRolledBackException extends JmsException {
+
+ public TransactionRolledBackException(javax.jms.TransactionRolledBackException cause) {
+ super(cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/UncategorizedJmsException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/UncategorizedJmsException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/UncategorizedJmsException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2002-2007 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.jms;
+
+/**
+ * JmsException to be thrown when no other matching subclass found.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ */
+public class UncategorizedJmsException extends JmsException {
+
+ /**
+ * Constructor that takes a message.
+ * @param msg the detail message
+ */
+ public UncategorizedJmsException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor that takes a message and a root cause.
+ * @param msg the detail message
+ * @param cause the cause of the exception. This argument is generally
+ * expected to be a proper subclass of {@link javax.jms.JMSException},
+ * but can also be a JNDI NamingException or the like.
+ */
+ public UncategorizedJmsException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructor that takes a root cause only.
+ * @param cause the cause of the exception. This argument is generally
+ * expected to be a proper subclass of {@link javax.jms.JMSException},
+ * but can also be a JNDI NamingException or the like.
+ */
+ public UncategorizedJmsException(Throwable cause) {
+ super("Uncategorized exception occured during JMS processing", cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/package.html 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+This package contains integration classes for JMS,
+allowing for Spring-style JMS access.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/config/AbstractListenerContainerParser.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/AbstractListenerContainerParser.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/AbstractListenerContainerParser.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2002-2007 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.jms.config;
+
+import javax.jms.Session;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * Abstract parser for JMS listener container elements, providing support for
+ * common properties that are identical for all listener container variants.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+abstract class AbstractListenerContainerParser implements BeanDefinitionParser {
+
+ protected static final String LISTENER_ELEMENT = "listener";
+
+ protected static final String ID_ATTRIBUTE = "id";
+
+ protected static final String DESTINATION_ATTRIBUTE = "destination";
+
+ protected static final String SUBSCRIPTION_ATTRIBUTE = "subscription";
+
+ protected static final String SELECTOR_ATTRIBUTE = "selector";
+
+ protected static final String REF_ATTRIBUTE = "ref";
+
+ protected static final String METHOD_ATTRIBUTE = "method";
+
+ protected static final String DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver";
+
+ protected static final String MESSAGE_CONVERTER_ATTRIBUTE = "message-converter";
+
+ protected static final String RESPONSE_DESTINATION_ATTRIBUTE = "response-destination";
+
+ protected static final String DESTINATION_TYPE_ATTRIBUTE = "destination-type";
+
+ protected static final String DESTINATION_TYPE_QUEUE = "queue";
+
+ protected static final String DESTINATION_TYPE_TOPIC = "topic";
+
+ protected static final String DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic";
+
+ protected static final String CLIENT_ID_ATTRIBUTE = "client-id";
+
+ protected static final String ACKNOWLEDGE_ATTRIBUTE = "acknowledge";
+
+ protected static final String ACKNOWLEDGE_AUTO = "auto";
+
+ protected static final String ACKNOWLEDGE_CLIENT = "client";
+
+ protected static final String ACKNOWLEDGE_DUPS_OK = "dups-ok";
+
+ protected static final String ACKNOWLEDGE_TRANSACTED = "transacted";
+
+ protected static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
+
+ protected static final String CONCURRENCY_ATTRIBUTE = "concurrency";
+
+ protected static final String PREFETCH_ATTRIBUTE = "prefetch";
+
+
+ public BeanDefinition parse(Element element, ParserContext parserContext) {
+ CompositeComponentDefinition compositeDef =
+ new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
+ parserContext.pushContainingComponent(compositeDef);
+
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node child = childNodes.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String localName = child.getLocalName();
+ if (LISTENER_ELEMENT.equals(localName)) {
+ parseListener((Element) child, element, parserContext);
+ }
+ }
+ }
+
+ parserContext.popAndRegisterContainingComponent();
+ return null;
+ }
+
+ private void parseListener(Element listenerEle, Element containerEle, ParserContext parserContext) {
+ RootBeanDefinition listenerDef = new RootBeanDefinition();
+ listenerDef.setSource(parserContext.extractSource(listenerEle));
+
+ String ref = listenerEle.getAttribute(REF_ATTRIBUTE);
+ if (!StringUtils.hasText(ref)) {
+ parserContext.getReaderContext().error(
+ "Listener 'ref' attribute contains empty value.", listenerEle);
+ }
+ listenerDef.getPropertyValues().addPropertyValue("delegate", new RuntimeBeanReference(ref));
+
+ String method = null;
+ if (listenerEle.hasAttribute(METHOD_ATTRIBUTE)) {
+ method = listenerEle.getAttribute(METHOD_ATTRIBUTE);
+ if (!StringUtils.hasText(method)) {
+ parserContext.getReaderContext().error(
+ "Listener 'method' attribute contains empty value.", listenerEle);
+ }
+ }
+ listenerDef.getPropertyValues().addPropertyValue("defaultListenerMethod", method);
+
+ if (containerEle.hasAttribute(MESSAGE_CONVERTER_ATTRIBUTE)) {
+ String messageConverter = containerEle.getAttribute(MESSAGE_CONVERTER_ATTRIBUTE);
+ listenerDef.getPropertyValues().addPropertyValue("messageConverter",
+ new RuntimeBeanReference(messageConverter));
+ }
+
+ BeanDefinition containerDef = parseContainer(listenerEle, containerEle, parserContext);
+
+ if (listenerEle.hasAttribute(RESPONSE_DESTINATION_ATTRIBUTE)) {
+ String responseDestination = listenerEle.getAttribute(RESPONSE_DESTINATION_ATTRIBUTE);
+ boolean pubSubDomain = indicatesPubSub(containerDef);
+ listenerDef.getPropertyValues().addPropertyValue(
+ pubSubDomain ? "defaultResponseTopicName" : "defaultResponseQueueName", responseDestination);
+ if (containerDef.getPropertyValues().contains("destinationResolver")) {
+ listenerDef.getPropertyValues().addPropertyValue("destinationResolver",
+ containerDef.getPropertyValues().getPropertyValue("destinationResolver").getValue());
+ }
+ }
+
+ // Remain JMS 1.0.2 compatible for the adapter if the container class indicates this.
+ boolean jms102 = indicatesJms102(containerDef);
+ listenerDef.setBeanClassName(
+ "org.springframework.jms.listener.adapter.MessageListenerAdapter" + (jms102 ? "102" : ""));
+
+ containerDef.getPropertyValues().addPropertyValue("messageListener", listenerDef);
+
+ String containerBeanName = listenerEle.getAttribute(ID_ATTRIBUTE);
+ // If no bean id is given auto generate one using the ReaderContext's BeanNameGenerator
+ if (!StringUtils.hasText(containerBeanName)) {
+ containerBeanName = parserContext.getReaderContext().generateBeanName(containerDef);
+ }
+
+ // Register the listener and fire event
+ parserContext.registerBeanComponent(new BeanComponentDefinition(containerDef, containerBeanName));
+ }
+
+ protected abstract BeanDefinition parseContainer(
+ Element listenerEle, Element containerEle, ParserContext parserContext);
+
+ protected boolean indicatesPubSub(BeanDefinition containerDef) {
+ return false;
+ }
+
+ protected boolean indicatesJms102(BeanDefinition containerDef) {
+ return false;
+ }
+
+ protected void parseListenerConfiguration(Element ele, ParserContext parserContext, BeanDefinition configDef) {
+ String destination = ele.getAttribute(DESTINATION_ATTRIBUTE);
+ if (!StringUtils.hasText(destination)) {
+ parserContext.getReaderContext().error(
+ "Listener 'destination' attribute contains empty value.", ele);
+ }
+ configDef.getPropertyValues().addPropertyValue("destinationName", destination);
+
+ if (ele.hasAttribute(SUBSCRIPTION_ATTRIBUTE)) {
+ String subscription = ele.getAttribute(SUBSCRIPTION_ATTRIBUTE);
+ if (!StringUtils.hasText(subscription)) {
+ parserContext.getReaderContext().error(
+ "Listener 'subscription' attribute contains empty value.", ele);
+ }
+ configDef.getPropertyValues().addPropertyValue("durableSubscriptionName", subscription);
+ }
+
+ if (ele.hasAttribute(SELECTOR_ATTRIBUTE)) {
+ String selector = ele.getAttribute(SELECTOR_ATTRIBUTE);
+ if (!StringUtils.hasText(selector)) {
+ parserContext.getReaderContext().error(
+ "Listener 'selector' attribute contains empty value.", ele);
+ }
+ configDef.getPropertyValues().addPropertyValue("messageSelector", selector);
+ }
+ }
+
+ protected void parseContainerConfiguration(Element ele, ParserContext parserContext, BeanDefinition configDef) {
+ String destinationType = ele.getAttribute(DESTINATION_TYPE_ATTRIBUTE);
+ boolean pubSubDomain = false;
+ boolean subscriptionDurable = false;
+ if (DESTINATION_TYPE_DURABLE_TOPIC.equals(destinationType)) {
+ pubSubDomain = true;
+ subscriptionDurable = true;
+ }
+ else if (DESTINATION_TYPE_TOPIC.equals(destinationType)) {
+ pubSubDomain = true;
+ }
+ else if ("".equals(destinationType) || DESTINATION_TYPE_QUEUE.equals(destinationType)) {
+ // the default: queue
+ }
+ else {
+ parserContext.getReaderContext().error("Invalid listener container 'destination-type': " +
+ "only \"queue\", \"topic\" and \"durableTopic\" supported.", ele);
+ }
+ configDef.getPropertyValues().addPropertyValue("pubSubDomain", Boolean.valueOf(pubSubDomain));
+ configDef.getPropertyValues().addPropertyValue("subscriptionDurable", Boolean.valueOf(subscriptionDurable));
+
+ if (ele.hasAttribute(CLIENT_ID_ATTRIBUTE)) {
+ String clientId = ele.getAttribute(CLIENT_ID_ATTRIBUTE);
+ if (!StringUtils.hasText(clientId)) {
+ parserContext.getReaderContext().error(
+ "Listener 'client-id' attribute contains empty value.", ele);
+ }
+ configDef.getPropertyValues().addPropertyValue("clientId", clientId);
+ }
+ }
+
+ protected Integer parseAcknowledgeMode(Element ele, ParserContext parserContext) {
+ String acknowledge = ele.getAttribute(ACKNOWLEDGE_ATTRIBUTE);
+ if (StringUtils.hasText(acknowledge)) {
+ int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+ if (ACKNOWLEDGE_TRANSACTED.equals(acknowledge)) {
+ acknowledgeMode = Session.SESSION_TRANSACTED;
+ }
+ else if (ACKNOWLEDGE_DUPS_OK.equals(acknowledge)) {
+ acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
+ }
+ else if (ACKNOWLEDGE_CLIENT.equals(acknowledge)) {
+ acknowledgeMode = Session.CLIENT_ACKNOWLEDGE;
+ }
+ else if (!ACKNOWLEDGE_AUTO.equals(acknowledge)) {
+ parserContext.getReaderContext().error("Invalid listener container 'acknowledge' setting [" +
+ acknowledge + "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported.", ele);
+ }
+ return new Integer(acknowledgeMode);
+ }
+ else {
+ return null;
+ }
+ }
+
+ protected boolean indicatesPubSubConfig(BeanDefinition configDef) {
+ return ((Boolean) configDef.getPropertyValues().getPropertyValue("pubSubDomain").getValue()).booleanValue();
+ }
+
+ protected int[] parseConcurrency(Element ele, ParserContext parserContext) {
+ String concurrency = ele.getAttribute(CONCURRENCY_ATTRIBUTE);
+ if (!StringUtils.hasText(concurrency)) {
+ return null;
+ }
+ try {
+ int separatorIndex = concurrency.indexOf('-');
+ if (separatorIndex != -1) {
+ int[] result = new int[2];
+ result[0] = Integer.parseInt(concurrency.substring(0, separatorIndex));
+ result[1] = Integer.parseInt(concurrency.substring(separatorIndex + 1, concurrency.length()));
+ return result;
+ }
+ else {
+ return new int[] {1, Integer.parseInt(concurrency)};
+ }
+ }
+ catch (NumberFormatException ex) {
+ parserContext.getReaderContext().error("Invalid concurrency value [" + concurrency + "]: only " +
+ "single maximum integer (e.g. \"5\") and minimum-maximum combo (e.g. \"3-5\") supported.", ele, ex);
+ return null;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/config/JcaListenerContainerParser.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/JcaListenerContainerParser.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/JcaListenerContainerParser.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2002-2007 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.jms.config;
+
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * Parser for the JMS <jca-listener-container> element.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+class JcaListenerContainerParser extends AbstractListenerContainerParser {
+
+ private static final String RESOURCE_ADAPTER_ATTRIBUTE = "resource-adapter";
+
+ private static final String ACTIVATION_SPEC_FACTORY_ATTRIBUTE = "activation-spec-factory";
+
+
+ protected BeanDefinition parseContainer(Element listenerEle, Element containerEle, ParserContext parserContext) {
+ RootBeanDefinition containerDef = new RootBeanDefinition();
+ containerDef.setSource(parserContext.extractSource(containerEle));
+ containerDef.setBeanClassName("org.springframework.jms.listener.endpoint.JmsMessageEndpointManager");
+
+ String resourceAdapterBeanName = "resourceAdapter";
+ if (containerEle.hasAttribute(RESOURCE_ADAPTER_ATTRIBUTE)) {
+ resourceAdapterBeanName = containerEle.getAttribute(RESOURCE_ADAPTER_ATTRIBUTE);
+ if (!StringUtils.hasText(resourceAdapterBeanName)) {
+ parserContext.getReaderContext().error(
+ "Listener container 'resource-adapter' attribute contains empty value.", containerEle);
+ }
+ }
+ containerDef.getPropertyValues().addPropertyValue("resourceAdapter",
+ new RuntimeBeanReference(resourceAdapterBeanName));
+
+ String activationSpecFactoryBeanName = containerEle.getAttribute(ACTIVATION_SPEC_FACTORY_ATTRIBUTE);
+ String destinationResolverBeanName = containerEle.getAttribute(DESTINATION_RESOLVER_ATTRIBUTE);
+ if (StringUtils.hasText(activationSpecFactoryBeanName)) {
+ if (StringUtils.hasText(destinationResolverBeanName)) {
+ parserContext.getReaderContext().error("Specify either 'activation-spec-factory' or " +
+ "'destination-resolver', not both. If you define a dedicated JmsActivationSpecFactory bean, " +
+ "specify the custom DestinationResolver there (if possible).", containerEle);
+ }
+ containerDef.getPropertyValues().addPropertyValue("activationSpecFactory",
+ new RuntimeBeanReference(activationSpecFactoryBeanName));
+ }
+ if (StringUtils.hasText(destinationResolverBeanName)) {
+ containerDef.getPropertyValues().addPropertyValue("destinationResolver",
+ new RuntimeBeanReference(destinationResolverBeanName));
+ }
+
+ RootBeanDefinition configDef = new RootBeanDefinition();
+ configDef.setSource(parserContext.extractSource(configDef));
+ configDef.setBeanClassName("org.springframework.jms.listener.endpoint.JmsActivationSpecConfig");
+
+ parseListenerConfiguration(listenerEle, parserContext, configDef);
+ parseContainerConfiguration(containerEle, parserContext, configDef);
+
+ Integer acknowledgeMode = parseAcknowledgeMode(containerEle, parserContext);
+ if (acknowledgeMode != null) {
+ configDef.getPropertyValues().addPropertyValue("acknowledgeMode", acknowledgeMode);
+ }
+
+ String transactionManagerBeanName = containerEle.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE);
+ if (StringUtils.hasText(transactionManagerBeanName)) {
+ containerDef.getPropertyValues().addPropertyValue("transactionManager",
+ new RuntimeBeanReference(transactionManagerBeanName));
+ }
+
+ int[] concurrency = parseConcurrency(containerEle, parserContext);
+ if (concurrency != null) {
+ configDef.getPropertyValues().addPropertyValue("maxConcurrency", new Integer(concurrency[1]));
+ }
+
+ String prefetch = containerEle.getAttribute(PREFETCH_ATTRIBUTE);
+ if (StringUtils.hasText(prefetch)) {
+ configDef.getPropertyValues().addPropertyValue("prefetchSize", new Integer(prefetch));
+ }
+
+ containerDef.getPropertyValues().addPropertyValue("activationSpecConfig", configDef);
+
+ return containerDef;
+ }
+
+ protected boolean indicatesPubSub(BeanDefinition containerDef) {
+ BeanDefinition configDef =
+ (BeanDefinition) containerDef.getPropertyValues().getPropertyValue("activationSpecConfig").getValue();
+ return indicatesPubSubConfig(configDef);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/config/JmsListenerContainerParser.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/JmsListenerContainerParser.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/JmsListenerContainerParser.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2002-2008 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.jms.config;
+
+import javax.jms.Session;
+
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * Parser for the JMS <listener-container> element.
+ *
+ * @author Mark Fisher
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+class JmsListenerContainerParser extends AbstractListenerContainerParser {
+
+ private static final String CONTAINER_TYPE_ATTRIBUTE = "container-type";
+
+ private static final String CONTAINER_CLASS_ATTRIBUTE = "container-class";
+
+ private static final String CONNECTION_FACTORY_ATTRIBUTE = "connection-factory";
+
+ private static final String TASK_EXECUTOR_ATTRIBUTE = "task-executor";
+
+ private static final String CACHE_ATTRIBUTE = "cache";
+
+
+ protected BeanDefinition parseContainer(Element listenerEle, Element containerEle, ParserContext parserContext) {
+ RootBeanDefinition containerDef = new RootBeanDefinition();
+ containerDef.setSource(parserContext.extractSource(containerEle));
+
+ parseListenerConfiguration(listenerEle, parserContext, containerDef);
+ parseContainerConfiguration(containerEle, parserContext, containerDef);
+
+ String containerType = containerEle.getAttribute(CONTAINER_TYPE_ATTRIBUTE);
+ String containerClass = containerEle.getAttribute(CONTAINER_CLASS_ATTRIBUTE);
+ if (!"".equals(containerClass)) {
+ containerDef.setBeanClassName(containerClass);
+ }
+ else if ("".equals(containerType) || "default".equals(containerType)) {
+ containerDef.setBeanClassName("org.springframework.jms.listener.DefaultMessageListenerContainer");
+ }
+ else if ("default102".equals(containerType)) {
+ containerDef.setBeanClassName("org.springframework.jms.listener.DefaultMessageListenerContainer102");
+ }
+ else if ("simple".equals(containerType)) {
+ containerDef.setBeanClassName("org.springframework.jms.listener.SimpleMessageListenerContainer");
+ }
+ else if ("simple102".equals(containerType)) {
+ containerDef.setBeanClassName("org.springframework.jms.listener.SimpleMessageListenerContainer102");
+ }
+ else {
+ parserContext.getReaderContext().error(
+ "Invalid 'container-type' attribute: only \"default(102)\" and \"simple(102)\" supported.", containerEle);
+ }
+
+ String connectionFactoryBeanName = "connectionFactory";
+ if (containerEle.hasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) {
+ connectionFactoryBeanName = containerEle.getAttribute(CONNECTION_FACTORY_ATTRIBUTE);
+ if (!StringUtils.hasText(connectionFactoryBeanName)) {
+ parserContext.getReaderContext().error(
+ "Listener container 'connection-factory' attribute contains empty value.", containerEle);
+ }
+ }
+ containerDef.getPropertyValues().addPropertyValue("connectionFactory",
+ new RuntimeBeanReference(connectionFactoryBeanName));
+
+ String taskExecutorBeanName = containerEle.getAttribute(TASK_EXECUTOR_ATTRIBUTE);
+ if (StringUtils.hasText(taskExecutorBeanName)) {
+ containerDef.getPropertyValues().addPropertyValue("taskExecutor",
+ new RuntimeBeanReference(taskExecutorBeanName));
+ }
+
+ String destinationResolverBeanName = containerEle.getAttribute(DESTINATION_RESOLVER_ATTRIBUTE);
+ if (StringUtils.hasText(destinationResolverBeanName)) {
+ containerDef.getPropertyValues().addPropertyValue("destinationResolver",
+ new RuntimeBeanReference(destinationResolverBeanName));
+ }
+
+ String cache = containerEle.getAttribute(CACHE_ATTRIBUTE);
+ if (StringUtils.hasText(cache)) {
+ if (containerType.startsWith("simple")) {
+ if (!("auto".equals(cache) || "consumer".equals(cache))) {
+ parserContext.getReaderContext().warning(
+ "'cache' attribute not actively supported for listener container of type \"simple\". " +
+ "Effective runtime behavior will be equivalent to \"consumer\" / \"auto\".", containerEle);
+ }
+ }
+ else {
+ containerDef.getPropertyValues().addPropertyValue("cacheLevelName", "CACHE_" + cache.toUpperCase());
+ }
+ }
+
+ Integer acknowledgeMode = parseAcknowledgeMode(containerEle, parserContext);
+ if (acknowledgeMode != null) {
+ if (acknowledgeMode.intValue() == Session.SESSION_TRANSACTED) {
+ containerDef.getPropertyValues().addPropertyValue("sessionTransacted", Boolean.TRUE);
+ }
+ else {
+ containerDef.getPropertyValues().addPropertyValue("sessionAcknowledgeMode", acknowledgeMode);
+ }
+ }
+
+ String transactionManagerBeanName = containerEle.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE);
+ if (StringUtils.hasText(transactionManagerBeanName)) {
+ if (containerType.startsWith("simple")) {
+ parserContext.getReaderContext().error(
+ "'transaction-manager' attribute not supported for listener container of type \"simple\".", containerEle);
+ }
+ else {
+ containerDef.getPropertyValues().addPropertyValue("transactionManager",
+ new RuntimeBeanReference(transactionManagerBeanName));
+ }
+ }
+
+ int[] concurrency = parseConcurrency(containerEle, parserContext);
+ if (concurrency != null) {
+ if (containerType.startsWith("default")) {
+ containerDef.getPropertyValues().addPropertyValue("concurrentConsumers", new Integer(concurrency[0]));
+ containerDef.getPropertyValues().addPropertyValue("maxConcurrentConsumers", new Integer(concurrency[1]));
+ }
+ else {
+ containerDef.getPropertyValues().addPropertyValue("concurrentConsumers", new Integer(concurrency[1]));
+ }
+ }
+
+ String prefetch = containerEle.getAttribute(PREFETCH_ATTRIBUTE);
+ if (StringUtils.hasText(prefetch)) {
+ if (containerType.startsWith("default")) {
+ containerDef.getPropertyValues().addPropertyValue("maxMessagesPerTask", new Integer(prefetch));
+ }
+ }
+
+ return containerDef;
+ }
+
+ protected boolean indicatesPubSub(BeanDefinition containerDef) {
+ return indicatesPubSubConfig(containerDef);
+ }
+
+ protected boolean indicatesJms102(BeanDefinition containerDef) {
+ return containerDef.getBeanClassName().endsWith("102");
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/config/JmsNamespaceHandler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/JmsNamespaceHandler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/JmsNamespaceHandler.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2007 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.jms.config;
+
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+
+/**
+ * A {@link org.springframework.beans.factory.xml.NamespaceHandler}
+ * for the JMS namespace.
+ *
+ * @author Mark Fisher
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class JmsNamespaceHandler extends NamespaceHandlerSupport {
+
+ public void init() {
+ registerBeanDefinitionParser("listener-container", new JmsListenerContainerParser());
+ registerBeanDefinitionParser("jca-listener-container", new JcaListenerContainerParser());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/config/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/package.html 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Support package for declarative messaging configuration,
+with XML schema being the primary configuration format.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/config/spring-jms-2.5.xsd
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/config/spring-jms-2.5.xsd,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/config/spring-jms-2.5.xsd 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,439 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageConsumer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageConsumer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageConsumer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+/**
+ * JMS MessageConsumer decorator that adapts all calls
+ * to a shared MessageConsumer instance underneath.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.6
+ */
+class CachedMessageConsumer implements MessageConsumer, QueueReceiver, TopicSubscriber {
+
+ protected final MessageConsumer target;
+
+
+ public CachedMessageConsumer(MessageConsumer target) {
+ this.target = target;
+ }
+
+
+ public String getMessageSelector() throws JMSException {
+ return this.target.getMessageSelector();
+ }
+
+ public Queue getQueue() throws JMSException {
+ return (this.target instanceof QueueReceiver ? ((QueueReceiver) this.target).getQueue() : null);
+ }
+
+ public Topic getTopic() throws JMSException {
+ return (this.target instanceof TopicSubscriber ? ((TopicSubscriber) this.target).getTopic() : null);
+ }
+
+ public boolean getNoLocal() throws JMSException {
+ return (this.target instanceof TopicSubscriber && ((TopicSubscriber) this.target).getNoLocal());
+ }
+
+ public MessageListener getMessageListener() throws JMSException {
+ return this.target.getMessageListener();
+ }
+
+ public void setMessageListener(MessageListener messageListener) throws JMSException {
+ this.target.setMessageListener(messageListener);
+ }
+
+ public Message receive() throws JMSException {
+ return this.target.receive();
+ }
+
+ public Message receive(long timeout) throws JMSException {
+ return this.target.receive(timeout);
+ }
+
+ public Message receiveNoWait() throws JMSException {
+ return this.target.receiveNoWait();
+ }
+
+ public void close() throws JMSException {
+ // It's a cached MessageConsumer...
+ }
+
+
+ public String toString() {
+ return "Cached JMS MessageConsumer: " + this.target;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageProducer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageProducer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/CachedMessageProducer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+
+/**
+ * JMS MessageProducer decorator that adapts calls to a shared MessageProducer
+ * instance underneath, managing QoS settings locally within the decorator.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.3
+ */
+class CachedMessageProducer implements MessageProducer, QueueSender, TopicPublisher {
+
+ private final MessageProducer target;
+
+ private Boolean originalDisableMessageID;
+
+ private Boolean originalDisableMessageTimestamp;
+
+ private int deliveryMode;
+
+ private int priority;
+
+ private long timeToLive;
+
+
+ public CachedMessageProducer(MessageProducer target) throws JMSException {
+ this.target = target;
+ this.deliveryMode = target.getDeliveryMode();
+ this.priority = target.getPriority();
+ this.timeToLive = target.getTimeToLive();
+ }
+
+
+ public void setDisableMessageID(boolean disableMessageID) throws JMSException {
+ if (this.originalDisableMessageID == null) {
+ this.originalDisableMessageID = Boolean.valueOf(this.target.getDisableMessageID());
+ }
+ this.target.setDisableMessageID(disableMessageID);
+ }
+
+ public boolean getDisableMessageID() throws JMSException {
+ return this.target.getDisableMessageID();
+ }
+
+ public void setDisableMessageTimestamp(boolean disableMessageTimestamp) throws JMSException {
+ if (this.originalDisableMessageTimestamp == null) {
+ this.originalDisableMessageTimestamp = Boolean.valueOf(this.target.getDisableMessageTimestamp());
+ }
+ this.target.setDisableMessageTimestamp(disableMessageTimestamp);
+ }
+
+ public boolean getDisableMessageTimestamp() throws JMSException {
+ return this.target.getDisableMessageTimestamp();
+ }
+
+ public void setDeliveryMode(int deliveryMode) {
+ this.deliveryMode = deliveryMode;
+ }
+
+ public int getDeliveryMode() {
+ return this.deliveryMode;
+ }
+
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ public int getPriority() {
+ return this.priority;
+ }
+
+ public void setTimeToLive(long timeToLive) {
+ this.timeToLive = timeToLive;
+ }
+
+ public long getTimeToLive() {
+ return this.timeToLive;
+ }
+
+ public Destination getDestination() throws JMSException {
+ return this.target.getDestination();
+ }
+
+ public Queue getQueue() throws JMSException {
+ return (Queue) this.target.getDestination();
+ }
+
+ public Topic getTopic() throws JMSException {
+ return (Topic) this.target.getDestination();
+ }
+
+ public void send(Message message) throws JMSException {
+ this.target.send(message, this.deliveryMode, this.priority, this.timeToLive);
+ }
+
+ public void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+ this.target.send(message, deliveryMode, priority, timeToLive);
+ }
+
+ public void send(Destination destination, Message message) throws JMSException {
+ this.target.send(destination, message, this.deliveryMode, this.priority, this.timeToLive);
+ }
+
+ public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+ this.target.send(destination, message, deliveryMode, priority, timeToLive);
+ }
+
+ public void send(Queue queue, Message message) throws JMSException {
+ this.target.send(queue, message, this.deliveryMode, this.priority, this.timeToLive);
+ }
+
+ public void send(Queue queue, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+ this.target.send(queue, message, deliveryMode, priority, timeToLive);
+ }
+
+ public void publish(Message message) throws JMSException {
+ this.target.send(message, this.deliveryMode, this.priority, this.timeToLive);
+ }
+
+ public void publish(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+ this.target.send(message, deliveryMode, priority, timeToLive);
+ }
+
+ public void publish(Topic topic, Message message) throws JMSException {
+ this.target.send(topic, message, this.deliveryMode, this.priority, this.timeToLive);
+ }
+
+ public void publish(Topic topic, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+ this.target.send(topic, message, deliveryMode, priority, timeToLive);
+ }
+
+ public void close() throws JMSException {
+ // It's a cached MessageProducer... reset properties only.
+ if (this.originalDisableMessageID != null) {
+ this.target.setDisableMessageID(this.originalDisableMessageID.booleanValue());
+ this.originalDisableMessageID = null;
+ }
+ if (this.originalDisableMessageTimestamp != null) {
+ this.target.setDisableMessageTimestamp(this.originalDisableMessageTimestamp.booleanValue());
+ this.originalDisableMessageTimestamp = null;
+ }
+ }
+
+
+ public String toString() {
+ return "Cached JMS MessageProducer: " + this.target;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/CachingConnectionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/CachingConnectionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/CachingConnectionFactory.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicSession;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * {@link SingleConnectionFactory} subclass that adds {@link javax.jms.Session}
+ * caching as well {@link javax.jms.MessageProducer} caching. This ConnectionFactory
+ * also switches the {@link #setReconnectOnException "reconnectOnException" property}
+ * to "true" by default, allowing for automatic recovery of the underlying Connection.
+ *
+ *
By default, only one single Session will be cached, with further requested
+ * Sessions being created and disposed on demand. Consider raising the
+ * {@link #setSessionCacheSize "sessionCacheSize" value} in case of a
+ * high-concurrency environment.
+ *
+ *
NOTE: This ConnectionFactory decorator requires JMS 1.1 or higher.
+ * You may use it through the JMS 1.0.2 API; however, the target JMS driver
+ * needs to be compliant with JMS 1.1.
+ *
+ *
When using the JMS 1.0.2 API, this ConnectionFactory will switch
+ * into queue/topic mode according to the JMS API methods used at runtime:
+ * createQueueConnection and createTopicConnection will
+ * lead to queue/topic mode, respectively; generic createConnection
+ * calls will lead to a JMS 1.1 connection which is able to serve both modes.
+ *
+ *
NOTE: This ConnectionFactory requires explicit closing of all Sessions
+ * obtained from its shared Connection. This is the usual recommendation for
+ * native JMS access code anyway. However, with this ConnectionFactory, its use
+ * is mandatory in order to actually allow for Session reuse.
+ *
+ *
Note also that MessageConsumers obtained from a cached Session won't get
+ * closed until the Session will eventually be removed from the pool. This may
+ * lead to semantic side effects in some cases. For a durable subscriber, the
+ * logical Session.close() call will also close the subscription.
+ * Re-registering a durable consumer for the same subscription on the same
+ * Session handle is not supported; close and reobtain a cached Session first.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.3
+ */
+public class CachingConnectionFactory extends SingleConnectionFactory {
+
+ private int sessionCacheSize = 1;
+
+ private boolean cacheProducers = true;
+
+ private boolean cacheConsumers = true;
+
+ private volatile boolean active = true;
+
+ private final Map cachedSessions = new HashMap();
+
+
+ /**
+ * Create a new CachingConnectionFactory for bean-style usage.
+ * @see #setTargetConnectionFactory
+ */
+ public CachingConnectionFactory() {
+ super();
+ setReconnectOnException(true);
+ }
+
+ /**
+ * Create a new CachingConnectionFactory for the given target
+ * ConnectionFactory.
+ * @param targetConnectionFactory the target ConnectionFactory
+ */
+ public CachingConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ super(targetConnectionFactory);
+ setReconnectOnException(true);
+ }
+
+
+ /**
+ * Specify the desired size for the JMS Session cache (per JMS Session type).
+ *
This cache size is the maximum limit for the number of cached Sessions
+ * per session acknowledgement type (auto, client, dups_ok, transacted).
+ * As a consequence, the actual number of cached Sessions may be up to
+ * four times as high as the specified value - in the unlikely case
+ * of mixing and matching different acknowledgement types.
+ *
Default is 1: caching a single Session, (re-)creating further ones on
+ * demand. Specify a number like 10 if you'd like to raise the number of cached
+ * Sessions; that said, 1 may be sufficient for low-concurrency scenarios.
+ * @see #setCacheProducers
+ */
+ public void setSessionCacheSize(int sessionCacheSize) {
+ Assert.isTrue(sessionCacheSize >= 1, "Session cache size must be 1 or higher");
+ this.sessionCacheSize = sessionCacheSize;
+ }
+
+ /**
+ * Return the desired size for the JMS Session cache (per JMS Session type).
+ */
+ public int getSessionCacheSize() {
+ return this.sessionCacheSize;
+ }
+
+ /**
+ * Specify whether to cache JMS MessageProducers per JMS Session instance
+ * (more specifically: one MessageProducer per Destination and Session).
+ *
Default is "true". Switch this to "false" in order to always
+ * recreate MessageProducers on demand.
+ */
+ public void setCacheProducers(boolean cacheProducers) {
+ this.cacheProducers = cacheProducers;
+ }
+
+ /**
+ * Return whether to cache JMS MessageProducers per JMS Session instance.
+ */
+ public boolean isCacheProducers() {
+ return this.cacheProducers;
+ }
+
+ /**
+ * Specify whether to cache JMS MessageConsumers per JMS Session instance
+ * (more specifically: one MessageConsumer per Destination, selector String
+ * and Session). Note that durable subscribers will only be cached until
+ * logical closing of the Session handle.
+ *
Default is "true". Switch this to "false" in order to always
+ * recreate MessageConsumers on demand.
+ */
+ public void setCacheConsumers(boolean cacheConsumers) {
+ this.cacheConsumers = cacheConsumers;
+ }
+
+ /**
+ * Return whether to cache JMS MessageConsumers per JMS Session instance.
+ */
+ public boolean isCacheConsumers() {
+ return this.cacheConsumers;
+ }
+
+
+ /**
+ * Resets the Session cache as well.
+ */
+ public void resetConnection() {
+ this.active = false;
+ synchronized (this.cachedSessions) {
+ for (Iterator it = this.cachedSessions.values().iterator(); it.hasNext();) {
+ LinkedList sessionList = (LinkedList) it.next();
+ synchronized (sessionList) {
+ for (Iterator it2 = sessionList.iterator(); it2.hasNext();) {
+ Session session = (Session) it2.next();
+ try {
+ session.close();
+ }
+ catch (Throwable ex) {
+ logger.trace("Could not close cached JMS Session", ex);
+ }
+ }
+ }
+ }
+ this.cachedSessions.clear();
+ }
+ this.active = true;
+
+ // Now proceed with actual closing of the shared Connection...
+ super.resetConnection();
+ }
+
+ /**
+ * Checks for a cached Session for the given mode.
+ */
+ protected Session getSession(Connection con, Integer mode) throws JMSException {
+ LinkedList sessionList = null;
+ synchronized (this.cachedSessions) {
+ sessionList = (LinkedList) this.cachedSessions.get(mode);
+ if (sessionList == null) {
+ sessionList = new LinkedList();
+ this.cachedSessions.put(mode, sessionList);
+ }
+ }
+ Session session = null;
+ synchronized (sessionList) {
+ if (!sessionList.isEmpty()) {
+ session = (Session) sessionList.removeFirst();
+ }
+ }
+ if (session != null) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Found cached JMS Session for mode " + mode + ": " +
+ (session instanceof SessionProxy ? ((SessionProxy) session).getTargetSession() : session));
+ }
+ }
+ else {
+ Session targetSession = createSession(con, mode);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating cached JMS Session for mode " + mode + ": " + targetSession);
+ }
+ session = getCachedSessionProxy(targetSession, sessionList);
+ }
+ return session;
+ }
+
+ /**
+ * Wrap the given Session with a proxy that delegates every method call to it
+ * but adapts close calls. This is useful for allowing application code to
+ * handle a special framework Session just like an ordinary Session.
+ * @param target the original Session to wrap
+ * @param sessionList the List of cached Sessions that the given Session belongs to
+ * @return the wrapped Session
+ */
+ protected Session getCachedSessionProxy(Session target, LinkedList sessionList) {
+ List classes = new ArrayList(3);
+ classes.add(SessionProxy.class);
+ if (target instanceof QueueSession) {
+ classes.add(QueueSession.class);
+ }
+ if (target instanceof TopicSession) {
+ classes.add(TopicSession.class);
+ }
+ return (Session) Proxy.newProxyInstance(
+ SessionProxy.class.getClassLoader(),
+ (Class[]) classes.toArray(new Class[classes.size()]),
+ new CachedSessionInvocationHandler(target, sessionList));
+ }
+
+
+ /**
+ * Invocation handler for a cached JMS Session proxy.
+ */
+ private class CachedSessionInvocationHandler implements InvocationHandler {
+
+ private final Session target;
+
+ private final LinkedList sessionList;
+
+ private final Map cachedProducers = new HashMap();
+
+ private final Map cachedConsumers = new HashMap();
+
+ private boolean transactionOpen = false;
+
+ public CachedSessionInvocationHandler(Session target, LinkedList sessionList) {
+ this.target = target;
+ this.sessionList = sessionList;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ if (methodName.equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (methodName.equals("hashCode")) {
+ // Use hashCode of Session proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (methodName.equals("toString")) {
+ return "Cached JMS Session: " + this.target;
+ }
+ else if (methodName.equals("close")) {
+ // Handle close method: don't pass the call on.
+ if (active) {
+ synchronized (this.sessionList) {
+ if (this.sessionList.size() < getSessionCacheSize()) {
+ logicalClose(proxy);
+ // Remain open in the session list.
+ return null;
+ }
+ }
+ }
+ // If we get here, we're supposed to shut down.
+ physicalClose();
+ return null;
+ }
+ else if (methodName.equals("getTargetSession")) {
+ // Handle getTargetSession method: return underlying Session.
+ return this.target;
+ }
+ else if (methodName.equals("commit") || methodName.equals("rollback")) {
+ this.transactionOpen = false;
+ }
+ else {
+ this.transactionOpen = true;
+ if ((methodName.equals("createProducer") || methodName.equals("createSender") ||
+ methodName.equals("createPublisher")) && isCacheProducers()) {
+ return getCachedProducer((Destination) args[0]);
+ }
+ else if ((methodName.equals("createConsumer") || methodName.equals("createReceiver") ||
+ methodName.equals("createSubscriber")) && isCacheConsumers()) {
+ return getCachedConsumer((Destination) args[0], (args.length > 1 ? (String) args[1] : null),
+ (args.length > 2 && ((Boolean) args[2]).booleanValue()), null);
+ }
+ else if (methodName.equals("createDurableSubscriber") && isCacheConsumers()) {
+ return getCachedConsumer((Destination) args[0], (args.length > 2 ? (String) args[2] : null),
+ (args.length > 3 && ((Boolean) args[3]).booleanValue()), (String) args[1]);
+ }
+ }
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ private MessageProducer getCachedProducer(Destination dest) throws JMSException {
+ MessageProducer producer = (MessageProducer) this.cachedProducers.get(dest);
+ if (producer != null) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Found cached JMS MessageProducer for destination [" + dest + "]: " + producer);
+ }
+ }
+ else {
+ producer = this.target.createProducer(dest);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating cached JMS MessageProducer for destination [" + dest + "]: " + producer);
+ }
+ this.cachedProducers.put(dest, producer);
+ }
+ return new CachedMessageProducer(producer);
+ }
+
+ private MessageConsumer getCachedConsumer(
+ Destination dest, String selector, boolean noLocal, String subscription) throws JMSException {
+
+ Object cacheKey = new ConsumerCacheKey(dest, selector, noLocal, subscription);
+ MessageConsumer consumer = (MessageConsumer) this.cachedConsumers.get(cacheKey);
+ if (consumer != null) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Found cached JMS MessageConsumer for destination [" + dest + "]: " + consumer);
+ }
+ }
+ else {
+ if (dest instanceof Topic) {
+ consumer = (subscription != null ?
+ this.target.createDurableSubscriber((Topic) dest, subscription, selector, noLocal) :
+ this.target.createConsumer(dest, selector, noLocal));
+ }
+ else {
+ consumer = this.target.createConsumer(dest, selector);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating cached JMS MessageConsumer for destination [" + dest + "]: " + consumer);
+ }
+ this.cachedConsumers.put(cacheKey, consumer);
+ }
+ return new CachedMessageConsumer(consumer);
+ }
+
+ private void logicalClose(Object proxy) throws JMSException {
+ // Preserve rollback-on-close semantics.
+ if (this.transactionOpen && this.target.getTransacted()) {
+ this.transactionOpen = false;
+ this.target.rollback();
+ }
+ // Physically close durable subscribers at time of Session close call.
+ for (Iterator it = this.cachedConsumers.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ ConsumerCacheKey key = (ConsumerCacheKey) entry.getKey();
+ if (key.subscription != null) {
+ ((MessageConsumer) entry.getValue()).close();
+ it.remove();
+ }
+ }
+ // Allow for multiple close calls...
+ if (!this.sessionList.contains(proxy)) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Returning cached Session: " + this.target);
+ }
+ this.sessionList.addLast(proxy);
+ }
+ }
+
+ private void physicalClose() throws JMSException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Closing cached Session: " + this.target);
+ }
+ // Explicitly close all MessageProducers and MessageConsumers that
+ // this Session happens to cache...
+ try {
+ for (Iterator it = this.cachedProducers.values().iterator(); it.hasNext();) {
+ ((MessageProducer) it.next()).close();
+ }
+ for (Iterator it = this.cachedConsumers.values().iterator(); it.hasNext();) {
+ ((MessageConsumer) it.next()).close();
+ }
+ }
+ finally {
+ this.cachedProducers.clear();
+ this.cachedConsumers.clear();
+ // Now actually close the Session.
+ this.target.close();
+ }
+ }
+ }
+
+
+ /**
+ * Simple wrapper class around a Destination and other consumer attributes.
+ * Used as the key when caching consumers.
+ */
+ private static class ConsumerCacheKey {
+
+ private final Destination destination;
+
+ private final String selector;
+
+ private final boolean noLocal;
+
+ private final String subscription;
+
+ private ConsumerCacheKey(Destination destination, String selector, boolean noLocal, String subscription) {
+ this.destination = destination;
+ this.selector = selector;
+ this.noLocal = noLocal;
+ this.subscription = subscription;
+ }
+
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ ConsumerCacheKey otherKey = (ConsumerCacheKey) other;
+ return (this.destination.equals(otherKey.destination) &&
+ ObjectUtils.nullSafeEquals(this.selector, otherKey.selector) &&
+ this.noLocal == otherKey.noLocal &&
+ ObjectUtils.nullSafeEquals(this.subscription, otherKey.subscription));
+ }
+
+ public int hashCode() {
+ return this.destination.hashCode();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/ChainedExceptionListener.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/ChainedExceptionListener.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/ChainedExceptionListener.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2002-2006 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.jms.connection;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import org.springframework.util.Assert;
+
+/**
+ * Implementation of the JMS ExceptionListener interface that supports chaining,
+ * allowing the addition of multiple ExceptionListener instances in order.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public class ChainedExceptionListener implements ExceptionListener {
+
+ /** List of ExceptionListeners */
+ private final List delegates = new ArrayList(2);
+
+
+ /**
+ * Add an ExceptionListener to the chained delegate list.
+ */
+ public final void addDelegate(ExceptionListener listener) {
+ Assert.notNull(listener, "ExceptionListener must not be null");
+ this.delegates.add(listener);
+ }
+
+ /**
+ * Return all registered ExceptionListener delegates (as array).
+ */
+ public final ExceptionListener[] getDelegates() {
+ return (ExceptionListener[]) this.delegates.toArray(new ExceptionListener[this.delegates.size()]);
+ }
+
+
+ public void onException(JMSException ex) {
+ for (Iterator it = this.delegates.iterator(); it.hasNext();) {
+ ExceptionListener listener = (ExceptionListener) it.next();
+ listener.onException(ex);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/ConnectionFactoryUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/ConnectionFactoryUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/ConnectionFactoryUtils.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.transaction.support.ResourceHolder;
+import org.springframework.transaction.support.ResourceHolderSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class for managing a JMS {@link javax.jms.ConnectionFactory}, in particular
+ * for obtaining transactional JMS resources for a given ConnectionFactory.
+ *
+ *
Mainly for internal use within the framework. Used by
+ * {@link org.springframework.jms.core.JmsTemplate} as well as
+ * {@link org.springframework.jms.listener.DefaultMessageListenerContainer}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see SmartConnectionFactory
+ */
+public abstract class ConnectionFactoryUtils {
+
+ private static final Log logger = LogFactory.getLog(ConnectionFactoryUtils.class);
+
+
+ /**
+ * Release the given Connection, stopping it (if necessary) and eventually closing it.
+ *
Checks {@link SmartConnectionFactory#shouldStop}, if available.
+ * This is essentially a more sophisticated version of
+ * {@link org.springframework.jms.support.JmsUtils#closeConnection}.
+ * @param con the Connection to release
+ * (if this is null, the call will be ignored)
+ * @param cf the ConnectionFactory that the Connection was obtained from
+ * (may be null)
+ * @param started whether the Connection might have been started by the application
+ * @see SmartConnectionFactory#shouldStop
+ * @see org.springframework.jms.support.JmsUtils#closeConnection
+ */
+ public static void releaseConnection(Connection con, ConnectionFactory cf, boolean started) {
+ if (con == null) {
+ return;
+ }
+ if (started && cf instanceof SmartConnectionFactory && ((SmartConnectionFactory) cf).shouldStop(con)) {
+ try {
+ con.stop();
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not stop JMS Connection before closing it", ex);
+ }
+ }
+ try {
+ con.close();
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not close JMS Connection", ex);
+ }
+ }
+
+ /**
+ * Return the innermost target Session of the given Session. If the given
+ * Session is a proxy, it will be unwrapped until a non-proxy Session is
+ * found. Otherwise, the passed-in Session will be returned as-is.
+ * @param session the Session proxy to unwrap
+ * @return the innermost target Session, or the passed-in one if no proxy
+ * @see SessionProxy#getTargetSession()
+ */
+ public static Session getTargetSession(Session session) {
+ Session sessionToUse = session;
+ while (sessionToUse instanceof SessionProxy) {
+ sessionToUse = ((SessionProxy) sessionToUse).getTargetSession();
+ }
+ return sessionToUse;
+ }
+
+
+
+ /**
+ * Determine whether the given JMS Session is transactional, that is,
+ * bound to the current thread by Spring's transaction facilities.
+ * @param session the JMS Session to check
+ * @param cf the JMS ConnectionFactory that the Session originated from
+ * @return whether the Session is transactional
+ */
+ public static boolean isSessionTransactional(Session session, ConnectionFactory cf) {
+ if (session == null || cf == null) {
+ return false;
+ }
+ JmsResourceHolder resourceHolder = (JmsResourceHolder) TransactionSynchronizationManager.getResource(cf);
+ return (resourceHolder != null && resourceHolder.containsSession(session));
+ }
+
+
+ /**
+ * Obtain a JMS Session that is synchronized with the current transaction, if any.
+ * @param cf the ConnectionFactory to obtain a Session for
+ * @param existingCon the existing JMS Connection to obtain a Session for
+ * (may be null)
+ * @param synchedLocalTransactionAllowed whether to allow for a local JMS transaction
+ * that is synchronized with a Spring-managed transaction (where the main transaction
+ * might be a JDBC-based one for a specific DataSource, for example), with the JMS
+ * transaction committing right after the main transaction. If not allowed, the given
+ * ConnectionFactory needs to handle transaction enlistment underneath the covers.
+ * @return the transactional Session, or null if none found
+ * @throws JMSException in case of JMS failure
+ */
+ public static Session getTransactionalSession(
+ final ConnectionFactory cf, final Connection existingCon, final boolean synchedLocalTransactionAllowed)
+ throws JMSException {
+
+ return doGetTransactionalSession(cf, new ResourceFactory() {
+ public Session getSession(JmsResourceHolder holder) {
+ return holder.getSession(Session.class, existingCon);
+ }
+ public Connection getConnection(JmsResourceHolder holder) {
+ return (existingCon != null ? existingCon : holder.getConnection());
+ }
+ public Connection createConnection() throws JMSException {
+ return cf.createConnection();
+ }
+ public Session createSession(Connection con) throws JMSException {
+ return con.createSession(synchedLocalTransactionAllowed, Session.AUTO_ACKNOWLEDGE);
+ }
+ public boolean isSynchedLocalTransactionAllowed() {
+ return synchedLocalTransactionAllowed;
+ }
+ }, true);
+ }
+
+ /**
+ * Obtain a JMS QueueSession that is synchronized with the current transaction, if any.
+ *
Mainly intended for use with the JMS 1.0.2 API.
+ * @param cf the ConnectionFactory to obtain a Session for
+ * @param existingCon the existing JMS Connection to obtain a Session for
+ * (may be null)
+ * @param synchedLocalTransactionAllowed whether to allow for a local JMS transaction
+ * that is synchronized with a Spring-managed transaction (where the main transaction
+ * might be a JDBC-based one for a specific DataSource, for example), with the JMS
+ * transaction committing right after the main transaction. If not allowed, the given
+ * ConnectionFactory needs to handle transaction enlistment underneath the covers.
+ * @return the transactional Session, or null if none found
+ * @throws JMSException in case of JMS failure
+ */
+ public static QueueSession getTransactionalQueueSession(
+ final QueueConnectionFactory cf, final QueueConnection existingCon, final boolean synchedLocalTransactionAllowed)
+ throws JMSException {
+
+ return (QueueSession) doGetTransactionalSession(cf, new ResourceFactory() {
+ public Session getSession(JmsResourceHolder holder) {
+ return holder.getSession(QueueSession.class, existingCon);
+ }
+ public Connection getConnection(JmsResourceHolder holder) {
+ return (existingCon != null ? existingCon : holder.getConnection(QueueConnection.class));
+ }
+ public Connection createConnection() throws JMSException {
+ return cf.createQueueConnection();
+ }
+ public Session createSession(Connection con) throws JMSException {
+ return ((QueueConnection) con).createQueueSession(synchedLocalTransactionAllowed, Session.AUTO_ACKNOWLEDGE);
+ }
+ public boolean isSynchedLocalTransactionAllowed() {
+ return synchedLocalTransactionAllowed;
+ }
+ }, true);
+ }
+
+ /**
+ * Obtain a JMS TopicSession that is synchronized with the current transaction, if any.
+ *
Mainly intended for use with the JMS 1.0.2 API.
+ * @param cf the ConnectionFactory to obtain a Session for
+ * @param existingCon the existing JMS Connection to obtain a Session for
+ * (may be null)
+ * @param synchedLocalTransactionAllowed whether to allow for a local JMS transaction
+ * that is synchronized with a Spring-managed transaction (where the main transaction
+ * might be a JDBC-based one for a specific DataSource, for example), with the JMS
+ * transaction committing right after the main transaction. If not allowed, the given
+ * ConnectionFactory needs to handle transaction enlistment underneath the covers.
+ * @return the transactional Session, or null if none found
+ * @throws JMSException in case of JMS failure
+ */
+ public static TopicSession getTransactionalTopicSession(
+ final TopicConnectionFactory cf, final TopicConnection existingCon, final boolean synchedLocalTransactionAllowed)
+ throws JMSException {
+
+ return (TopicSession) doGetTransactionalSession(cf, new ResourceFactory() {
+ public Session getSession(JmsResourceHolder holder) {
+ return holder.getSession(TopicSession.class, existingCon);
+ }
+ public Connection getConnection(JmsResourceHolder holder) {
+ return (existingCon != null ? existingCon : holder.getConnection(TopicConnection.class));
+ }
+ public Connection createConnection() throws JMSException {
+ return cf.createTopicConnection();
+ }
+ public Session createSession(Connection con) throws JMSException {
+ return ((TopicConnection) con).createTopicSession(synchedLocalTransactionAllowed, Session.AUTO_ACKNOWLEDGE);
+ }
+ public boolean isSynchedLocalTransactionAllowed() {
+ return synchedLocalTransactionAllowed;
+ }
+ }, true);
+ }
+
+ /**
+ * Obtain a JMS Session that is synchronized with the current transaction, if any.
+ *
This doGetTransactionalSession variant always starts the underlying
+ * JMS Connection, assuming that the Session will be used for receiving messages.
+ * @param connectionFactory the JMS ConnectionFactory to bind for
+ * (used as TransactionSynchronizationManager key)
+ * @param resourceFactory the ResourceFactory to use for extracting or creating
+ * JMS resources
+ * @return the transactional Session, or null if none found
+ * @throws JMSException in case of JMS failure
+ * @see #doGetTransactionalSession(javax.jms.ConnectionFactory, ResourceFactory, boolean)
+ */
+ public static Session doGetTransactionalSession(
+ ConnectionFactory connectionFactory, ResourceFactory resourceFactory) throws JMSException {
+
+ return doGetTransactionalSession(connectionFactory, resourceFactory, true);
+ }
+
+ /**
+ * Obtain a JMS Session that is synchronized with the current transaction, if any.
+ * @param connectionFactory the JMS ConnectionFactory to bind for
+ * (used as TransactionSynchronizationManager key)
+ * @param resourceFactory the ResourceFactory to use for extracting or creating
+ * JMS resources
+ * @param startConnection whether the underlying JMS Connection approach should be
+ * started in order to allow for receiving messages. Note that a reused Connection
+ * may already have been started before, even if this flag is false.
+ * @return the transactional Session, or null if none found
+ * @throws JMSException in case of JMS failure
+ */
+ public static Session doGetTransactionalSession(
+ ConnectionFactory connectionFactory, ResourceFactory resourceFactory, boolean startConnection)
+ throws JMSException {
+
+ Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
+ Assert.notNull(resourceFactory, "ResourceFactory must not be null");
+
+ JmsResourceHolder resourceHolder =
+ (JmsResourceHolder) TransactionSynchronizationManager.getResource(connectionFactory);
+ if (resourceHolder != null) {
+ Session session = resourceFactory.getSession(resourceHolder);
+ if (session != null) {
+ if (startConnection) {
+ Connection con = resourceFactory.getConnection(resourceHolder);
+ if (con != null) {
+ con.start();
+ }
+ }
+ return session;
+ }
+ if (resourceHolder.isFrozen()) {
+ return null;
+ }
+ }
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ return null;
+ }
+ JmsResourceHolder resourceHolderToUse = resourceHolder;
+ if (resourceHolderToUse == null) {
+ resourceHolderToUse = new JmsResourceHolder(connectionFactory);
+ }
+ Connection con = resourceFactory.getConnection(resourceHolderToUse);
+ Session session = null;
+ try {
+ boolean isExistingCon = (con != null);
+ if (!isExistingCon) {
+ con = resourceFactory.createConnection();
+ resourceHolderToUse.addConnection(con);
+ }
+ session = resourceFactory.createSession(con);
+ resourceHolderToUse.addSession(session, con);
+ if (startConnection) {
+ con.start();
+ }
+ }
+ catch (JMSException ex) {
+ if (session != null) {
+ try {
+ session.close();
+ }
+ catch (Throwable ex2) {
+ // ignore
+ }
+ }
+ if (con != null) {
+ try {
+ con.close();
+ }
+ catch (Throwable ex2) {
+ // ignore
+ }
+ }
+ throw ex;
+ }
+ if (resourceHolderToUse != resourceHolder) {
+ TransactionSynchronizationManager.registerSynchronization(
+ new JmsResourceSynchronization(
+ resourceHolderToUse, connectionFactory, resourceFactory.isSynchedLocalTransactionAllowed()));
+ resourceHolderToUse.setSynchronizedWithTransaction(true);
+ TransactionSynchronizationManager.bindResource(connectionFactory, resourceHolderToUse);
+ }
+ return session;
+ }
+
+
+ /**
+ * Callback interface for resource creation.
+ * Serving as argument for the doGetTransactionalSession method.
+ */
+ public interface ResourceFactory {
+
+ /**
+ * Fetch an appropriate Session from the given JmsResourceHolder.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Session fetched from the holder,
+ * or null if none found
+ */
+ Session getSession(JmsResourceHolder holder);
+
+ /**
+ * Fetch an appropriate Connection from the given JmsResourceHolder.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Connection fetched from the holder,
+ * or null if none found
+ */
+ Connection getConnection(JmsResourceHolder holder);
+
+ /**
+ * Create a new JMS Connection for registration with a JmsResourceHolder.
+ * @return the new JMS Connection
+ * @throws JMSException if thrown by JMS API methods
+ */
+ Connection createConnection() throws JMSException;
+
+ /**
+ * Create a new JMS Session for registration with a JmsResourceHolder.
+ * @param con the JMS Connection to create a Session for
+ * @return the new JMS Session
+ * @throws JMSException if thrown by JMS API methods
+ */
+ Session createSession(Connection con) throws JMSException;
+
+ /**
+ * Return whether to allow for a local JMS transaction that is synchronized with
+ * a Spring-managed transaction (where the main transaction might be a JDBC-based
+ * one for a specific DataSource, for example), with the JMS transaction
+ * committing right after the main transaction.
+ * @return whether to allow for synchronizing a local JMS transaction
+ */
+ boolean isSynchedLocalTransactionAllowed();
+ }
+
+
+ /**
+ * Callback for resource cleanup at the end of a non-native JMS transaction
+ * (e.g. when participating in a JtaTransactionManager transaction).
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+ private static class JmsResourceSynchronization extends ResourceHolderSynchronization {
+
+ private final boolean transacted;
+
+ public JmsResourceSynchronization(JmsResourceHolder resourceHolder, Object resourceKey, boolean transacted) {
+ super(resourceHolder, resourceKey);
+ this.transacted = transacted;
+ }
+
+ protected boolean shouldReleaseBeforeCompletion() {
+ return !this.transacted;
+ }
+
+ protected void processResourceAfterCommit(ResourceHolder resourceHolder) {
+ try {
+ ((JmsResourceHolder) resourceHolder).commitAll();
+ }
+ catch (JMSException ex) {
+ throw new SynchedLocalTransactionFailedException("Local JMS transaction failed to commit", ex);
+ }
+ }
+
+ protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
+ ((JmsResourceHolder) resourceHolder).closeAll();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/DelegatingConnectionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/DelegatingConnectionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/DelegatingConnectionFactory.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2002-2007 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+/**
+ * {@link javax.jms.ConnectionFactory} implementation that delegates all calls
+ * to a given target {@link javax.jms.ConnectionFactory}, adapting specific
+ * create(Queue/Topic)Connection calls to the target ConnectionFactory
+ * if necessary (e.g. when running JMS 1.0.2 API based code against a generic
+ * JMS 1.1 ConnectionFactory, such as ActiveMQ's PooledConnectionFactory).
+ *
+ *
This class allows for being subclassed, with subclasses overriding only
+ * those methods (such as {@link #createConnection()}) that should not simply
+ * delegate to the target ConnectionFactory.
+ *
+ *
Can also be defined as-is, wrapping a specific target ConnectionFactory,
+ * using the "shouldStopConnections" flag to indicate whether Connections
+ * obtained from the target factory are supposed to be stopped before closed.
+ * The latter may be necessary for some connection pools that simply return
+ * released connections to the pool, not stopping them while they sit in the pool.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.2
+ * @see #createConnection()
+ * @see #setShouldStopConnections
+ * @see ConnectionFactoryUtils#releaseConnection
+ */
+public class DelegatingConnectionFactory
+ implements SmartConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, InitializingBean {
+
+ private ConnectionFactory targetConnectionFactory;
+
+ private boolean shouldStopConnections = false;
+
+
+ /**
+ * Set the target ConnectionFactory that this ConnectionFactory should delegate to.
+ */
+ public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ Assert.notNull(targetConnectionFactory, "'targetConnectionFactory' must not be null");
+ this.targetConnectionFactory = targetConnectionFactory;
+ }
+
+ /**
+ * Return the target ConnectionFactory that this ConnectionFactory delegates to.
+ */
+ public ConnectionFactory getTargetConnectionFactory() {
+ return this.targetConnectionFactory;
+ }
+
+ /**
+ * Indicate whether Connections obtained from the target factory are supposed
+ * to be stopped before closed ("true") or simply closed ("false").
+ * The latter may be necessary for some connection pools that simply return
+ * released connections to the pool, not stopping them while they sit in the pool.
+ *
Default is "false", simply closing Connections.
+ * @see ConnectionFactoryUtils#releaseConnection
+ */
+ public void setShouldStopConnections(boolean shouldStopConnections) {
+ this.shouldStopConnections = shouldStopConnections;
+ }
+
+ public void afterPropertiesSet() {
+ if (getTargetConnectionFactory() == null) {
+ throw new IllegalArgumentException("'targetConnectionFactory' is required");
+ }
+ }
+
+
+ public Connection createConnection() throws JMSException {
+ return getTargetConnectionFactory().createConnection();
+ }
+
+ public Connection createConnection(String username, String password) throws JMSException {
+ return getTargetConnectionFactory().createConnection(username, password);
+ }
+
+ public QueueConnection createQueueConnection() throws JMSException {
+ ConnectionFactory cf = getTargetConnectionFactory();
+ if (cf instanceof QueueConnectionFactory) {
+ return ((QueueConnectionFactory) cf).createQueueConnection();
+ }
+ else {
+ Connection con = cf.createConnection();
+ if (!(con instanceof QueueConnection)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory");
+ }
+ return (QueueConnection) con;
+ }
+ }
+
+ public QueueConnection createQueueConnection(String username, String password) throws JMSException {
+ ConnectionFactory cf = getTargetConnectionFactory();
+ if (cf instanceof QueueConnectionFactory) {
+ return ((QueueConnectionFactory) cf).createQueueConnection(username, password);
+ }
+ else {
+ Connection con = cf.createConnection(username, password);
+ if (!(con instanceof QueueConnection)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory");
+ }
+ return (QueueConnection) con;
+ }
+ }
+
+ public TopicConnection createTopicConnection() throws JMSException {
+ ConnectionFactory cf = getTargetConnectionFactory();
+ if (cf instanceof TopicConnectionFactory) {
+ return ((TopicConnectionFactory) cf).createTopicConnection();
+ }
+ else {
+ Connection con = cf.createConnection();
+ if (!(con instanceof TopicConnection)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory");
+ }
+ return (TopicConnection) con;
+ }
+ }
+
+ public TopicConnection createTopicConnection(String username, String password) throws JMSException {
+ ConnectionFactory cf = getTargetConnectionFactory();
+ if (cf instanceof TopicConnectionFactory) {
+ return ((TopicConnectionFactory) cf).createTopicConnection(username, password);
+ }
+ else {
+ Connection con = cf.createConnection(username, password);
+ if (!(con instanceof TopicConnection)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory");
+ }
+ return (TopicConnection) con;
+ }
+ }
+
+ public boolean shouldStop(Connection con) {
+ return this.shouldStopConnections;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/JmsResourceHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/JmsResourceHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/JmsResourceHolder.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.jms.TransactionInProgressException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.transaction.support.ResourceHolderSupport;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * JMS resource holder, wrapping a JMS Connection and a JMS Session.
+ * JmsTransactionManager binds instances of this class to the thread,
+ * for a given JMS ConnectionFactory.
+ *
+ *
Note: This is an SPI class, not intended to be used by applications.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see JmsTransactionManager
+ * @see org.springframework.jms.core.JmsTemplate
+ */
+public class JmsResourceHolder extends ResourceHolderSupport {
+
+ private static final Log logger = LogFactory.getLog(JmsResourceHolder.class);
+
+ private ConnectionFactory connectionFactory;
+
+ private boolean frozen = false;
+
+ private final List connections = new LinkedList();
+
+ private final List sessions = new LinkedList();
+
+ private final Map sessionsPerConnection = new HashMap();
+
+
+ /**
+ * Create a new JmsResourceHolder that is open for resources to be added.
+ * @see #addConnection
+ * @see #addSession
+ */
+ public JmsResourceHolder() {
+ }
+
+ /**
+ * Create a new JmsResourceHolder that is open for resources to be added.
+ * @param connectionFactory the JMS ConnectionFactory that this
+ * resource holder is associated with (may be null)
+ */
+ public JmsResourceHolder(ConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ }
+
+ /**
+ * Create a new JmsResourceHolder for the given JMS Session.
+ * @param session the JMS Session
+ */
+ public JmsResourceHolder(Session session) {
+ addSession(session);
+ this.frozen = true;
+ }
+
+ /**
+ * Create a new JmsResourceHolder for the given JMS resources.
+ * @param connection the JMS Connection
+ * @param session the JMS Session
+ */
+ public JmsResourceHolder(Connection connection, Session session) {
+ addConnection(connection);
+ addSession(session, connection);
+ this.frozen = true;
+ }
+
+ /**
+ * Create a new JmsResourceHolder for the given JMS resources.
+ * @param connectionFactory the JMS ConnectionFactory that this
+ * resource holder is associated with (may be null)
+ * @param connection the JMS Connection
+ * @param session the JMS Session
+ */
+ public JmsResourceHolder(ConnectionFactory connectionFactory, Connection connection, Session session) {
+ this.connectionFactory = connectionFactory;
+ addConnection(connection);
+ addSession(session, connection);
+ this.frozen = true;
+ }
+
+
+ public final boolean isFrozen() {
+ return this.frozen;
+ }
+
+ public final void addConnection(Connection connection) {
+ Assert.isTrue(!this.frozen, "Cannot add Connection because JmsResourceHolder is frozen");
+ Assert.notNull(connection, "Connection must not be null");
+ if (!this.connections.contains(connection)) {
+ this.connections.add(connection);
+ }
+ }
+
+ public final void addSession(Session session) {
+ addSession(session, null);
+ }
+
+ public final void addSession(Session session, Connection connection) {
+ Assert.isTrue(!this.frozen, "Cannot add Session because JmsResourceHolder is frozen");
+ Assert.notNull(session, "Session must not be null");
+ if (!this.sessions.contains(session)) {
+ this.sessions.add(session);
+ if (connection != null) {
+ List sessions = (List) this.sessionsPerConnection.get(connection);
+ if (sessions == null) {
+ sessions = new LinkedList();
+ this.sessionsPerConnection.put(connection, sessions);
+ }
+ sessions.add(session);
+ }
+ }
+ }
+
+ public boolean containsSession(Session session) {
+ return this.sessions.contains(session);
+ }
+
+
+ public Connection getConnection() {
+ return (!this.connections.isEmpty() ? (Connection) this.connections.get(0) : null);
+ }
+
+ public Connection getConnection(Class connectionType) {
+ return (Connection) CollectionUtils.findValueOfType(this.connections, connectionType);
+ }
+
+ public Session getSession() {
+ return (!this.sessions.isEmpty() ? (Session) this.sessions.get(0) : null);
+ }
+
+ public Session getSession(Class sessionType) {
+ return getSession(sessionType, null);
+ }
+
+ public Session getSession(Class sessionType, Connection connection) {
+ List sessions = this.sessions;
+ if (connection != null) {
+ sessions = (List) this.sessionsPerConnection.get(connection);
+ }
+ return (Session) CollectionUtils.findValueOfType(sessions, sessionType);
+ }
+
+
+ public void commitAll() throws JMSException {
+ for (Iterator it = this.sessions.iterator(); it.hasNext();) {
+ try {
+ ((Session) it.next()).commit();
+ }
+ catch (TransactionInProgressException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ }
+ }
+
+ public void closeAll() {
+ for (Iterator it = this.sessions.iterator(); it.hasNext();) {
+ try {
+ ((Session) it.next()).close();
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not close synchronized JMS Session after transaction", ex);
+ }
+ }
+ for (Iterator it = this.connections.iterator(); it.hasNext();) {
+ Connection con = (Connection) it.next();
+ ConnectionFactoryUtils.releaseConnection(con, this.connectionFactory, true);
+ }
+ this.connections.clear();
+ this.sessions.clear();
+ this.sessionsPerConnection.clear();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.jms.TransactionRolledBackException;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.transaction.CannotCreateTransactionException;
+import org.springframework.transaction.InvalidIsolationLevelException;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionSystemException;
+import org.springframework.transaction.UnexpectedRollbackException;
+import org.springframework.transaction.support.AbstractPlatformTransactionManager;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+import org.springframework.transaction.support.ResourceTransactionManager;
+import org.springframework.transaction.support.SmartTransactionObject;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * {@link org.springframework.transaction.PlatformTransactionManager} implementation
+ * for a single JMS {@link javax.jms.ConnectionFactory}. Binds a JMS
+ * Connection/Session pair from the specified ConnectionFactory to the thread,
+ * potentially allowing for one thread-bound Session per ConnectionFactory.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider because it builds on
+ * the domain-independent API. Use the {@link JmsTransactionManager102} subclass
+ * for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.
+ *
+ *
This local strategy is an alternative to executing JMS operations within
+ * JTA transactions. Its advantage is that it is able to work in any environment,
+ * for example a standalone application or a test suite, with any message broker
+ * as target. However, this strategy is not able to provide XA transactions,
+ * for example in order to share transactions between messaging and database access.
+ * A full JTA/XA setup is required for XA transactions, typically using Spring's
+ * {@link org.springframework.transaction.jta.JtaTransactionManager} as strategy.
+ *
+ *
Application code is required to retrieve the transactional JMS Session via
+ * {@link ConnectionFactoryUtils#getTransactionalSession} instead of a standard
+ * J2EE-style {@link ConnectionFactory#createConnection()} call with subsequent
+ * Session creation. Spring's {@link org.springframework.jms.core.JmsTemplate}
+ * will autodetect a thread-bound Session and automatically participate in it.
+ *
+ *
Alternatively, you can allow application code to work with the standard
+ * J2EE-style lookup pattern on a ConnectionFactory, for example for legacy code
+ * that is not aware of Spring at all. In that case, define a
+ * {@link TransactionAwareConnectionFactoryProxy} for your target ConnectionFactory,
+ * which will automatically participate in Spring-managed transactions.
+ *
+ *
The use of {@link CachingConnectionFactory} as a target for this
+ * transaction manager is strongly recommended. CachingConnectionFactory
+ * uses a single JMS Connection for all JMS access in order to avoid the overhead
+ * of repeated Connection creation, as well as maintaining a cache of Sessions.
+ * Each transaction will then share the same JMS Connection, while still using
+ * its own individual JMS Session.
+ *
+ *
The use of a raw target ConnectionFactory would not only be inefficient
+ * because of the lack of resource reuse. It might also lead to strange effects
+ * when your JMS driver doesn't accept MessageProducer.close() calls
+ * and/or MessageConsumer.close() calls before Session.commit(),
+ * with the latter supposed to commit all the messages that have been sent through the
+ * producer handle and received through the consumer handle. As a safe general solution,
+ * always pass in a {@link CachingConnectionFactory} into this transaction manager's
+ * {@link #setConnectionFactory "connectionFactory"} property.
+ *
+ *
Transaction synchronization is turned off by default, as this manager might
+ * be used alongside a datastore-based Spring transaction manager such as the
+ * JDBC {@link org.springframework.jdbc.datasource.DataSourceTransactionManager},
+ * which has stronger needs for synchronization.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see ConnectionFactoryUtils#getTransactionalSession
+ * @see TransactionAwareConnectionFactoryProxy
+ * @see org.springframework.jms.core.JmsTemplate
+ */
+public class JmsTransactionManager extends AbstractPlatformTransactionManager
+ implements ResourceTransactionManager, InitializingBean {
+
+ private ConnectionFactory connectionFactory;
+
+
+ /**
+ * Create a new JmsTransactionManager for bean-style usage.
+ *
Note: The ConnectionFactory has to be set before using the instance.
+ * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
+ * typically setting the ConnectionFactory via setConnectionFactory.
+ *
Turns off transaction synchronization by default, as this manager might
+ * be used alongside a datastore-based Spring transaction manager like
+ * DataSourceTransactionManager, which has stronger needs for synchronization.
+ * Only one manager is allowed to drive synchronization at any point of time.
+ * @see #setConnectionFactory
+ * @see #setTransactionSynchronization
+ */
+ public JmsTransactionManager() {
+ setTransactionSynchronization(SYNCHRONIZATION_NEVER);
+ }
+
+ /**
+ * Create a new JmsTransactionManager, given a ConnectionFactory.
+ * @param connectionFactory the ConnectionFactory to obtain connections from
+ */
+ public JmsTransactionManager(ConnectionFactory connectionFactory) {
+ this();
+ setConnectionFactory(connectionFactory);
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set the JMS ConnectionFactory that this instance should manage transactions for.
+ */
+ public void setConnectionFactory(ConnectionFactory cf) {
+ if (cf instanceof TransactionAwareConnectionFactoryProxy) {
+ // If we got a TransactionAwareConnectionFactoryProxy, we need to perform transactions
+ // for its underlying target ConnectionFactory, else JMS access code won't see
+ // properly exposed transactions (i.e. transactions for the target ConnectionFactory).
+ this.connectionFactory = ((TransactionAwareConnectionFactoryProxy) cf).getTargetConnectionFactory();
+ }
+ else {
+ this.connectionFactory = cf;
+ }
+ }
+
+ /**
+ * Return the JMS ConnectionFactory that this instance should manage transactions for.
+ */
+ public ConnectionFactory getConnectionFactory() {
+ return this.connectionFactory;
+ }
+
+ /**
+ * Make sure the ConnectionFactory has been set.
+ */
+ public void afterPropertiesSet() {
+ if (getConnectionFactory() == null) {
+ throw new IllegalArgumentException("Property 'connectionFactory' is required");
+ }
+ }
+
+
+ public Object getResourceFactory() {
+ return getConnectionFactory();
+ }
+
+ protected Object doGetTransaction() {
+ JmsTransactionObject txObject = new JmsTransactionObject();
+ txObject.setResourceHolder(
+ (JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory()));
+ return txObject;
+ }
+
+ protected boolean isExistingTransaction(Object transaction) {
+ JmsTransactionObject txObject = (JmsTransactionObject) transaction;
+ return (txObject.getResourceHolder() != null);
+ }
+
+ protected void doBegin(Object transaction, TransactionDefinition definition) {
+ if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
+ throw new InvalidIsolationLevelException("JMS does not support an isolation level concept");
+ }
+ JmsTransactionObject txObject = (JmsTransactionObject) transaction;
+ Connection con = null;
+ Session session = null;
+ try {
+ con = createConnection();
+ session = createSession(con);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Created JMS transaction on Session [" + session + "] from Connection [" + con + "]");
+ }
+ txObject.setResourceHolder(new JmsResourceHolder(getConnectionFactory(), con, session));
+ txObject.getResourceHolder().setSynchronizedWithTransaction(true);
+ int timeout = determineTimeout(definition);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ txObject.getResourceHolder().setTimeoutInSeconds(timeout);
+ }
+ TransactionSynchronizationManager.bindResource(
+ getConnectionFactory(), txObject.getResourceHolder());
+ }
+ catch (JMSException ex) {
+ if (session != null) {
+ try {
+ session.close();
+ }
+ catch (Throwable ex2) {
+ // ignore
+ }
+ }
+ if (con != null) {
+ try {
+ con.close();
+ }
+ catch (Throwable ex2) {
+ // ignore
+ }
+ }
+ throw new CannotCreateTransactionException("Could not create JMS transaction", ex);
+ }
+ }
+
+ protected Object doSuspend(Object transaction) {
+ JmsTransactionObject txObject = (JmsTransactionObject) transaction;
+ txObject.setResourceHolder(null);
+ return TransactionSynchronizationManager.unbindResource(getConnectionFactory());
+ }
+
+ protected void doResume(Object transaction, Object suspendedResources) {
+ JmsResourceHolder conHolder = (JmsResourceHolder) suspendedResources;
+ TransactionSynchronizationManager.bindResource(getConnectionFactory(), conHolder);
+ }
+
+ protected void doCommit(DefaultTransactionStatus status) {
+ JmsTransactionObject txObject = (JmsTransactionObject) status.getTransaction();
+ Session session = txObject.getResourceHolder().getSession();
+ try {
+ if (status.isDebug()) {
+ logger.debug("Committing JMS transaction on Session [" + session + "]");
+ }
+ session.commit();
+ }
+ catch (TransactionRolledBackException ex) {
+ throw new UnexpectedRollbackException("JMS transaction rolled back", ex);
+ }
+ catch (JMSException ex) {
+ throw new TransactionSystemException("Could not commit JMS transaction", ex);
+ }
+ }
+
+ protected void doRollback(DefaultTransactionStatus status) {
+ JmsTransactionObject txObject = (JmsTransactionObject) status.getTransaction();
+ Session session = txObject.getResourceHolder().getSession();
+ try {
+ if (status.isDebug()) {
+ logger.debug("Rolling back JMS transaction on Session [" + session + "]");
+ }
+ session.rollback();
+ }
+ catch (JMSException ex) {
+ throw new TransactionSystemException("Could not roll back JMS transaction", ex);
+ }
+ }
+
+ protected void doSetRollbackOnly(DefaultTransactionStatus status) {
+ JmsTransactionObject txObject = (JmsTransactionObject) status.getTransaction();
+ txObject.getResourceHolder().setRollbackOnly();
+ }
+
+ protected void doCleanupAfterCompletion(Object transaction) {
+ JmsTransactionObject txObject = (JmsTransactionObject) transaction;
+ TransactionSynchronizationManager.unbindResource(getConnectionFactory());
+ txObject.getResourceHolder().closeAll();
+ txObject.getResourceHolder().clear();
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Create a JMS Connection via this template's ConnectionFactory.
+ *
This implementation uses JMS 1.1 API.
+ * @return the new JMS Connection
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ protected Connection createConnection() throws JMSException {
+ return getConnectionFactory().createConnection();
+ }
+
+ /**
+ * Create a JMS Session for the given Connection.
+ *
This implementation uses JMS 1.1 API.
+ * @param con the JMS Connection to create a Session for
+ * @return the new JMS Session
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ return con.createSession(true, Session.AUTO_ACKNOWLEDGE);
+ }
+
+
+ /**
+ * JMS transaction object, representing a JmsResourceHolder.
+ * Used as transaction object by JmsTransactionManager.
+ * @see JmsResourceHolder
+ */
+ private static class JmsTransactionObject implements SmartTransactionObject {
+
+ private JmsResourceHolder resourceHolder;
+
+ public void setResourceHolder(JmsResourceHolder resourceHolder) {
+ this.resourceHolder = resourceHolder;
+ }
+
+ public JmsResourceHolder getResourceHolder() {
+ return this.resourceHolder;
+ }
+
+ public boolean isRollbackOnly() {
+ return this.resourceHolder.isRollbackOnly();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/JmsTransactionManager102.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2002-2007 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.Session;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+/**
+ * A subclass of {@link JmsTransactionManager} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like JmsTransactionManager itself.
+ * This class can be used for JMS 1.0.2 providers, offering the same API as
+ * JmsTransactionManager does for JMS 1.1 providers.
+ *
+ *
You need to set the {@link #setPubSubDomain "pubSubDomain" property},
+ * since this class will always explicitly differentiate between a
+ * {@link javax.jms.QueueConnection} and a {@link javax.jms.TopicConnection}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setConnectionFactory
+ * @see #setPubSubDomain
+ */
+public class JmsTransactionManager102 extends JmsTransactionManager {
+
+ private boolean pubSubDomain = false;
+
+
+ /**
+ * Create a new JmsTransactionManager102 for bean-style usage.
+ *
Note: The ConnectionFactory has to be set before using the instance.
+ * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
+ * typically setting the ConnectionFactory via setConnectionFactory.
+ * @see #setConnectionFactory
+ */
+ public JmsTransactionManager102() {
+ super();
+ }
+
+ /**
+ * Create a new JmsTransactionManager102, given a ConnectionFactory.
+ * @param connectionFactory the ConnectionFactory to manage transactions for
+ * @param pubSubDomain whether the Publish/Subscribe domain (Topics) or
+ * Point-to-Point domain (Queues) should be used
+ * @see #setPubSubDomain
+ */
+ public JmsTransactionManager102(ConnectionFactory connectionFactory, boolean pubSubDomain) {
+ setConnectionFactory(connectionFactory);
+ this.pubSubDomain = pubSubDomain;
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Configure the transaction manager with knowledge of the JMS domain used.
+ * This tells the JMS 1.0.2 provider which class hierarchy to use for creating
+ * Connections and Sessions.
+ *
Default is Point-to-Point (Queues).
+ * @param pubSubDomain true for Publish/Subscribe domain (Topics),
+ * false for Point-to-Point domain (Queues)
+ */
+ public void setPubSubDomain(boolean pubSubDomain) {
+ this.pubSubDomain = pubSubDomain;
+ }
+
+ /**
+ * Return whether the Publish/Subscribe domain (Topics) is used.
+ * Otherwise, the Point-to-Point domain (Queues) is used.
+ */
+ public boolean isPubSubDomain() {
+ return this.pubSubDomain;
+ }
+
+
+ /**
+ * In addition to checking if the connection factory is set, make sure
+ * that the supplied connection factory is of the appropriate type for
+ * the specified destination type: QueueConnectionFactory for queues,
+ * and TopicConnectionFactory for topics.
+ */
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+
+ // Make sure that the ConnectionFactory passed is consistent.
+ // Some provider implementations of the ConnectionFactory interface
+ // implement both domain interfaces under the cover, so just check if
+ // the selected domain is consistent with the type of connection factory.
+ if (isPubSubDomain()) {
+ if (!(getConnectionFactory() instanceof TopicConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 transaction manager for topics " +
+ "but did not supply an instance of TopicConnectionFactory");
+ }
+ }
+ else {
+ if (!(getConnectionFactory() instanceof QueueConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 transaction manager for queues " +
+ "but did not supply an instance of QueueConnectionFactory");
+ }
+ }
+ }
+
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection createConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnection) con).createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
+ }
+ else {
+ return ((QueueConnection) con).createQueueSession(true, Session.AUTO_ACKNOWLEDGE);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/SessionProxy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/SessionProxy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/SessionProxy.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.Session;
+
+/**
+ * Subinterface of {@link javax.jms.Session} to be implemented by
+ * Session proxies. Allows access to the the underlying target Session.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.4
+ * @see TransactionAwareConnectionFactoryProxy
+ * @see CachingConnectionFactory
+ * @see ConnectionFactoryUtils#getTargetSession(javax.jms.Session)
+ */
+public interface SessionProxy extends Session {
+
+ /**
+ * Return the target Session of this proxy.
+ *
This will typically be the native provider Session
+ * or a wrapper from a session pool.
+ * @return the underlying Session (never null)
+ */
+ Session getTargetSession();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,587 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.Session;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+/**
+ * A JMS ConnectionFactory adapter that returns the same Connection
+ * from all {@link #createConnection()} calls, and ignores calls to
+ * {@link javax.jms.Connection#close()}. According to the JMS Connection
+ * model, this is perfectly thread-safe (in contrast to e.g. JDBC). The
+ * shared Connection can be automatically recovered in case of an Exception.
+ *
+ *
You can either pass in a specific JMS Connection directly or let this
+ * factory lazily create a Connection via a given target ConnectionFactory.
+ * This factory generally works with JMS 1.1 as well as JMS 1.0.2; use
+ * {@link SingleConnectionFactory102} for strict JMS 1.0.2 only usage.
+ *
+ *
Note that when using the JMS 1.0.2 API, this ConnectionFactory will switch
+ * into queue/topic mode according to the JMS API methods used at runtime:
+ * createQueueConnection and createTopicConnection will
+ * lead to queue/topic mode, respectively; generic createConnection
+ * calls will lead to a JMS 1.1 connection which is able to serve both modes.
+ *
+ *
Useful for testing and standalone environments in order to keep using the
+ * same Connection for multiple {@link org.springframework.jms.core.JmsTemplate}
+ * calls, without having a pooling ConnectionFactory underneath. This may span
+ * any number of transactions, even concurrently executing transactions.
+ *
+ *
Note that Spring's message listener containers support the use of
+ * a shared Connection within each listener container instance. Using
+ * SingleConnectionFactory in combination only really makes sense for
+ * sharing a single JMS Connection across multiple listener containers.
+ *
+ * @author Juergen Hoeller
+ * @author Mark Pollack
+ * @since 1.1
+ * @see org.springframework.jms.core.JmsTemplate
+ * @see org.springframework.jms.listener.SimpleMessageListenerContainer
+ * @see org.springframework.jms.listener.DefaultMessageListenerContainer#setCacheLevel
+ */
+public class SingleConnectionFactory
+ implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, ExceptionListener,
+ InitializingBean, DisposableBean {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private ConnectionFactory targetConnectionFactory;
+
+ private String clientId;
+
+ private ExceptionListener exceptionListener;
+
+ private boolean reconnectOnException = false;
+
+ /** Wrapped Connection */
+ private Connection target;
+
+ /** Proxy Connection */
+ private Connection connection;
+
+ /** A hint whether to create a queue or topic connection */
+ private Boolean pubSubMode;
+
+ /** Whether the shared Connection has been started */
+ private boolean started = false;
+
+ /** Synchronization monitor for the shared Connection */
+ private final Object connectionMonitor = new Object();
+
+
+ /**
+ * Create a new SingleConnectionFactory for bean-style usage.
+ * @see #setTargetConnectionFactory
+ */
+ public SingleConnectionFactory() {
+ }
+
+ /**
+ * Create a new SingleConnectionFactory that always returns the given Connection.
+ * @param target the single Connection
+ */
+ public SingleConnectionFactory(Connection target) {
+ Assert.notNull(target, "Target Connection must not be null");
+ this.target = target;
+ this.connection = getSharedConnectionProxy(target);
+ }
+
+ /**
+ * Create a new SingleConnectionFactory that always returns a single
+ * Connection that it will lazily create via the given target
+ * ConnectionFactory.
+ * @param targetConnectionFactory the target ConnectionFactory
+ */
+ public SingleConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ Assert.notNull(targetConnectionFactory, "Target ConnectionFactory must not be null");
+ this.targetConnectionFactory = targetConnectionFactory;
+ }
+
+
+ /**
+ * Set the target ConnectionFactory which will be used to lazily
+ * create a single Connection.
+ */
+ public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ this.targetConnectionFactory = targetConnectionFactory;
+ }
+
+ /**
+ * Return the target ConnectionFactory which will be used to lazily
+ * create a single Connection, if any.
+ */
+ public ConnectionFactory getTargetConnectionFactory() {
+ return this.targetConnectionFactory;
+ }
+
+ /**
+ * Specify a JMS client ID for the single Connection created and exposed
+ * by this ConnectionFactory.
+ *
Note that client IDs need to be unique among all active Connections
+ * of the underlying JMS provider. Furthermore, a client ID can only be
+ * assigned if the original ConnectionFactory hasn't already assigned one.
+ * @see javax.jms.Connection#setClientID
+ * @see #setTargetConnectionFactory
+ */
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ /**
+ * Return a JMS client ID for the single Connection created and exposed
+ * by this ConnectionFactory, if any.
+ */
+ protected String getClientId() {
+ return this.clientId;
+ }
+
+ /**
+ * Specify an JMS ExceptionListener implementation that should be
+ * registered with with the single Connection created by this factory.
+ * @see #setReconnectOnException
+ */
+ public void setExceptionListener(ExceptionListener exceptionListener) {
+ this.exceptionListener = exceptionListener;
+ }
+
+ /**
+ * Return the JMS ExceptionListener implementation that should be registered
+ * with with the single Connection created by this factory, if any.
+ */
+ protected ExceptionListener getExceptionListener() {
+ return this.exceptionListener;
+ }
+
+ /**
+ * Specify whether the single Connection should be reset (to be subsequently renewed)
+ * when a JMSException is reported by the underlying Connection.
+ *
Default is "false". Switch this to "true" to automatically trigger
+ * recovery based on your JMS provider's exception notifications.
+ *
Internally, this will lead to a special JMS ExceptionListener
+ * (this SingleConnectionFactory itself) being registered with the
+ * underlying Connection. This can also be combined with a
+ * user-specified ExceptionListener, if desired.
+ * @see #setExceptionListener
+ */
+ public void setReconnectOnException(boolean reconnectOnException) {
+ this.reconnectOnException = reconnectOnException;
+ }
+
+ /**
+ * Return whether the single Connection should be renewed when
+ * a JMSException is reported by the underlying Connection.
+ */
+ protected boolean isReconnectOnException() {
+ return this.reconnectOnException;
+ }
+
+ /**
+ * Make sure a Connection or ConnectionFactory has been set.
+ */
+ public void afterPropertiesSet() {
+ if (this.connection == null && getTargetConnectionFactory() == null) {
+ throw new IllegalArgumentException("Connection or 'targetConnectionFactory' is required");
+ }
+ }
+
+
+ public Connection createConnection() throws JMSException {
+ synchronized (this.connectionMonitor) {
+ if (this.connection == null) {
+ initConnection();
+ }
+ return this.connection;
+ }
+ }
+
+ public Connection createConnection(String username, String password) throws JMSException {
+ throw new javax.jms.IllegalStateException(
+ "SingleConnectionFactory does not support custom username and password");
+ }
+
+ public QueueConnection createQueueConnection() throws JMSException {
+ Connection con = null;
+ synchronized (this.connectionMonitor) {
+ this.pubSubMode = Boolean.FALSE;
+ con = createConnection();
+ }
+ if (!(con instanceof QueueConnection)) {
+ throw new javax.jms.IllegalStateException(
+ "This SingleConnectionFactory does not hold a QueueConnection but rather: " + con);
+ }
+ return ((QueueConnection) con);
+ }
+
+ public QueueConnection createQueueConnection(String username, String password) throws JMSException {
+ throw new javax.jms.IllegalStateException(
+ "SingleConnectionFactory does not support custom username and password");
+ }
+
+ public TopicConnection createTopicConnection() throws JMSException {
+ Connection con = null;
+ synchronized (this.connectionMonitor) {
+ this.pubSubMode = Boolean.TRUE;
+ con = createConnection();
+ }
+ if (!(con instanceof TopicConnection)) {
+ throw new javax.jms.IllegalStateException(
+ "This SingleConnectionFactory does not hold a TopicConnection but rather: " + con);
+ }
+ return ((TopicConnection) con);
+ }
+
+ public TopicConnection createTopicConnection(String username, String password) throws JMSException {
+ throw new javax.jms.IllegalStateException(
+ "SingleConnectionFactory does not support custom username and password");
+ }
+
+
+ /**
+ * Initialize the underlying shared Connection.
+ *
Closes and reinitializes the Connection if an underlying
+ * Connection is present already.
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ public void initConnection() throws JMSException {
+ if (getTargetConnectionFactory() == null) {
+ throw new IllegalStateException(
+ "'targetConnectionFactory' is required for lazily initializing a Connection");
+ }
+ synchronized (this.connectionMonitor) {
+ if (this.target != null) {
+ closeConnection(this.target);
+ }
+ this.target = doCreateConnection();
+ prepareConnection(this.target);
+ if (logger.isInfoEnabled()) {
+ logger.info("Established shared JMS Connection: " + this.target);
+ }
+ this.connection = getSharedConnectionProxy(this.target);
+ }
+ }
+
+ /**
+ * Exception listener callback that renews the underlying single Connection.
+ */
+ public void onException(JMSException ex) {
+ resetConnection();
+ }
+
+ /**
+ * Close the underlying shared connection.
+ * The provider of this ConnectionFactory needs to care for proper shutdown.
+ *
As this bean implements DisposableBean, a bean factory will
+ * automatically invoke this on destruction of its cached singletons.
+ */
+ public void destroy() {
+ resetConnection();
+ }
+
+ /**
+ * Reset the underlying shared Connection, to be reinitialized on next access.
+ */
+ public void resetConnection() {
+ synchronized (this.connectionMonitor) {
+ if (this.target != null) {
+ closeConnection(this.target);
+ }
+ this.target = null;
+ this.connection = null;
+ }
+ }
+
+ /**
+ * Create a JMS Connection via this template's ConnectionFactory.
+ * @return the new JMS Connection
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ protected Connection doCreateConnection() throws JMSException {
+ ConnectionFactory cf = getTargetConnectionFactory();
+ if (Boolean.FALSE.equals(this.pubSubMode) && cf instanceof QueueConnectionFactory) {
+ return ((QueueConnectionFactory) cf).createQueueConnection();
+ }
+ else if (Boolean.TRUE.equals(this.pubSubMode) && cf instanceof TopicConnectionFactory) {
+ return ((TopicConnectionFactory) cf).createTopicConnection();
+ }
+ else {
+ return getTargetConnectionFactory().createConnection();
+ }
+ }
+
+ /**
+ * Prepare the given Connection before it is exposed.
+ *
The default implementation applies ExceptionListener and client id.
+ * Can be overridden in subclasses.
+ * @param con the Connection to prepare
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setExceptionListener
+ * @see #setReconnectOnException
+ */
+ protected void prepareConnection(Connection con) throws JMSException {
+ if (getClientId() != null) {
+ con.setClientID(getClientId());
+ }
+ if (getExceptionListener() != null || isReconnectOnException()) {
+ ExceptionListener listenerToUse = getExceptionListener();
+ if (isReconnectOnException()) {
+ listenerToUse = new InternalChainedExceptionListener(this, listenerToUse);
+ }
+ con.setExceptionListener(listenerToUse);
+ }
+ }
+
+ /**
+ * Template method for obtaining a (potentially cached) Session.
+ *
The default implementation always returns null.
+ * Subclasses may override this for exposing specific Session handles,
+ * possibly delegating to {@link #createSession} for the creation of raw
+ * Session objects that will then get wrapped and returned from here.
+ * @param con the JMS Connection to operate on
+ * @param mode the Session acknowledgement mode
+ * (Session.TRANSACTED or one of the common modes)
+ * @return the Session to use, or null to indicate
+ * creation of a raw standard Session
+ * @throws JMSException if thrown by the JMS API
+ */
+ protected Session getSession(Connection con, Integer mode) throws JMSException {
+ return null;
+ }
+
+ /**
+ * Create a default Session for this ConnectionFactory,
+ * adaptign to JMS 1.0.2 style queue/topic mode if necessary.
+ * @param con the JMS Connection to operate on
+ * @param mode the Session acknowledgement mode
+ * (Session.TRANSACTED or one of the common modes)
+ * @return the newly created Session
+ * @throws JMSException if thrown by the JMS API
+ */
+ protected Session createSession(Connection con, Integer mode) throws JMSException {
+ // Determine JMS API arguments...
+ boolean transacted = (mode.intValue() == Session.SESSION_TRANSACTED);
+ int ackMode = (transacted ? Session.AUTO_ACKNOWLEDGE : mode.intValue());
+ // Now actually call the appropriate JMS factory method...
+ if (Boolean.FALSE.equals(this.pubSubMode) && con instanceof QueueConnection) {
+ return ((QueueConnection) con).createQueueSession(transacted, ackMode);
+ }
+ else if (Boolean.TRUE.equals(this.pubSubMode) && con instanceof TopicConnection) {
+ return ((TopicConnection) con).createTopicSession(transacted, ackMode);
+ }
+ else {
+ return con.createSession(transacted, ackMode);
+ }
+ }
+
+ /**
+ * Close the given Connection.
+ * @param con the Connection to close
+ */
+ protected void closeConnection(Connection con) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Closing shared JMS Connection: " + this.target);
+ }
+ try {
+ try {
+ if (this.started) {
+ this.started = false;
+ con.stop();
+ }
+ }
+ finally {
+ con.close();
+ }
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ logger.debug("Ignoring Connection state exception - assuming already closed: " + ex);
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not close shared JMS Connection", ex);
+ }
+ }
+
+ /**
+ * Wrap the given Connection with a proxy that delegates every method call to it
+ * but suppresses close calls. This is useful for allowing application code to
+ * handle a special framework Connection just like an ordinary Connection from a
+ * JMS ConnectionFactory.
+ * @param target the original Connection to wrap
+ * @return the wrapped Connection
+ */
+ protected Connection getSharedConnectionProxy(Connection target) {
+ List classes = new ArrayList(3);
+ classes.add(Connection.class);
+ if (target instanceof QueueConnection) {
+ classes.add(QueueConnection.class);
+ }
+ if (target instanceof TopicConnection) {
+ classes.add(TopicConnection.class);
+ }
+ return (Connection) Proxy.newProxyInstance(
+ Connection.class.getClassLoader(),
+ (Class[]) classes.toArray(new Class[classes.size()]),
+ new SharedConnectionInvocationHandler(target));
+ }
+
+
+ /**
+ * Invocation handler for a cached JMS Connection proxy.
+ */
+ private class SharedConnectionInvocationHandler implements InvocationHandler {
+
+ private final Connection target;
+
+ public SharedConnectionInvocationHandler(Connection target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of Connection proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("toString")) {
+ return "Shared JMS Connection: " + this.target;
+ }
+ else if (method.getName().equals("setClientID")) {
+ // Handle setClientID method: throw exception if not compatible.
+ String currentClientId = this.target.getClientID();
+ if (currentClientId != null && currentClientId.equals(args[0])) {
+ return null;
+ }
+ else {
+ throw new javax.jms.IllegalStateException(
+ "setClientID call not supported on proxy for shared Connection. " +
+ "Set the 'clientId' property on the SingleConnectionFactory instead.");
+ }
+ }
+ else if (method.getName().equals("setExceptionListener")) {
+ // Handle setExceptionListener method: add to the chain.
+ ExceptionListener currentExceptionListener = this.target.getExceptionListener();
+ if (currentExceptionListener instanceof InternalChainedExceptionListener && args[0] != null) {
+ ((InternalChainedExceptionListener) currentExceptionListener).addDelegate((ExceptionListener) args[0]);
+ return null;
+ }
+ else {
+ throw new javax.jms.IllegalStateException(
+ "setExceptionListener call not supported on proxy for shared Connection. " +
+ "Set the 'exceptionListener' property on the SingleConnectionFactory instead. " +
+ "Alternatively, activate SingleConnectionFactory's 'reconnectOnException' feature, " +
+ "which will allow for registering further ExceptionListeners to the recovery chain.");
+ }
+ }
+ else if (method.getName().equals("start")) {
+ // Handle start method: track started state.
+ this.target.start();
+ synchronized (connectionMonitor) {
+ started = true;
+ }
+ return null;
+ }
+ else if (method.getName().equals("stop")) {
+ // Handle stop method: don't pass the call on.
+ return null;
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: don't pass the call on.
+ return null;
+ }
+ else if (method.getName().equals("createSession") || method.getName().equals("createQueueSession") ||
+ method.getName().equals("createTopicSession")) {
+ boolean transacted = ((Boolean) args[0]).booleanValue();
+ Integer ackMode = (Integer) args[1];
+ Integer mode = (transacted ? new Integer(Session.SESSION_TRANSACTED) : ackMode);
+ Session session = getSession(this.target, mode);
+ if (session != null) {
+ if (!method.getReturnType().isInstance(session)) {
+ String msg = "JMS Session does not implement specific domain: " + session;
+ try {
+ session.close();
+ }
+ catch (Throwable ex) {
+ logger.trace("Failed to close newly obtained JMS Session", ex);
+ }
+ throw new javax.jms.IllegalStateException(msg);
+ }
+ return session;
+ }
+ }
+ try {
+ Object retVal = method.invoke(this.target, args);
+ if (method.getName().equals("getExceptionListener") && retVal instanceof InternalChainedExceptionListener) {
+ // Handle getExceptionListener method: hide internal chain.
+ InternalChainedExceptionListener listener = (InternalChainedExceptionListener) retVal;
+ return listener.getUserListener();
+ }
+ else {
+ return retVal;
+ }
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+
+ /**
+ * Internal chained ExceptionListener for handling the internal recovery listener
+ * in combination with a user-specified listener.
+ */
+ private static class InternalChainedExceptionListener extends ChainedExceptionListener {
+
+ private ExceptionListener userListener;
+
+ public InternalChainedExceptionListener(ExceptionListener internalListener, ExceptionListener userListener) {
+ addDelegate(internalListener);
+ if (userListener != null) {
+ addDelegate(userListener);
+ this.userListener = userListener;
+ }
+ }
+
+ public ExceptionListener getUserListener() {
+ return this.userListener;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/SingleConnectionFactory102.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2007 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnectionFactory;
+
+/**
+ * A subclass of {@link SingleConnectionFactory} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like SingleConnectionFactory itself.
+ * This class can be used for JMS 1.0.2 providers, offering the same API as
+ * SingleConnectionFactory does for JMS 1.1 providers.
+ *
+ *
You need to set the {@link #setPubSubDomain "pubSubDomain" property},
+ * since this class will always explicitly differentiate between a
+ * {@link javax.jms.QueueConnection} and a {@link javax.jms.TopicConnection}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setTargetConnectionFactory
+ * @see #setPubSubDomain
+ */
+public class SingleConnectionFactory102 extends SingleConnectionFactory {
+
+ private boolean pubSubDomain = false;
+
+
+ /**
+ * Create a new SingleConnectionFactory102 for bean-style usage.
+ */
+ public SingleConnectionFactory102() {
+ super();
+ }
+
+ /**
+ * Create a new SingleConnectionFactory102 that always returns a single
+ * Connection that it will lazily create via the given target
+ * ConnectionFactory.
+ * @param connectionFactory the target ConnectionFactory
+ * @param pubSubDomain whether the Publish/Subscribe domain (Topics) or
+ * Point-to-Point domain (Queues) should be used
+ */
+ public SingleConnectionFactory102(ConnectionFactory connectionFactory, boolean pubSubDomain) {
+ setTargetConnectionFactory(connectionFactory);
+ this.pubSubDomain = pubSubDomain;
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Configure the factory with knowledge of the JMS domain used.
+ * This tells the JMS 1.0.2 provider which class hierarchy to use for creating
+ * Connections and Sessions.
+ *
Default is Point-to-Point (Queues).
+ * @param pubSubDomain true for Publish/Subscribe domain (Topics),
+ * false for Point-to-Point domain (Queues)
+ */
+ public void setPubSubDomain(boolean pubSubDomain) {
+ this.pubSubDomain = pubSubDomain;
+ }
+
+ /**
+ * Return whether the Publish/Subscribe domain (Topics) is used.
+ * Otherwise, the Point-to-Point domain (Queues) is used.
+ */
+ public boolean isPubSubDomain() {
+ return this.pubSubDomain;
+ }
+
+
+ /**
+ * In addition to checking whether the target ConnectionFactory is set,
+ * make sure that the supplied factory is of the appropriate type for
+ * the specified destination type: QueueConnectionFactory for queues,
+ * TopicConnectionFactory for topics.
+ */
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+
+ // Make sure that the ConnectionFactory passed is consistent.
+ // Some provider implementations of the ConnectionFactory interface
+ // implement both domain interfaces under the cover, so just check if
+ // the selected domain is consistent with the type of connection factory.
+ if (isPubSubDomain()) {
+ if (!(getTargetConnectionFactory() instanceof TopicConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 SingleConnectionFactory for topics " +
+ "but did not supply an instance of TopicConnectionFactory");
+ }
+ }
+ else {
+ if (!(getTargetConnectionFactory() instanceof QueueConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 SingleConnectionFactory for queues " +
+ "but did not supply an instance of QueueConnectionFactory");
+ }
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection doCreateConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getTargetConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getTargetConnectionFactory()).createQueueConnection();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/SmartConnectionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/SmartConnectionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/SmartConnectionFactory.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2007 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+
+/**
+ * Extension of the javax.jms.ConnectionFactory interface,
+ * indicating how to release Connections obtained from it.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.2
+ */
+public interface SmartConnectionFactory extends ConnectionFactory {
+
+ /**
+ * Should we stop the Connection, obtained from this ConnectionFactory?
+ * @param con the Connection to check
+ * @return whether a stop call is necessary
+ * @see javax.jms.Connection#stop()
+ */
+ boolean shouldStop(Connection con);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/SynchedLocalTransactionFailedException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/SynchedLocalTransactionFailedException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/SynchedLocalTransactionFailedException.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006 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.jms.connection;
+
+import javax.jms.JMSException;
+
+import org.springframework.jms.JmsException;
+
+/**
+ * Exception thrown when a synchronized local transaction failed to complete
+ * (after the main transaction has already completed).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see ConnectionFactoryUtils
+ */
+public class SynchedLocalTransactionFailedException extends JmsException {
+
+ /**
+ * Create a new SynchedLocalTransactionFailedException.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public SynchedLocalTransactionFailedException(String msg, JMSException cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/TransactionAwareConnectionFactoryProxy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/TransactionAwareConnectionFactoryProxy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/TransactionAwareConnectionFactoryProxy.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSession;
+import javax.jms.TransactionInProgressException;
+
+import org.springframework.util.Assert;
+
+/**
+ * Proxy for a target JMS {@link javax.jms.ConnectionFactory}, adding awareness of
+ * Spring-managed transactions. Similar to a transactional JNDI ConnectionFactory
+ * as provided by a J2EE server.
+ *
+ *
Messaging code that should remain unaware of Spring's JMS support can work
+ * with this proxy to seamlessly participate in Spring-managed transactions.
+ * Note that the transaction manager, for example {@link JmsTransactionManager},
+ * still needs to work with the underlying ConnectionFactory, not with
+ * this proxy.
+ *
+ *
Make sure that TransactionAwareConnectionFactoryProxy is the outermost
+ * ConnectionFactory of a chain of ConnectionFactory proxies/adapters.
+ * TransactionAwareConnectionFactoryProxy can delegate either directly to the
+ * target factory or to some intermediary adapter like
+ * {@link UserCredentialsConnectionFactoryAdapter}.
+ *
+ *
Delegates to {@link ConnectionFactoryUtils} for automatically participating
+ * in thread-bound transactions, for example managed by {@link JmsTransactionManager}.
+ * createSession calls and close calls on returned Sessions
+ * will behave properly within a transaction, that is, always work on the transactional
+ * Session. If not within a transaction, normal ConnectionFactory behavior applies.
+ *
+ *
Note that transactional JMS Sessions will be registered on a per-Connection
+ * basis. To share the same JMS Session across a transaction, make sure that you
+ * operate on the same JMS Connection handle - either through reusing the handle
+ * or through configuring a {@link SingleConnectionFactory} underneath.
+ *
+ *
Returned transactional Session proxies will implement the {@link SessionProxy}
+ * interface to allow for access to the underlying target Session. This is only
+ * intended for accessing vendor-specific Session API or for testing purposes
+ * (e.g. to perform manual transaction control). For typical application purposes,
+ * simply use the standard JMS Session interface.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see UserCredentialsConnectionFactoryAdapter
+ * @see SingleConnectionFactory
+ */
+public class TransactionAwareConnectionFactoryProxy
+ implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory {
+
+ private boolean synchedLocalTransactionAllowed = false;
+
+ private ConnectionFactory targetConnectionFactory;
+
+
+ /**
+ * Create a new TransactionAwareConnectionFactoryProxy.
+ */
+ public TransactionAwareConnectionFactoryProxy() {
+ }
+
+ /**
+ * Create a new TransactionAwareConnectionFactoryProxy.
+ * @param targetConnectionFactory the target ConnectionFactory
+ */
+ public TransactionAwareConnectionFactoryProxy(ConnectionFactory targetConnectionFactory) {
+ setTargetConnectionFactory(targetConnectionFactory);
+ }
+
+
+ /**
+ * Set the target ConnectionFactory that this ConnectionFactory should delegate to.
+ */
+ public final void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ Assert.notNull(targetConnectionFactory, "targetConnectionFactory must not be nul");
+ this.targetConnectionFactory = targetConnectionFactory;
+ }
+
+ /**
+ * Return the target ConnectionFactory that this ConnectionFactory should delegate to.
+ */
+ protected ConnectionFactory getTargetConnectionFactory() {
+ return this.targetConnectionFactory;
+ }
+
+ /**
+ * Set whether to allow for a local JMS transaction that is synchronized with a
+ * Spring-managed transaction (where the main transaction might be a JDBC-based
+ * one for a specific DataSource, for example), with the JMS transaction committing
+ * right after the main transaction. If not allowed, the given ConnectionFactory
+ * needs to handle transaction enlistment underneath the covers.
+ *
Default is "false": If not within a managed transaction that encompasses
+ * the underlying JMS ConnectionFactory, standard Sessions will be returned.
+ * Turn this flag on to allow participation in any Spring-managed transaction,
+ * with a local JMS transaction synchronized with the main transaction.
+ */
+ public void setSynchedLocalTransactionAllowed(boolean synchedLocalTransactionAllowed) {
+ this.synchedLocalTransactionAllowed = synchedLocalTransactionAllowed;
+ }
+
+ /**
+ * Return whether to allow for a local JMS transaction that is synchronized
+ * with a Spring-managed transaction.
+ */
+ protected boolean isSynchedLocalTransactionAllowed() {
+ return this.synchedLocalTransactionAllowed;
+ }
+
+
+ public Connection createConnection() throws JMSException {
+ Connection targetConnection = this.targetConnectionFactory.createConnection();
+ return getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+ public Connection createConnection(String username, String password) throws JMSException {
+ Connection targetConnection = this.targetConnectionFactory.createConnection(username, password);
+ return getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+ public QueueConnection createQueueConnection() throws JMSException {
+ if (!(this.targetConnectionFactory instanceof QueueConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is no QueueConnectionFactory");
+ }
+ QueueConnection targetConnection =
+ ((QueueConnectionFactory) this.targetConnectionFactory).createQueueConnection();
+ return (QueueConnection) getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+ public QueueConnection createQueueConnection(String username, String password) throws JMSException {
+ if (!(this.targetConnectionFactory instanceof QueueConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is no QueueConnectionFactory");
+ }
+ QueueConnection targetConnection =
+ ((QueueConnectionFactory) this.targetConnectionFactory).createQueueConnection(username, password);
+ return (QueueConnection) getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+ public TopicConnection createTopicConnection() throws JMSException {
+ if (!(this.targetConnectionFactory instanceof TopicConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is no TopicConnectionFactory");
+ }
+ TopicConnection targetConnection =
+ ((TopicConnectionFactory) this.targetConnectionFactory).createTopicConnection();
+ return (TopicConnection) getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+ public TopicConnection createTopicConnection(String username, String password) throws JMSException {
+ if (!(this.targetConnectionFactory instanceof TopicConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is no TopicConnectionFactory");
+ }
+ TopicConnection targetConnection =
+ ((TopicConnectionFactory) this.targetConnectionFactory).createTopicConnection(username, password);
+ return (TopicConnection) getTransactionAwareConnectionProxy(targetConnection);
+ }
+
+
+ /**
+ * Wrap the given Connection with a proxy that delegates every method call to it
+ * but handles Session lookup in a transaction-aware fashion.
+ * @param target the original Connection to wrap
+ * @return the wrapped Connection
+ */
+ private Connection getTransactionAwareConnectionProxy(Connection target) {
+ List classes = new ArrayList(3);
+ classes.add(Connection.class);
+ if (target instanceof QueueConnection) {
+ classes.add(QueueConnection.class);
+ }
+ if (target instanceof TopicConnection) {
+ classes.add(TopicConnection.class);
+ }
+ return (Connection) Proxy.newProxyInstance(
+ Connection.class.getClassLoader(),
+ (Class[]) classes.toArray(new Class[classes.size()]),
+ new TransactionAwareConnectionInvocationHandler(target));
+ }
+
+
+ /**
+ * Invocation handler that exposes transactional Sessions for the underlying Connection.
+ */
+ private class TransactionAwareConnectionInvocationHandler implements InvocationHandler {
+
+ private final Connection target;
+
+ public TransactionAwareConnectionInvocationHandler(Connection target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on ConnectionProxy interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of Connection proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (Session.class.equals(method.getReturnType())) {
+ Session session = ConnectionFactoryUtils.getTransactionalSession(
+ getTargetConnectionFactory(), this.target, isSynchedLocalTransactionAllowed());
+ if (session != null) {
+ return getCloseSuppressingSessionProxy(session);
+ }
+ }
+ else if (QueueSession.class.equals(method.getReturnType())) {
+ QueueSession session = ConnectionFactoryUtils.getTransactionalQueueSession(
+ (QueueConnectionFactory) getTargetConnectionFactory(), (QueueConnection) this.target,
+ isSynchedLocalTransactionAllowed());
+ if (session != null) {
+ return getCloseSuppressingSessionProxy(session);
+ }
+ }
+ else if (TopicSession.class.equals(method.getReturnType())) {
+ TopicSession session = ConnectionFactoryUtils.getTransactionalTopicSession(
+ (TopicConnectionFactory) getTargetConnectionFactory(), (TopicConnection) this.target,
+ isSynchedLocalTransactionAllowed());
+ if (session != null) {
+ return getCloseSuppressingSessionProxy(session);
+ }
+ }
+
+ // Invoke method on target Connection.
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ private Session getCloseSuppressingSessionProxy(Session target) {
+ List classes = new ArrayList(3);
+ classes.add(SessionProxy.class);
+ if (target instanceof QueueSession) {
+ classes.add(QueueSession.class);
+ }
+ if (target instanceof TopicSession) {
+ classes.add(TopicSession.class);
+ }
+ return (Session) Proxy.newProxyInstance(
+ SessionProxy.class.getClassLoader(),
+ (Class[]) classes.toArray(new Class[classes.size()]),
+ new CloseSuppressingSessionInvocationHandler(target));
+ }
+ }
+
+
+ /**
+ * Invocation handler that suppresses close calls for a transactional JMS Session.
+ */
+ private static class CloseSuppressingSessionInvocationHandler implements InvocationHandler {
+
+ private final Session target;
+
+ public CloseSuppressingSessionInvocationHandler(Session target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on SessionProxy interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of Connection proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("commit")) {
+ throw new TransactionInProgressException("Commit call not allowed within a managed transaction");
+ }
+ else if (method.getName().equals("rollback")) {
+ throw new TransactionInProgressException("Rollback call not allowed within a managed transaction");
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: not to be closed within a transaction.
+ return null;
+ }
+ else if (method.getName().equals("getTargetSession")) {
+ // Handle getTargetSession method: return underlying Session.
+ return this.target;
+ }
+
+ // Invoke method on target Session.
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/UserCredentialsConnectionFactoryAdapter.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2002-2008 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.jms.connection;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.NamedThreadLocal;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * An adapter for a target JMS {@link javax.jms.ConnectionFactory}, applying the
+ * given user credentials to every standard createConnection() call,
+ * that is, implicitly invoking createConnection(username, password)
+ * on the target. All other methods simply delegate to the corresponding methods
+ * of the target ConnectionFactory.
+ *
+ *
Can be used to proxy a target JNDI ConnectionFactory that does not have user
+ * credentials configured. Client code can work with the ConnectionFactory without
+ * passing in username and password on every createConnection() call.
+ *
+ *
In the following example, client code can simply transparently work
+ * with the preconfigured "myConnectionFactory", implicitly accessing
+ * "myTargetConnectionFactory" with the specified user credentials.
+ *
+ *
If the "username" is empty, this proxy will simply delegate to the standard
+ * createConnection() method of the target ConnectionFactory.
+ * This can be used to keep a UserCredentialsConnectionFactoryAdapter bean
+ * definition just for the option of implicitly passing in user credentials
+ * if the particular target ConnectionFactory requires it.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #createConnection
+ * @see #createQueueConnection
+ * @see #createTopicConnection
+ */
+public class UserCredentialsConnectionFactoryAdapter
+ implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, InitializingBean {
+
+ private ConnectionFactory targetConnectionFactory;
+
+ private String username;
+
+ private String password;
+
+ private final ThreadLocal threadBoundCredentials = new NamedThreadLocal("Current JMS user credentials");
+
+
+ /**
+ * Set the target ConnectionFactory that this ConnectionFactory should delegate to.
+ */
+ public void setTargetConnectionFactory(ConnectionFactory targetConnectionFactory) {
+ Assert.notNull(targetConnectionFactory, "'targetConnectionFactory' must not be null");
+ this.targetConnectionFactory = targetConnectionFactory;
+ }
+
+ /**
+ * Set the username that this adapter should use for retrieving Connections.
+ * Default is no specific user.
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Set the password that this adapter should use for retrieving Connections.
+ * Default is no specific password.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void afterPropertiesSet() {
+ if (this.targetConnectionFactory == null) {
+ throw new IllegalArgumentException("Property 'targetConnectionFactory' is required");
+ }
+ }
+
+
+ /**
+ * Set user credententials for this proxy and the current thread.
+ * The given username and password will be applied to all subsequent
+ * createConnection() calls on this ConnectionFactory proxy.
+ *
This will override any statically specified user credentials,
+ * that is, values of the "username" and "password" bean properties.
+ * @param username the username to apply
+ * @param password the password to apply
+ * @see #removeCredentialsFromCurrentThread
+ */
+ public void setCredentialsForCurrentThread(String username, String password) {
+ this.threadBoundCredentials.set(new JmsUserCredentials(username, password));
+ }
+
+ /**
+ * Remove any user credentials for this proxy from the current thread.
+ * Statically specified user credentials apply again afterwards.
+ * @see #setCredentialsForCurrentThread
+ */
+ public void removeCredentialsFromCurrentThread() {
+ this.threadBoundCredentials.set(null);
+ }
+
+
+ /**
+ * Determine whether there are currently thread-bound credentials,
+ * using them if available, falling back to the statically specified
+ * username and password (i.e. values of the bean properties) else.
+ * @see #doCreateConnection
+ */
+ public final Connection createConnection() throws JMSException {
+ JmsUserCredentials threadCredentials = (JmsUserCredentials) this.threadBoundCredentials.get();
+ if (threadCredentials != null) {
+ return doCreateConnection(threadCredentials.username, threadCredentials.password);
+ }
+ else {
+ return doCreateConnection(this.username, this.password);
+ }
+ }
+
+ /**
+ * Delegate the call straight to the target ConnectionFactory.
+ */
+ public Connection createConnection(String username, String password) throws JMSException {
+ return doCreateConnection(username, password);
+ }
+
+ /**
+ * This implementation delegates to the createConnection(username, password)
+ * method of the target ConnectionFactory, passing in the specified user credentials.
+ * If the specified username is empty, it will simply delegate to the standard
+ * createConnection() method of the target ConnectionFactory.
+ * @param username the username to use
+ * @param password the password to use
+ * @return the Connection
+ * @see javax.jms.ConnectionFactory#createConnection(String, String)
+ * @see javax.jms.ConnectionFactory#createConnection()
+ */
+ protected Connection doCreateConnection(String username, String password) throws JMSException {
+ Assert.state(this.targetConnectionFactory != null, "'targetConnectionFactory' is required");
+ if (StringUtils.hasLength(username)) {
+ return this.targetConnectionFactory.createConnection(username, password);
+ }
+ else {
+ return this.targetConnectionFactory.createConnection();
+ }
+ }
+
+
+ /**
+ * Determine whether there are currently thread-bound credentials,
+ * using them if available, falling back to the statically specified
+ * username and password (i.e. values of the bean properties) else.
+ * @see #doCreateQueueConnection
+ */
+ public final QueueConnection createQueueConnection() throws JMSException {
+ JmsUserCredentials threadCredentials = (JmsUserCredentials) this.threadBoundCredentials.get();
+ if (threadCredentials != null) {
+ return doCreateQueueConnection(threadCredentials.username, threadCredentials.password);
+ }
+ else {
+ return doCreateQueueConnection(this.username, this.password);
+ }
+ }
+
+ /**
+ * Delegate the call straight to the target QueueConnectionFactory.
+ */
+ public QueueConnection createQueueConnection(String username, String password) throws JMSException {
+ return doCreateQueueConnection(username, password);
+ }
+
+ /**
+ * This implementation delegates to the createQueueConnection(username, password)
+ * method of the target QueueConnectionFactory, passing in the specified user credentials.
+ * If the specified username is empty, it will simply delegate to the standard
+ * createQueueConnection() method of the target ConnectionFactory.
+ * @param username the username to use
+ * @param password the password to use
+ * @return the Connection
+ * @see javax.jms.QueueConnectionFactory#createQueueConnection(String, String)
+ * @see javax.jms.QueueConnectionFactory#createQueueConnection()
+ */
+ protected QueueConnection doCreateQueueConnection(String username, String password) throws JMSException {
+ Assert.state(this.targetConnectionFactory != null, "'targetConnectionFactory' is required");
+ if (!(this.targetConnectionFactory instanceof QueueConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory");
+ }
+ QueueConnectionFactory queueFactory = (QueueConnectionFactory) this.targetConnectionFactory;
+ if (StringUtils.hasLength(username)) {
+ return queueFactory.createQueueConnection(username, password);
+ }
+ else {
+ return queueFactory.createQueueConnection();
+ }
+ }
+
+
+ /**
+ * Determine whether there are currently thread-bound credentials,
+ * using them if available, falling back to the statically specified
+ * username and password (i.e. values of the bean properties) else.
+ * @see #doCreateTopicConnection
+ */
+ public final TopicConnection createTopicConnection() throws JMSException {
+ JmsUserCredentials threadCredentials = (JmsUserCredentials) this.threadBoundCredentials.get();
+ if (threadCredentials != null) {
+ return doCreateTopicConnection(threadCredentials.username, threadCredentials.password);
+ }
+ else {
+ return doCreateTopicConnection(this.username, this.password);
+ }
+ }
+
+ /**
+ * Delegate the call straight to the target TopicConnectionFactory.
+ */
+ public TopicConnection createTopicConnection(String username, String password) throws JMSException {
+ return doCreateTopicConnection(username, password);
+ }
+
+ /**
+ * This implementation delegates to the createTopicConnection(username, password)
+ * method of the target TopicConnectionFactory, passing in the specified user credentials.
+ * If the specified username is empty, it will simply delegate to the standard
+ * createTopicConnection() method of the target ConnectionFactory.
+ * @param username the username to use
+ * @param password the password to use
+ * @return the Connection
+ * @see javax.jms.TopicConnectionFactory#createTopicConnection(String, String)
+ * @see javax.jms.TopicConnectionFactory#createTopicConnection()
+ */
+ protected TopicConnection doCreateTopicConnection(String username, String password) throws JMSException {
+ Assert.state(this.targetConnectionFactory != null, "'targetConnectionFactory' is required");
+ if (!(this.targetConnectionFactory instanceof TopicConnectionFactory)) {
+ throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory");
+ }
+ TopicConnectionFactory queueFactory = (TopicConnectionFactory) this.targetConnectionFactory;
+ if (StringUtils.hasLength(username)) {
+ return queueFactory.createTopicConnection(username, password);
+ }
+ else {
+ return queueFactory.createTopicConnection();
+ }
+ }
+
+
+ /**
+ * Inner class used as ThreadLocal value.
+ */
+ private static class JmsUserCredentials {
+
+ public final String username;
+
+ public final String password;
+
+ private JmsUserCredentials(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ public String toString() {
+ return "JmsUserCredentials[username='" + this.username + "',password='" + this.password + "']";
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/connection/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/connection/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/connection/package.html 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides a PlatformTransactionManager implementation for a single
+JMS ConnectionFactory, and a SingleConnectionFactory adapter.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/core/BrowserCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/BrowserCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/BrowserCallback.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2008 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.jms.core;
+
+import javax.jms.JMSException;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+
+/**
+ * Callback for browsing the messages in a JMS queue.
+ *
+ *
To be used with JmsTemplate's callback methods that take a BrowserCallback
+ * argument, often implemented as an anonymous inner class.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.1
+ * @see JmsTemplate#browse(BrowserCallback)
+ * @see JmsTemplate#browseSelected(String, BrowserCallback)
+ */
+public interface BrowserCallback {
+
+ /**
+ * Perform operations on the given {@link javax.jms.Session} and {@link javax.jms.QueueBrowser}.
+ *
The message producer is not associated with any destination.
+ * @param session the JMS Session object to use
+ * @param browser the JMS QueueBrowser object to use
+ * @return a result object from working with the Session, if any (can be null)
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ Object doInJms(Session session, QueueBrowser browser) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/JmsOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/JmsOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/JmsOperations.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2002-2008 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.jms.core;
+
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.Queue;
+
+import org.springframework.jms.JmsException;
+
+/**
+ * Specifies a basic set of JMS operations.
+ *
+ *
Implemented by {@link JmsTemplate}. Not often used but a useful option
+ * to enhance testability, as it can easily be mocked or stubbed.
+ *
+ *
Provides JmsTemplate'ssend(..) and
+ * receive(..) methods that mirror various JMS API methods.
+ * See the JMS specification and javadocs for details on those methods.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see JmsTemplate
+ * @see javax.jms.Destination
+ * @see javax.jms.Session
+ * @see javax.jms.MessageProducer
+ * @see javax.jms.MessageConsumer
+ */
+public interface JmsOperations {
+
+ /**
+ * Execute the action specified by the given action object within a JMS Session.
+ *
When used with a 1.0.2 provider, you may need to downcast
+ * to the appropriate domain implementation, either QueueSession or
+ * TopicSession in the action objects doInJms callback method.
+ * @param action callback object that exposes the session
+ * @return the result object from working with the session
+ * @throws JmsException if there is any problem
+ */
+ Object execute(SessionCallback action) throws JmsException;
+
+ /**
+ * Send messages to the default JMS destination (or one specified
+ * for each send operation). The callback gives access to the JMS Session
+ * and MessageProducer in order to perform complex send operations.
+ * @param action callback object that exposes the session/producer pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object execute(ProducerCallback action) throws JmsException;
+
+ /**
+ * Send messages to a JMS destination. The callback gives access to the JMS Session
+ * and MessageProducer in order to perform complex send operations.
+ * @param destination the destination to send messages to
+ * @param action callback object that exposes the session/producer pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object execute(Destination destination, ProducerCallback action) throws JmsException;
+
+ /**
+ * Send messages to a JMS destination. The callback gives access to the JMS Session
+ * and MessageProducer in order to perform complex send operations.
+ * @param destinationName the name of the destination to send messages to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param action callback object that exposes the session/producer pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object execute(String destinationName, ProducerCallback action) throws JmsException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for sending messages
+ //-------------------------------------------------------------------------
+
+ /**
+ * Send a message to the default destination.
+ *
This will only work with a default destination specified!
+ * @param messageCreator callback to create a message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void send(MessageCreator messageCreator) throws JmsException;
+
+ /**
+ * Send a message to the specified destination.
+ * The MessageCreator callback creates the message given a Session.
+ * @param destination the destination to send this message to
+ * @param messageCreator callback to create a message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void send(Destination destination, MessageCreator messageCreator) throws JmsException;
+
+ /**
+ * Send a message to the specified destination.
+ * The MessageCreator callback creates the message given a Session.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param messageCreator callback to create a message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void send(String destinationName, MessageCreator messageCreator) throws JmsException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for sending auto-converted messages
+ //-------------------------------------------------------------------------
+
+ /**
+ * Send the given object to the default destination, converting the object
+ * to a JMS message with a configured MessageConverter.
+ *
This will only work with a default destination specified!
+ * @param message the object to convert to a message
+ * @throws JmsException converted checked JMSException to unchecked
+ */
+ void convertAndSend(Object message) throws JmsException;
+
+ /**
+ * Send the given object to the specified destination, converting the object
+ * to a JMS message with a configured MessageConverter.
+ * @param destination the destination to send this message to
+ * @param message the object to convert to a message
+ * @throws JmsException converted checked JMSException to unchecked
+ */
+ void convertAndSend(Destination destination, Object message) throws JmsException;
+
+ /**
+ * Send the given object to the specified destination, converting the object
+ * to a JMS message with a configured MessageConverter.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param message the object to convert to a message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void convertAndSend(String destinationName, Object message) throws JmsException;
+
+ /**
+ * Send the given object to the default destination, converting the object
+ * to a JMS message with a configured MessageConverter. The MessagePostProcessor
+ * callback allows for modification of the message after conversion.
+ *
This will only work with a default destination specified!
+ * @param message the object to convert to a message
+ * @param postProcessor the callback to modify the message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void convertAndSend(Object message, MessagePostProcessor postProcessor)
+ throws JmsException;
+
+ /**
+ * Send the given object to the specified destination, converting the object
+ * to a JMS message with a configured MessageConverter. The MessagePostProcessor
+ * callback allows for modification of the message after conversion.
+ * @param destination the destination to send this message to
+ * @param message the object to convert to a message
+ * @param postProcessor the callback to modify the message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void convertAndSend(Destination destination, Object message, MessagePostProcessor postProcessor)
+ throws JmsException;
+
+ /**
+ * Send the given object to the specified destination, converting the object
+ * to a JMS message with a configured MessageConverter. The MessagePostProcessor
+ * callback allows for modification of the message after conversion.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param message the object to convert to a message.
+ * @param postProcessor the callback to modify the message
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ void convertAndSend(String destinationName, Object message, MessagePostProcessor postProcessor)
+ throws JmsException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for receiving messages
+ //-------------------------------------------------------------------------
+
+ /**
+ * Receive a message synchronously from the default destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ *
This will only work with a default destination specified!
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receive() throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destination the destination to receive a message from
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receive(Destination destination) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receive(String destinationName) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the default destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ *
This will only work with a default destination specified!
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receiveSelected(String messageSelector) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destination the destination to receive a message from
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receiveSelected(Destination destination, String messageSelector) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message received by the consumer, or null if the timeout expires
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Message receiveSelected(String destinationName, String messageSelector) throws JmsException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for receiving auto-converted messages
+ //-------------------------------------------------------------------------
+
+ /**
+ * Receive a message synchronously from the default destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ *
This will only work with a default destination specified!
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveAndConvert() throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destination the destination to receive a message from
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveAndConvert(Destination destination) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveAndConvert(String destinationName) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the default destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ *
This will only work with a default destination specified!
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveSelectedAndConvert(String messageSelector) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destination the destination to receive a message from
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveSelectedAndConvert(Destination destination, String messageSelector) throws JmsException;
+
+ /**
+ * Receive a message synchronously from the specified destination, but only
+ * wait up to a specified time for delivery. Convert the message into an
+ * object with a configured MessageConverter.
+ *
This method should be used carefully, since it will block the thread
+ * until the message becomes available or until the timeout value is exceeded.
+ * @param destinationName the name of the destination to send this message to
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @return the message produced for the consumer or null if the timeout expires.
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object receiveSelectedAndConvert(String destinationName, String messageSelector) throws JmsException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for browsing messages
+ //-------------------------------------------------------------------------
+
+ /**
+ * Browse messages in the default JMS queue. The callback gives access to the JMS
+ * Session and QueueBrowser in order to browse the queue and react to the contents.
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browse(BrowserCallback action) throws JmsException;
+
+ /**
+ * Browse messages in a JMS queue. The callback gives access to the JMS Session
+ * and QueueBrowser in order to browse the queue and react to the contents.
+ * @param queue the queue to browse
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browse(Queue queue, BrowserCallback action) throws JmsException;
+
+ /**
+ * Browse messages in a JMS queue. The callback gives access to the JMS Session
+ * and QueueBrowser in order to browse the queue and react to the contents.
+ * @param queueName the name of the queue to browse
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browse(String queueName, BrowserCallback action) throws JmsException;
+
+ /**
+ * Browse selected messages in a JMS queue. The callback gives access to the JMS
+ * Session and QueueBrowser in order to browse the queue and react to the contents.
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browseSelected(String messageSelector, BrowserCallback action) throws JmsException;
+
+ /**
+ * Browse selected messages in a JMS queue. The callback gives access to the JMS
+ * Session and QueueBrowser in order to browse the queue and react to the contents.
+ * @param queue the queue to browse
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browseSelected(Queue queue, String messageSelector, BrowserCallback action) throws JmsException;
+
+ /**
+ * Browse selected messages in a JMS queue. The callback gives access to the JMS
+ * Session and QueueBrowser in order to browse the queue and react to the contents.
+ * @param queueName the name of the queue to browse
+ * (to be resolved to an actual destination by a DestinationResolver)
+ * @param messageSelector the JMS message selector expression (or null if none).
+ * See the JMS specification for a detailed definition of selector expressions.
+ * @param action callback object that exposes the session/browser pair
+ * @return the result object from working with the session
+ * @throws JmsException checked JMSException converted to unchecked
+ */
+ Object browseSelected(String queueName, String messageSelector, BrowserCallback action) throws JmsException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,1040 @@
+/*
+ * Copyright 2002-2008 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.jms.core;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+
+import org.springframework.jms.JmsException;
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.connection.JmsResourceHolder;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.converter.MessageConverter;
+import org.springframework.jms.support.converter.SimpleMessageConverter;
+import org.springframework.jms.support.destination.JmsDestinationAccessor;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class that simplifies synchronous JMS access code.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider because it builds
+ * on the domain-independent API. Use the {@link JmsTemplate102} subclass
+ * for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.
+ *
+ *
If you want to use dynamic destination creation, you must specify
+ * the type of JMS destination to create, using the "pubSubDomain" property.
+ * For other operations, this is not necessary, in contrast to when working
+ * with JmsTemplate102. Point-to-Point (Queues) is the default domain.
+ *
+ *
Default settings for JMS Sessions are "not transacted" and "auto-acknowledge".
+ * As defined by the J2EE specification, the transaction and acknowledgement
+ * parameters are ignored when a JMS Session is created inside an active
+ * transaction, no matter if a JTA transaction or a Spring-managed transaction.
+ * To configure them for native JMS usage, specify appropriate values for
+ * the "sessionTransacted" and "sessionAcknowledgeMode" bean properties.
+ *
+ *
This template uses a
+ * {@link org.springframework.jms.support.destination.DynamicDestinationResolver}
+ * and a {@link org.springframework.jms.support.converter.SimpleMessageConverter}
+ * as default strategies for resolving a destination name or converting a message,
+ * respectively. These defaults can be overridden through the "destinationResolver"
+ * and "messageConverter" bean properties.
+ *
+ *
NOTE: The ConnectionFactory used with this template should
+ * return pooled Connections (or a single shared Connection) as well as pooled
+ * Sessions and MessageProducers. Otherwise, performance of ad-hoc JMS operations
+ * is going to suffer. The simplest option is to use the Spring-provided
+ * {@link org.springframework.jms.connection.SingleConnectionFactory} as a
+ * decorator for your target ConnectionFactory, reusing a single
+ * JMS Connection in a thread-safe fashion; this is often good enough for the
+ * purpose of sending messages via this template. In a J2EE environment,
+ * make sure that the ConnectionFactory is obtained from the
+ * application's environment naming context via JNDI; application servers
+ * typically expose pooled, transaction-aware factories there.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setConnectionFactory
+ * @see #setPubSubDomain
+ * @see #setDestinationResolver
+ * @see #setMessageConverter
+ * @see JmsTemplate102
+ * @see javax.jms.MessageProducer
+ * @see javax.jms.MessageConsumer
+ */
+public class JmsTemplate extends JmsDestinationAccessor implements JmsOperations {
+
+ /**
+ * Timeout value indicating that a receive operation should
+ * check if a message is immediately available without blocking.
+ */
+ public static final long RECEIVE_TIMEOUT_NO_WAIT = -1;
+
+ /**
+ * Timeout value indicating a blocking receive without timeout.
+ */
+ public static final long RECEIVE_TIMEOUT_INDEFINITE_WAIT = 0;
+
+
+ /** Internal ResourceFactory adapter for interacting with ConnectionFactoryUtils */
+ private final JmsTemplateResourceFactory transactionalResourceFactory = new JmsTemplateResourceFactory();
+
+
+ private Object defaultDestination;
+
+ private MessageConverter messageConverter;
+
+
+ private boolean messageIdEnabled = true;
+
+ private boolean messageTimestampEnabled = true;
+
+ private boolean pubSubNoLocal = false;
+
+ private long receiveTimeout = RECEIVE_TIMEOUT_INDEFINITE_WAIT;
+
+
+ private boolean explicitQosEnabled = false;
+
+ private int deliveryMode = Message.DEFAULT_DELIVERY_MODE;
+
+ private int priority = Message.DEFAULT_PRIORITY;
+
+ private long timeToLive = Message.DEFAULT_TIME_TO_LIVE;
+
+
+ /**
+ * Create a new JmsTemplate for bean-style usage.
+ *
Note: The ConnectionFactory has to be set before using the instance.
+ * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
+ * typically setting the ConnectionFactory via setConnectionFactory.
+ * @see #setConnectionFactory
+ */
+ public JmsTemplate() {
+ initDefaultStrategies();
+ }
+
+ /**
+ * Create a new JmsTemplate, given a ConnectionFactory.
+ * @param connectionFactory the ConnectionFactory to obtain Connections from
+ */
+ public JmsTemplate(ConnectionFactory connectionFactory) {
+ this();
+ setConnectionFactory(connectionFactory);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Initialize the default implementations for the template's strategies:
+ * DynamicDestinationResolver and SimpleMessageConverter.
+ * @see #setDestinationResolver
+ * @see #setMessageConverter
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter
+ */
+ protected void initDefaultStrategies() {
+ setMessageConverter(new SimpleMessageConverter());
+ }
+
+
+ /**
+ * Set the destination to be used on send/receive operations that do not
+ * have a destination parameter.
+ *
Alternatively, specify a "defaultDestinationName", to be
+ * dynamically resolved via the DestinationResolver.
+ * @see #send(MessageCreator)
+ * @see #convertAndSend(Object)
+ * @see #convertAndSend(Object, MessagePostProcessor)
+ * @see #setDefaultDestinationName(String)
+ */
+ public void setDefaultDestination(Destination destination) {
+ this.defaultDestination = destination;
+ }
+
+ /**
+ * Return the destination to be used on send/receive operations that do not
+ * have a destination parameter.
+ */
+ public Destination getDefaultDestination() {
+ return (this.defaultDestination instanceof Destination ? (Destination) this.defaultDestination : null);
+ }
+
+ private Queue getDefaultQueue() {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null && !(defaultDestination instanceof Queue)) {
+ throw new IllegalStateException(
+ "'defaultDestination' does not correspond to a Queue. Check configuration of JmsTemplate.");
+ }
+ return (Queue) defaultDestination;
+ }
+
+ /**
+ * Set the destination name to be used on send/receive operations that
+ * do not have a destination parameter. The specified name will be
+ * dynamically resolved via the DestinationResolver.
+ *
Alternatively, specify a JMS Destination object as "defaultDestination".
+ * @see #send(MessageCreator)
+ * @see #convertAndSend(Object)
+ * @see #convertAndSend(Object, MessagePostProcessor)
+ * @see #setDestinationResolver
+ * @see #setDefaultDestination(javax.jms.Destination)
+ */
+ public void setDefaultDestinationName(String destinationName) {
+ this.defaultDestination = destinationName;
+ }
+
+ /**
+ * Return the destination name to be used on send/receive operations that
+ * do not have a destination parameter.
+ */
+ public String getDefaultDestinationName() {
+ return (this.defaultDestination instanceof String ? (String) this.defaultDestination : null);
+ }
+
+ private String getRequiredDefaultDestinationName() throws IllegalStateException {
+ String name = getDefaultDestinationName();
+ if (name == null) {
+ throw new IllegalStateException(
+ "No 'defaultDestination' or 'defaultDestinationName' specified. Check configuration of JmsTemplate.");
+ }
+ return name;
+ }
+
+ /**
+ * Set the message converter for this template. Used to resolve
+ * Object parameters to convertAndSend methods and Object results
+ * from receiveAndConvert methods.
+ *
The default converter is a SimpleMessageConverter, which is able
+ * to handle BytesMessages, TextMessages and ObjectMessages.
+ * @see #convertAndSend
+ * @see #receiveAndConvert
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter
+ */
+ public void setMessageConverter(MessageConverter messageConverter) {
+ this.messageConverter = messageConverter;
+ }
+
+ /**
+ * Return the message converter for this template.
+ */
+ public MessageConverter getMessageConverter() {
+ return this.messageConverter;
+ }
+
+ private MessageConverter getRequiredMessageConverter() throws IllegalStateException {
+ MessageConverter converter = getMessageConverter();
+ if (converter == null) {
+ throw new IllegalStateException("No 'messageConverter' specified. Check configuration of JmsTemplate.");
+ }
+ return converter;
+ }
+
+
+ /**
+ * Set whether message IDs are enabled. Default is "true".
+ *
This is only a hint to the JMS producer.
+ * See the JMS javadocs for details.
+ * @see javax.jms.MessageProducer#setDisableMessageID
+ */
+ public void setMessageIdEnabled(boolean messageIdEnabled) {
+ this.messageIdEnabled = messageIdEnabled;
+ }
+
+ /**
+ * Return whether message IDs are enabled.
+ */
+ public boolean isMessageIdEnabled() {
+ return this.messageIdEnabled;
+ }
+
+ /**
+ * Set whether message timestamps are enabled. Default is "true".
+ *
This is only a hint to the JMS producer.
+ * See the JMS javadocs for details.
+ * @see javax.jms.MessageProducer#setDisableMessageTimestamp
+ */
+ public void setMessageTimestampEnabled(boolean messageTimestampEnabled) {
+ this.messageTimestampEnabled = messageTimestampEnabled;
+ }
+
+ /**
+ * Return whether message timestamps are enabled.
+ */
+ public boolean isMessageTimestampEnabled() {
+ return this.messageTimestampEnabled;
+ }
+
+ /**
+ * Set whether to inhibit the delivery of messages published by its own connection.
+ * Default is "false".
+ * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic, String, boolean)
+ */
+ public void setPubSubNoLocal(boolean pubSubNoLocal) {
+ this.pubSubNoLocal = pubSubNoLocal;
+ }
+
+ /**
+ * Return whether to inhibit the delivery of messages published by its own connection.
+ */
+ public boolean isPubSubNoLocal() {
+ return this.pubSubNoLocal;
+ }
+
+ /**
+ * Set the timeout to use for receive calls (in milliseconds).
+ *
The default is {@link #RECEIVE_TIMEOUT_INDEFINITE_WAIT}, which indicates
+ * a blocking receive without timeout.
+ *
Specify {@link #RECEIVE_TIMEOUT_NO_WAIT} to inidicate that a receive operation
+ * should check if a message is immediately available without blocking.
+ * @see javax.jms.MessageConsumer#receive(long)
+ * @see javax.jms.MessageConsumer#receive()
+ * @see javax.jms.MessageConsumer#receiveNoWait()
+ */
+ public void setReceiveTimeout(long receiveTimeout) {
+ this.receiveTimeout = receiveTimeout;
+ }
+
+ /**
+ * Return the timeout to use for receive calls (in milliseconds).
+ */
+ public long getReceiveTimeout() {
+ return this.receiveTimeout;
+ }
+
+
+ /**
+ * Set if the QOS values (deliveryMode, priority, timeToLive)
+ * should be used for sending a message.
+ * @see #setDeliveryMode
+ * @see #setPriority
+ * @see #setTimeToLive
+ */
+ public void setExplicitQosEnabled(boolean explicitQosEnabled) {
+ this.explicitQosEnabled = explicitQosEnabled;
+ }
+
+ /**
+ * If "true", then the values of deliveryMode, priority, and timeToLive
+ * will be used when sending a message. Otherwise, the default values,
+ * that may be set administratively, will be used.
+ * @return true if overriding default values of QOS parameters
+ * (deliveryMode, priority, and timeToLive)
+ * @see #setDeliveryMode
+ * @see #setPriority
+ * @see #setTimeToLive
+ */
+ public boolean isExplicitQosEnabled() {
+ return this.explicitQosEnabled;
+ }
+
+ /**
+ * Set whether message delivery should be persistent or non-persistent,
+ * specified as boolean value ("true" or "false"). This will set the delivery
+ * mode accordingly, to either "PERSISTENT" (1) or "NON_PERSISTENT" (2).
+ *
Default it "true" aka delivery mode "PERSISTENT".
+ * @see #setDeliveryMode(int)
+ * @see javax.jms.DeliveryMode#PERSISTENT
+ * @see javax.jms.DeliveryMode#NON_PERSISTENT
+ */
+ public void setDeliveryPersistent(boolean deliveryPersistent) {
+ this.deliveryMode = (deliveryPersistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
+ }
+
+ /**
+ * Set the delivery mode to use when sending a message.
+ * Default is the Message default: "PERSISTENT".
+ *
Since a default value may be defined administratively,
+ * this is only used when "isExplicitQosEnabled" equals "true".
+ * @param deliveryMode the delivery mode to use
+ * @see #isExplicitQosEnabled
+ * @see javax.jms.DeliveryMode#PERSISTENT
+ * @see javax.jms.DeliveryMode#NON_PERSISTENT
+ * @see javax.jms.Message#DEFAULT_DELIVERY_MODE
+ * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
+ */
+ public void setDeliveryMode(int deliveryMode) {
+ this.deliveryMode = deliveryMode;
+ }
+
+ /**
+ * Return the delivery mode to use when sending a message.
+ */
+ public int getDeliveryMode() {
+ return this.deliveryMode;
+ }
+
+ /**
+ * Set the priority of a message when sending.
+ *
Since a default value may be defined administratively,
+ * this is only used when "isExplicitQosEnabled" equals "true".
+ * @see #isExplicitQosEnabled
+ * @see javax.jms.Message#DEFAULT_PRIORITY
+ * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
+ */
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ /**
+ * Return the priority of a message when sending.
+ */
+ public int getPriority() {
+ return this.priority;
+ }
+
+ /**
+ * Set the time-to-live of the message when sending.
+ *
Since a default value may be defined administratively,
+ * this is only used when "isExplicitQosEnabled" equals "true".
+ * @param timeToLive the message's lifetime (in milliseconds)
+ * @see #isExplicitQosEnabled
+ * @see javax.jms.Message#DEFAULT_TIME_TO_LIVE
+ * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
+ */
+ public void setTimeToLive(long timeToLive) {
+ this.timeToLive = timeToLive;
+ }
+
+ /**
+ * Return the time-to-live of the message when sending.
+ */
+ public long getTimeToLive() {
+ return this.timeToLive;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JmsOperations execute methods
+ //-------------------------------------------------------------------------
+
+ public Object execute(SessionCallback action) throws JmsException {
+ return execute(action, false);
+ }
+
+ /**
+ * Execute the action specified by the given action object within a
+ * JMS Session. Generalized version of execute(SessionCallback),
+ * allowing the JMS Connection to be started on the fly.
+ *
Use execute(SessionCallback) for the general case.
+ * Starting the JMS Connection is just necessary for receiving messages,
+ * which is preferably achieved through the receive methods.
+ * @param action callback object that exposes the Session
+ * @param startConnection whether to start the Connection
+ * @return the result object from working with the Session
+ * @throws JmsException if there is any problem
+ * @see #execute(SessionCallback)
+ * @see #receive
+ */
+ public Object execute(SessionCallback action, boolean startConnection) throws JmsException {
+ Assert.notNull(action, "Callback object must not be null");
+ Connection conToClose = null;
+ Session sessionToClose = null;
+ try {
+ Session sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
+ getConnectionFactory(), this.transactionalResourceFactory, startConnection);
+ if (sessionToUse == null) {
+ conToClose = createConnection();
+ sessionToClose = createSession(conToClose);
+ if (startConnection) {
+ conToClose.start();
+ }
+ sessionToUse = sessionToClose;
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Executing callback on JMS Session: " + sessionToUse);
+ }
+ return action.doInJms(sessionToUse);
+ }
+ catch (JMSException ex) {
+ throw convertJmsAccessException(ex);
+ }
+ finally {
+ JmsUtils.closeSession(sessionToClose);
+ ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), startConnection);
+ }
+ }
+
+ public Object execute(ProducerCallback action) throws JmsException {
+ String defaultDestinationName = getDefaultDestinationName();
+ if (defaultDestinationName != null) {
+ return execute(defaultDestinationName, action);
+ }
+ else {
+ return execute(getDefaultDestination(), action);
+ }
+ }
+
+ public Object execute(final Destination destination, final ProducerCallback action) throws JmsException {
+ Assert.notNull(action, "Callback object must not be null");
+ return execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ MessageProducer producer = createProducer(session, destination);
+ try {
+ return action.doInJms(session, producer);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(producer);
+ }
+ }
+ }, false);
+ }
+
+ public Object execute(final String destinationName, final ProducerCallback action) throws JmsException {
+ Assert.notNull(action, "Callback object must not be null");
+ return execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ Destination destination = resolveDestinationName(session, destinationName);
+ MessageProducer producer = createProducer(session, destination);
+ try {
+ return action.doInJms(session, producer);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(producer);
+ }
+ }
+ }, false);
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for sending messages
+ //-------------------------------------------------------------------------
+
+ public void send(MessageCreator messageCreator) throws JmsException {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null) {
+ send(defaultDestination, messageCreator);
+ }
+ else {
+ send(getRequiredDefaultDestinationName(), messageCreator);
+ }
+ }
+
+ public void send(final Destination destination, final MessageCreator messageCreator) throws JmsException {
+ execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ doSend(session, destination, messageCreator);
+ return null;
+ }
+ }, false);
+ }
+
+ public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
+ execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ Destination destination = resolveDestinationName(session, destinationName);
+ doSend(session, destination, messageCreator);
+ return null;
+ }
+ }, false);
+ }
+
+ /**
+ * Send the given JMS message.
+ * @param session the JMS Session to operate on
+ * @param destination the JMS Destination to send to
+ * @param messageCreator callback to create a JMS Message
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected void doSend(Session session, Destination destination, MessageCreator messageCreator)
+ throws JMSException {
+
+ Assert.notNull(messageCreator, "MessageCreator must not be null");
+ MessageProducer producer = createProducer(session, destination);
+ try {
+ Message message = messageCreator.createMessage(session);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Sending created message: " + message);
+ }
+ doSend(producer, message);
+ // Check commit - avoid commit call within a JTA transaction.
+ if (session.getTransacted() && isSessionLocallyTransacted(session)) {
+ // Transacted session created by this template -> commit.
+ JmsUtils.commitIfNecessary(session);
+ }
+ }
+ finally {
+ JmsUtils.closeMessageProducer(producer);
+ }
+ }
+
+ /**
+ * Actually send the given JMS message.
+ * @param producer the JMS MessageProducer to send with
+ * @param message the JMS Message to send
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected void doSend(MessageProducer producer, Message message) throws JMSException {
+ if (isExplicitQosEnabled()) {
+ producer.send(message, getDeliveryMode(), getPriority(), getTimeToLive());
+ }
+ else {
+ producer.send(message);
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for sending auto-converted messages
+ //-------------------------------------------------------------------------
+
+ public void convertAndSend(Object message) throws JmsException {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null) {
+ convertAndSend(defaultDestination, message);
+ }
+ else {
+ convertAndSend(getRequiredDefaultDestinationName(), message);
+ }
+ }
+
+ public void convertAndSend(Destination destination, final Object message) throws JmsException {
+ send(destination, new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ return getRequiredMessageConverter().toMessage(message, session);
+ }
+ });
+ }
+
+ public void convertAndSend(String destinationName, final Object message) throws JmsException {
+ send(destinationName, new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ return getRequiredMessageConverter().toMessage(message, session);
+ }
+ });
+ }
+
+ public void convertAndSend(Object message, MessagePostProcessor postProcessor) throws JmsException {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null) {
+ convertAndSend(defaultDestination, message, postProcessor);
+ }
+ else {
+ convertAndSend(getRequiredDefaultDestinationName(), message, postProcessor);
+ }
+ }
+
+ public void convertAndSend(
+ Destination destination, final Object message, final MessagePostProcessor postProcessor)
+ throws JmsException {
+
+ send(destination, new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ Message msg = getRequiredMessageConverter().toMessage(message, session);
+ return postProcessor.postProcessMessage(msg);
+ }
+ });
+ }
+
+ public void convertAndSend(
+ String destinationName, final Object message, final MessagePostProcessor postProcessor)
+ throws JmsException {
+
+ send(destinationName, new MessageCreator() {
+ public Message createMessage(Session session) throws JMSException {
+ Message msg = getRequiredMessageConverter().toMessage(message, session);
+ return postProcessor.postProcessMessage(msg);
+ }
+ });
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for receiving messages
+ //-------------------------------------------------------------------------
+
+ public Message receive() throws JmsException {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null) {
+ return receive(defaultDestination);
+ }
+ else {
+ return receive(getRequiredDefaultDestinationName());
+ }
+ }
+
+ public Message receive(Destination destination) throws JmsException {
+ return receiveSelected(destination, null);
+ }
+
+ public Message receive(String destinationName) throws JmsException {
+ return receiveSelected(destinationName, null);
+ }
+
+ public Message receiveSelected(String messageSelector) throws JmsException {
+ Destination defaultDestination = getDefaultDestination();
+ if (defaultDestination != null) {
+ return receiveSelected(defaultDestination, messageSelector);
+ }
+ else {
+ return receiveSelected(getRequiredDefaultDestinationName(), messageSelector);
+ }
+ }
+
+ public Message receiveSelected(final Destination destination, final String messageSelector) throws JmsException {
+ return (Message) execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ return doReceive(session, destination, messageSelector);
+ }
+ }, true);
+ }
+
+ public Message receiveSelected(final String destinationName, final String messageSelector) throws JmsException {
+ return (Message) execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ Destination destination = resolveDestinationName(session, destinationName);
+ return doReceive(session, destination, messageSelector);
+ }
+ }, true);
+ }
+
+ /**
+ * Receive a JMS message.
+ * @param session the JMS Session to operate on
+ * @param destination the JMS Destination to receive from
+ * @param messageSelector the message selector for this consumer (can be null)
+ * @return the JMS Message received, or null if none
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected Message doReceive(Session session, Destination destination, String messageSelector)
+ throws JMSException {
+
+ return doReceive(session, createConsumer(session, destination, messageSelector));
+ }
+
+ /**
+ * Actually receive a JMS message.
+ * @param session the JMS Session to operate on
+ * @param consumer the JMS MessageConsumer to send with
+ * @return the JMS Message received, or null if none
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected Message doReceive(Session session, MessageConsumer consumer) throws JMSException {
+ try {
+ // Use transaction timeout (if available).
+ long timeout = getReceiveTimeout();
+ JmsResourceHolder resourceHolder =
+ (JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
+ if (resourceHolder != null && resourceHolder.hasTimeout()) {
+ timeout = resourceHolder.getTimeToLiveInMillis();
+ }
+
+ Message message = null;
+ if (timeout == RECEIVE_TIMEOUT_NO_WAIT) {
+ message = consumer.receiveNoWait();
+ }
+ else if (timeout > 0) {
+ message = consumer.receive(timeout);
+ }
+ else {
+ message = consumer.receive();
+ }
+
+ if (session.getTransacted()) {
+ // Commit necessary - but avoid commit call within a JTA transaction.
+ if (isSessionLocallyTransacted(session)) {
+ // Transacted session created by this template -> commit.
+ JmsUtils.commitIfNecessary(session);
+ }
+ }
+ else if (isClientAcknowledge(session)) {
+ // Manually acknowledge message, if any.
+ if (message != null) {
+ message.acknowledge();
+ }
+ }
+ return message;
+ }
+ finally {
+ JmsUtils.closeMessageConsumer(consumer);
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for receiving auto-converted messages
+ //-------------------------------------------------------------------------
+
+ public Object receiveAndConvert() throws JmsException {
+ return doConvertFromMessage(receive());
+ }
+
+ public Object receiveAndConvert(Destination destination) throws JmsException {
+ return doConvertFromMessage(receive(destination));
+ }
+
+ public Object receiveAndConvert(String destinationName) throws JmsException {
+ return doConvertFromMessage(receive(destinationName));
+ }
+
+ public Object receiveSelectedAndConvert(String messageSelector) throws JmsException {
+ return doConvertFromMessage(receiveSelected(messageSelector));
+ }
+
+ public Object receiveSelectedAndConvert(Destination destination, String messageSelector) throws JmsException {
+ return doConvertFromMessage(receiveSelected(destination, messageSelector));
+ }
+
+ public Object receiveSelectedAndConvert(String destinationName, String messageSelector) throws JmsException {
+ return doConvertFromMessage(receiveSelected(destinationName, messageSelector));
+ }
+
+ /**
+ * Extract the content from the given JMS message.
+ * @param message the JMS Message to convert (can be null)
+ * @return the content of the message, or null if none
+ */
+ protected Object doConvertFromMessage(Message message) {
+ if (message != null) {
+ try {
+ return getRequiredMessageConverter().fromMessage(message);
+ }
+ catch (JMSException ex) {
+ throw convertJmsAccessException(ex);
+ }
+ }
+ return null;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for browsing messages
+ //-------------------------------------------------------------------------
+
+ public Object browse(BrowserCallback action) throws JmsException {
+ Queue defaultQueue = getDefaultQueue();
+ if (defaultQueue != null) {
+ return browse(defaultQueue, action);
+ }
+ else {
+ return browse(getRequiredDefaultDestinationName(), action);
+ }
+ }
+
+ public Object browse(Queue queue, BrowserCallback action) throws JmsException {
+ return browseSelected(queue, null, action);
+ }
+
+ public Object browse(String queueName, BrowserCallback action) throws JmsException {
+ return browseSelected(queueName, null, action);
+ }
+
+ public Object browseSelected(String messageSelector, BrowserCallback action) throws JmsException {
+ Queue defaultQueue = getDefaultQueue();
+ if (defaultQueue != null) {
+ return browseSelected(defaultQueue, messageSelector, action);
+ }
+ else {
+ return browseSelected(getRequiredDefaultDestinationName(), messageSelector, action);
+ }
+ }
+
+ public Object browseSelected(final Queue queue, final String messageSelector, final BrowserCallback action)
+ throws JmsException {
+
+ Assert.notNull(action, "Callback object must not be null");
+ return execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ QueueBrowser browser = createBrowser(session, queue, messageSelector);
+ try {
+ return action.doInJms(session, browser);
+ }
+ finally {
+ JmsUtils.closeQueueBrowser(browser);
+ }
+ }
+ }, true);
+ }
+
+ public Object browseSelected(final String queueName, final String messageSelector, final BrowserCallback action)
+ throws JmsException {
+
+ Assert.notNull(action, "Callback object must not be null");
+ return execute(new SessionCallback() {
+ public Object doInJms(Session session) throws JMSException {
+ Queue queue = (Queue) getDestinationResolver().resolveDestinationName(session, queueName, false);
+ QueueBrowser browser = createBrowser(session, queue, messageSelector);
+ try {
+ return action.doInJms(session, browser);
+ }
+ finally {
+ JmsUtils.closeQueueBrowser(browser);
+ }
+ }
+ }, true);
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Fetch an appropriate Connection from the given JmsResourceHolder.
+ *
This implementation accepts any JMS 1.1 Connection.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Connection fetched from the holder,
+ * or null if none found
+ */
+ protected Connection getConnection(JmsResourceHolder holder) {
+ return holder.getConnection();
+ }
+
+ /**
+ * Fetch an appropriate Session from the given JmsResourceHolder.
+ *
This implementation accepts any JMS 1.1 Session.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Session fetched from the holder,
+ * or null if none found
+ */
+ protected Session getSession(JmsResourceHolder holder) {
+ return holder.getSession();
+ }
+
+ /**
+ * Check whether the given Session is locally transacted, that is, whether
+ * its transaction is managed by this listener container's Session handling
+ * and not by an external transaction coordinator.
+ *
Note: The Session's own transacted flag will already have been checked
+ * before. This method is about finding out whether the Session's transaction
+ * is local or externally coordinated.
+ * @param session the Session to check
+ * @return whether the given Session is locally transacted
+ * @see #isSessionTransacted()
+ * @see org.springframework.jms.connection.ConnectionFactoryUtils#isSessionTransactional
+ */
+ protected boolean isSessionLocallyTransacted(Session session) {
+ return isSessionTransacted() &&
+ !ConnectionFactoryUtils.isSessionTransactional(session, getConnectionFactory());
+ }
+
+ /**
+ * Create a JMS MessageProducer for the given Session and Destination,
+ * configuring it to disable message ids and/or timestamps (if necessary).
+ *
Delegates to {@link #doCreateProducer} for creation of the raw
+ * JMS MessageProducer, which needs to be specific to JMS 1.1 or 1.0.2.
+ * @param session the JMS Session to create a MessageProducer for
+ * @param destination the JMS Destination to create a MessageProducer for
+ * @return the new JMS MessageProducer
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setMessageIdEnabled
+ * @see #setMessageTimestampEnabled
+ */
+ protected MessageProducer createProducer(Session session, Destination destination) throws JMSException {
+ MessageProducer producer = doCreateProducer(session, destination);
+ if (!isMessageIdEnabled()) {
+ producer.setDisableMessageID(true);
+ }
+ if (!isMessageTimestampEnabled()) {
+ producer.setDisableMessageTimestamp(true);
+ }
+ return producer;
+ }
+
+ /**
+ * Create a raw JMS MessageProducer for the given Session and Destination.
+ *
This implementation uses JMS 1.1 API.
+ * @param session the JMS Session to create a MessageProducer for
+ * @param destination the JMS Destination to create a MessageProducer for
+ * @return the new JMS MessageProducer
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected MessageProducer doCreateProducer(Session session, Destination destination) throws JMSException {
+ return session.createProducer(destination);
+ }
+
+ /**
+ * Create a JMS MessageConsumer for the given Session and Destination.
+ *
This implementation uses JMS 1.1 API.
+ * @param session the JMS Session to create a MessageConsumer for
+ * @param destination the JMS Destination to create a MessageConsumer for
+ * @param messageSelector the message selector for this consumer (can be null)
+ * @return the new JMS MessageConsumer
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination, String messageSelector)
+ throws JMSException {
+
+ // Only pass in the NoLocal flag in case of a Topic:
+ // Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
+ // in case of the NoLocal flag being specified for a Queue.
+ if (isPubSubDomain()) {
+ return session.createConsumer(destination, messageSelector, isPubSubNoLocal());
+ }
+ else {
+ return session.createConsumer(destination, messageSelector);
+ }
+ }
+
+ /**
+ * Create a JMS MessageProducer for the given Session and Destination,
+ * configuring it to disable message ids and/or timestamps (if necessary).
+ *
Delegates to {@link #doCreateProducer} for creation of the raw
+ * JMS MessageProducer, which needs to be specific to JMS 1.1 or 1.0.2.
+ * @param session the JMS Session to create a QueueBrowser for
+ * @param queue the JMS Queue to create a QueueBrowser for
+ * @param messageSelector the message selector for this consumer (can be null)
+ * @return the new JMS QueueBrowser
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setMessageIdEnabled
+ * @see #setMessageTimestampEnabled
+ */
+ protected QueueBrowser createBrowser(Session session, Queue queue, String messageSelector)
+ throws JMSException {
+
+ return session.createBrowser(queue, messageSelector);
+ }
+
+
+ /**
+ * ResourceFactory implementation that delegates to this template's protected callback methods.
+ */
+ private class JmsTemplateResourceFactory implements ConnectionFactoryUtils.ResourceFactory {
+
+ public Connection getConnection(JmsResourceHolder holder) {
+ return JmsTemplate.this.getConnection(holder);
+ }
+
+ public Session getSession(JmsResourceHolder holder) {
+ return JmsTemplate.this.getSession(holder);
+ }
+
+ public Connection createConnection() throws JMSException {
+ return JmsTemplate.this.createConnection();
+ }
+
+ public Session createSession(Connection con) throws JMSException {
+ return JmsTemplate.this.createSession(con);
+ }
+
+ public boolean isSynchedLocalTransactionAllowed() {
+ return JmsTemplate.this.isSessionTransacted();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/JmsTemplate102.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2002-2008 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.jms.core;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import org.springframework.jms.connection.JmsResourceHolder;
+import org.springframework.jms.support.converter.SimpleMessageConverter102;
+
+/**
+ * A subclass of {@link JmsTemplate} for the JMS 1.0.2 specification, not relying
+ * on JMS 1.1 methods like JmsTemplate itself. This class can be used for JMS
+ * 1.0.2 providers, offering the same API as JmsTemplate does for JMS 1.1 providers.
+ *
+ *
You must specify the domain (or style) of messaging to be either
+ * Point-to-Point (Queues) or Publish/Subscribe (Topics), using the
+ * {@link #setPubSubDomain "pubSubDomain" property}.
+ * Point-to-Point (Queues) is the default domain.
+ *
+ *
The "pubSubDomain" property is an important setting due to the use of similar
+ * but separate class hierarchies in the JMS 1.0.2 API. JMS 1.1 provides a new
+ * domain-independent API that allows for easy mix-and-match use of Point-to-Point
+ * and Publish/Subscribe styles.
+ *
+ *
This template uses a
+ * {@link org.springframework.jms.support.destination.DynamicDestinationResolver}
+ * and a {@link org.springframework.jms.support.converter.SimpleMessageConverter102}
+ * as default strategies for resolving a destination name and converting a message,
+ * respectively.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setConnectionFactory
+ * @see #setPubSubDomain
+ * @see javax.jms.Queue
+ * @see javax.jms.Topic
+ * @see javax.jms.QueueSession
+ * @see javax.jms.TopicSession
+ * @see javax.jms.QueueSender
+ * @see javax.jms.TopicPublisher
+ * @see javax.jms.QueueReceiver
+ * @see javax.jms.TopicSubscriber
+ */
+public class JmsTemplate102 extends JmsTemplate {
+
+ /**
+ * Create a new JmsTemplate102 for bean-style usage.
+ *
Note: The ConnectionFactory has to be set before using the instance.
+ * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
+ * typically setting the ConnectionFactory via setConnectionFactory.
+ * @see #setConnectionFactory
+ */
+ public JmsTemplate102() {
+ super();
+ }
+
+ /**
+ * Create a new JmsTemplate102, given a ConnectionFactory.
+ * @param connectionFactory the ConnectionFactory to obtain Connections from
+ * @param pubSubDomain whether the Publish/Subscribe domain (Topics) or
+ * Point-to-Point domain (Queues) should be used
+ * @see #setPubSubDomain
+ */
+ public JmsTemplate102(ConnectionFactory connectionFactory, boolean pubSubDomain) {
+ this();
+ setConnectionFactory(connectionFactory);
+ setPubSubDomain(pubSubDomain);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Initialize the default implementations for the template's strategies:
+ * DynamicDestinationResolver and SimpleMessageConverter102.
+ * @see #setDestinationResolver
+ * @see #setMessageConverter
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter102
+ */
+ protected void initDefaultStrategies() {
+ setMessageConverter(new SimpleMessageConverter102());
+ }
+
+ /**
+ * In addition to checking if the connection factory is set, make sure
+ * that the supplied connection factory is of the appropriate type for
+ * the specified destination type: QueueConnectionFactory for queues,
+ * and TopicConnectionFactory for topics.
+ */
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+
+ // Make sure that the ConnectionFactory passed is consistent.
+ // Some provider implementations of the ConnectionFactory interface
+ // implement both domain interfaces under the cover, so just check if
+ // the selected domain is consistent with the type of connection factory.
+ if (isPubSubDomain()) {
+ if (!(getConnectionFactory() instanceof TopicConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 template for topics " +
+ "but did not supply an instance of TopicConnectionFactory");
+ }
+ }
+ else {
+ if (!(getConnectionFactory() instanceof QueueConnectionFactory)) {
+ throw new IllegalArgumentException(
+ "Specified a Spring JMS 1.0.2 template for queues " +
+ "but did not supply an instance of QueueConnectionFactory");
+ }
+ }
+ }
+
+
+ /**
+ * This implementation overrides the superclass method to accept either
+ * a QueueConnection or a TopicConnection, depending on the domain.
+ */
+ protected Connection getConnection(JmsResourceHolder holder) {
+ return holder.getConnection(isPubSubDomain() ? (Class) TopicConnection.class : QueueConnection.class);
+ }
+
+ /**
+ * This implementation overrides the superclass method to accept either
+ * a QueueSession or a TopicSession, depending on the domain.
+ */
+ protected Session getSession(JmsResourceHolder holder) {
+ return holder.getSession(isPubSubDomain() ? (Class) TopicSession.class : QueueSession.class);
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection createConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ else {
+ return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected MessageProducer doCreateProducer(Session session, Destination destination) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicSession) session).createPublisher((Topic) destination);
+ }
+ else {
+ return ((QueueSession) session).createSender((Queue) destination);
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination, String messageSelector)
+ throws JMSException {
+
+ if (isPubSubDomain()) {
+ return ((TopicSession) session).createSubscriber((Topic) destination, messageSelector, isPubSubNoLocal());
+ }
+ else {
+ return ((QueueSession) session).createReceiver((Queue) destination, messageSelector);
+ }
+ }
+
+ protected QueueBrowser createBrowser(Session session, Queue queue, String messageSelector)
+ throws JMSException {
+
+ if (isPubSubDomain()) {
+ throw new javax.jms.IllegalStateException("Cannot create QueueBrowser for a TopicSession");
+ }
+ else {
+ return ((QueueSession) session).createBrowser(queue, messageSelector);
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected void doSend(MessageProducer producer, Message message) throws JMSException {
+ if (isPubSubDomain()) {
+ if (isExplicitQosEnabled()) {
+ ((TopicPublisher) producer).publish(message, getDeliveryMode(), getPriority(), getTimeToLive());
+ }
+ else {
+ ((TopicPublisher) producer).publish(message);
+ }
+ }
+ else {
+ if (isExplicitQosEnabled()) {
+ ((QueueSender) producer).send(message, getDeliveryMode(), getPriority(), getTimeToLive());
+ }
+ else {
+ ((QueueSender) producer).send(message);
+ }
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to avoid using
+ * JMS 1.1's Session getAcknowledgeMode() method.
+ * The best we can do here is to check the setting on the template.
+ * @see #getSessionAcknowledgeMode()
+ */
+ protected boolean isClientAcknowledge(Session session) throws JMSException {
+ return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/MessageCreator.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/MessageCreator.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/MessageCreator.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2005 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.jms.core;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+/**
+ * Creates a JMS message given a {@link Session}.
+ *
+ *
The Session typically is provided by an instance
+ * of the {@link JmsTemplate} class.
+ *
+ *
Implementations do not need to concern themselves with
+ * checked JMSExceptions (from the 'javax.jms'
+ * package) that may be thrown from operations they attempt. The
+ * JmsTemplate will catch and handle these
+ * JMSExceptions appropriately.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ */
+public interface MessageCreator {
+
+ /**
+ * Create a {@link Message} to be sent.
+ * @param session the JMS {@link Session} to be used to create the
+ * Message (never null)
+ * @return the Message to be sent
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ Message createMessage(Session session) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/MessagePostProcessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/MessagePostProcessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/MessagePostProcessor.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2005 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.jms.core;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+/**
+ * To be used with JmsTemplate's send method that convert an object to a message.
+ * It allows for further modification of the message after it has been processed
+ * by the converter. This is useful for setting of JMS Header and Properties.
+ *
+ *
This often as an anonymous class within a method implementation.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see JmsTemplate#convertAndSend(String, Object, MessagePostProcessor)
+ * @see JmsTemplate#convertAndSend(javax.jms.Destination, Object, MessagePostProcessor)
+ * @see org.springframework.jms.support.converter.MessageConverter
+ */
+public interface MessagePostProcessor {
+
+ /**
+ * Apply a MessagePostProcessor to the message. The returned message is
+ * typically a modified version of the original.
+ * @param message the JMS message from the MessageConverter
+ * @return the modified version of the Message
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ Message postProcessMessage(Message message) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/ProducerCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/ProducerCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/ProducerCallback.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2008 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.jms.core;
+
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * Callback for sending a message to a JMS destination.
+ *
+ *
To be used with JmsTemplate's callback methods that take a ProducerCallback
+ * argument, often implemented as an anonymous inner class.
+ *
+ *
The typical implementation will perform multiple operations on the
+ * supplied JMS {@link Session} and {@link MessageProducer}. When used with
+ * a 1.0.2 provider, you need to downcast to the appropriate domain
+ * implementation, either {@link javax.jms.QueueSender} or
+ * {@link javax.jms.TopicPublisher}, to actually send a message.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see JmsTemplate#execute(ProducerCallback)
+ * @see JmsTemplate#execute(javax.jms.Destination, ProducerCallback)
+ * @see JmsTemplate#execute(String, ProducerCallback)
+ */
+public interface ProducerCallback {
+
+ /**
+ * Perform operations on the given {@link Session} and {@link MessageProducer}.
+ *
The message producer is not associated with any destination unless
+ * when specified in the JmsTemplate call.
+ * @param session the JMS Session object to use
+ * @param producer the JMS MessageProducer object to use
+ * @return a result object from working with the Session, if any (can be null)
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ Object doInJms(Session session, MessageProducer producer) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/SessionCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/SessionCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/SessionCallback.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2002-2005 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.jms.core;
+
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+/**
+ * Callback for executing any number of operations on a provided
+ * {@link Session}.
+ *
+ *
To be used with the {@link JmsTemplate#execute(SessionCallback)}
+ * method, often implemented as an anonymous inner class.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see JmsTemplate#execute(SessionCallback)
+ */
+public interface SessionCallback {
+
+ /**
+ * Execute any number of operations against the supplied JMS
+ * {@link Session}, possibly returning a result.
+ * @param session the JMS Session
+ * @return a result object from working with the Session, if any (so can be null)
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ Object doInJms(Session session) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/package.html 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Core package of the JMS support.
+Provides a JmsTemplate class and various callback interfaces.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/core/support/JmsGatewaySupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/support/JmsGatewaySupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/support/JmsGatewaySupport.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2002-2005 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.jms.core.support;
+
+import javax.jms.ConnectionFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jms.core.JmsTemplate;
+
+/**
+ * Convenient super class for application classes that need JMS access.
+ *
+ *
Requires a ConnectionFactory or a JmsTemplate instance to be set.
+ * It will create its own JmsTemplate if a ConnectionFactory is passed in.
+ * A custom JmsTemplate instance can be created for a given ConnectionFactory
+ * through overriding the createJmsTemplate method.
+ *
+ * @author Mark Pollack
+ * @since 1.1.1
+ * @see #setConnectionFactory
+ * @see #setJmsTemplate
+ * @see #createJmsTemplate
+ * @see org.springframework.jms.core.JmsTemplate
+ */
+public abstract class JmsGatewaySupport implements InitializingBean {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private JmsTemplate jmsTemplate;
+
+
+ /**
+ * Set the JMS connection factory to be used by the gateway.
+ * Will automatically create a JmsTemplate for the given ConnectionFactory.
+ * @see #createJmsTemplate
+ * @see #setConnectionFactory(javax.jms.ConnectionFactory)
+ * @param connectionFactory
+ */
+ public final void setConnectionFactory(ConnectionFactory connectionFactory) {
+ this.jmsTemplate = createJmsTemplate(connectionFactory);
+ }
+
+ /**
+ * Create a JmsTemplate for the given ConnectionFactory.
+ * Only invoked if populating the gateway with a ConnectionFactory reference.
+ *
Can be overridden in subclasses to provide a JmsTemplate instance with
+ * a different configuration or the JMS 1.0.2 version, JmsTemplate102.
+ * @param connectionFactory the JMS ConnectionFactory to create a JmsTemplate for
+ * @return the new JmsTemplate instance
+ * @see #setConnectionFactory
+ * @see org.springframework.jms.core.JmsTemplate102
+ */
+ protected JmsTemplate createJmsTemplate(ConnectionFactory connectionFactory) {
+ return new JmsTemplate(connectionFactory);
+ }
+
+ /**
+ * Return the JMS ConnectionFactory used by the gateway.
+ */
+ public final ConnectionFactory getConnectionFactory() {
+ return (this.jmsTemplate != null ? this.jmsTemplate.getConnectionFactory() : null);
+ }
+
+ /**
+ * Set the JmsTemplate for the gateway.
+ * @param jmsTemplate
+ * @see #setConnectionFactory(javax.jms.ConnectionFactory)
+ */
+ public final void setJmsTemplate(JmsTemplate jmsTemplate) {
+ this.jmsTemplate = jmsTemplate;
+ }
+
+ /**
+ * Return the JmsTemplate for the gateway.
+ */
+ public final JmsTemplate getJmsTemplate() {
+ return jmsTemplate;
+ }
+
+ public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
+ if (this.jmsTemplate == null) {
+ throw new IllegalArgumentException("connectionFactory or jmsTemplate is required");
+ }
+ try {
+ initGateway();
+ }
+ catch (Exception ex) {
+ throw new BeanInitializationException("Initialization of JMS gateway failed: " + ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * Subclasses can override this for custom initialization behavior.
+ * Gets called after population of this instance's bean properties.
+ * @throws java.lang.Exception if initialization fails
+ */
+ protected void initGateway() throws Exception {
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/core/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/core/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/core/support/package.html 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Classes supporting the org.springframework.jms.core package.
+Contains a base class for JmsTemplate usage.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/listener/AbstractJmsListeningContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/AbstractJmsListeningContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/AbstractJmsListeningContainer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,609 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.Lifecycle;
+import org.springframework.jms.JmsException;
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.destination.JmsDestinationAccessor;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Common base class for all containers which need to implement listening
+ * based on a JMS Connection (either shared or freshly obtained for each attempt).
+ * Inherits basic Connection and Session configuration handling from the
+ * {@link org.springframework.jms.support.JmsAccessor} base class.
+ *
+ *
This class provides basic lifecycle management, in particular management
+ * of a shared JMS Connection. Subclasses are supposed to plug into this
+ * lifecycle, implementing the {@link #sharedConnectionEnabled()} as well
+ * as the {@link #doInitialize()} and {@link #doShutdown()} template methods.
+ *
+ *
This base class does not assume any specific listener programming model
+ * or listener invoker mechanism. It just provides the general runtime
+ * lifecycle management needed for any kind of JMS-based listening mechanism
+ * that operates on a JMS Connection/Session.
+ *
+ *
For a concrete listener programming model, check out the
+ * {@link AbstractMessageListenerContainer} subclass. For a concrete listener
+ * invoker mechanism, check out the {@link DefaultMessageListenerContainer} class.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.3
+ * @see #sharedConnectionEnabled()
+ * @see #doInitialize()
+ * @see #doShutdown()
+ */
+public abstract class AbstractJmsListeningContainer extends JmsDestinationAccessor
+ implements Lifecycle, BeanNameAware, DisposableBean {
+
+ private String clientId;
+
+ private boolean autoStartup = true;
+
+ private String beanName;
+
+ private Connection sharedConnection;
+
+ private boolean sharedConnectionStarted = false;
+
+ protected final Object sharedConnectionMonitor = new Object();
+
+ private boolean active = false;
+
+ private boolean running = false;
+
+ private final List pausedTasks = new LinkedList();
+
+ protected final Object lifecycleMonitor = new Object();
+
+
+ /**
+ * Specify the JMS client id for a shared Connection created and used
+ * by this container.
+ *
Note that client ids need to be unique among all active Connections
+ * of the underlying JMS provider. Furthermore, a client id can only be
+ * assigned if the original ConnectionFactory hasn't already assigned one.
+ * @see javax.jms.Connection#setClientID
+ * @see #setConnectionFactory
+ */
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ /**
+ * Return the JMS client ID for the shared Connection created and used
+ * by this container, if any.
+ */
+ public String getClientId() {
+ return this.clientId;
+ }
+
+ /**
+ * Set whether to automatically start the container after initialization.
+ *
Default is "true"; set this to "false" to allow for manual startup
+ * through the {@link #start()} method.
+ */
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
+ }
+
+ public void setBeanName(String beanName) {
+ this.beanName = beanName;
+ }
+
+ /**
+ * Return the bean name that this listener container has been assigned
+ * in its containing bean factory, if any.
+ */
+ protected final String getBeanName() {
+ return this.beanName;
+ }
+
+
+ /**
+ * Delegates to {@link #validateConfiguration()} and {@link #initialize()}.
+ */
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+ validateConfiguration();
+ initialize();
+ }
+
+ /**
+ * Validate the configuration of this container.
+ *
The default implementation is empty. To be overridden in subclasses.
+ */
+ protected void validateConfiguration() {
+ }
+
+ /**
+ * Calls {@link #shutdown()} when the BeanFactory destroys the container instance.
+ * @see #shutdown()
+ */
+ public void destroy() {
+ shutdown();
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Lifecycle methods for starting and stopping the container
+ //-------------------------------------------------------------------------
+
+ /**
+ * Initialize this container.
+ *
Creates a JMS Connection, starts the {@link javax.jms.Connection}
+ * (if {@link #setAutoStartup(boolean) "autoStartup"} hasn't been turned off),
+ * and calls {@link #doInitialize()}.
+ * @throws org.springframework.jms.JmsException if startup failed
+ */
+ public void initialize() throws JmsException {
+ try {
+ synchronized (this.lifecycleMonitor) {
+ this.active = true;
+ this.lifecycleMonitor.notifyAll();
+ }
+ if (this.autoStartup) {
+ doStart();
+ }
+ doInitialize();
+ }
+ catch (JMSException ex) {
+ synchronized (this.sharedConnectionMonitor) {
+ ConnectionFactoryUtils.releaseConnection(this.sharedConnection, getConnectionFactory(), this.autoStartup);
+ this.sharedConnection = null;
+ }
+ throw convertJmsAccessException(ex);
+ }
+ }
+
+ /**
+ * Stop the shared Connection, call {@link #doShutdown()},
+ * and close this container.
+ * @throws JmsException if shutdown failed
+ */
+ public void shutdown() throws JmsException {
+ logger.debug("Shutting down JMS listener container");
+ boolean wasRunning = false;
+ synchronized (this.lifecycleMonitor) {
+ wasRunning = this.running;
+ this.running = false;
+ this.active = false;
+ this.lifecycleMonitor.notifyAll();
+ }
+
+ // Stop shared Connection early, if necessary.
+ if (wasRunning && sharedConnectionEnabled()) {
+ try {
+ stopSharedConnection();
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not stop JMS Connection on shutdown", ex);
+ }
+ }
+
+ // Shut down the invokers.
+ try {
+ doShutdown();
+ }
+ catch (JMSException ex) {
+ throw convertJmsAccessException(ex);
+ }
+ finally {
+ if (sharedConnectionEnabled()) {
+ synchronized (this.sharedConnectionMonitor) {
+ ConnectionFactoryUtils.releaseConnection(this.sharedConnection, getConnectionFactory(), false);
+ this.sharedConnection = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Return whether this container is currently active,
+ * that is, whether it has been set up but not shut down yet.
+ */
+ public final boolean isActive() {
+ synchronized (this.lifecycleMonitor) {
+ return this.active;
+ }
+ }
+
+ /**
+ * Start this container.
+ * @throws JmsException if starting failed
+ * @see #doStart
+ */
+ public void start() throws JmsException {
+ try {
+ doStart();
+ }
+ catch (JMSException ex) {
+ throw convertJmsAccessException(ex);
+ }
+ }
+
+ /**
+ * Start the shared Connection, if any, and notify all invoker tasks.
+ * @throws JMSException if thrown by JMS API methods
+ * @see #startSharedConnection
+ */
+ protected void doStart() throws JMSException {
+ // Lazily establish a shared Connection, if necessary.
+ if (sharedConnectionEnabled()) {
+ establishSharedConnection();
+ }
+
+ // Reschedule paused tasks, if any.
+ synchronized (this.lifecycleMonitor) {
+ this.running = true;
+ this.lifecycleMonitor.notifyAll();
+ resumePausedTasks();
+ }
+
+ // Start the shared Connection, if any.
+ if (sharedConnectionEnabled()) {
+ startSharedConnection();
+ }
+ }
+
+ /**
+ * Stop this container.
+ * @throws JmsException if stopping failed
+ * @see #doStop
+ */
+ public void stop() throws JmsException {
+ try {
+ doStop();
+ }
+ catch (JMSException ex) {
+ throw convertJmsAccessException(ex);
+ }
+ }
+
+ /**
+ * Notify all invoker tasks and stop the shared Connection, if any.
+ * @throws JMSException if thrown by JMS API methods
+ * @see #stopSharedConnection
+ */
+ protected void doStop() throws JMSException {
+ synchronized (this.lifecycleMonitor) {
+ this.running = false;
+ this.lifecycleMonitor.notifyAll();
+ }
+
+ if (sharedConnectionEnabled()) {
+ stopSharedConnection();
+ }
+ }
+
+ /**
+ * Determine whether this container is currently running,
+ * that is, whether it has been started and not stopped yet.
+ * @see #start()
+ * @see #stop()
+ * @see #runningAllowed()
+ */
+ public final boolean isRunning() {
+ synchronized (this.lifecycleMonitor) {
+ return (this.running && runningAllowed());
+ }
+ }
+
+ /**
+ * Check whether this container's listeners are generally allowed to run.
+ *
This implementation always returns true; the default 'running'
+ * state is purely determined by {@link #start()} / {@link #stop()}.
+ *
Subclasses may override this method to check against temporary
+ * conditions that prevent listeners from actually running. In other words,
+ * they may apply further restrictions to the 'running' state, returning
+ * false if such a restriction prevents listeners from running.
+ */
+ protected boolean runningAllowed() {
+ return true;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Management of a shared JMS Connection
+ //-------------------------------------------------------------------------
+
+ /**
+ * Establish a shared Connection for this container.
+ *
The default implementation delegates to {@link #createSharedConnection()},
+ * which does one immediate attempt and throws an exception if it fails.
+ * Can be overridden to have a recovery process in place, retrying
+ * until a Connection can be successfully established.
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected void establishSharedConnection() throws JMSException {
+ synchronized (this.sharedConnectionMonitor) {
+ if (this.sharedConnection == null) {
+ this.sharedConnection = createSharedConnection();
+ logger.debug("Established shared JMS Connection");
+ }
+ }
+ }
+
+ /**
+ * Refresh the shared Connection that this container holds.
+ *
Called on startup and also after an infrastructure exception
+ * that occurred during invoker setup and/or execution.
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected final void refreshSharedConnection() throws JMSException {
+ synchronized (this.sharedConnectionMonitor) {
+ ConnectionFactoryUtils.releaseConnection(
+ this.sharedConnection, getConnectionFactory(), this.sharedConnectionStarted);
+ this.sharedConnection = null;
+ this.sharedConnection = createSharedConnection();
+ if (this.sharedConnectionStarted) {
+ this.sharedConnection.start();
+ }
+ }
+ }
+
+ /**
+ * Create a shared Connection for this container.
+ *
The default implementation creates a standard Connection
+ * and prepares it through {@link #prepareSharedConnection}.
+ * @return the prepared Connection
+ * @throws JMSException if the creation failed
+ */
+ protected Connection createSharedConnection() throws JMSException {
+ Connection con = createConnection();
+ try {
+ prepareSharedConnection(con);
+ return con;
+ }
+ catch (JMSException ex) {
+ JmsUtils.closeConnection(con);
+ throw ex;
+ }
+ }
+
+ /**
+ * Prepare the given Connection, which is about to be registered
+ * as shared Connection for this container.
+ *
The default implementation sets the specified client id, if any.
+ * Subclasses can override this to apply further settings.
+ * @param connection the Connection to prepare
+ * @throws JMSException if the preparation efforts failed
+ * @see #getClientId()
+ */
+ protected void prepareSharedConnection(Connection connection) throws JMSException {
+ String clientId = getClientId();
+ if (clientId != null) {
+ connection.setClientID(clientId);
+ }
+ }
+
+ /**
+ * Start the shared Connection.
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.Connection#start()
+ */
+ protected void startSharedConnection() throws JMSException {
+ synchronized (this.sharedConnectionMonitor) {
+ this.sharedConnectionStarted = true;
+ if (this.sharedConnection != null) {
+ try {
+ this.sharedConnection.start();
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ logger.debug("Ignoring Connection start exception - assuming already started: " + ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Stop the shared Connection.
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.Connection#start()
+ */
+ protected void stopSharedConnection() throws JMSException {
+ synchronized (this.sharedConnectionMonitor) {
+ this.sharedConnectionStarted = false;
+ if (this.sharedConnection != null) {
+ try {
+ this.sharedConnection.stop();
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ logger.debug("Ignoring Connection stop exception - assuming already stopped: " + ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the shared JMS Connection maintained by this container.
+ * Available after initialization.
+ * @return the shared Connection (never null)
+ * @throws IllegalStateException if this container does not maintain a
+ * shared Connection, or if the Connection hasn't been initialized yet
+ * @see #sharedConnectionEnabled()
+ */
+ protected final Connection getSharedConnection() {
+ if (!sharedConnectionEnabled()) {
+ throw new IllegalStateException(
+ "This listener container does not maintain a shared Connection");
+ }
+ synchronized (this.sharedConnectionMonitor) {
+ if (this.sharedConnection == null) {
+ throw new SharedConnectionNotInitializedException(
+ "This listener container's shared Connection has not been initialized yet");
+ }
+ return this.sharedConnection;
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Management of paused tasks
+ //-------------------------------------------------------------------------
+
+ /**
+ * Take the given task object and reschedule it, either immediately if
+ * this container is currently running, or later once this container
+ * has been restarted.
+ *
If this container has already been shut down, the task will not
+ * get rescheduled at all.
+ * @param task the task object to reschedule
+ * @return whether the task has been rescheduled
+ * (either immediately or for a restart of this container)
+ * @see #doRescheduleTask
+ */
+ protected final boolean rescheduleTaskIfNecessary(Object task) {
+ if (this.running) {
+ try {
+ doRescheduleTask(task);
+ }
+ catch (RuntimeException ex) {
+ logRejectedTask(task, ex);
+ this.pausedTasks.add(task);
+ }
+ return true;
+ }
+ else if (this.active) {
+ this.pausedTasks.add(task);
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ /**
+ * Try to resume all paused tasks.
+ * Tasks for which rescheduling failed simply remain in paused mode.
+ */
+ protected void resumePausedTasks() {
+ synchronized (this.lifecycleMonitor) {
+ if (!this.pausedTasks.isEmpty()) {
+ for (Iterator it = this.pausedTasks.iterator(); it.hasNext();) {
+ Object task = it.next();
+ try {
+ doRescheduleTask(task);
+ it.remove();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Resumed paused task: " + task);
+ }
+ }
+ catch (RuntimeException ex) {
+ logRejectedTask(task, ex);
+ // Keep the task in paused mode...
+ }
+ }
+ }
+ }
+ }
+
+ public int getPausedTaskCount() {
+ synchronized (this.lifecycleMonitor) {
+ return this.pausedTasks.size();
+ }
+ }
+
+ /**
+ * Reschedule the given task object immediately.
+ *
To be implemented by subclasses if they ever call
+ * rescheduleTaskIfNecessary.
+ * This implementation throws an UnsupportedOperationException.
+ * @param task the task object to reschedule
+ * @see #rescheduleTaskIfNecessary
+ */
+ protected void doRescheduleTask(Object task) {
+ throw new UnsupportedOperationException(
+ ClassUtils.getShortName(getClass()) + " does not support rescheduling of tasks");
+ }
+
+ /**
+ * Log a task that has been rejected by {@link #doRescheduleTask}.
+ *
The default implementation simply logs a corresponding message
+ * at debug level.
+ * @param task the rejected task object
+ * @param ex the exception thrown from {@link #doRescheduleTask}
+ */
+ protected void logRejectedTask(Object task, RuntimeException ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Listener container task [" + task + "] has been rejected and paused: " + ex);
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Template methods to be implemented by subclasses
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return whether a shared JMS Connection should be maintained
+ * by this container base class.
+ * @see #getSharedConnection()
+ */
+ protected abstract boolean sharedConnectionEnabled();
+
+ /**
+ * Register any invokers within this container.
+ *
Subclasses need to implement this method for their specific
+ * invoker management process.
+ *
A shared JMS Connection, if any, will already have been
+ * started at this point.
+ * @throws JMSException if registration failed
+ * @see #getSharedConnection()
+ */
+ protected abstract void doInitialize() throws JMSException;
+
+ /**
+ * Close the registered invokers.
+ *
Subclasses need to implement this method for their specific
+ * invoker management process.
+ *
A shared JMS Connection, if any, will automatically be closed
+ * afterwards.
+ * @throws JMSException if shutdown failed
+ * @see #shutdown()
+ */
+ protected abstract void doShutdown() throws JMSException;
+
+
+ /**
+ * Exception that indicates that the initial setup of this container's
+ * shared JMS Connection failed. This is indicating to invokers that they need
+ * to establish the shared Connection themselves on first access.
+ */
+ public static class SharedConnectionNotInitializedException extends RuntimeException {
+
+ /**
+ * Create a new SharedConnectionNotInitializedException.
+ * @param msg the detail message
+ */
+ protected SharedConnectionNotInitializedException(String msg) {
+ super(msg);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/AbstractMessageListenerContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/AbstractMessageListenerContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/AbstractMessageListenerContainer.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,676 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.util.Assert;
+
+/**
+ * Abstract base class for message listener containers. Can either host
+ * a standard JMS {@link javax.jms.MessageListener} or a Spring-specific
+ * {@link SessionAwareMessageListener}.
+ *
+ *
Usually holds a single JMS {@link Connection} that all listeners are
+ * supposed to be registered on, which is the standard JMS way of managing
+ * listeners. Can alternatively also be used with a fresh Connection per
+ * listener, for J2EE-style XA-aware JMS messaging. The actual registration
+ * process is up to concrete subclasses.
+ *
+ *
NOTE: The default behavior of this message listener container
+ * is to never propagate an exception thrown by a message listener up to
+ * the JMS provider. Instead, it will log any such exception at the error level.
+ * This means that from the perspective of the attendant JMS provider no such
+ * listener will ever fail.
+ *
+ *
The listener container offers the following message acknowledgment options:
+ *
+ *
"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
+ * Automatic message acknowledgment before listener execution;
+ * no redelivery in case of exception thrown.
+ *
"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE":
+ * Automatic message acknowledgment after successful listener execution;
+ * no redelivery in case of exception thrown.
+ *
"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE":
+ * Lazy message acknowledgment during or after listener execution;
+ * potential redelivery in case of exception thrown.
+ *
"sessionTransacted" set to "true":
+ * Transactional acknowledgment after successful listener execution;
+ * guaranteed redelivery in case of exception thrown.
+ *
+ * The exact behavior might vary according to the concrete listener container
+ * and JMS provider used.
+ *
+ *
There are two solutions to the duplicate processing problem:
+ *
+ *
Either add duplicate message detection to your listener, in the
+ * form of a business entity existence check or a protocol table check. This
+ * usually just needs to be done in case of the JMSRedelivered flag being
+ * set on the incoming message (else just process straightforwardly).
+ *
Or wrap the entire processing with an XA transaction, covering the
+ * reception of the message as well as the execution of the message listener.
+ * This is only supported by {@link DefaultMessageListenerContainer}, through
+ * specifying a "transactionManager" (typically a
+ * {@link org.springframework.transaction.jta.JtaTransactionManager}, with
+ * a corresponding XA-aware JMS {@link javax.jms.ConnectionFactory} passed in as
+ * "connectionFactory").
+ *
+ * Note that XA transaction coordination adds significant runtime overhead,
+ * so it might be feasible to avoid it unless absolutely necessary.
+ *
+ *
Recommendations:
+ *
+ *
The general recommendation is to set "sessionTransacted" to "true",
+ * typically in combination with local database transactions triggered by the
+ * listener implementation, through Spring's standard transaction facilities.
+ * This will work nicely in Tomcat or in a standalone environment, often
+ * combined with custom duplicate message detection (if it is unacceptable
+ * to ever process the same message twice).
+ *
Alternatively, specify a
+ * {@link org.springframework.transaction.jta.JtaTransactionManager} as
+ * "transactionManager" for a fully XA-aware JMS provider - typically when
+ * running on a J2EE server, but also for other environments with a JTA
+ * transaction manager present. This will give full "exactly-once" guarantees
+ * without custom duplicate message checks, at the price of additional
+ * runtime processing overhead.
+ *
+ *
+ *
Note that it is also possible to specify a
+ * {@link org.springframework.jms.connection.JmsTransactionManager} as external
+ * "transactionManager", providing fully synchronized Spring transactions based
+ * on local JMS transactions. The effect is similar to "sessionTransacted" set
+ * to "true", the difference being that this external transaction management
+ * will also affect independent JMS access code within the service layer
+ * (e.g. based on {@link org.springframework.jms.core.JmsTemplate} or
+ * {@link org.springframework.jms.connection.TransactionAwareConnectionFactoryProxy}),
+ * not just direct JMS Session usage in a {@link SessionAwareMessageListener}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setMessageListener
+ * @see javax.jms.MessageListener
+ * @see SessionAwareMessageListener
+ * @see #handleListenerException
+ * @see DefaultMessageListenerContainer
+ * @see SimpleMessageListenerContainer
+ * @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
+ */
+public abstract class AbstractMessageListenerContainer extends AbstractJmsListeningContainer {
+
+ private volatile Object destination;
+
+ private volatile String messageSelector;
+
+ private volatile Object messageListener;
+
+ private boolean subscriptionDurable = false;
+
+ private String durableSubscriptionName;
+
+ private ExceptionListener exceptionListener;
+
+ private boolean exposeListenerSession = true;
+
+ private boolean acceptMessagesWhileStopping = false;
+
+
+ /**
+ * Set the destination to receive messages from.
+ *
Alternatively, specify a "destinationName", to be dynamically
+ * resolved via the {@link org.springframework.jms.support.destination.DestinationResolver}.
+ *
Note: The destination may be replaced at runtime, with the listener
+ * container picking up the new destination immediately (works e.g. with
+ * DefaultMessageListenerContainer, as long as the cache level is less than
+ * CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
+ * @see #setDestinationName(String)
+ */
+ public void setDestination(Destination destination) {
+ Assert.notNull(destination, "'destination' must not be null");
+ this.destination = destination;
+ if (destination instanceof Topic && !(destination instanceof Queue)) {
+ // Clearly a Topic: let's set the "pubSubDomain" flag accordingly.
+ setPubSubDomain(true);
+ }
+ }
+
+ /**
+ * Return the destination to receive messages from. Will be null
+ * if the configured destination is not an actual {@link Destination} type;
+ * c.f. {@link #setDestinationName(String) when the destination is a String}.
+ */
+ public Destination getDestination() {
+ return (this.destination instanceof Destination ? (Destination) this.destination : null);
+ }
+
+ /**
+ * Set the name of the destination to receive messages from.
+ *
The specified name will be dynamically resolved via the configured
+ * {@link #setDestinationResolver destination resolver}.
+ *
Alternatively, specify a JMS {@link Destination} object as "destination".
+ *
Note: The destination may be replaced at runtime, with the listener
+ * container picking up the new destination immediately (works e.g. with
+ * DefaultMessageListenerContainer, as long as the cache level is less than
+ * CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
+ * @param destinationName the desired destination (can be null)
+ * @see #setDestination(javax.jms.Destination)
+ */
+ public void setDestinationName(String destinationName) {
+ Assert.notNull(destinationName, "'destinationName' must not be null");
+ this.destination = destinationName;
+ }
+
+ /**
+ * Return the name of the destination to receive messages from.
+ * Will be null if the configured destination is not a
+ * {@link String} type; c.f. {@link #setDestination(Destination) when
+ * it is an actual Destination}.
+ */
+ public String getDestinationName() {
+ return (this.destination instanceof String ? (String) this.destination : null);
+ }
+
+ /**
+ * Return a descriptive String for this container's JMS destination
+ * (never null).
+ */
+ protected String getDestinationDescription() {
+ return this.destination.toString();
+ }
+
+ /**
+ * Set the JMS message selector expression (or null if none).
+ * Default is none.
+ *
See the JMS specification for a detailed definition of selector expressions.
+ *
Note: The message selector may be replaced at runtime, with the listener
+ * container picking up the new selector value immediately (works e.g. with
+ * DefaultMessageListenerContainer, as long as the cache level is less than
+ * CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
+ */
+ public void setMessageSelector(String messageSelector) {
+ this.messageSelector = messageSelector;
+ }
+
+ /**
+ * Return the JMS message selector expression (or null if none).
+ */
+ public String getMessageSelector() {
+ return this.messageSelector;
+ }
+
+
+ /**
+ * Set the message listener implementation to register.
+ * This can be either a standard JMS {@link MessageListener} object
+ * or a Spring {@link SessionAwareMessageListener} object.
+ *
Note: The message listener may be replaced at runtime, with the listener
+ * container picking up the new listener object immediately (works e.g. with
+ * DefaultMessageListenerContainer, as long as the cache level is less than
+ * CACHE_CONSUMER). However, this is considered advanced usage; use it with care!
+ * @throws IllegalArgumentException if the supplied listener is not a
+ * {@link MessageListener} or a {@link SessionAwareMessageListener}
+ * @see javax.jms.MessageListener
+ * @see SessionAwareMessageListener
+ */
+ public void setMessageListener(Object messageListener) {
+ checkMessageListener(messageListener);
+ this.messageListener = messageListener;
+ if (this.durableSubscriptionName == null) {
+ this.durableSubscriptionName = getDefaultSubscriptionName(messageListener);
+ }
+ }
+
+ /**
+ * Return the message listener object to register.
+ */
+ public Object getMessageListener() {
+ return this.messageListener;
+ }
+
+ /**
+ * Check the given message listener, throwing an exception
+ * if it does not correspond to a supported listener type.
+ *
By default, only a standard JMS {@link MessageListener} object or a
+ * Spring {@link SessionAwareMessageListener} object will be accepted.
+ * @param messageListener the message listener object to check
+ * @throws IllegalArgumentException if the supplied listener is not a
+ * {@link MessageListener} or a {@link SessionAwareMessageListener}
+ * @see javax.jms.MessageListener
+ * @see SessionAwareMessageListener
+ */
+ protected void checkMessageListener(Object messageListener) {
+ if (!(messageListener instanceof MessageListener ||
+ messageListener instanceof SessionAwareMessageListener)) {
+ throw new IllegalArgumentException(
+ "Message listener needs to be of type [" + MessageListener.class.getName() +
+ "] or [" + SessionAwareMessageListener.class.getName() + "]");
+ }
+ }
+
+ /**
+ * Determine the default subscription name for the given message listener.
+ * @param messageListener the message listener object to check
+ * @return the default subscription name
+ * @see SubscriptionNameProvider
+ */
+ protected String getDefaultSubscriptionName(Object messageListener) {
+ if (messageListener instanceof SubscriptionNameProvider) {
+ return ((SubscriptionNameProvider) messageListener).getSubscriptionName();
+ }
+ else {
+ return messageListener.getClass().getName();
+ }
+ }
+
+ /**
+ * Set whether to make the subscription durable. The durable subscription name
+ * to be used can be specified through the "durableSubscriptionName" property.
+ *
Default is "false". Set this to "true" to register a durable subscription,
+ * typically in combination with a "durableSubscriptionName" value (unless
+ * your message listener class name is good enough as subscription name).
+ *
Only makes sense when listening to a topic (pub-sub domain).
+ * @see #setDurableSubscriptionName
+ */
+ public void setSubscriptionDurable(boolean subscriptionDurable) {
+ this.subscriptionDurable = subscriptionDurable;
+ }
+
+ /**
+ * Return whether to make the subscription durable.
+ */
+ public boolean isSubscriptionDurable() {
+ return this.subscriptionDurable;
+ }
+
+ /**
+ * Set the name of a durable subscription to create. To be applied in case
+ * of a topic (pub-sub domain) with subscription durability activated.
+ *
The durable subscription name needs to be unique within this client's
+ * JMS client id. Default is the class name of the specified message listener.
+ *
Note: Only 1 concurrent consumer (which is the default of this
+ * message listener container) is allowed for each durable subscription.
+ * @see #setSubscriptionDurable
+ * @see #setClientId
+ * @see #setMessageListener
+ */
+ public void setDurableSubscriptionName(String durableSubscriptionName) {
+ this.durableSubscriptionName = durableSubscriptionName;
+ }
+
+ /**
+ * Return the name of a durable subscription to create, if any.
+ */
+ public String getDurableSubscriptionName() {
+ return this.durableSubscriptionName;
+ }
+
+ /**
+ * Set the JMS ExceptionListener to notify in case of a JMSException thrown
+ * by the registered message listener or the invocation infrastructure.
+ */
+ public void setExceptionListener(ExceptionListener exceptionListener) {
+ this.exceptionListener = exceptionListener;
+ }
+
+ /**
+ * Return the JMS ExceptionListener to notify in case of a JMSException thrown
+ * by the registered message listener or the invocation infrastructure, if any.
+ */
+ public ExceptionListener getExceptionListener() {
+ return this.exceptionListener;
+ }
+
+ /**
+ * Set whether to expose the listener JMS Session to a registered
+ * {@link SessionAwareMessageListener} as well as to
+ * {@link org.springframework.jms.core.JmsTemplate} calls.
+ *
Default is "true", reusing the listener's {@link Session}.
+ * Turn this off to expose a fresh JMS Session fetched from the same
+ * underlying JMS {@link Connection} instead, which might be necessary
+ * on some JMS providers.
+ *
Note that Sessions managed by an external transaction manager will
+ * always get exposed to {@link org.springframework.jms.core.JmsTemplate}
+ * calls. So in terms of JmsTemplate exposure, this setting only affects
+ * locally transacted Sessions.
+ * @see SessionAwareMessageListener
+ */
+ public void setExposeListenerSession(boolean exposeListenerSession) {
+ this.exposeListenerSession = exposeListenerSession;
+ }
+
+ /**
+ * Return whether to expose the listener JMS {@link Session} to a
+ * registered {@link SessionAwareMessageListener}.
+ */
+ public boolean isExposeListenerSession() {
+ return this.exposeListenerSession;
+ }
+
+ /**
+ * Set whether to accept received messages while the listener container
+ * in the process of stopping.
+ *
Default is "false", rejecting such messages through aborting the
+ * receive attempt. Switch this flag on to fully process such messages
+ * even in the stopping phase, with the drawback that even newly sent
+ * messages might still get processed (if coming in before all receive
+ * timeouts have expired).
+ *
NOTE: Aborting receive attempts for such incoming messages
+ * might lead to the provider's retry count decreasing for the affected
+ * messages. If you have a high number of concurrent consumers, make sure
+ * that the number of retries is higher than the number of consumers,
+ * to be on the safe side for all potential stopping scenarios.
+ */
+ public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
+ this.acceptMessagesWhileStopping = acceptMessagesWhileStopping;
+ }
+
+ /**
+ * Return whether to accept received messages while the listener container
+ * in the process of stopping.
+ */
+ public boolean isAcceptMessagesWhileStopping() {
+ return this.acceptMessagesWhileStopping;
+ }
+
+ protected void validateConfiguration() {
+ if (this.destination == null) {
+ throw new IllegalArgumentException("Property 'destination' or 'destinationName' is required");
+ }
+ if (isSubscriptionDurable() && !isPubSubDomain()) {
+ throw new IllegalArgumentException("A durable subscription requires a topic (pub-sub domain)");
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Template methods for listener execution
+ //-------------------------------------------------------------------------
+
+ /**
+ * Execute the specified listener,
+ * committing or rolling back the transaction afterwards (if necessary).
+ * @param session the JMS Session to operate on
+ * @param message the received JMS Message
+ * @see #invokeListener
+ * @see #commitIfNecessary
+ * @see #rollbackOnExceptionIfNecessary
+ * @see #handleListenerException
+ */
+ protected void executeListener(Session session, Message message) {
+ try {
+ doExecuteListener(session, message);
+ }
+ catch (Throwable ex) {
+ handleListenerException(ex);
+ }
+ }
+
+ /**
+ * Execute the specified listener,
+ * committing or rolling back the transaction afterwards (if necessary).
+ * @param session the JMS Session to operate on
+ * @param message the received JMS Message
+ * @throws JMSException if thrown by JMS API methods
+ * @see #invokeListener
+ * @see #commitIfNecessary
+ * @see #rollbackOnExceptionIfNecessary
+ * @see #convertJmsAccessException
+ */
+ protected void doExecuteListener(Session session, Message message) throws JMSException {
+ if (!isAcceptMessagesWhileStopping() && !isRunning()) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Rejecting received message because of the listener container " +
+ "having been stopped in the meantime: " + message);
+ }
+ rollbackIfNecessary(session);
+ throw new MessageRejectedWhileStoppingException();
+ }
+ try {
+ invokeListener(session, message);
+ }
+ catch (JMSException ex) {
+ rollbackOnExceptionIfNecessary(session, ex);
+ throw ex;
+ }
+ catch (RuntimeException ex) {
+ rollbackOnExceptionIfNecessary(session, ex);
+ throw ex;
+ }
+ catch (Error err) {
+ rollbackOnExceptionIfNecessary(session, err);
+ throw err;
+ }
+ commitIfNecessary(session, message);
+ }
+
+ /**
+ * Invoke the specified listener: either as standard JMS MessageListener
+ * or (preferably) as Spring SessionAwareMessageListener.
+ * @param session the JMS Session to operate on
+ * @param message the received JMS Message
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setMessageListener
+ */
+ protected void invokeListener(Session session, Message message) throws JMSException {
+ Object listener = getMessageListener();
+ if (listener instanceof SessionAwareMessageListener) {
+ doInvokeListener((SessionAwareMessageListener) listener, session, message);
+ }
+ else if (listener instanceof MessageListener) {
+ doInvokeListener((MessageListener) listener, message);
+ }
+ else if (listener != null) {
+ throw new IllegalArgumentException(
+ "Only MessageListener and SessionAwareMessageListener supported: " + listener);
+ }
+ else {
+ throw new IllegalStateException("No message listener specified - see property 'messageListener'");
+ }
+ }
+
+ /**
+ * Invoke the specified listener as Spring SessionAwareMessageListener,
+ * exposing a new JMS Session (potentially with its own transaction)
+ * to the listener if demanded.
+ * @param listener the Spring SessionAwareMessageListener to invoke
+ * @param session the JMS Session to operate on
+ * @param message the received JMS Message
+ * @throws JMSException if thrown by JMS API methods
+ * @see SessionAwareMessageListener
+ * @see #setExposeListenerSession
+ */
+ protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message)
+ throws JMSException {
+
+ Connection conToClose = null;
+ Session sessionToClose = null;
+ try {
+ Session sessionToUse = session;
+ if (!isExposeListenerSession()) {
+ // We need to expose a separate Session.
+ conToClose = createConnection();
+ sessionToClose = createSession(conToClose);
+ sessionToUse = sessionToClose;
+ }
+ // Actually invoke the message listener...
+ listener.onMessage(message, sessionToUse);
+ // Clean up specially exposed Session, if any.
+ if (sessionToUse != session) {
+ if (sessionToUse.getTransacted() && isSessionLocallyTransacted(sessionToUse)) {
+ // Transacted session created by this container -> commit.
+ JmsUtils.commitIfNecessary(sessionToUse);
+ }
+ }
+ }
+ finally {
+ JmsUtils.closeSession(sessionToClose);
+ JmsUtils.closeConnection(conToClose);
+ }
+ }
+
+ /**
+ * Invoke the specified listener as standard JMS MessageListener.
+ *
Default implementation performs a plain invocation of the
+ * onMessage method.
+ * @param listener the JMS MessageListener to invoke
+ * @param message the received JMS Message
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.MessageListener#onMessage
+ */
+ protected void doInvokeListener(MessageListener listener, Message message) throws JMSException {
+ listener.onMessage(message);
+ }
+
+ /**
+ * Perform a commit or message acknowledgement, as appropriate.
+ * @param session the JMS Session to commit
+ * @param message the Message to acknowledge
+ * @throws javax.jms.JMSException in case of commit failure
+ */
+ protected void commitIfNecessary(Session session, Message message) throws JMSException {
+ // Commit session or acknowledge message.
+ if (session.getTransacted()) {
+ // Commit necessary - but avoid commit call within a JTA transaction.
+ if (isSessionLocallyTransacted(session)) {
+ // Transacted session created by this container -> commit.
+ JmsUtils.commitIfNecessary(session);
+ }
+ }
+ else if (isClientAcknowledge(session)) {
+ message.acknowledge();
+ }
+ }
+
+ /**
+ * Perform a rollback, if appropriate.
+ * @param session the JMS Session to rollback
+ * @throws javax.jms.JMSException in case of a rollback error
+ */
+ protected void rollbackIfNecessary(Session session) throws JMSException {
+ if (session.getTransacted() && isSessionLocallyTransacted(session)) {
+ // Transacted session created by this container -> rollback.
+ JmsUtils.rollbackIfNecessary(session);
+ }
+ }
+
+ /**
+ * Perform a rollback, handling rollback exceptions properly.
+ * @param session the JMS Session to rollback
+ * @param ex the thrown application exception or error
+ * @throws javax.jms.JMSException in case of a rollback error
+ */
+ protected void rollbackOnExceptionIfNecessary(Session session, Throwable ex) throws JMSException {
+ try {
+ if (session.getTransacted() && isSessionLocallyTransacted(session)) {
+ // Transacted session created by this container -> rollback.
+ if (logger.isDebugEnabled()) {
+ logger.debug("Initiating transaction rollback on application exception", ex);
+ }
+ JmsUtils.rollbackIfNecessary(session);
+ }
+ }
+ catch (IllegalStateException ex2) {
+ logger.debug("Could not roll back because Session already closed", ex2);
+ }
+ catch (JMSException ex2) {
+ logger.error("Application exception overridden by rollback exception", ex);
+ throw ex2;
+ }
+ catch (RuntimeException ex2) {
+ logger.error("Application exception overridden by rollback exception", ex);
+ throw ex2;
+ }
+ catch (Error err) {
+ logger.error("Application exception overridden by rollback error", ex);
+ throw err;
+ }
+ }
+
+ /**
+ * Check whether the given Session is locally transacted, that is, whether
+ * its transaction is managed by this listener container's Session handling
+ * and not by an external transaction coordinator.
+ *
Note: The Session's own transacted flag will already have been checked
+ * before. This method is about finding out whether the Session's transaction
+ * is local or externally coordinated.
+ * @param session the Session to check
+ * @return whether the given Session is locally transacted
+ * @see #isSessionTransacted()
+ * @see org.springframework.jms.connection.ConnectionFactoryUtils#isSessionTransactional
+ */
+ protected boolean isSessionLocallyTransacted(Session session) {
+ return isSessionTransacted();
+ }
+
+ /**
+ * Handle the given exception that arose during listener execution.
+ *
The default implementation logs the exception at error level,
+ * not propagating it to the JMS provider - assuming that all handling of
+ * acknowledgement and/or transactions is done by this listener container.
+ * This can be overridden in subclasses.
+ * @param ex the exception to handle
+ */
+ protected void handleListenerException(Throwable ex) {
+ if (ex instanceof MessageRejectedWhileStoppingException) {
+ // Internal exception - has been handled before.
+ return;
+ }
+ if (ex instanceof JMSException) {
+ invokeExceptionListener((JMSException) ex);
+ }
+ if (isActive()) {
+ // Regular case: failed while active.
+ // Log at error level.
+ logger.warn("Execution of JMS message listener failed", ex);
+ }
+ else {
+ // Rare case: listener thread failed after container shutdown.
+ // Log at debug level, to avoid spamming the shutdown log.
+ logger.debug("Listener exception after container shutdown", ex);
+ }
+ }
+
+ /**
+ * Invoke the registered JMS ExceptionListener, if any.
+ * @param ex the exception that arose during JMS processing
+ * @see #setExceptionListener
+ */
+ protected void invokeExceptionListener(JMSException ex) {
+ ExceptionListener exceptionListener = getExceptionListener();
+ if (exceptionListener != null) {
+ exceptionListener.onException(ex);
+ }
+ }
+
+
+ /**
+ * Internal exception class that indicates a rejected message on shutdown.
+ * Used to trigger a rollback for an external transaction manager in that case.
+ */
+ private static class MessageRejectedWhileStoppingException extends RuntimeException {
+
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/AbstractPollingMessageListenerContainer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.connection.JmsResourceHolder;
+import org.springframework.jms.connection.SingleConnectionFactory;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+import org.springframework.transaction.support.ResourceTransactionManager;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.transaction.support.TransactionSynchronizationUtils;
+
+/**
+ * Base class for listener container implementations which are based on polling.
+ * Provides support for listener handling based on {@link javax.jms.MessageConsumer},
+ * optionally participating in externally managed transactions.
+ *
+ *
This listener container variant is built for repeated polling attempts,
+ * each invoking the {@link #receiveAndExecute} method. The MessageConsumer used
+ * may be reobtained fo reach attempt or cached inbetween attempts; this is up
+ * to the concrete implementation. The receive timeout for each attempt can be
+ * configured through the {@link #setReceiveTimeout "receiveTimeout"} property.
+ *
+ *
The underlying mechanism is based on standard JMS MessageConsumer handling,
+ * which is perfectly compatible with both native JMS and JMS in a J2EE environment.
+ * Neither the JMS MessageConsumer.setMessageListener facility
+ * nor the JMS ServerSessionPool facility is required. A further advantage
+ * of this approach is full control over the listening process, allowing for
+ * custom scaling and throttling and of concurrent message processing
+ * (which is up to concrete subclasses).
+ *
+ *
Message reception and listener execution can automatically be wrapped
+ * in transactions through passing a Spring
+ * {@link org.springframework.transaction.PlatformTransactionManager} into the
+ * {@link #setTransactionManager "transactionManager"} property. This will usually
+ * be a {@link org.springframework.transaction.jta.JtaTransactionManager} in a
+ * J2EE enviroment, in combination with a JTA-aware JMS ConnectionFactory obtained
+ * from JNDI (check your J2EE server's documentation).
+ *
+ *
This base class does not assume any specific mechanism for asynchronous
+ * execution of polling invokers. Check out {@link DefaultMessageListenerContainer}
+ * for a concrete implementation which is based on Spring's
+ * {@link org.springframework.core.task.TaskExecutor} abstraction,
+ * including dynamic scaling of concurrent consumers and automatic self recovery.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.3
+ * @see #createListenerConsumer
+ * @see #receiveAndExecute
+ * @see #setTransactionManager
+ */
+public abstract class AbstractPollingMessageListenerContainer extends AbstractMessageListenerContainer
+ implements BeanNameAware {
+
+ /**
+ * The default receive timeout: 1000 ms = 1 second.
+ */
+ public static final long DEFAULT_RECEIVE_TIMEOUT = 1000;
+
+
+ private final MessageListenerContainerResourceFactory transactionalResourceFactory =
+ new MessageListenerContainerResourceFactory();
+
+ private boolean sessionTransactedCalled = false;
+
+ private boolean pubSubNoLocal = false;
+
+ private PlatformTransactionManager transactionManager;
+
+ private DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
+
+ private long receiveTimeout = DEFAULT_RECEIVE_TIMEOUT;
+
+
+ public void setSessionTransacted(boolean sessionTransacted) {
+ super.setSessionTransacted(sessionTransacted);
+ this.sessionTransactedCalled = true;
+ }
+
+ /**
+ * Set whether to inhibit the delivery of messages published by its own connection.
+ * Default is "false".
+ * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic, String, boolean)
+ */
+ public void setPubSubNoLocal(boolean pubSubNoLocal) {
+ this.pubSubNoLocal = pubSubNoLocal;
+ }
+
+ /**
+ * Return whether to inhibit the delivery of messages published by its own connection.
+ */
+ protected boolean isPubSubNoLocal() {
+ return this.pubSubNoLocal;
+ }
+
+ /**
+ * Specify the Spring {@link org.springframework.transaction.PlatformTransactionManager}
+ * to use for transactional wrapping of message reception plus listener execution.
+ *
Default is none, not performing any transactional wrapping.
+ * If specified, this will usually be a Spring
+ * {@link org.springframework.transaction.jta.JtaTransactionManager} or one
+ * of its subclasses, in combination with a JTA-aware ConnectionFactory that
+ * this message listener container obtains its Connections from.
+ *
Note: Consider the use of local JMS transactions instead.
+ * Simply switch the {@link #setSessionTransacted "sessionTransacted"} flag
+ * to "true" in order to use a locally transacted JMS Session for the entire
+ * receive processing, including any Session operations performed by a
+ * {@link SessionAwareMessageListener} (e.g. sending a response message).
+ * Alternatively, a {@link org.springframework.jms.connection.JmsTransactionManager}
+ * may be used for fully synchronized Spring transactions based on local JMS
+ * transactions. Check {@link AbstractMessageListenerContainer}'s javadoc for
+ * a discussion of transaction choices and message redelivery scenarios.
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.jms.connection.JmsTransactionManager
+ */
+ public void setTransactionManager(PlatformTransactionManager transactionManager) {
+ this.transactionManager = transactionManager;
+ }
+
+ /**
+ * Return the Spring PlatformTransactionManager to use for transactional
+ * wrapping of message reception plus listener execution.
+ */
+ protected final PlatformTransactionManager getTransactionManager() {
+ return this.transactionManager;
+ }
+
+ /**
+ * Specify the transaction name to use for transactional wrapping.
+ * Default is the bean name of this listener container, if any.
+ * @see org.springframework.transaction.TransactionDefinition#getName()
+ */
+ public void setTransactionName(String transactionName) {
+ this.transactionDefinition.setName(transactionName);
+ }
+
+ /**
+ * Specify the transaction timeout to use for transactional wrapping, in seconds.
+ * Default is none, using the transaction manager's default timeout.
+ * @see org.springframework.transaction.TransactionDefinition#getTimeout()
+ * @see #setReceiveTimeout
+ */
+ public void setTransactionTimeout(int transactionTimeout) {
+ this.transactionDefinition.setTimeout(transactionTimeout);
+ }
+
+ /**
+ * Set the timeout to use for receive calls, in milliseconds.
+ * The default is 1000 ms, that is, 1 second.
+ *
NOTE: This value needs to be smaller than the transaction
+ * timeout used by the transaction manager (in the appropriate unit,
+ * of course). -1 indicates no timeout at all; however, this is only
+ * feasible if not running within a transaction manager.
+ * @see javax.jms.MessageConsumer#receive(long)
+ * @see javax.jms.MessageConsumer#receive()
+ * @see #setTransactionTimeout
+ */
+ public void setReceiveTimeout(long receiveTimeout) {
+ this.receiveTimeout = receiveTimeout;
+ }
+
+
+ public void initialize() {
+ // Set sessionTransacted=true in case of a non-JTA transaction manager.
+ if (!this.sessionTransactedCalled &&
+ this.transactionManager instanceof ResourceTransactionManager &&
+ !TransactionSynchronizationUtils.sameResourceFactory(
+ (ResourceTransactionManager) this.transactionManager, getConnectionFactory())) {
+ super.setSessionTransacted(true);
+ }
+
+ // Use bean name as default transaction name.
+ if (this.transactionDefinition.getName() == null) {
+ this.transactionDefinition.setName(getBeanName());
+ }
+
+ // Proceed with superclass initialization.
+ super.initialize();
+ }
+
+
+ /**
+ * Create a MessageConsumer for the given JMS Session,
+ * registering a MessageListener for the specified listener.
+ * @param session the JMS Session to work on
+ * @return the MessageConsumer
+ * @throws javax.jms.JMSException if thrown by JMS methods
+ * @see #receiveAndExecute
+ */
+ protected MessageConsumer createListenerConsumer(Session session) throws JMSException {
+ Destination destination = getDestination();
+ if (destination == null) {
+ destination = resolveDestinationName(session, getDestinationName());
+ }
+ return createConsumer(session, destination);
+ }
+
+ /**
+ * Execute the listener for a message received from the given consumer,
+ * wrapping the entire operation in an external transaction if demanded.
+ * @param session the JMS Session to work on
+ * @param consumer the MessageConsumer to work on
+ * @return whether a message has been received
+ * @throws JMSException if thrown by JMS methods
+ * @see #doReceiveAndExecute
+ */
+ protected boolean receiveAndExecute(Object invoker, Session session, MessageConsumer consumer)
+ throws JMSException {
+
+ if (this.transactionManager != null) {
+ // Execute receive within transaction.
+ TransactionStatus status = this.transactionManager.getTransaction(this.transactionDefinition);
+ boolean messageReceived = true;
+ try {
+ messageReceived = doReceiveAndExecute(invoker, session, consumer, status);
+ }
+ catch (JMSException ex) {
+ rollbackOnException(status, ex);
+ throw ex;
+ }
+ catch (RuntimeException ex) {
+ rollbackOnException(status, ex);
+ throw ex;
+ }
+ catch (Error err) {
+ rollbackOnException(status, err);
+ throw err;
+ }
+ this.transactionManager.commit(status);
+ return messageReceived;
+ }
+
+ else {
+ // Execute receive outside of transaction.
+ return doReceiveAndExecute(invoker, session, consumer, null);
+ }
+ }
+
+ /**
+ * Actually execute the listener for a message received from the given consumer,
+ * fetching all requires resources and invoking the listener.
+ * @param session the JMS Session to work on
+ * @param consumer the MessageConsumer to work on
+ * @param status the TransactionStatus (may be null)
+ * @return whether a message has been received
+ * @throws JMSException if thrown by JMS methods
+ * @see #doExecuteListener(javax.jms.Session, javax.jms.Message)
+ */
+ protected boolean doReceiveAndExecute(
+ Object invoker, Session session, MessageConsumer consumer, TransactionStatus status)
+ throws JMSException {
+
+ Connection conToClose = null;
+ Session sessionToClose = null;
+ MessageConsumer consumerToClose = null;
+ try {
+ Session sessionToUse = session;
+ boolean transactional = false;
+ if (sessionToUse == null) {
+ sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
+ getConnectionFactory(), this.transactionalResourceFactory, true);
+ transactional = (sessionToUse != null);
+ }
+ if (sessionToUse == null) {
+ Connection conToUse = null;
+ if (sharedConnectionEnabled()) {
+ conToUse = getSharedConnection();
+ }
+ else {
+ conToUse = createConnection();
+ conToClose = conToUse;
+ conToUse.start();
+ }
+ sessionToUse = createSession(conToUse);
+ sessionToClose = sessionToUse;
+ }
+ MessageConsumer consumerToUse = consumer;
+ if (consumerToUse == null) {
+ consumerToUse = createListenerConsumer(sessionToUse);
+ consumerToClose = consumerToUse;
+ }
+ Message message = receiveMessage(consumerToUse);
+ if (message != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Received message of type [" + message.getClass() + "] from consumer [" +
+ consumerToUse + "] of " + (transactional ? "transactional " : "") + "session [" +
+ sessionToUse + "]");
+ }
+ messageReceived(invoker, sessionToUse);
+ boolean exposeResource = (!transactional && isExposeListenerSession() &&
+ !TransactionSynchronizationManager.hasResource(getConnectionFactory()));
+ if (exposeResource) {
+ TransactionSynchronizationManager.bindResource(
+ getConnectionFactory(), new LocallyExposedJmsResourceHolder(sessionToUse));
+ }
+ try {
+ doExecuteListener(sessionToUse, message);
+ }
+ catch (Throwable ex) {
+ if (status != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Rolling back transaction because of listener exception thrown: " + ex);
+ }
+ status.setRollbackOnly();
+ }
+ handleListenerException(ex);
+ // Rethrow JMSException to indicate an infrastructure problem
+ // that may have to trigger recovery...
+ if (ex instanceof JMSException) {
+ throw (JMSException) ex;
+ }
+ }
+ finally {
+ if (exposeResource) {
+ TransactionSynchronizationManager.unbindResource(getConnectionFactory());
+ }
+ }
+ return true;
+ }
+ else {
+ if (logger.isTraceEnabled()) {
+ logger.trace("Consumer [" + consumerToUse + "] of " + (transactional ? "transactional " : "") +
+ "session [" + sessionToUse + "] did not receive a message");
+ }
+ noMessageReceived(invoker, sessionToUse);
+ return false;
+ }
+ }
+ finally {
+ JmsUtils.closeMessageConsumer(consumerToClose);
+ JmsUtils.closeSession(sessionToClose);
+ ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), true);
+ }
+ }
+
+ /**
+ * This implementation checks whether the Session is externally synchronized.
+ * In this case, the Session is not locally transacted, despite the listener
+ * container's "sessionTransacted" flag being set to "true".
+ * @see org.springframework.jms.connection.JmsResourceHolder
+ */
+ protected boolean isSessionLocallyTransacted(Session session) {
+ if (!super.isSessionLocallyTransacted(session)) {
+ return false;
+ }
+ JmsResourceHolder resourceHolder =
+ (JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
+ return (resourceHolder == null || resourceHolder instanceof LocallyExposedJmsResourceHolder ||
+ !resourceHolder.containsSession(session));
+ }
+
+ /**
+ * Perform a rollback, handling rollback exceptions properly.
+ * @param status object representing the transaction
+ * @param ex the thrown listener exception or error
+ */
+ private void rollbackOnException(TransactionStatus status, Throwable ex) {
+ logger.debug("Initiating transaction rollback on listener exception", ex);
+ try {
+ this.transactionManager.rollback(status);
+ }
+ catch (RuntimeException ex2) {
+ logger.error("Listener exception overridden by rollback exception", ex);
+ throw ex2;
+ }
+ catch (Error err) {
+ logger.error("Listener exception overridden by rollback error", ex);
+ throw err;
+ }
+ }
+
+ /**
+ * Receive a message from the given consumer.
+ * @param consumer the MessageConsumer to use
+ * @return the Message, or null if none
+ * @throws JMSException if thrown by JMS methods
+ */
+ protected Message receiveMessage(MessageConsumer consumer) throws JMSException {
+ return (this.receiveTimeout < 0 ? consumer.receive() : consumer.receive(this.receiveTimeout));
+ }
+
+ /**
+ * Template method that gets called right when a new message has been received,
+ * before attempting to process it. Allows subclasses to react to the event
+ * of an actual incoming message, for example adapting their consumer count.
+ * @param invoker the invoker object (passed through)
+ * @param session the receiving JMS Session
+ */
+ protected void messageReceived(Object invoker, Session session) {
+ }
+
+ /**
+ * Template method that gets called right no message has been received,
+ * before attempting to process it. Allows subclasses to react to the event
+ * of an actual incoming message, for example marking .
+ * @param invoker the invoker object (passed through)
+ * @param session the receiving JMS Session
+ */
+ protected void noMessageReceived(Object invoker, Session session) {
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Fetch an appropriate Connection from the given JmsResourceHolder.
+ *
This implementation accepts any JMS 1.1 Connection.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Connection fetched from the holder,
+ * or null if none found
+ */
+ protected Connection getConnection(JmsResourceHolder holder) {
+ return holder.getConnection();
+ }
+
+ /**
+ * Fetch an appropriate Session from the given JmsResourceHolder.
+ *
This implementation accepts any JMS 1.1 Session.
+ * @param holder the JmsResourceHolder
+ * @return an appropriate Session fetched from the holder,
+ * or null if none found
+ */
+ protected Session getSession(JmsResourceHolder holder) {
+ return holder.getSession();
+ }
+
+ /**
+ * Create a JMS MessageConsumer for the given Session and Destination.
+ *
This implementation uses JMS 1.1 API.
+ * @param session the JMS Session to create a MessageConsumer for
+ * @param destination the JMS Destination to create a MessageConsumer for
+ * @return the new JMS MessageConsumer
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
+ // Only pass in the NoLocal flag in case of a Topic:
+ // Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
+ // in case of the NoLocal flag being specified for a Queue.
+ if (isPubSubDomain()) {
+ if (isSubscriptionDurable() && destination instanceof Topic) {
+ return session.createDurableSubscriber(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
+ }
+ else {
+ return session.createConsumer(destination, getMessageSelector(), isPubSubNoLocal());
+ }
+ }
+ else {
+ return session.createConsumer(destination, getMessageSelector());
+ }
+ }
+
+
+ /**
+ * ResourceFactory implementation that delegates to this listener container's protected callback methods.
+ */
+ private class MessageListenerContainerResourceFactory implements ConnectionFactoryUtils.ResourceFactory {
+
+ public Connection getConnection(JmsResourceHolder holder) {
+ return AbstractPollingMessageListenerContainer.this.getConnection(holder);
+ }
+
+ public Session getSession(JmsResourceHolder holder) {
+ return AbstractPollingMessageListenerContainer.this.getSession(holder);
+ }
+
+ public Connection createConnection() throws JMSException {
+ if (AbstractPollingMessageListenerContainer.this.sharedConnectionEnabled()) {
+ Connection sharedCon = AbstractPollingMessageListenerContainer.this.getSharedConnection();
+ return new SingleConnectionFactory(sharedCon).createConnection();
+ }
+ else {
+ return AbstractPollingMessageListenerContainer.this.createConnection();
+ }
+ }
+
+ public Session createSession(Connection con) throws JMSException {
+ return AbstractPollingMessageListenerContainer.this.createSession(con);
+ }
+
+ public boolean isSynchedLocalTransactionAllowed() {
+ return AbstractPollingMessageListenerContainer.this.isSessionTransacted();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,1044 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+
+import org.springframework.core.Constants;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.jms.JmsException;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.destination.CachingDestinationResolver;
+import org.springframework.jms.support.destination.DestinationResolver;
+import org.springframework.scheduling.SchedulingAwareRunnable;
+import org.springframework.scheduling.SchedulingTaskExecutor;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Message listener container variant that uses plain JMS client API, specifically
+ * a loop of MessageConsumer.receive() calls that also allow for
+ * transactional reception of messages (registering them with XA transactions).
+ * Designed to work in a native JMS environment as well as in a J2EE environment,
+ * with only minimal differences in configuration.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider, because it builds on
+ * the domain-independent API. Use the {@link DefaultMessageListenerContainer102}
+ * subclass for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.
+ *
+ *
This is a simple but nevertheless powerful form of message listener container.
+ * On startup, it obtains a fixed number of JMS Sessions to invoke the listener,
+ * and optionally allows for dynamic adaptation at runtime (up until a maximum number).
+ * Like {@link SimpleMessageListenerContainer}, its main advantage is its low level
+ * of runtime complexity, in particular the minimal requirements on the JMS provider:
+ * Not even the JMS ServerSessionPool facility is required. Beyond that, it is
+ * fully self-recovering in case of the broker being temporarily unavailable,
+ * and allows for stops/restarts as well as runtime changes to its configuration.
+ *
+ *
Actual MessageListener execution happens in asynchronous work units which are
+ * created through Spring's {@link org.springframework.core.task.TaskExecutor}
+ * abstraction. By default, the specified number of invoker tasks will be created
+ * on startup, according to the {@link #setConcurrentConsumers "concurrentConsumers"}
+ * setting. Specify an alternative TaskExecutor to integrate with an existing
+ * thread pool facility (such as a J2EE server's), for example using a
+ * {@link org.springframework.scheduling.commonj.WorkManagerTaskExecutor CommonJ WorkManager}.
+ * With a native JMS setup, each of those listener threads is going to use a
+ * cached JMS Session and MessageConsumer (only refreshed in case of failure),
+ * using the JMS provider's resources as efficiently as possible.
+ *
+ *
Message reception and listener execution can automatically be wrapped
+ * in transactions through passing a Spring
+ * {@link org.springframework.transaction.PlatformTransactionManager} into the
+ * {@link #setTransactionManager "transactionManager"} property. This will usually
+ * be a {@link org.springframework.transaction.jta.JtaTransactionManager} in a
+ * J2EE enviroment, in combination with a JTA-aware JMS ConnectionFactory obtained
+ * from JNDI (check your J2EE server's documentation). Note that this listener
+ * container will automatically reobtain all JMS handles for each transaction
+ * in case of an external transaction manager specified, for compatibility with
+ * all J2EE servers (in particular JBoss). This non-caching behavior can be
+ * overridden through the {@link #setCacheLevel "cacheLevel"} /
+ * {@link #setCacheLevelName "cacheLevelName"} property, enforcing caching
+ * of the Connection (or also Session and MessageConsumer) even in case of
+ * an external transaction manager being involved.
+ *
+ *
Dynamic scaling of the number of concurrent invokers can be activated
+ * through specifying a {@link #setMaxConcurrentConsumers "maxConcurrentConsumers"}
+ * value that is higher than the {@link #setConcurrentConsumers "concurrentConsumers"}
+ * value. Since the latter's default is 1, you can also simply specify a
+ * "maxConcurrentConsumers" of e.g. 5, which will lead to dynamic scaling up to
+ * 5 concurrent consumers in case of increasing message load, as well as dynamic
+ * shrinking back to the standard number of consumers once the load decreases.
+ * Consider adapting the {@link #setIdleTaskExecutionLimit "idleTaskExecutionLimit"}
+ * setting to control the lifespan of each new task, to avoid frequent scaling up
+ * and down, in particular if the ConnectionFactory does not pool JMS Sessions
+ * and/or the TaskExecutor does not pool threads (check your configuration!).
+ * Note that dynamic scaling only really makes sense for a queue in the first
+ * place; for a topic, you will typically stick with the default number of 1
+ * consumer, else you'd receive the same message multiple times on the same node.
+ *
+ *
It is strongly recommended to either set {@link #setSessionTransacted
+ * "sessionTransacted"} to "true" or specify an external {@link #setTransactionManager
+ * "transactionManager"}. See the {@link AbstractMessageListenerContainer}
+ * javadoc for details on acknowledge modes and native transaction options,
+ * as well as the {@link AbstractPollingMessageListenerContainer} javadoc
+ * for details on configuring an external transaction manager.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setTransactionManager
+ * @see #setCacheLevel
+ * @see javax.jms.MessageConsumer#receive(long)
+ * @see SimpleMessageListenerContainer
+ * @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
+ */
+public class DefaultMessageListenerContainer extends AbstractPollingMessageListenerContainer {
+
+ /**
+ * Default thread name prefix: "DefaultMessageListenerContainer-".
+ */
+ public static final String DEFAULT_THREAD_NAME_PREFIX =
+ ClassUtils.getShortName(DefaultMessageListenerContainer.class) + "-";
+
+ /**
+ * The default recovery interval: 5000 ms = 5 seconds.
+ */
+ public static final long DEFAULT_RECOVERY_INTERVAL = 5000;
+
+
+ /**
+ * Constant that indicates to cache no JMS resources at all.
+ * @see #setCacheLevel
+ */
+ public static final int CACHE_NONE = 0;
+
+ /**
+ * Constant that indicates to cache a shared JMS Connection.
+ * @see #setCacheLevel
+ */
+ public static final int CACHE_CONNECTION = 1;
+
+ /**
+ * Constant that indicates to cache a shared JMS Connection
+ * and a JMS Session for each listener thread.
+ * @see #setCacheLevel
+ */
+ public static final int CACHE_SESSION = 2;
+
+ /**
+ * Constant that indicates to cache a shared JMS Connection
+ * and a JMS Session for each listener thread, as well as
+ * a JMS MessageConsumer for each listener thread.
+ * @see #setCacheLevel
+ */
+ public static final int CACHE_CONSUMER = 3;
+
+ /**
+ * Constant that indicates automatic choice of an appropriate
+ * caching level (depending on the transaction management strategy).
+ * @see #setCacheLevel
+ */
+ public static final int CACHE_AUTO = 4;
+
+
+ private static final Constants constants = new Constants(DefaultMessageListenerContainer.class);
+
+
+ private TaskExecutor taskExecutor;
+
+ private long recoveryInterval = DEFAULT_RECOVERY_INTERVAL;
+
+ private int cacheLevel = CACHE_AUTO;
+
+ private int concurrentConsumers = 1;
+
+ private int maxConcurrentConsumers = 1;
+
+ private int maxMessagesPerTask = Integer.MIN_VALUE;
+
+ private int idleTaskExecutionLimit = 1;
+
+ private final Set scheduledInvokers = new HashSet();
+
+ private int activeInvokerCount = 0;
+
+ private Runnable stopCallback;
+
+ private Object currentRecoveryMarker = new Object();
+
+ private final Object recoveryMonitor = new Object();
+
+
+ /**
+ * Set the Spring TaskExecutor to use for running the listener threads.
+ *
Default is a {@link org.springframework.core.task.SimpleAsyncTaskExecutor},
+ * starting up a number of new threads, according to the specified number
+ * of concurrent consumers.
+ *
Specify an alternative TaskExecutor for integration with an existing
+ * thread pool. Note that this really only adds value if the threads are
+ * managed in a specific fashion, for example within a J2EE environment.
+ * A plain thread pool does not add much value, as this listener container
+ * will occupy a number of threads for its entire lifetime.
+ * @see #setConcurrentConsumers
+ * @see org.springframework.core.task.SimpleAsyncTaskExecutor
+ * @see org.springframework.scheduling.commonj.WorkManagerTaskExecutor
+ */
+ public void setTaskExecutor(TaskExecutor taskExecutor) {
+ this.taskExecutor = taskExecutor;
+ }
+
+ /**
+ * Specify the interval between recovery attempts, in milliseconds.
+ * The default is 5000 ms, that is, 5 seconds.
+ * @see #handleListenerSetupFailure
+ */
+ public void setRecoveryInterval(long recoveryInterval) {
+ this.recoveryInterval = recoveryInterval;
+ }
+
+ /**
+ * Specify the level of caching that this listener container is allowed to apply,
+ * in the form of the name of the corresponding constant: e.g. "CACHE_CONNECTION".
+ * @see #setCacheLevel
+ */
+ public void setCacheLevelName(String constantName) throws IllegalArgumentException {
+ if (constantName == null || !constantName.startsWith("CACHE_")) {
+ throw new IllegalArgumentException("Only cache constants allowed");
+ }
+ setCacheLevel(constants.asNumber(constantName).intValue());
+ }
+
+ /**
+ * Specify the level of caching that this listener container is allowed to apply.
+ *
Default is CACHE_NONE if an external transaction manager has been specified
+ * (to reobtain all resources freshly within the scope of the external transaction),
+ * and CACHE_CONSUMER else (operating with local JMS resources).
+ *
Some J2EE servers only register their JMS resources with an ongoing XA
+ * transaction in case of a freshly obtained JMS Connection and Session,
+ * which is why this listener container does by default not cache any of those.
+ * However, if you want to optimize for a specific server, consider switching
+ * this setting to at least CACHE_CONNECTION or CACHE_SESSION even in
+ * conjunction with an external transaction manager.
+ *
Currently known servers that absolutely require CACHE_NONE for XA
+ * transaction processing: JBoss 4. For any others, consider raising the
+ * cache level.
+ * @see #CACHE_NONE
+ * @see #CACHE_CONNECTION
+ * @see #CACHE_SESSION
+ * @see #CACHE_CONSUMER
+ * @see #setCacheLevelName
+ * @see #setTransactionManager
+ */
+ public void setCacheLevel(int cacheLevel) {
+ this.cacheLevel = cacheLevel;
+ }
+
+ /**
+ * Return the level of caching that this listener container is allowed to apply.
+ */
+ public int getCacheLevel() {
+ return this.cacheLevel;
+ }
+
+
+ /**
+ * Specify the number of concurrent consumers to create. Default is 1.
+ *
Specifying a higher value for this setting will increase the standard
+ * level of scheduled concurrent consumers at runtime: This is effectively
+ * the minimum number of concurrent consumers which will be scheduled
+ * at any given time. This is a static setting; for dynamic scaling,
+ * consider specifying the "maxConcurrentConsumers" setting instead.
+ *
Raising the number of concurrent consumers is recommendable in order
+ * to scale the consumption of messages coming in from a queue. However,
+ * note that any ordering guarantees are lost once multiple consumers are
+ * registered. In general, stick with 1 consumer for low-volume queues.
+ *
Do not raise the number of concurrent consumers for a topic.
+ * This would lead to concurrent consumption of the same message,
+ * which is hardly ever desirable.
+ *
This setting can be modified at runtime, for example through JMX.
+ * @see #setMaxConcurrentConsumers
+ */
+ public void setConcurrentConsumers(int concurrentConsumers) {
+ Assert.isTrue(concurrentConsumers > 0, "'concurrentConsumers' value must be at least 1 (one)");
+ synchronized (this.lifecycleMonitor) {
+ this.concurrentConsumers = concurrentConsumers;
+ if (this.maxConcurrentConsumers < concurrentConsumers) {
+ this.maxConcurrentConsumers = concurrentConsumers;
+ }
+ }
+ }
+
+ /**
+ * Return the "concurrentConsumer" setting.
+ *
This returns the currently configured "concurrentConsumers" value;
+ * the number of currently scheduled/active consumers might differ.
+ * @see #getScheduledConsumerCount()
+ * @see #getActiveConsumerCount()
+ */
+ public final int getConcurrentConsumers() {
+ synchronized (this.lifecycleMonitor) {
+ return this.concurrentConsumers;
+ }
+ }
+
+ /**
+ * Specify the maximum number of concurrent consumers to create. Default is 1.
+ *
If this setting is higher than "concurrentConsumers", the listener container
+ * will dynamically schedule new consumers at runtime, provided that enough
+ * incoming messages are encountered. Once the load goes down again, the number of
+ * consumers will be reduced to the standard level ("concurrentConsumers") again.
+ *
Raising the number of concurrent consumers is recommendable in order
+ * to scale the consumption of messages coming in from a queue. However,
+ * note that any ordering guarantees are lost once multiple consumers are
+ * registered. In general, stick with 1 consumer for low-volume queues.
+ *
Do not raise the number of concurrent consumers for a topic.
+ * This would lead to concurrent consumption of the same message,
+ * which is hardly ever desirable.
+ *
This setting can be modified at runtime, for example through JMX.
+ * @see #setConcurrentConsumers
+ */
+ public void setMaxConcurrentConsumers(int maxConcurrentConsumers) {
+ Assert.isTrue(maxConcurrentConsumers > 0, "'maxConcurrentConsumers' value must be at least 1 (one)");
+ synchronized (this.lifecycleMonitor) {
+ this.maxConcurrentConsumers =
+ (maxConcurrentConsumers > this.concurrentConsumers ? maxConcurrentConsumers : this.concurrentConsumers);
+ }
+ }
+
+ /**
+ * Return the "maxConcurrentConsumer" setting.
+ *
This returns the currently configured "maxConcurrentConsumers" value;
+ * the number of currently scheduled/active consumers might differ.
+ * @see #getScheduledConsumerCount()
+ * @see #getActiveConsumerCount()
+ */
+ public final int getMaxConcurrentConsumers() {
+ synchronized (this.lifecycleMonitor) {
+ return this.maxConcurrentConsumers;
+ }
+ }
+
+ /**
+ * Specify the maximum number of messages to process in one task.
+ * More concretely, this limits the number of message reception attempts
+ * per task, which includes receive iterations that did not actually
+ * pick up a message until they hit their timeout (see the
+ * {@link #setReceiveTimeout "receiveTimeout"} property).
+ *
Default is unlimited (-1) in case of a standard TaskExecutor,
+ * reusing the original invoker threads until shutdown (at the
+ * expense of limited dynamic scheduling).
+ *
In case of a SchedulingTaskExecutor indicating a preference for
+ * short-lived tasks, the default is 10 instead. Specify a number
+ * of 10 to 100 messages to balance between rather long-lived and
+ * rather short-lived tasks here.
+ *
Long-lived tasks avoid frequent thread context switches through
+ * sticking with the same thread all the way through, while short-lived
+ * tasks allow thread pools to control the scheduling. Hence, thread
+ * pools will usually prefer short-lived tasks.
+ *
This setting can be modified at runtime, for example through JMX.
+ * @see #setTaskExecutor
+ * @see #setReceiveTimeout
+ * @see org.springframework.scheduling.SchedulingTaskExecutor#prefersShortLivedTasks()
+ */
+ public void setMaxMessagesPerTask(int maxMessagesPerTask) {
+ Assert.isTrue(maxMessagesPerTask != 0, "'maxMessagesPerTask' must not be 0");
+ synchronized (this.lifecycleMonitor) {
+ this.maxMessagesPerTask = maxMessagesPerTask;
+ }
+ }
+
+ /**
+ * Return the maximum number of messages to process in one task.
+ */
+ public int getMaxMessagesPerTask() {
+ synchronized (this.lifecycleMonitor) {
+ return this.maxMessagesPerTask;
+ }
+ }
+
+ /**
+ * Specify the limit for idle executions of a receive task, not having
+ * received any message within its execution. If this limit is reached,
+ * the task will shut down and leave receiving to other executing tasks.
+ *
Default is 1, closing idle resources early once a task didn't
+ * receive a message. This applies to dynamic scheduling only; see the
+ * {@link #setMaxConcurrentConsumers "maxConcurrentConsumers"} setting.
+ * The minimum number of consumers
+ * (see {@link #setConcurrentConsumers "concurrentConsumers"})
+ * will be kept around until shutdown in any case.
+ *
Within each task execution, a number of message reception attempts
+ * (according to the "maxMessagesPerTask" setting) will each wait for an incoming
+ * message (according to the "receiveTimeout" setting). If all of those receive
+ * attempts in a given task return without a message, the task is considered
+ * idle with respect to received messages. Such a task may still be rescheduled;
+ * however, once it reached the specified "idleTaskExecutionLimit", it will
+ * shut down (in case of dynamic scaling).
+ *
Raise this limit if you encounter too frequent scaling up and down.
+ * With this limit being higher, an idle consumer will be kept around longer,
+ * avoiding the restart of a consumer once a new load of messages comes in.
+ * Alternatively, specify a higher "maxMessagesPerTask" and/or "receiveTimeout" value,
+ * which will also lead to idle consumers being kept around for a longer time
+ * (while also increasing the average execution time of each scheduled task).
+ *
This setting can be modified at runtime, for example through JMX.
+ * @see #setMaxMessagesPerTask
+ * @see #setReceiveTimeout
+ */
+ public void setIdleTaskExecutionLimit(int idleTaskExecutionLimit) {
+ Assert.isTrue(idleTaskExecutionLimit > 0, "'idleTaskExecutionLimit' must be 1 or higher");
+ synchronized (this.lifecycleMonitor) {
+ this.idleTaskExecutionLimit = idleTaskExecutionLimit;
+ }
+ }
+
+ /**
+ * Return the limit for idle executions of a receive task.
+ */
+ public int getIdleTaskExecutionLimit() {
+ synchronized (this.lifecycleMonitor) {
+ return this.idleTaskExecutionLimit;
+ }
+ }
+
+ protected void validateConfiguration() {
+ super.validateConfiguration();
+ synchronized (this.lifecycleMonitor) {
+ if (isSubscriptionDurable() && this.concurrentConsumers != 1) {
+ throw new IllegalArgumentException("Only 1 concurrent consumer supported for durable subscription");
+ }
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Implementation of AbstractMessageListenerContainer's template methods
+ //-------------------------------------------------------------------------
+
+ public void initialize() {
+ // Adapt default cache level.
+ if (this.cacheLevel == CACHE_AUTO) {
+ this.cacheLevel = (getTransactionManager() != null ? CACHE_NONE : CACHE_CONSUMER);
+ }
+
+ // Prepare taskExecutor and maxMessagesPerTask.
+ synchronized (this.lifecycleMonitor) {
+ if (this.taskExecutor == null) {
+ this.taskExecutor = createDefaultTaskExecutor();
+ }
+ else if (this.taskExecutor instanceof SchedulingTaskExecutor &&
+ ((SchedulingTaskExecutor) this.taskExecutor).prefersShortLivedTasks() &&
+ this.maxMessagesPerTask == Integer.MIN_VALUE) {
+ // TaskExecutor indicated a preference for short-lived tasks. According to
+ // setMaxMessagesPerTask javadoc, we'll use 10 message per task in this case
+ // unless the user specified a custom value.
+ this.maxMessagesPerTask = 10;
+ }
+ }
+
+ // Proceed with actual listener initialization.
+ super.initialize();
+ }
+
+ /**
+ * Creates the specified number of concurrent consumers,
+ * in the form of a JMS Session plus associated MessageConsumer
+ * running in a separate thread.
+ * @see #scheduleNewInvoker
+ * @see #setTaskExecutor
+ */
+ protected void doInitialize() throws JMSException {
+ synchronized (this.lifecycleMonitor) {
+ for (int i = 0; i < this.concurrentConsumers; i++) {
+ scheduleNewInvoker();
+ }
+ }
+ }
+
+ /**
+ * Destroy the registered JMS Sessions and associated MessageConsumers.
+ */
+ protected void doShutdown() throws JMSException {
+ logger.debug("Waiting for shutdown of message listener invokers");
+ try {
+ synchronized (this.lifecycleMonitor) {
+ while (this.activeInvokerCount > 0) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Still waiting for shutdown of " + this.activeInvokerCount +
+ " message listener invokers");
+ }
+ this.lifecycleMonitor.wait();
+ }
+ }
+ }
+ catch (InterruptedException ex) {
+ // Re-interrupt current thread, to allow other threads to react.
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ /**
+ * Overridden to reset the stop callback, if any.
+ */
+ public void start() throws JmsException {
+ synchronized (this.lifecycleMonitor) {
+ this.stopCallback = null;
+ }
+ super.start();
+ }
+
+ /**
+ * Stop this listener container, invoking the specific callback
+ * once all listener processing has actually stopped.
+ *
Note: Further stop(runnable) calls (before processing
+ * has actually stopped) will override the specified callback. Only the
+ * latest specified callback will be invoked.
+ *
If a subsequent {@link #start()} call restarts the listener container
+ * before it has fully stopped, the callback will not get invoked at all.
+ * @param callback the callback to invoke once listener processing
+ * has fully stopped
+ * @throws JmsException if stopping failed
+ * @see #stop()
+ */
+ public void stop(Runnable callback) throws JmsException {
+ synchronized (this.lifecycleMonitor) {
+ this.stopCallback = callback;
+ }
+ stop();
+ }
+
+ /**
+ * Return the number of currently scheduled consumers.
+ *
This number will always be inbetween "concurrentConsumers" and
+ * "maxConcurrentConsumers", but might be higher than "activeConsumerCount"
+ * (in case of some consumers being scheduled but not executed at the moment).
+ * @see #getConcurrentConsumers()
+ * @see #getMaxConcurrentConsumers()
+ * @see #getActiveConsumerCount()
+ */
+ public final int getScheduledConsumerCount() {
+ synchronized (this.lifecycleMonitor) {
+ return this.scheduledInvokers.size();
+ }
+ }
+
+ /**
+ * Return the number of currently active consumers.
+ *
This number will always be inbetween "concurrentConsumers" and
+ * "maxConcurrentConsumers", but might be lower than "scheduledConsumerCount".
+ * (in case of some consumers being scheduled but not executed at the moment).
+ * @see #getConcurrentConsumers()
+ * @see #getMaxConcurrentConsumers()
+ * @see #getActiveConsumerCount()
+ */
+ public final int getActiveConsumerCount() {
+ synchronized (this.lifecycleMonitor) {
+ return this.activeInvokerCount;
+ }
+ }
+
+
+ /**
+ * Create a default TaskExecutor. Called if no explicit TaskExecutor has been specified.
+ *
The default implementation builds a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}
+ * with the specified bean name (or the class name, if no bean name specified) as thread name prefix.
+ * @see org.springframework.core.task.SimpleAsyncTaskExecutor#SimpleAsyncTaskExecutor(String)
+ */
+ protected TaskExecutor createDefaultTaskExecutor() {
+ String beanName = getBeanName();
+ String threadNamePrefix = (beanName != null ? beanName + "-" : DEFAULT_THREAD_NAME_PREFIX);
+ return new SimpleAsyncTaskExecutor(threadNamePrefix);
+ }
+
+ /**
+ * Schedule a new invoker, increasing the total number of scheduled
+ * invokers for this listener container.
+ */
+ private void scheduleNewInvoker() {
+ AsyncMessageListenerInvoker invoker = new AsyncMessageListenerInvoker();
+ if (rescheduleTaskIfNecessary(invoker)) {
+ // This should always be true, since we're only calling this when active.
+ this.scheduledInvokers.add(invoker);
+ }
+ }
+
+ /**
+ * Use a shared JMS Connection depending on the "cacheLevel" setting.
+ * @see #setCacheLevel
+ * @see #CACHE_CONNECTION
+ */
+ protected final boolean sharedConnectionEnabled() {
+ return (getCacheLevel() >= CACHE_CONNECTION);
+ }
+
+ /**
+ * Re-executes the given task via this listener container's TaskExecutor.
+ * @see #setTaskExecutor
+ */
+ protected void doRescheduleTask(Object task) {
+ this.taskExecutor.execute((Runnable) task);
+ }
+
+ /**
+ * Tries scheduling a new invoker, since we know messages are coming in...
+ * @see #scheduleNewInvokerIfAppropriate()
+ */
+ protected void messageReceived(Object invoker, Session session) {
+ ((AsyncMessageListenerInvoker) invoker).setIdle(false);
+ scheduleNewInvokerIfAppropriate();
+ }
+
+ /**
+ * Marks the affected invoker as idle.
+ */
+ protected void noMessageReceived(Object invoker, Session session) {
+ ((AsyncMessageListenerInvoker) invoker).setIdle(true);
+ }
+
+ /**
+ * Schedule a new invoker, increasing the total number of scheduled
+ * invokers for this listener container, but only if the specified
+ * "maxConcurrentConsumers" limit has not been reached yet, and only
+ * if this listener container does not currently have idle invokers
+ * that are waiting for new messages already.
+ *
Called once a message has been received, to scale up while
+ * processing the message in the invoker that originally received it.
+ * @see #setTaskExecutor
+ * @see #getMaxConcurrentConsumers()
+ */
+ protected void scheduleNewInvokerIfAppropriate() {
+ if (isRunning()) {
+ resumePausedTasks();
+ synchronized (this.lifecycleMonitor) {
+ if (this.scheduledInvokers.size() < this.maxConcurrentConsumers && getIdleInvokerCount() == 0) {
+ scheduleNewInvoker();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Raised scheduled invoker count: " + this.scheduledInvokers.size());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Determine whether the current invoker should be rescheduled,
+ * given that it might not have received a message in a while.
+ * @param idleTaskExecutionCount the number of idle executions
+ * that this invoker task has already accumulated (in a row)
+ */
+ private boolean shouldRescheduleInvoker(int idleTaskExecutionCount) {
+ boolean superfluous =
+ (idleTaskExecutionCount >= this.idleTaskExecutionLimit && getIdleInvokerCount() > 1);
+ return (this.scheduledInvokers.size() <=
+ (superfluous ? this.concurrentConsumers : this.maxConcurrentConsumers));
+ }
+
+ /**
+ * Determine whether this listener container currently has more
+ * than one idle instance among its scheduled invokers.
+ */
+ private int getIdleInvokerCount() {
+ int count = 0;
+ for (Iterator it = this.scheduledInvokers.iterator(); it.hasNext();) {
+ AsyncMessageListenerInvoker invoker = (AsyncMessageListenerInvoker) it.next();
+ if (invoker.isIdle()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+
+ /**
+ * Overridden to accept a failure in the initial setup - leaving it up to the
+ * asynchronous invokers to establish the shared Connection on first access.
+ * @see #refreshConnectionUntilSuccessful()
+ */
+ protected void establishSharedConnection() {
+ try {
+ super.establishSharedConnection();
+ }
+ catch (Exception ex) {
+ logger.debug("Could not establish shared JMS Connection - " +
+ "leaving it up to asynchronous invokers to establish a Connection as soon as possible", ex);
+ }
+ }
+
+ /**
+ * This implementations proceeds even after an exception thrown from
+ * Connection.start(), relying on listeners to perform
+ * appropriate recovery.
+ */
+ protected void startSharedConnection() {
+ try {
+ super.startSharedConnection();
+ }
+ catch (Exception ex) {
+ logger.debug("Connection start failed - relying on listeners to perform recovery", ex);
+ }
+ }
+
+ /**
+ * This implementations proceeds even after an exception thrown from
+ * Connection.stop(), relying on listeners to perform
+ * appropriate recovery after a restart.
+ */
+ protected void stopSharedConnection() {
+ try {
+ super.stopSharedConnection();
+ }
+ catch (Exception ex) {
+ logger.debug("Connection stop failed - relying on listeners to perform recovery after restart", ex);
+ }
+ }
+
+ /**
+ * Handle the given exception that arose during setup of a listener.
+ * Called for every such exception in every concurrent listener.
+ *
The default implementation logs the exception at error level
+ * if not recovered yet, and at debug level if already recovered.
+ * Can be overridden in subclasses.
+ * @param ex the exception to handle
+ * @param alreadyRecovered whether a previously executing listener
+ * already recovered from the present listener setup failure
+ * (this usually indicates a follow-up failure than can be ignored
+ * other than for debug log purposes)
+ * @see #recoverAfterListenerSetupFailure()
+ */
+ protected void handleListenerSetupFailure(Throwable ex, boolean alreadyRecovered) {
+ if (ex instanceof JMSException) {
+ invokeExceptionListener((JMSException) ex);
+ }
+ if (ex instanceof SharedConnectionNotInitializedException) {
+ if (!alreadyRecovered) {
+ logger.debug("JMS message listener invoker needs to establish shared Connection");
+ }
+ }
+ else {
+ // Recovery during active operation..
+ if (alreadyRecovered) {
+ logger.debug("Setup of JMS message listener invoker failed - already recovered by other invoker", ex);
+ }
+ else {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Setup of JMS message listener invoker failed for destination '");
+ msg.append(getDestinationDescription()).append("' - trying to recover. Cause: ");
+ msg.append(ex instanceof JMSException ? JmsUtils.buildExceptionMessage((JMSException) ex) : ex.getMessage());
+ if (logger.isDebugEnabled()) {
+ logger.info(msg, ex);
+ }
+ else {
+ logger.info(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Recover this listener container after a listener failed to set itself up,
+ * for example reestablishing the underlying Connection.
+ *
The default implementation delegates to DefaultMessageListenerContainer's
+ * recovery-capable {@link #refreshConnectionUntilSuccessful()} method, which will
+ * try to re-establish a Connection to the JMS provider both for the shared
+ * and the non-shared Connection case.
+ * @see #refreshConnectionUntilSuccessful()
+ * @see #refreshDestination()
+ */
+ protected void recoverAfterListenerSetupFailure() {
+ refreshConnectionUntilSuccessful();
+ refreshDestination();
+ }
+
+ /**
+ * Refresh the underlying Connection, not returning before an attempt has been
+ * successful. Called in case of a shared Connection as well as without shared
+ * Connection, so either needs to operate on the shared Connection or on a
+ * temporary Connection that just gets established for validation purposes.
+ *
The default implementation retries until it successfully established a
+ * Connection, for as long as this message listener container is active.
+ * Applies the specified recovery interval between retries.
+ * @see #setRecoveryInterval
+ */
+ protected void refreshConnectionUntilSuccessful() {
+ while (isRunning()) {
+ try {
+ if (sharedConnectionEnabled()) {
+ refreshSharedConnection();
+ }
+ else {
+ Connection con = createConnection();
+ JmsUtils.closeConnection(con);
+ }
+ logger.info("Successfully refreshed JMS Connection");
+ break;
+ }
+ catch (Exception ex) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Could not refresh JMS Connection for destination '");
+ msg.append(getDestinationDescription()).append("' - retrying in ");
+ msg.append(this.recoveryInterval).append(" ms. Cause: ");
+ msg.append(ex instanceof JMSException ? JmsUtils.buildExceptionMessage((JMSException) ex) : ex.getMessage());
+ if (logger.isDebugEnabled()) {
+ logger.info(msg, ex);
+ }
+ else if (logger.isInfoEnabled()) {
+ logger.info(msg);
+ }
+ }
+ sleepInbetweenRecoveryAttempts();
+ }
+ }
+
+ /**
+ * Refresh the JMS destination that this listener container operates on.
+ *
Called after listener setup failure, assuming that a cached Destination
+ * object might have become invalid (a typical case on WebLogic JMS).
+ *
The default implementation removes the destination from a
+ * DestinationResolver's cache, in case of a CachingDestinationResolver.
+ * @see #setDestinationName
+ * @see org.springframework.jms.support.destination.CachingDestinationResolver
+ */
+ protected void refreshDestination() {
+ String destName = getDestinationName();
+ if (destName != null) {
+ DestinationResolver destResolver = getDestinationResolver();
+ if (destResolver instanceof CachingDestinationResolver) {
+ ((CachingDestinationResolver) destResolver).removeFromCache(destName);
+ }
+ }
+ }
+
+ /**
+ * Sleep according to the specified recovery interval.
+ * Called inbetween recovery attempts.
+ */
+ protected void sleepInbetweenRecoveryAttempts() {
+ if (this.recoveryInterval > 0) {
+ try {
+ Thread.sleep(this.recoveryInterval);
+ }
+ catch (InterruptedException interEx) {
+ // Re-interrupt current thread, to allow other threads to react.
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Inner classes used as internal adapters
+ //-------------------------------------------------------------------------
+
+ /**
+ * Runnable that performs looped MessageConsumer.receive() calls.
+ */
+ private class AsyncMessageListenerInvoker implements SchedulingAwareRunnable {
+
+ private Session session;
+
+ private MessageConsumer consumer;
+
+ private Object lastRecoveryMarker;
+
+ private boolean lastMessageSucceeded;
+
+ private int idleTaskExecutionCount = 0;
+
+ private volatile boolean idle = true;
+
+ public void run() {
+ synchronized (lifecycleMonitor) {
+ activeInvokerCount++;
+ lifecycleMonitor.notifyAll();
+ }
+ boolean messageReceived = false;
+ try {
+ if (maxMessagesPerTask < 0) {
+ messageReceived = executeOngoingLoop();
+ }
+ else {
+ int messageCount = 0;
+ while (isRunning() && messageCount < maxMessagesPerTask) {
+ messageReceived = (invokeListener() || messageReceived);
+ messageCount++;
+ }
+ }
+ }
+ catch (Throwable ex) {
+ clearResources();
+ if (!this.lastMessageSucceeded) {
+ // We failed more than once in a row - sleep for recovery interval
+ // even before first recovery attempt.
+ sleepInbetweenRecoveryAttempts();
+ }
+ this.lastMessageSucceeded = false;
+ boolean alreadyRecovered = false;
+ synchronized (recoveryMonitor) {
+ if (this.lastRecoveryMarker == currentRecoveryMarker) {
+ handleListenerSetupFailure(ex, false);
+ recoverAfterListenerSetupFailure();
+ currentRecoveryMarker = new Object();
+ }
+ else {
+ alreadyRecovered = true;
+ }
+ }
+ if (alreadyRecovered) {
+ handleListenerSetupFailure(ex, true);
+ }
+ }
+ synchronized (lifecycleMonitor) {
+ decreaseActiveInvokerCount();
+ lifecycleMonitor.notifyAll();
+ }
+ if (!messageReceived) {
+ this.idleTaskExecutionCount++;
+ }
+ else {
+ this.idleTaskExecutionCount = 0;
+ }
+ synchronized (lifecycleMonitor) {
+ if (!shouldRescheduleInvoker(this.idleTaskExecutionCount) || !rescheduleTaskIfNecessary(this)) {
+ // We're shutting down completely.
+ scheduledInvokers.remove(this);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Lowered scheduled invoker count: " + scheduledInvokers.size());
+ }
+ lifecycleMonitor.notifyAll();
+ clearResources();
+ }
+ else if (isRunning()) {
+ int nonPausedConsumers = getScheduledConsumerCount() - getPausedTaskCount();
+ if (nonPausedConsumers < 1) {
+ logger.error("All scheduled consumers have been paused, probably due to tasks having been rejected. " +
+ "Check your thread pool configuration! Manual recovery necessary through a start() call.");
+ }
+ else if (nonPausedConsumers < getConcurrentConsumers()) {
+ logger.warn("Number of scheduled consumers has dropped below concurrentConsumers limit, probably " +
+ "due to tasks having been rejected. Check your thread pool configuration! Automatic recovery " +
+ "to be triggered by remaining consumers.");
+ }
+ }
+ }
+ }
+
+ private boolean executeOngoingLoop() throws JMSException {
+ boolean messageReceived = false;
+ boolean active = true;
+ while (active) {
+ synchronized (lifecycleMonitor) {
+ boolean interrupted = false;
+ boolean wasWaiting = false;
+ while ((active = isActive()) && !isRunning()) {
+ if (interrupted) {
+ throw new IllegalStateException("Thread was interrupted while waiting for " +
+ "a restart of the listener container, but container is still stopped");
+ }
+ if (!wasWaiting) {
+ decreaseActiveInvokerCount();
+ }
+ wasWaiting = true;
+ try {
+ lifecycleMonitor.wait();
+ }
+ catch (InterruptedException ex) {
+ // Re-interrupt current thread, to allow other threads to react.
+ Thread.currentThread().interrupt();
+ interrupted = true;
+ }
+ }
+ if (wasWaiting) {
+ activeInvokerCount++;
+ }
+ }
+ if (active) {
+ messageReceived = (invokeListener() || messageReceived);
+ }
+ }
+ return messageReceived;
+ }
+
+ private boolean invokeListener() throws JMSException {
+ initResourcesIfNecessary();
+ boolean messageReceived = receiveAndExecute(this, this.session, this.consumer);
+ this.lastMessageSucceeded = true;
+ return messageReceived;
+ }
+
+ private void decreaseActiveInvokerCount() {
+ activeInvokerCount--;
+ if (stopCallback != null && activeInvokerCount == 0) {
+ stopCallback.run();
+ stopCallback = null;
+ }
+ }
+
+ private void initResourcesIfNecessary() throws JMSException {
+ if (getCacheLevel() <= CACHE_CONNECTION) {
+ updateRecoveryMarker();
+ }
+ else {
+ if (this.session == null && getCacheLevel() >= CACHE_SESSION) {
+ updateRecoveryMarker();
+ this.session = createSession(getSharedConnection());
+ }
+ if (this.consumer == null && getCacheLevel() >= CACHE_CONSUMER) {
+ this.consumer = createListenerConsumer(this.session);
+ }
+ }
+ }
+
+ private void updateRecoveryMarker() {
+ synchronized (recoveryMonitor) {
+ this.lastRecoveryMarker = currentRecoveryMarker;
+ }
+ }
+
+ private void clearResources() {
+ if (sharedConnectionEnabled()) {
+ synchronized (sharedConnectionMonitor) {
+ JmsUtils.closeMessageConsumer(this.consumer);
+ JmsUtils.closeSession(this.session);
+ }
+ }
+ else {
+ JmsUtils.closeMessageConsumer(this.consumer);
+ JmsUtils.closeSession(this.session);
+ }
+ this.consumer = null;
+ this.session = null;
+ }
+
+ public boolean isLongLived() {
+ return (maxMessagesPerTask < 0);
+ }
+
+ public void setIdle(boolean idle) {
+ this.idle = idle;
+ }
+
+ public boolean isIdle() {
+ return this.idle;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/DefaultMessageListenerContainer102.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2002-2007 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.jms.listener;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSession;
+
+import org.springframework.jms.connection.JmsResourceHolder;
+
+/**
+ * A subclass of {@link DefaultMessageListenerContainer} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like SimpleMessageListenerContainer itself.
+ *
+ *
This class can be used for JMS 1.0.2 providers, offering the same facility as
+ * DefaultMessageListenerContainer does for JMS 1.1 providers.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public class DefaultMessageListenerContainer102 extends DefaultMessageListenerContainer {
+
+ /**
+ * This implementation overrides the superclass method to accept either
+ * a QueueConnection or a TopicConnection, depending on the domain.
+ */
+ protected Connection getConnection(JmsResourceHolder holder) {
+ return holder.getConnection(isPubSubDomain() ? (Class) TopicConnection.class : QueueConnection.class);
+ }
+
+ /**
+ * This implementation overrides the superclass method to accept either
+ * a QueueSession or a TopicSession, depending on the domain.
+ */
+ protected Session getSession(JmsResourceHolder holder) {
+ return holder.getSession(isPubSubDomain() ? (Class) TopicSession.class : QueueSession.class);
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection createConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ else {
+ return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
+ if (isPubSubDomain()) {
+ if (isSubscriptionDurable()) {
+ return ((TopicSession) session).createDurableSubscriber(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
+ }
+ else {
+ return ((TopicSession) session).createSubscriber(
+ (Topic) destination, getMessageSelector(), isPubSubNoLocal());
+ }
+ }
+ else {
+ return ((QueueSession) session).createReceiver((Queue) destination, getMessageSelector());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to avoid using
+ * JMS 1.1's Session getAcknowledgeMode() method.
+ * The best we can do here is to check the setting on the listener container.
+ */
+ protected boolean isClientAcknowledge(Session session) throws JMSException {
+ return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/LocallyExposedJmsResourceHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/LocallyExposedJmsResourceHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/LocallyExposedJmsResourceHolder.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import javax.jms.Session;
+
+import org.springframework.jms.connection.JmsResourceHolder;
+
+/**
+ * JmsResourceHolder marker subclass that indicates local exposure,
+ * i.e. that does not indicate an externally managed transaction.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.2
+ */
+class LocallyExposedJmsResourceHolder extends JmsResourceHolder {
+
+ public LocallyExposedJmsResourceHolder(Session session) {
+ super(session);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/SessionAwareMessageListener.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/SessionAwareMessageListener.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/SessionAwareMessageListener.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+/**
+ * Variant of the standard JMS {@link javax.jms.MessageListener} interface,
+ * offering not only the received Message but also the underlying
+ * JMS Session object. The latter can be used to send reply messages,
+ * without the need to access an external Connection/Session,
+ * i.e. without the need to access the underlying ConnectionFactory.
+ *
+ *
Supported by Spring's {@link DefaultMessageListenerContainer}
+ * and {@link SimpleMessageListenerContainer},
+ * as direct alternative to the standard JMS MessageListener interface.
+ * Typically not supported by JCA-based listener containers:
+ * For maximum compatibility, implement a standard JMS MessageListener instead.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see AbstractMessageListenerContainer#setMessageListener
+ * @see DefaultMessageListenerContainer
+ * @see SimpleMessageListenerContainer
+ * @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
+ * @see javax.jms.MessageListener
+ */
+public interface SessionAwareMessageListener {
+
+ /**
+ * Callback for processing a received JMS message.
+ *
Implementors are supposed to process the given Message,
+ * typically sending reply messages through the given Session.
+ * @param message the received JMS message (never null)
+ * @param session the underlying JMS Session (never null)
+ * @throws JMSException if thrown by JMS methods
+ */
+ void onMessage(Message message, Session session) throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+
+/**
+ * Message listener container that uses the plain JMS client API's
+ * MessageConsumer.setMessageListener() method to
+ * create concurrent MessageConsumers for the specified listeners.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider, because it builds on
+ * the domain-independent API. Use the {@link SimpleMessageListenerContainer102}
+ * subclass for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.
+ *
+ *
This is the simplest form of a message listener container.
+ * It creates a fixed number of JMS Sessions to invoke the listener,
+ * not allowing for dynamic adaptation to runtime demands. Its main
+ * advantage is its low level of complexity and the minimum requirements
+ * on the JMS provider: Not even the ServerSessionPool facility is required.
+ *
+ *
See the {@link AbstractMessageListenerContainer} javadoc for details
+ * on acknowledge modes and transaction options.
+ *
+ *
For a different style of MessageListener handling, through looped
+ * MessageConsumer.receive() calls that also allow for
+ * transactional reception of messages (registering them with XA transactions),
+ * see {@link DefaultMessageListenerContainer}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see javax.jms.MessageConsumer#setMessageListener
+ * @see DefaultMessageListenerContainer
+ * @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
+ */
+public class SimpleMessageListenerContainer extends AbstractMessageListenerContainer implements ExceptionListener {
+
+ private boolean pubSubNoLocal = false;
+
+ private int concurrentConsumers = 1;
+
+ private TaskExecutor taskExecutor;
+
+ private Set sessions;
+
+ private Set consumers;
+
+ private final Object consumersMonitor = new Object();
+
+
+ /**
+ * Set whether to inhibit the delivery of messages published by its own connection.
+ * Default is "false".
+ * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic, String, boolean)
+ */
+ public void setPubSubNoLocal(boolean pubSubNoLocal) {
+ this.pubSubNoLocal = pubSubNoLocal;
+ }
+
+ /**
+ * Return whether to inhibit the delivery of messages published by its own connection.
+ */
+ protected boolean isPubSubNoLocal() {
+ return this.pubSubNoLocal;
+ }
+
+ /**
+ * Specify the number of concurrent consumers to create. Default is 1.
+ *
Raising the number of concurrent consumers is recommendable in order
+ * to scale the consumption of messages coming in from a queue. However,
+ * note that any ordering guarantees are lost once multiple consumers are
+ * registered. In general, stick with 1 consumer for low-volume queues.
+ *
Do not raise the number of concurrent consumers for a topic.
+ * This would lead to concurrent consumption of the same message,
+ * which is hardly ever desirable.
+ */
+ public void setConcurrentConsumers(int concurrentConsumers) {
+ Assert.isTrue(concurrentConsumers > 0, "'concurrentConsumers' value must be at least 1 (one)");
+ this.concurrentConsumers = concurrentConsumers;
+ }
+
+ /**
+ * Set the Spring TaskExecutor to use for executing the listener once
+ * a message has been received by the provider.
+ *
Default is none, that is, to run in the JMS provider's own receive thread,
+ * blocking the provider's receive endpoint while executing the listener.
+ *
Specify a TaskExecutor for executing the listener in a different thread,
+ * rather than blocking the JMS provider, usually integrating with an existing
+ * thread pool. This allows to keep the number of concurrent consumers low (1)
+ * while still processing messages concurrently (decoupled from receiving!).
+ *
NOTE: Specifying a TaskExecutor for listener execution affects
+ * acknowledgement semantics. Messages will then always get acknowledged
+ * before listener execution, with the underlying Session immediately reused
+ * for receiving the next message. Using this in combination with a transacted
+ * session or with client acknowledgement will lead to unspecified results!
+ *
NOTE: Concurrent listener execution via a TaskExecutor will lead
+ * to concurrent processing of messages that have been received by the same
+ * underlying Session. As a consequence, it is not recommended to use
+ * this setting with a {@link SessionAwareMessageListener}, at least not
+ * if the latter performs actual work on the given Session. A standard
+ * {@link javax.jms.MessageListener} will work fine, in general.
+ * @see #setConcurrentConsumers
+ * @see org.springframework.core.task.SimpleAsyncTaskExecutor
+ * @see org.springframework.scheduling.commonj.WorkManagerTaskExecutor
+ */
+ public void setTaskExecutor(TaskExecutor taskExecutor) {
+ this.taskExecutor = taskExecutor;
+ }
+
+ protected void validateConfiguration() {
+ super.validateConfiguration();
+ if (isSubscriptionDurable() && this.concurrentConsumers != 1) {
+ throw new IllegalArgumentException("Only 1 concurrent consumer supported for durable subscription");
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Implementation of AbstractMessageListenerContainer's template methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Always use a shared JMS Connection.
+ */
+ protected final boolean sharedConnectionEnabled() {
+ return true;
+ }
+
+ /**
+ * Creates the specified number of concurrent consumers,
+ * in the form of a JMS Session plus associated MessageConsumer.
+ * @see #createListenerConsumer
+ */
+ protected void doInitialize() throws JMSException {
+ establishSharedConnection();
+ initializeConsumers();
+ }
+
+ /**
+ * Re-initializes this container's JMS message consumers,
+ * if not initialized already.
+ */
+ protected void doStart() throws JMSException {
+ super.doStart();
+ initializeConsumers();
+ }
+
+ /**
+ * Registers this listener container as JMS ExceptionListener on the shared connection.
+ */
+ protected void prepareSharedConnection(Connection connection) throws JMSException {
+ super.prepareSharedConnection(connection);
+ connection.setExceptionListener(this);
+ }
+
+ /**
+ * JMS ExceptionListener implementation, invoked by the JMS provider in
+ * case of connection failures. Re-initializes this listener container's
+ * shared connection and its sessions and consumers.
+ * @param ex the reported connection exception
+ */
+ public void onException(JMSException ex) {
+ // First invoke the user-specific ExceptionListener, if any.
+ invokeExceptionListener(ex);
+
+ // Now try to recover the shared Connection and all consumers...
+ if (logger.isInfoEnabled()) {
+ logger.info("Trying to recover from JMS Connection exception: " + ex);
+ }
+ try {
+ synchronized (this.consumersMonitor) {
+ this.sessions = null;
+ this.consumers = null;
+ }
+ refreshSharedConnection();
+ initializeConsumers();
+ logger.info("Successfully refreshed JMS Connection");
+ }
+ catch (JMSException recoverEx) {
+ logger.debug("Failed to recover JMS Connection", recoverEx);
+ logger.error("Encountered non-recoverable JMSException", ex);
+ }
+ }
+
+ /**
+ * Initialize the JMS Sessions and MessageConsumers for this container.
+ * @throws JMSException in case of setup failure
+ */
+ protected void initializeConsumers() throws JMSException {
+ // Register Sessions and MessageConsumers.
+ synchronized (this.consumersMonitor) {
+ if (this.consumers == null) {
+ this.sessions = new HashSet(this.concurrentConsumers);
+ this.consumers = new HashSet(this.concurrentConsumers);
+ Connection con = getSharedConnection();
+ for (int i = 0; i < this.concurrentConsumers; i++) {
+ Session session = createSession(con);
+ MessageConsumer consumer = createListenerConsumer(session);
+ this.sessions.add(session);
+ this.consumers.add(consumer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a MessageConsumer for the given JMS Session,
+ * registering a MessageListener for the specified listener.
+ * @param session the JMS Session to work on
+ * @return the MessageConsumer
+ * @throws JMSException if thrown by JMS methods
+ * @see #executeListener
+ */
+ protected MessageConsumer createListenerConsumer(final Session session) throws JMSException {
+ Destination destination = getDestination();
+ if (destination == null) {
+ destination = resolveDestinationName(session, getDestinationName());
+ }
+ MessageConsumer consumer = createConsumer(session, destination);
+
+ if (this.taskExecutor != null) {
+ consumer.setMessageListener(new MessageListener() {
+ public void onMessage(final Message message) {
+ taskExecutor.execute(new Runnable() {
+ public void run() {
+ processMessage(message, session);
+ }
+ });
+ }
+ });
+ }
+ else {
+ consumer.setMessageListener(new MessageListener() {
+ public void onMessage(Message message) {
+ processMessage(message, session);
+ }
+ });
+ }
+
+ return consumer;
+ }
+
+ /**
+ * Process a message received from the provider.
+ *
Executes the listener, exposing the current JMS Session as
+ * thread-bound resource (if "exposeListenerSession" is "true").
+ * @param message the received JMS Message
+ * @param session the JMS Session to operate on
+ * @see #executeListener
+ * @see #setExposeListenerSession
+ */
+ protected void processMessage(Message message, Session session) {
+ boolean exposeResource = isExposeListenerSession();
+ if (exposeResource) {
+ TransactionSynchronizationManager.bindResource(
+ getConnectionFactory(), new LocallyExposedJmsResourceHolder(session));
+ }
+ try {
+ executeListener(session, message);
+ }
+ finally {
+ if (exposeResource) {
+ TransactionSynchronizationManager.unbindResource(getConnectionFactory());
+ }
+ }
+ }
+
+ /**
+ * Destroy the registered JMS Sessions and associated MessageConsumers.
+ */
+ protected void doShutdown() throws JMSException {
+ logger.debug("Closing JMS MessageConsumers");
+ for (Iterator it = this.consumers.iterator(); it.hasNext();) {
+ MessageConsumer consumer = (MessageConsumer) it.next();
+ JmsUtils.closeMessageConsumer(consumer);
+ }
+ logger.debug("Closing JMS Sessions");
+ for (Iterator it = this.sessions.iterator(); it.hasNext();) {
+ Session session = (Session) it.next();
+ JmsUtils.closeSession(session);
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Create a JMS MessageConsumer for the given Session and Destination.
+ *
This implementation uses JMS 1.1 API.
+ * @param session the JMS Session to create a MessageConsumer for
+ * @param destination the JMS Destination to create a MessageConsumer for
+ * @return the new JMS MessageConsumer
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
+ // Only pass in the NoLocal flag in case of a Topic:
+ // Some JMS providers, such as WebSphere MQ 6.0, throw IllegalStateException
+ // in case of the NoLocal flag being specified for a Queue.
+ if (isPubSubDomain()) {
+ if (isSubscriptionDurable() && destination instanceof Topic) {
+ return session.createDurableSubscriber(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
+ }
+ else {
+ return session.createConsumer(destination, getMessageSelector(), isPubSubNoLocal());
+ }
+ }
+ else {
+ return session.createConsumer(destination, getMessageSelector());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/SimpleMessageListenerContainer102.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2002-2007 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.jms.listener;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSession;
+
+/**
+ * A subclass of {@link SimpleMessageListenerContainer} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like SimpleMessageListenerContainer itself.
+ *
+ *
This class can be used for JMS 1.0.2 providers, offering the same facility as
+ * SimpleMessageListenerContainer does for JMS 1.1 providers.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public class SimpleMessageListenerContainer102 extends SimpleMessageListenerContainer {
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection createConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ else {
+ return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected MessageConsumer createConsumer(Session session, Destination destination) throws JMSException {
+ if (isPubSubDomain()) {
+ if (isSubscriptionDurable()) {
+ return ((TopicSession) session).createDurableSubscriber(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), isPubSubNoLocal());
+ }
+ else {
+ return ((TopicSession) session).createSubscriber(
+ (Topic) destination, getMessageSelector(), isPubSubNoLocal());
+ }
+ }
+ else {
+ return ((QueueSession) session).createReceiver((Queue) destination, getMessageSelector());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to avoid using
+ * JMS 1.1's Session getAcknowledgeMode() method.
+ * The best we can do here is to check the setting on the listener container.
+ */
+ protected boolean isClientAcknowledge(Session session) throws JMSException {
+ return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/SubscriptionNameProvider.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/SubscriptionNameProvider.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/SubscriptionNameProvider.java 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2008 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.jms.listener;
+
+/**
+ * Interface to be implemented by message listener objects that suggest a specific
+ * name for a durable subscription that they might be registered with. Otherwise
+ * the listener class name will be used as a default subscription name.
+ *
+ *
Applies to {@link javax.jms.MessageListener} objects as well as to
+ * {@link SessionAwareMessageListener} objects and plain listener methods
+ * (as supported by {@link org.springframework.jms.listener.adapter.MessageListenerAdapter}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.6
+ */
+public interface SubscriptionNameProvider {
+
+ /**
+ * Determine the subscription name for this message listener object.
+ */
+ String getSubscriptionName();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/package.html 17 Aug 2012 15:15:25 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
+This package contains the base message listener container facility.
+It also offers the DefaultMessageListenerContainer and SimpleMessageListenerContainer
+implementations, based on the plain JMS client API.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/listener/adapter/ListenerExecutionFailedException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/adapter/ListenerExecutionFailedException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/adapter/ListenerExecutionFailedException.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2006 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.jms.listener.adapter;
+
+import org.springframework.jms.JmsException;
+
+/**
+ * Exception to be thrown when the execution of a listener method failed.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see MessageListenerAdapter
+ */
+public class ListenerExecutionFailedException extends JmsException {
+
+ /**
+ * Constructor for ListenerExecutionFailedException.
+ * @param msg the detail message
+ * @param cause the exception thrown by the listener method
+ */
+ public ListenerExecutionFailedException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.adapter;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.jms.Destination;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.jms.listener.SessionAwareMessageListener;
+import org.springframework.jms.listener.SubscriptionNameProvider;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.converter.MessageConversionException;
+import org.springframework.jms.support.converter.MessageConverter;
+import org.springframework.jms.support.converter.SimpleMessageConverter;
+import org.springframework.jms.support.destination.DestinationResolver;
+import org.springframework.jms.support.destination.DynamicDestinationResolver;
+import org.springframework.util.Assert;
+import org.springframework.util.MethodInvoker;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Message listener adapter that delegates the handling of messages to target
+ * listener methods via reflection, with flexible message type conversion.
+ * Allows listener methods to operate on message content types, completely
+ * independent from the JMS API.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider, because it builds
+ * on the domain-independent API. Use the {@link MessageListenerAdapter102
+ * MessageListenerAdapter102} subclass for JMS 1.0.2 providers.
+ *
+ *
By default, the content of incoming JMS messages gets extracted before
+ * being passed into the target listener method, to let the target method
+ * operate on message content types such as String or byte array instead of
+ * the raw {@link Message}. Message type conversion is delegated to a Spring
+ * JMS {@link MessageConverter}. By default, a {@link SimpleMessageConverter}
+ * {@link org.springframework.jms.support.converter.SimpleMessageConverter102 (102)}
+ * will be used. (If you do not want such automatic message conversion taking
+ * place, then be sure to set the {@link #setMessageConverter MessageConverter}
+ * to null.)
+ *
+ *
If a target listener method returns a non-null object (typically of a
+ * message content type such as String or byte array), it will get
+ * wrapped in a JMS Message and sent to the response destination
+ * (either the JMS "reply-to" destination or a
+ * {@link #setDefaultResponseDestination(javax.jms.Destination) specified default
+ * destination}).
+ *
+ *
Note: The sending of response messages is only available when
+ * using the {@link SessionAwareMessageListener} entry point (typically through a
+ * Spring message listener container). Usage as standard JMS {@link MessageListener}
+ * does not support the generation of response messages.
+ *
+ *
Find below some examples of method signatures compliant with this
+ * adapter class. This first example handles all Message types
+ * and gets passed the contents of each Message type as an
+ * argument. No Message will be sent back as all of these
+ * methods return void.
+ *
+ *
+ *
+ * This next example handles all Message types and gets
+ * passed the actual (raw) Message as an argument. Again, no
+ * Message will be sent back as all of these methods return
+ * void.
+ *
+ *
+ *
+ * This next example illustrates a Message delegate
+ * that just consumes the String contents of
+ * {@link javax.jms.TextMessage TextMessages}. Notice also how the
+ * name of the Message handling method is different from the
+ * {@link #ORIGINAL_DEFAULT_LISTENER_METHOD original} (this will have to
+ * be configured in the attandant bean definition). Again, no Message
+ * will be sent back as the method returns void.
+ *
+ *
+ *
+ * This final example illustrates a Message delegate
+ * that just consumes the String contents of
+ * {@link javax.jms.TextMessage TextMessages}. Notice how the return type
+ * of this method is String: This will result in the configured
+ * {@link MessageListenerAdapter} sending a {@link javax.jms.TextMessage} in response.
+ *
+ *
+ *
+ * For further examples and discussion please do refer to the Spring
+ * reference documentation which describes this class (and it's attendant
+ * XML configuration) in detail.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setDelegate
+ * @see #setDefaultListenerMethod
+ * @see #setDefaultResponseDestination
+ * @see #setMessageConverter
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter
+ * @see org.springframework.jms.listener.SessionAwareMessageListener
+ * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setMessageListener
+ */
+public class MessageListenerAdapter implements MessageListener, SessionAwareMessageListener, SubscriptionNameProvider {
+
+ /**
+ * Out-of-the-box value for the default listener method: "handleMessage".
+ */
+ public static final String ORIGINAL_DEFAULT_LISTENER_METHOD = "handleMessage";
+
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private Object delegate;
+
+ private String defaultListenerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD;
+
+ private Object defaultResponseDestination;
+
+ private DestinationResolver destinationResolver = new DynamicDestinationResolver();
+
+ private MessageConverter messageConverter;
+
+
+ /**
+ * Create a new {@link MessageListenerAdapter} with default settings.
+ */
+ public MessageListenerAdapter() {
+ initDefaultStrategies();
+ this.delegate = this;
+ }
+
+ /**
+ * Create a new {@link MessageListenerAdapter} for the given delegate.
+ * @param delegate the delegate object
+ */
+ public MessageListenerAdapter(Object delegate) {
+ initDefaultStrategies();
+ setDelegate(delegate);
+ }
+
+
+ /**
+ * Set a target object to delegate message listening to.
+ * Specified listener methods have to be present on this target object.
+ *
If no explicit delegate object has been specified, listener
+ * methods are expected to present on this adapter instance, that is,
+ * on a custom subclass of this adapter, defining listener methods.
+ */
+ public void setDelegate(Object delegate) {
+ Assert.notNull(delegate, "Delegate must not be null");
+ this.delegate = delegate;
+ }
+
+ /**
+ * Return the target object to delegate message listening to.
+ */
+ protected Object getDelegate() {
+ return this.delegate;
+ }
+
+ /**
+ * Specify the name of the default listener method to delegate to,
+ * for the case where no specific listener method has been determined.
+ * Out-of-the-box value is {@link #ORIGINAL_DEFAULT_LISTENER_METHOD "handleMessage"}.
+ * @see #getListenerMethodName
+ */
+ public void setDefaultListenerMethod(String defaultListenerMethod) {
+ this.defaultListenerMethod = defaultListenerMethod;
+ }
+
+ /**
+ * Return the name of the default listener method to delegate to.
+ */
+ protected String getDefaultListenerMethod() {
+ return this.defaultListenerMethod;
+ }
+
+ /**
+ * Set the default destination to send response messages to. This will be applied
+ * in case of a request message that does not carry a "JMSReplyTo" field.
+ *
Response destinations are only relevant for listener methods that return
+ * result objects, which will be wrapped in a response message and sent to a
+ * response destination.
+ *
Alternatively, specify a "defaultResponseQueueName" or "defaultResponseTopicName",
+ * to be dynamically resolved via the DestinationResolver.
+ * @see #setDefaultResponseQueueName(String)
+ * @see #setDefaultResponseTopicName(String)
+ * @see #getResponseDestination
+ */
+ public void setDefaultResponseDestination(Destination destination) {
+ this.defaultResponseDestination = destination;
+ }
+
+ /**
+ * Set the name of the default response queue to send response messages to.
+ * This will be applied in case of a request message that does not carry a
+ * "JMSReplyTo" field.
+ *
Alternatively, specify a JMS Destination object as "defaultResponseDestination".
+ * @see #setDestinationResolver
+ * @see #setDefaultResponseDestination(javax.jms.Destination)
+ */
+ public void setDefaultResponseQueueName(String destinationName) {
+ this.defaultResponseDestination = new DestinationNameHolder(destinationName, false);
+ }
+
+ /**
+ * Set the name of the default response topic to send response messages to.
+ * This will be applied in case of a request message that does not carry a
+ * "JMSReplyTo" field.
+ *
Alternatively, specify a JMS Destination object as "defaultResponseDestination".
+ * @see #setDestinationResolver
+ * @see #setDefaultResponseDestination(javax.jms.Destination)
+ */
+ public void setDefaultResponseTopicName(String destinationName) {
+ this.defaultResponseDestination = new DestinationNameHolder(destinationName, true);
+ }
+
+ /**
+ * Set the DestinationResolver that should be used to resolve response
+ * destination names for this adapter.
+ *
The default resolver is a DynamicDestinationResolver. Specify a
+ * JndiDestinationResolver for resolving destination names as JNDI locations.
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.destination.JndiDestinationResolver
+ */
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ Assert.notNull(destinationResolver, "DestinationResolver must not be null");
+ this.destinationResolver = destinationResolver;
+ }
+
+ /**
+ * Return the DestinationResolver for this adapter.
+ */
+ protected DestinationResolver getDestinationResolver() {
+ return this.destinationResolver;
+ }
+
+ /**
+ * Set the converter that will convert incoming JMS messages to
+ * listener method arguments, and objects returned from listener
+ * methods back to JMS messages.
+ *
The default converter is a {@link SimpleMessageConverter}, which is able
+ * to handle {@link javax.jms.BytesMessage BytesMessages},
+ * {@link javax.jms.TextMessage TextMessages} and
+ * {@link javax.jms.ObjectMessage ObjectMessages}.
+ */
+ public void setMessageConverter(MessageConverter messageConverter) {
+ this.messageConverter = messageConverter;
+ }
+
+ /**
+ * Return the converter that will convert incoming JMS messages to
+ * listener method arguments, and objects returned from listener
+ * methods back to JMS messages.
+ */
+ protected MessageConverter getMessageConverter() {
+ return this.messageConverter;
+ }
+
+
+ /**
+ * Standard JMS {@link MessageListener} entry point.
+ *
Delegates the message to the target listener method, with appropriate
+ * conversion of the message argument. In case of an exception, the
+ * {@link #handleListenerException(Throwable)} method will be invoked.
+ *
Note: Does not support sending response messages based on
+ * result objects returned from listener methods. Use the
+ * {@link SessionAwareMessageListener} entry point (typically through a Spring
+ * message listener container) for handling result objects as well.
+ * @param message the incoming JMS message
+ * @see #handleListenerException
+ * @see #onMessage(javax.jms.Message, javax.jms.Session)
+ */
+ public void onMessage(Message message) {
+ try {
+ onMessage(message, null);
+ }
+ catch (Throwable ex) {
+ handleListenerException(ex);
+ }
+ }
+
+ /**
+ * Spring {@link SessionAwareMessageListener} entry point.
+ *
Delegates the message to the target listener method, with appropriate
+ * conversion of the message argument. If the target method returns a
+ * non-null object, wrap in a JMS message and send it back.
+ * @param message the incoming JMS message
+ * @param session the JMS session to operate on
+ * @throws JMSException if thrown by JMS API methods
+ */
+ public void onMessage(Message message, Session session) throws JMSException {
+ // Check whether the delegate is a MessageListener impl itself.
+ // In that case, the adapter will simply act as a pass-through.
+ Object delegate = getDelegate();
+ if (delegate != this) {
+ if (delegate instanceof SessionAwareMessageListener) {
+ if (session != null) {
+ ((SessionAwareMessageListener) delegate).onMessage(message, session);
+ return;
+ }
+ else if (!(delegate instanceof MessageListener)) {
+ throw new javax.jms.IllegalStateException("MessageListenerAdapter cannot handle a " +
+ "SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
+ }
+ }
+ if (delegate instanceof MessageListener) {
+ ((MessageListener) delegate).onMessage(message);
+ return;
+ }
+ }
+
+ // Regular case: find a handler method reflectively.
+ Object convertedMessage = extractMessage(message);
+ String methodName = getListenerMethodName(message, convertedMessage);
+ if (methodName == null) {
+ throw new javax.jms.IllegalStateException("No default listener method specified: " +
+ "Either specify a non-null value for the 'defaultListenerMethod' property or " +
+ "override the 'getListenerMethodName' method.");
+ }
+
+ // Invoke the handler method with appropriate arguments.
+ Object[] listenerArguments = buildListenerArguments(convertedMessage);
+ Object result = invokeListenerMethod(methodName, listenerArguments);
+ if (result != null) {
+ handleResult(result, message, session);
+ }
+ else {
+ logger.trace("No result object given - no result to handle");
+ }
+ }
+
+ public String getSubscriptionName() {
+ if (this.delegate instanceof SubscriptionNameProvider) {
+ return ((SubscriptionNameProvider) this.delegate).getSubscriptionName();
+ }
+ else {
+ return this.delegate.getClass().getName();
+ }
+ }
+
+
+ /**
+ * Initialize the default implementations for the adapter's strategies.
+ * @see #setMessageConverter
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter
+ */
+ protected void initDefaultStrategies() {
+ setMessageConverter(new SimpleMessageConverter());
+ }
+
+ /**
+ * Handle the given exception that arose during listener execution.
+ * The default implementation logs the exception at error level.
+ *
This method only applies when used as standard JMS {@link MessageListener}.
+ * In case of the Spring {@link SessionAwareMessageListener} mechanism,
+ * exceptions get handled by the caller instead.
+ * @param ex the exception to handle
+ * @see #onMessage(javax.jms.Message)
+ */
+ protected void handleListenerException(Throwable ex) {
+ logger.error("Listener execution failed", ex);
+ }
+
+ /**
+ * Extract the message body from the given JMS message.
+ * @param message the JMS Message
+ * @return the content of the message, to be passed into the
+ * listener method as argument
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected Object extractMessage(Message message) throws JMSException {
+ MessageConverter converter = getMessageConverter();
+ if (converter != null) {
+ return converter.fromMessage(message);
+ }
+ return message;
+ }
+
+ /**
+ * Determine the name of the listener method that is supposed to
+ * handle the given message.
+ *
The default implementation simply returns the configured
+ * default listener method, if any.
+ * @param originalMessage the JMS request message
+ * @param extractedMessage the converted JMS request message,
+ * to be passed into the listener method as argument
+ * @return the name of the listener method (never null)
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setDefaultListenerMethod
+ */
+ protected String getListenerMethodName(Message originalMessage, Object extractedMessage) throws JMSException {
+ return getDefaultListenerMethod();
+ }
+
+ /**
+ * Build an array of arguments to be passed into the target listener method.
+ * Allows for multiple method arguments to be built from a single message object.
+ *
The default implementation builds an array with the given message object
+ * as sole element. This means that the extracted message will always be passed
+ * into a single method argument, even if it is an array, with the target
+ * method having a corresponding single argument of the array's type declared.
+ *
This can be overridden to treat special message content such as arrays
+ * differently, for example passing in each element of the message array
+ * as distinct method argument.
+ * @param extractedMessage the content of the message
+ * @return the array of arguments to be passed into the
+ * listener method (each element of the array corresponding
+ * to a distinct method argument)
+ */
+ protected Object[] buildListenerArguments(Object extractedMessage) {
+ return new Object[] {extractedMessage};
+ }
+
+ /**
+ * Invoke the specified listener method.
+ * @param methodName the name of the listener method
+ * @param arguments the message arguments to be passed in
+ * @return the result returned from the listener method
+ * @throws JMSException if thrown by JMS API methods
+ * @see #getListenerMethodName
+ * @see #buildListenerArguments
+ */
+ protected Object invokeListenerMethod(String methodName, Object[] arguments) throws JMSException {
+ try {
+ MethodInvoker methodInvoker = new MethodInvoker();
+ methodInvoker.setTargetObject(getDelegate());
+ methodInvoker.setTargetMethod(methodName);
+ methodInvoker.setArguments(arguments);
+ methodInvoker.prepare();
+ return methodInvoker.invoke();
+ }
+ catch (InvocationTargetException ex) {
+ Throwable targetEx = ex.getTargetException();
+ if (targetEx instanceof JMSException) {
+ throw (JMSException) targetEx;
+ }
+ else {
+ throw new ListenerExecutionFailedException(
+ "Listener method '" + methodName + "' threw exception", targetEx);
+ }
+ }
+ catch (Throwable ex) {
+ throw new ListenerExecutionFailedException("Failed to invoke target method '" + methodName +
+ "' with arguments " + ObjectUtils.nullSafeToString(arguments), ex);
+ }
+ }
+
+
+ /**
+ * Handle the given result object returned from the listener method,
+ * sending a response message back.
+ * @param result the result object to handle (never null)
+ * @param request the original request message
+ * @param session the JMS Session to operate on (may be null)
+ * @throws JMSException if thrown by JMS API methods
+ * @see #buildMessage
+ * @see #postProcessResponse
+ * @see #getResponseDestination
+ * @see #sendResponse
+ */
+ protected void handleResult(Object result, Message request, Session session) throws JMSException {
+ if (session != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Listener method returned result [" + result +
+ "] - generating response message for it");
+ }
+ Message response = buildMessage(session, result);
+ postProcessResponse(request, response);
+ Destination destination = getResponseDestination(request, response, session);
+ sendResponse(session, destination, response);
+ }
+ else {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Listener method returned result [" + result +
+ "]: not generating response message for it because of no JMS Session given");
+ }
+ }
+ }
+
+ /**
+ * Build a JMS message to be sent as response based on the given result object.
+ * @param session the JMS Session to operate on
+ * @param result the content of the message, as returned from the listener method
+ * @return the JMS Message (never null)
+ * @throws JMSException if thrown by JMS API methods
+ * @see #setMessageConverter
+ */
+ protected Message buildMessage(Session session, Object result) throws JMSException {
+ MessageConverter converter = getMessageConverter();
+ if (converter != null) {
+ return converter.toMessage(result, session);
+ }
+ else {
+ if (!(result instanceof Message)) {
+ throw new MessageConversionException(
+ "No MessageConverter specified - cannot handle message [" + result + "]");
+ }
+ return (Message) result;
+ }
+ }
+
+ /**
+ * Post-process the given response message before it will be sent.
+ *
The default implementation sets the response's correlation id
+ * to the request message's correlation id, if any; otherwise to the
+ * request message id.
+ * @param request the original incoming JMS message
+ * @param response the outgoing JMS message about to be sent
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.Message#setJMSCorrelationID
+ */
+ protected void postProcessResponse(Message request, Message response) throws JMSException {
+ String correlation = request.getJMSCorrelationID();
+ if (correlation == null) {
+ correlation = request.getJMSMessageID();
+ }
+ response.setJMSCorrelationID(correlation);
+ }
+
+ /**
+ * Determine a response destination for the given message.
+ *
The default implementation first checks the JMS Reply-To
+ * {@link Destination} of the supplied request; if that is not null
+ * it is returned; if it is null, then the configured
+ * {@link #resolveDefaultResponseDestination default response destination}
+ * is returned; if this too is null, then an
+ * {@link InvalidDestinationException} is thrown.
+ * @param request the original incoming JMS message
+ * @param response the outgoing JMS message about to be sent
+ * @param session the JMS Session to operate on
+ * @return the response destination (never null)
+ * @throws JMSException if thrown by JMS API methods
+ * @throws InvalidDestinationException if no {@link Destination} can be determined
+ * @see #setDefaultResponseDestination
+ * @see javax.jms.Message#getJMSReplyTo()
+ */
+ protected Destination getResponseDestination(Message request, Message response, Session session)
+ throws JMSException {
+
+ Destination replyTo = request.getJMSReplyTo();
+ if (replyTo == null) {
+ replyTo = resolveDefaultResponseDestination(session);
+ if (replyTo == null) {
+ throw new InvalidDestinationException("Cannot determine response destination: " +
+ "Request message does not contain reply-to destination, and no default response destination set.");
+ }
+ }
+ return replyTo;
+ }
+
+ /**
+ * Resolve the default response destination into a JMS {@link Destination}, using this
+ * accessor's {@link DestinationResolver} in case of a destination name.
+ * @return the located {@link Destination}
+ * @throws javax.jms.JMSException if resolution failed
+ * @see #setDefaultResponseDestination
+ * @see #setDefaultResponseQueueName
+ * @see #setDefaultResponseTopicName
+ * @see #setDestinationResolver
+ */
+ protected Destination resolveDefaultResponseDestination(Session session) throws JMSException {
+ if (this.defaultResponseDestination instanceof Destination) {
+ return (Destination) this.defaultResponseDestination;
+ }
+ if (this.defaultResponseDestination instanceof DestinationNameHolder) {
+ DestinationNameHolder nameHolder = (DestinationNameHolder) this.defaultResponseDestination;
+ return getDestinationResolver().resolveDestinationName(session, nameHolder.name, nameHolder.isTopic);
+ }
+ return null;
+ }
+
+ /**
+ * Send the given response message to the given destination.
+ * @param response the JMS message to send
+ * @param destination the JMS destination to send to
+ * @param session the JMS session to operate on
+ * @throws JMSException if thrown by JMS API methods
+ * @see #postProcessProducer
+ * @see javax.jms.Session#createProducer
+ * @see javax.jms.MessageProducer#send
+ */
+ protected void sendResponse(Session session, Destination destination, Message response) throws JMSException {
+ MessageProducer producer = session.createProducer(destination);
+ try {
+ postProcessProducer(producer, response);
+ producer.send(response);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(producer);
+ }
+ }
+
+ /**
+ * Post-process the given message producer before using it to send the response.
+ *
The default implementation is empty.
+ * @param producer the JMS message producer that will be used to send the message
+ * @param response the outgoing JMS message about to be sent
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected void postProcessProducer(MessageProducer producer, Message response) throws JMSException {
+ }
+
+
+ /**
+ * Internal class combining a destination name
+ * and its target destination type (queue or topic).
+ */
+ private static class DestinationNameHolder {
+
+ public final String name;
+
+ public final boolean isTopic;
+
+ public DestinationNameHolder(String name, boolean isTopic) {
+ this.name = name;
+ this.isTopic = isTopic;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/adapter/MessageListenerAdapter102.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2002-2007 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.jms.listener.adapter;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.converter.SimpleMessageConverter102;
+
+/**
+ * A {@link MessageListenerAdapter} subclass for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like MessageListenerAdapter itself.
+ *
+ *
This class can be used for JMS 1.0.2 providers, offering the same facility
+ * as MessageListenerAdapter does for JMS 1.1 providers.
+ *
+ * @author Juergen Hoeller
+ * @author Rick Evans
+ * @since 2.0
+ */
+public class MessageListenerAdapter102 extends MessageListenerAdapter {
+
+ /**
+ * Create a new instance of the {@link MessageListenerAdapter102} class
+ * with the default settings.
+ */
+ public MessageListenerAdapter102() {
+ }
+
+ /**
+ * Create a new instance of the {@link MessageListenerAdapter102} class
+ * for the given delegate.
+ * @param delegate the target object to delegate message listening to
+ */
+ public MessageListenerAdapter102(Object delegate) {
+ super(delegate);
+ }
+
+
+ /**
+ * Initialize the default implementations for the adapter's strategies:
+ * SimpleMessageConverter102.
+ * @see #setMessageConverter
+ * @see org.springframework.jms.support.converter.SimpleMessageConverter102
+ */
+ protected void initDefaultStrategies() {
+ setMessageConverter(new SimpleMessageConverter102());
+ }
+
+ /**
+ * Overrides the superclass method to use the JMS 1.0.2 API to send a response.
+ *
+
+Message listener adapter mechanism that delegates to target listener
+methods, converting messages to appropriate message content types
+(such as String or byte array) that get passed into listener methods.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/DefaultJmsActivationSpecFactory.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.endpoint;
+
+import javax.jms.Session;
+import javax.resource.spi.ResourceAdapter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeanWrapper;
+
+/**
+ * Default implementation of the {@link JmsActivationSpecFactory} interface.
+ * Supports the standard JMS properties as defined by the JMS 1.5 specification,
+ * as well as Spring's extended "maxConcurrency" and "prefetchSize" settings
+ * through autodetection of well-known vendor-specific provider properties.
+ *
+ *
An ActivationSpec factory is effectively dependent on the concrete
+ * JMS provider, e.g. on ActiveMQ. This default implementation simply
+ * guesses the ActivationSpec class name from the provider's class name
+ * ("ActiveMQResourceAdapter" -> "ActiveMQActivationSpec" in the same package,
+ * or "ActivationSpecImpl" in the same package as the ResourceAdapter class),
+ * and populates the ActivationSpec properties as suggested by the
+ * JCA 1.5 specification (Appendix B). Specify the 'activationSpecClass'
+ * property explicitly if these default naming rules do not apply.
+ *
+ *
Note: ActiveMQ, JORAM and WebSphere are supported in terms of extended
+ * settings (through the detection of their bean property naming conventions).
+ * The default ActivationSpec class detection rules may apply to other
+ * JMS providers as well.
+ *
+ *
Thanks to Agim Emruli and Laurie Chan for pointing out WebSphere MQ
+ * settings and contributing corresponding tests!
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see #setActivationSpecClass
+ */
+public class DefaultJmsActivationSpecFactory extends StandardJmsActivationSpecFactory {
+
+ private static final String RESOURCE_ADAPTER_SUFFIX = "ResourceAdapter";
+
+ private static final String RESOURCE_ADAPTER_IMPL_SUFFIX = "ResourceAdapterImpl";
+
+ private static final String ACTIVATION_SPEC_SUFFIX = "ActivationSpec";
+
+ private static final String ACTIVATION_SPEC_IMPL_SUFFIX = "ActivationSpecImpl";
+
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+
+ /**
+ * This implementation guesses the ActivationSpec class name from the
+ * provider's class name: e.g. "ActiveMQResourceAdapter" ->
+ * "ActiveMQActivationSpec" in the same package, or a class named
+ * "ActivationSpecImpl" in the same package as the ResourceAdapter class.
+ */
+ protected Class determineActivationSpecClass(ResourceAdapter adapter) {
+ String adapterClassName = adapter.getClass().getName();
+
+ if (adapterClassName.endsWith(RESOURCE_ADAPTER_SUFFIX)) {
+ // e.g. ActiveMQ
+ String providerName =
+ adapterClassName.substring(0, adapterClassName.length() - RESOURCE_ADAPTER_SUFFIX.length());
+ String specClassName = providerName + ACTIVATION_SPEC_SUFFIX;
+ try {
+ return adapter.getClass().getClassLoader().loadClass(specClassName);
+ }
+ catch (ClassNotFoundException ex) {
+ logger.debug("No default ActivationSpec class found: " + specClassName);
+ }
+ }
+
+ else if (adapterClassName.endsWith(RESOURCE_ADAPTER_IMPL_SUFFIX)){
+ //e.g. WebSphere
+ String providerName =
+ adapterClassName.substring(0, adapterClassName.length() - RESOURCE_ADAPTER_IMPL_SUFFIX.length());
+ String specClassName = providerName + ACTIVATION_SPEC_IMPL_SUFFIX;
+ try {
+ return adapter.getClass().getClassLoader().loadClass(specClassName);
+ }
+ catch (ClassNotFoundException ex) {
+ logger.debug("No default ActivationSpecImpl class found: " + specClassName);
+ }
+ }
+
+ // e.g. JORAM
+ String providerPackage = adapterClassName.substring(0, adapterClassName.lastIndexOf('.') + 1);
+ String specClassName = providerPackage + ACTIVATION_SPEC_IMPL_SUFFIX;
+ try {
+ return adapter.getClass().getClassLoader().loadClass(specClassName);
+ }
+ catch (ClassNotFoundException ex) {
+ logger.debug("No default ActivationSpecImpl class found in provider package: " + specClassName);
+ }
+
+ // ActivationSpecImpl class in "inbound" subpackage (WebSphere MQ 6.0.2.1)
+ specClassName = providerPackage + "inbound." + ACTIVATION_SPEC_IMPL_SUFFIX;
+ try {
+ return adapter.getClass().getClassLoader().loadClass(specClassName);
+ }
+ catch (ClassNotFoundException ex) {
+ logger.debug("No default ActivationSpecImpl class found in inbound subpackage: " + specClassName);
+ }
+
+ throw new IllegalStateException("No ActivationSpec class defined - " +
+ "specify the 'activationSpecClass' property or override the 'determineActivationSpecClass' method");
+ }
+
+ /**
+ * This implementation supports Spring's extended "maxConcurrency"
+ * and "prefetchSize" settings through detecting corresponding
+ * ActivationSpec properties: "maxSessions"/"maxNumberOfWorks" and
+ * "maxMessagesPerSessions"/"maxMessages", respectively
+ * (following ActiveMQ's and JORAM's naming conventions).
+ */
+ protected void populateActivationSpecProperties(BeanWrapper bw, JmsActivationSpecConfig config) {
+ super.populateActivationSpecProperties(bw, config);
+ if (config.getMaxConcurrency() > 0) {
+ if (bw.isWritableProperty("maxSessions")) {
+ // ActiveMQ
+ bw.setPropertyValue("maxSessions", Integer.toString(config.getMaxConcurrency()));
+ }
+ else if (bw.isWritableProperty("maxNumberOfWorks")) {
+ // JORAM
+ bw.setPropertyValue("maxNumberOfWorks", Integer.toString(config.getMaxConcurrency()));
+ }
+ else if (bw.isWritableProperty("maxConcurrency")){
+ // WebSphere
+ bw.setPropertyValue("maxConcurrency", Integer.toString(config.getMaxConcurrency()));
+ }
+ }
+ if (config.getPrefetchSize() > 0) {
+ if (bw.isWritableProperty("maxMessagesPerSessions")) {
+ // ActiveMQ
+ bw.setPropertyValue("maxMessagesPerSessions", Integer.toString(config.getPrefetchSize()));
+ }
+ else if (bw.isWritableProperty("maxMessages")) {
+ // JORAM
+ bw.setPropertyValue("maxMessages", Integer.toString(config.getPrefetchSize()));
+ }
+ else if(bw.isWritableProperty("maxBatchSize")){
+ // WebSphere
+ bw.setPropertyValue("maxBatchSize", Integer.toString(config.getPrefetchSize()));
+ }
+ }
+ }
+
+ /**
+ * This implementation maps SESSION_TRANSACTED onto an
+ * ActivationSpec property named "useRAManagedTransaction", if available
+ * (following ActiveMQ's naming conventions).
+ */
+ protected void applyAcknowledgeMode(BeanWrapper bw, int ackMode) {
+ if (ackMode == Session.SESSION_TRANSACTED && bw.isWritableProperty("useRAManagedTransaction")) {
+ // ActiveMQ
+ bw.setPropertyValue("useRAManagedTransaction", "true");
+ }
+ else {
+ super.applyAcknowledgeMode(bw, ackMode);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecConfig.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002-2007 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.jms.listener.endpoint;
+
+import javax.jms.Session;
+
+/**
+ * Common configuration object for activating a JMS message endpoint.
+ * Gets converted into a provider-specific JCA 1.5 ActivationSpec
+ * object for activating the endpoint.
+ *
+ *
Typically used in combination with {@link JmsMessageEndpointManager},
+ * but not tied to it.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see JmsActivationSpecFactory
+ * @see JmsMessageEndpointManager#setActivationSpecConfig
+ * @see javax.resource.spi.ResourceAdapter#endpointActivation
+ */
+public class JmsActivationSpecConfig {
+
+ private String destinationName;
+
+ private boolean pubSubDomain = false;
+
+ private boolean subscriptionDurable = false;
+
+ private String durableSubscriptionName;
+
+ private String clientId;
+
+ private String messageSelector;
+
+ private int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+
+ private int maxConcurrency = -1;
+
+ private int prefetchSize = -1;
+
+
+ public void setDestinationName(String destinationName) {
+ this.destinationName = destinationName;
+ }
+
+ public String getDestinationName() {
+ return this.destinationName;
+ }
+
+ public void setPubSubDomain(boolean pubSubDomain) {
+ this.pubSubDomain = pubSubDomain;
+ }
+
+ public boolean isPubSubDomain() {
+ return this.pubSubDomain;
+ }
+
+ public void setSubscriptionDurable(boolean subscriptionDurable) {
+ this.subscriptionDurable = subscriptionDurable;
+ }
+
+ public boolean isSubscriptionDurable() {
+ return this.subscriptionDurable;
+ }
+
+ public void setDurableSubscriptionName(String durableSubscriptionName) {
+ this.durableSubscriptionName = durableSubscriptionName;
+ }
+
+ public String getDurableSubscriptionName() {
+ return this.durableSubscriptionName;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientId() {
+ return this.clientId;
+ }
+
+ public void setMessageSelector(String messageSelector) {
+ this.messageSelector = messageSelector;
+ }
+
+ public String getMessageSelector() {
+ return this.messageSelector;
+ }
+
+ public void setAcknowledgeMode(int acknowledgeMode) {
+ this.acknowledgeMode = acknowledgeMode;
+ }
+
+ public int getAcknowledgeMode() {
+ return this.acknowledgeMode;
+ }
+
+ public void setMaxConcurrency(int maxConcurrency) {
+ this.maxConcurrency = maxConcurrency;
+ }
+
+ public int getMaxConcurrency() {
+ return this.maxConcurrency;
+ }
+
+ public void setPrefetchSize(int prefetchSize) {
+ this.prefetchSize = prefetchSize;
+ }
+
+ public int getPrefetchSize() {
+ return this.prefetchSize;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsActivationSpecFactory.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2007 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.jms.listener.endpoint;
+
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.ResourceAdapter;
+
+/**
+ * Strategy interface for creating JCA 1.5 ActivationSpec objects
+ * based on a configured {@link JmsActivationSpecConfig} object.
+ *
+ *
JCA 1.5 ActivationSpec objects are typically JavaBeans, but
+ * unfortunately provider-specific. This strategy interface allows
+ * for plugging in any JCA-based JMS provider, creating corresponding
+ * ActivationSpec objects based on common JMS configuration settings.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see JmsActivationSpecConfig
+ * @see JmsMessageEndpointManager#setActivationSpecFactory
+ * @see javax.resource.spi.ResourceAdapter#endpointActivation
+ */
+public interface JmsActivationSpecFactory {
+
+ /**
+ * Create a JCA 1.5 ActivationSpec object based on the given
+ * {@link JmsActivationSpecConfig} object.
+ * @param adapter the ResourceAdapter to create an ActivationSpec object for
+ * @param config the configured object holding common JMS settings
+ * @return the provider-specific JCA ActivationSpec object,
+ * representing the same settings
+ */
+ ActivationSpec createActivationSpec(ResourceAdapter adapter, JmsActivationSpecConfig config);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointFactory.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2002-2007 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.jms.listener.endpoint;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.resource.ResourceException;
+import javax.resource.spi.UnavailableException;
+
+import org.springframework.jca.endpoint.AbstractMessageEndpointFactory;
+
+/**
+ * JMS-specific implementation of the JCA 1.5
+ * {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
+ * providing transaction management capabilities for a JMS listener object
+ * (e.g. a {@link javax.jms.MessageListener} object).
+ *
+ *
Uses a static endpoint implementation, simply wrapping the
+ * specified message listener object and exposing all of its implemented
+ * interfaces on the endpoint instance.
+ *
+ *
Typically used with Spring's {@link JmsMessageEndpointManager},
+ * but not tied to it. As a consequence, this endpoint factory could
+ * also be used with programmatic endpoint management on a native
+ * {@link javax.resource.spi.ResourceAdapter} instance.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see #setMessageListener
+ * @see #setTransactionManager
+ * @see JmsMessageEndpointManager
+ */
+public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory {
+
+ private MessageListener messageListener;
+
+
+ /**
+ * Set the JMS MessageListener for this endpoint.
+ */
+ public void setMessageListener(MessageListener messageListener) {
+ this.messageListener = messageListener;
+ }
+
+ /**
+ * Creates a concrete JMS message endpoint, internal to this factory.
+ */
+ protected AbstractMessageEndpoint createEndpointInternal() throws UnavailableException {
+ return new JmsMessageEndpoint();
+ }
+
+
+ /**
+ * Private inner class that implements the concrete JMS message endpoint.
+ */
+ private class JmsMessageEndpoint extends AbstractMessageEndpoint implements MessageListener {
+
+ public void onMessage(Message message) {
+ boolean applyDeliveryCalls = !hasBeforeDeliveryBeenCalled();
+ if (applyDeliveryCalls) {
+ try {
+ beforeDelivery(null);
+ }
+ catch (ResourceException ex) {
+ throw new JmsResourceException(ex);
+ }
+ }
+ try {
+ messageListener.onMessage(message);
+ }
+ catch (RuntimeException ex) {
+ onEndpointException(ex);
+ throw ex;
+ }
+ catch (Error err) {
+ onEndpointException(err);
+ throw err;
+ }
+ finally {
+ if (applyDeliveryCalls) {
+ try {
+ afterDelivery();
+ }
+ catch (ResourceException ex) {
+ throw new JmsResourceException(ex);
+ }
+ }
+ }
+ }
+
+ protected ClassLoader getEndpointClassLoader() {
+ return messageListener.getClass().getClassLoader();
+ }
+ }
+
+
+ /**
+ * Internal exception thrown when a ResourceExeption has been encountered
+ * during the endpoint invocation.
+ *
Will only be used if the ResourceAdapter does not invoke the
+ * endpoint's beforeDelivery and afterDelivery
+ * directly, leavng it up to the concrete endpoint to apply those -
+ * and to handle any ResourceExceptions thrown from them.
+ */
+ public static class JmsResourceException extends RuntimeException {
+
+ public JmsResourceException(ResourceException cause) {
+ super(cause);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/JmsMessageEndpointManager.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2002-2007 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.jms.listener.endpoint;
+
+import javax.jms.MessageListener;
+import javax.resource.ResourceException;
+
+import org.springframework.jca.endpoint.GenericMessageEndpointManager;
+import org.springframework.jms.support.destination.DestinationResolver;
+
+/**
+ * Extension of the generic JCA 1.5
+ * {@link org.springframework.jca.endpoint.GenericMessageEndpointManager},
+ * adding JMS-specific support for ActivationSpec configuration.
+ *
+ *
Allows for defining a common {@link JmsActivationSpecConfig} object
+ * that gets converted into a provider-specific JCA 1.5 ActivationSpec
+ * object for activating the endpoint.
+ *
+ *
NOTE: This JCA-based endpoint manager supports standard JMS
+ * {@link javax.jms.MessageListener} endpoints only. It does not support
+ * Spring's {@link org.springframework.jms.listener.SessionAwareMessageListener}
+ * variant, simply because the JCA endpoint management contract does not allow
+ * for obtaining the current JMS {@link javax.jms.Session}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see javax.jms.MessageListener
+ * @see #setActivationSpecConfig
+ * @see JmsActivationSpecConfig
+ * @see JmsActivationSpecFactory
+ * @see JmsMessageEndpointFactory
+ */
+public class JmsMessageEndpointManager extends GenericMessageEndpointManager {
+
+ private final JmsMessageEndpointFactory endpointFactory = new JmsMessageEndpointFactory();
+
+ private boolean messageListenerSet = false;
+
+ private JmsActivationSpecFactory activationSpecFactory = new DefaultJmsActivationSpecFactory();
+
+ private JmsActivationSpecConfig activationSpecConfig;
+
+
+ /**
+ * Set the JMS MessageListener for this endpoint.
+ *
This is a shortcut for configuring a dedicated JmsMessageEndpointFactory.
+ * @see JmsMessageEndpointFactory#setMessageListener
+ */
+ public void setMessageListener(MessageListener messageListener) {
+ this.endpointFactory.setMessageListener(messageListener);
+ this.messageListenerSet = true;
+ }
+
+ /**
+ * Set the XA transaction manager to use for wrapping endpoint
+ * invocations, enlisting the endpoint resource in each such transaction.
+ *
The passed-in object may be a transaction manager which implements
+ * Spring's {@link org.springframework.transaction.jta.TransactionFactory}
+ * interface, or a plain {@link javax.transaction.TransactionManager}.
+ *
If no transaction manager is specified, the endpoint invocation
+ * will simply not be wrapped in an XA transaction. Consult your
+ * resource provider's ActivationSpec documentation for the local
+ * transaction options of your particular provider.
+ *
This is a shortcut for configuring a dedicated JmsMessageEndpointFactory.
+ * @see JmsMessageEndpointFactory#setTransactionManager
+ */
+ public void setTransactionManager(Object transactionManager) {
+ this.endpointFactory.setTransactionManager(transactionManager);
+ }
+
+ /**
+ * Set the factory for concrete JCA 1.5 ActivationSpec objects,
+ * creating JCA ActivationSpecs based on
+ * {@link #setActivationSpecConfig JmsActivationSpecConfig} objects.
+ *
This factory is dependent on the concrete JMS provider, e.g. on ActiveMQ.
+ * The default implementation simply guesses the ActivationSpec class name
+ * from the provider's class name (e.g. "ActiveMQResourceAdapter" ->
+ * "ActiveMQActivationSpec" in the same package), and populates the
+ * ActivationSpec properties as suggested by the JCA 1.5 specification
+ * (plus a couple of autodetected vendor-specific properties).
+ * @see DefaultJmsActivationSpecFactory
+ */
+ public void setActivationSpecFactory(JmsActivationSpecFactory activationSpecFactory) {
+ this.activationSpecFactory =
+ (activationSpecFactory != null ? activationSpecFactory : new DefaultJmsActivationSpecFactory());
+ }
+
+ /**
+ * Set the DestinationResolver to use for resolving destination names
+ * into the JCA 1.5 ActivationSpec "destination" property.
+ *
If not specified, destination names will simply be passed in as Strings.
+ * If specified, destination names will be resolved into Destination objects first.
+ *
Note that a DestinationResolver is usually specified on the JmsActivationSpecFactory
+ * (see {@link StandardJmsActivationSpecFactory#setDestinationResolver}). This is simply
+ * a shortcut for parameterizing the default JmsActivationSpecFactory; it will replace
+ * any custom JmsActivationSpecFactory that might have been set before.
+ * @see StandardJmsActivationSpecFactory#setDestinationResolver
+ */
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ DefaultJmsActivationSpecFactory factory = new DefaultJmsActivationSpecFactory();
+ factory.setDestinationResolver(destinationResolver);
+ this.activationSpecFactory = factory;
+ }
+
+ /**
+ * Specify the {@link JmsActivationSpecConfig} object that this endpoint manager
+ * should use for activating its listener.
+ *
This config object will be turned into a concrete JCA 1.5 ActivationSpec
+ * object through a {@link #setActivationSpecFactory JmsActivationSpecFactory}.
+ */
+ public void setActivationSpecConfig(JmsActivationSpecConfig activationSpecConfig) {
+ this.activationSpecConfig = activationSpecConfig;
+ }
+
+
+ public void afterPropertiesSet() throws ResourceException {
+ if (this.messageListenerSet) {
+ setMessageEndpointFactory(this.endpointFactory);
+ }
+ if (this.activationSpecConfig != null) {
+ setActivationSpec(
+ this.activationSpecFactory.createActivationSpec(getResourceAdapter(), this.activationSpecConfig));
+ }
+ super.afterPropertiesSet();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/StandardJmsActivationSpecFactory.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.endpoint;
+
+import java.util.Properties;
+
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.resource.spi.ActivationSpec;
+import javax.resource.spi.ResourceAdapter;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.PropertyAccessorFactory;
+import org.springframework.jms.support.destination.DestinationResolutionException;
+import org.springframework.jms.support.destination.DestinationResolver;
+
+/**
+ * Standard implementation of the {@link JmsActivationSpecFactory} interface.
+ * Supports the standard JMS properties as defined by the JMS 1.5 specification
+ * (Appendix B); ignores Spring's "maxConcurrency" and "prefetchSize" settings.
+ *
+ *
The 'activationSpecClass' property is required, explicitly defining
+ * the fully-qualified class name of the provider's ActivationSpec class
+ * (e.g. "org.apache.activemq.ra.ActiveMQActivationSpec").
+ *
+ *
Check out {@link DefaultJmsActivationSpecFactory} for an extended variant
+ * of this class, supporting some further default conventions beyond the plain
+ * JMS 1.5 specification.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see #setActivationSpecClass
+ * @see DefaultJmsActivationSpecFactory
+ */
+public class StandardJmsActivationSpecFactory implements JmsActivationSpecFactory {
+
+ private Class activationSpecClass;
+
+ private Properties defaultProperties;
+
+ private DestinationResolver destinationResolver;
+
+
+ /**
+ * Specify the fully-qualified ActivationSpec class name for the target
+ * provider (e.g. "org.apache.activemq.ra.ActiveMQActivationSpec").
+ */
+ public void setActivationSpecClass(Class activationSpecClass) {
+ this.activationSpecClass = activationSpecClass;
+ }
+
+ /**
+ * Specify custom default properties, with String keys and String values.
+ *
Applied to each ActivationSpec object before it gets populated with
+ * listener-specific settings. Allows for configuring vendor-specific properties
+ * beyond the Spring-defined settings in {@link JmsActivationSpecConfig}.
+ */
+ public void setDefaultProperties(Properties defaultProperties) {
+ this.defaultProperties = defaultProperties;
+ }
+
+ /**
+ * Set the DestinationResolver to use for resolving destination names
+ * into the JCA 1.5 ActivationSpec "destination" property.
+ *
If not specified, destination names will simply be passed in as Strings.
+ * If specified, destination names will be resolved into Destination objects first.
+ *
Note that a DestinationResolver for use with this factory must be
+ * able to work without an active JMS Session: e.g.
+ * {@link org.springframework.jms.support.destination.JndiDestinationResolver}
+ * or {@link org.springframework.jms.support.destination.BeanFactoryDestinationResolver}
+ * but not {@link org.springframework.jms.support.destination.DynamicDestinationResolver}.
+ */
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ this.destinationResolver = destinationResolver;
+ }
+
+
+ public ActivationSpec createActivationSpec(ResourceAdapter adapter, JmsActivationSpecConfig config) {
+ Class activationSpecClassToUse = this.activationSpecClass;
+ if (activationSpecClassToUse == null) {
+ activationSpecClassToUse = determineActivationSpecClass(adapter);
+ if (activationSpecClassToUse == null) {
+ throw new IllegalStateException("Property 'activationSpecClass' is required");
+ }
+ }
+
+ ActivationSpec spec = (ActivationSpec) BeanUtils.instantiateClass(activationSpecClassToUse);
+ BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(spec);
+ if (this.defaultProperties != null) {
+ bw.setPropertyValues(this.defaultProperties);
+ }
+ populateActivationSpecProperties(bw, config);
+ return spec;
+ }
+
+ /**
+ * Determine the ActivationSpec class for the given ResourceAdapter,
+ * if possible. Called if no 'activationSpecClass' has been set explicitly
+ * @param adapter the ResourceAdapter to check
+ * @return the corresponding ActivationSpec class, or null
+ * if not determinable
+ * @see #setActivationSpecClass
+ */
+ protected Class determineActivationSpecClass(ResourceAdapter adapter) {
+ return null;
+ }
+
+ /**
+ * Populate the given ApplicationSpec object with the settings
+ * defined in the given configuration object.
+ *
This implementation applies all standard JMS settings, but ignores
+ * "maxConcurrency" and "prefetchSize" - not supported in standard JCA 1.5.
+ * @param bw the BeanWrapper wrapping the ActivationSpec object
+ * @param config the configured object holding common JMS settings
+ */
+ protected void populateActivationSpecProperties(BeanWrapper bw, JmsActivationSpecConfig config) {
+ String destinationName = config.getDestinationName();
+ boolean pubSubDomain = config.isPubSubDomain();
+ Object destination = destinationName;
+ if (this.destinationResolver != null) {
+ try {
+ destination = this.destinationResolver.resolveDestinationName(null, destinationName, pubSubDomain);
+ }
+ catch (JMSException ex) {
+ throw new DestinationResolutionException("Cannot resolve destination name [" + destinationName + "]", ex);
+ }
+ }
+ bw.setPropertyValue("destination", destination);
+ bw.setPropertyValue("destinationType", pubSubDomain ? Topic.class.getName() : Queue.class.getName());
+
+ if (bw.isWritableProperty("subscriptionDurability")) {
+ bw.setPropertyValue("subscriptionDurability", config.isSubscriptionDurable() ? "Durable" : "NonDurable");
+ }
+ else if (config.isSubscriptionDurable()) {
+ // Standard JCA 1.5 "subscriptionDurability" apparently not supported...
+ throw new IllegalArgumentException(
+ "Durable subscriptions not supported by underlying provider: " + this.activationSpecClass.getName());
+ }
+ if (config.getDurableSubscriptionName() != null) {
+ bw.setPropertyValue("subscriptionName", config.getDurableSubscriptionName());
+ }
+ if (config.getClientId() != null) {
+ bw.setPropertyValue("clientId", config.getClientId());
+ }
+
+ if (config.getMessageSelector() != null) {
+ bw.setPropertyValue("messageSelector", config.getMessageSelector());
+ }
+
+ applyAcknowledgeMode(bw, config.getAcknowledgeMode());
+ }
+
+ /**
+ * Apply the specified acknowledge mode to the ActivationSpec object.
+ *
This implementation applies the standard JCA 1.5 acknowledge modes
+ * "Auto-acknowledge" and "Dups-ok-acknowledge". It throws an exception in
+ * case of CLIENT_ACKNOWLEDGE or SESSION_TRANSACTED
+ * having been requested.
+ * @param bw the BeanWrapper wrapping the ActivationSpec object
+ * @param ackMode the configured acknowledge mode
+ * (according to the constants in {@link javax.jms.Session}
+ * @see javax.jms.Session#AUTO_ACKNOWLEDGE
+ * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
+ * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
+ * @see javax.jms.Session#SESSION_TRANSACTED
+ */
+ protected void applyAcknowledgeMode(BeanWrapper bw, int ackMode) {
+ if (ackMode == Session.SESSION_TRANSACTED) {
+ throw new IllegalArgumentException("No support for SESSION_TRANSACTED: Only \"Auto-acknowledge\" " +
+ "and \"Dups-ok-acknowledge\" supported in standard JCA 1.5");
+ }
+ else if (ackMode == Session.CLIENT_ACKNOWLEDGE) {
+ throw new IllegalArgumentException("No support for CLIENT_ACKNOWLEDGE: Only \"Auto-acknowledge\" " +
+ "and \"Dups-ok-acknowledge\" supported in standard JCA 1.5");
+ }
+ else if (bw.isWritableProperty("acknowledgeMode")) {
+ bw.setPropertyValue("acknowledgeMode",
+ ackMode == Session.DUPS_OK_ACKNOWLEDGE ? "Dups-ok-acknowledge" : "Auto-acknowledge");
+ }
+ else if (ackMode == Session.DUPS_OK_ACKNOWLEDGE) {
+ // Standard JCA 1.5 "acknowledgeMode" apparently not supported (e.g. WebSphere MQ 6.0.2.1)
+ throw new IllegalArgumentException(
+ "Dups-ok-acknowledge not supported by underlying provider: " + this.activationSpecClass.getName());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/endpoint/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/endpoint/package.html 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,7 @@
+
+
+
+This package provides JCA-based endpoint management for JMS message listeners.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/AbstractPoolingServerSessionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/AbstractPoolingServerSessionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/AbstractPoolingServerSessionFactory.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.JMSException;
+import javax.jms.ServerSession;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.scheduling.timer.TimerTaskExecutor;
+
+/**
+ * Abstract base class for ServerSessionFactory implementations
+ * that pool ServerSessionFactory instances.
+ *
+ *
Provides a factory method that creates a poolable ServerSession
+ * (to be added as new instance to a pool), a callback method invoked
+ * when a ServerSession finished an execution of its listener (to return
+ * an instance to the pool), and a method to destroy a ServerSession instance
+ * (after removing an instance from the pool).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see org.springframework.jms.listener.serversession.CommonsPoolServerSessionFactory
+ */
+public abstract class AbstractPoolingServerSessionFactory implements ServerSessionFactory {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private TaskExecutor taskExecutor;
+
+ private int maxSize;
+
+
+ /**
+ * Specify the TaskExecutor to use for executing ServerSessions
+ * (and consequently, the underlying MessageListener).
+ *
Default is a {@link org.springframework.scheduling.timer.TimerTaskExecutor}
+ * for each pooled ServerSession, using one Thread per pooled JMS Session.
+ * Alternatives are a shared TimerTaskExecutor, sharing a single Thread
+ * for the execution of all ServerSessions, or a TaskExecutor
+ * implementation backed by a thread pool.
+ */
+ public void setTaskExecutor(TaskExecutor taskExecutor) {
+ this.taskExecutor = taskExecutor;
+ }
+
+ /**
+ * Return the TaskExecutor to use for executing ServerSessions.
+ */
+ protected TaskExecutor getTaskExecutor() {
+ return this.taskExecutor;
+ }
+
+ /**
+ * Set the maximum size of the pool.
+ */
+ public void setMaxSize(int maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ /**
+ * Return the maximum size of the pool.
+ */
+ public int getMaxSize() {
+ return this.maxSize;
+ }
+
+
+ /**
+ * Create a new poolable ServerSession.
+ * To be called when a new instance should be added to the pool.
+ * @param sessionManager the listener session manager to create the
+ * poolable ServerSession for
+ * @return the new poolable ServerSession
+ * @throws JMSException if creation failed
+ */
+ protected final ServerSession createServerSession(ListenerSessionManager sessionManager) throws JMSException {
+ return new PoolableServerSession(sessionManager);
+ }
+
+ /**
+ * Destroy the given poolable ServerSession.
+ * To be called when an instance got removed from the pool.
+ * @param serverSession the poolable ServerSession to destroy
+ */
+ protected final void destroyServerSession(ServerSession serverSession) {
+ if (serverSession != null) {
+ ((PoolableServerSession) serverSession).close();
+ }
+ }
+
+
+ /**
+ * Template method called by a ServerSession if it finished
+ * execution of its listener and is ready to go back into the pool.
+ *
Subclasses should implement the actual returning of the instance
+ * to the pool.
+ * @param serverSession the ServerSession that finished its execution
+ * @param sessionManager the session manager that the ServerSession belongs to
+ */
+ protected abstract void serverSessionFinished(
+ ServerSession serverSession, ListenerSessionManager sessionManager);
+
+
+ /**
+ * ServerSession implementation designed to be pooled.
+ * Creates a new JMS Session on instantiation, reuses it
+ * for all executions, and closes it on close.
+ *
Creates a TimerTaskExecutor (using a single Thread) per
+ * ServerSession, unless given a specific TaskExecutor to use.
+ */
+ private class PoolableServerSession implements ServerSession {
+
+ private final ListenerSessionManager sessionManager;
+
+ private final Session session;
+
+ private TaskExecutor taskExecutor;
+
+ private TimerTaskExecutor internalExecutor;
+
+ public PoolableServerSession(final ListenerSessionManager sessionManager) throws JMSException {
+ this.sessionManager = sessionManager;
+ this.session = sessionManager.createListenerSession();
+ this.taskExecutor = getTaskExecutor();
+ if (this.taskExecutor == null) {
+ this.internalExecutor = new TimerTaskExecutor();
+ this.internalExecutor.afterPropertiesSet();
+ this.taskExecutor = this.internalExecutor;
+ }
+ }
+
+ public Session getSession() {
+ return this.session;
+ }
+
+ public void start() {
+ this.taskExecutor.execute(new Runnable() {
+ public void run() {
+ try {
+ sessionManager.executeListenerSession(session);
+ }
+ finally {
+ serverSessionFinished(PoolableServerSession.this, sessionManager);
+ }
+ }
+ });
+ }
+
+ public void close() {
+ if (this.internalExecutor != null) {
+ this.internalExecutor.destroy();
+ }
+ JmsUtils.closeSession(this.session);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/CommonsPoolServerSessionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/CommonsPoolServerSessionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/CommonsPoolServerSessionFactory.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.JMSException;
+import javax.jms.ServerSession;
+
+import org.apache.commons.pool.ObjectPool;
+import org.apache.commons.pool.PoolableObjectFactory;
+import org.apache.commons.pool.impl.GenericObjectPool;
+
+/**
+ * {@link ServerSessionFactory} implementation that holds JMS
+ * ServerSessions in a configurable Jakarta Commons Pool.
+ *
+ *
By default, an instance of GenericObjectPool is created.
+ * Subclasses may change the type of ObjectPool used by
+ * overriding the createObjectPool method.
+ *
+ *
Provides many configuration properties mirroring those of the Commons Pool
+ * GenericObjectPool class; these properties are passed to the
+ * GenericObjectPool during construction. If creating a subclass of this
+ * class to change the ObjectPool implementation type, pass in the values
+ * of configuration properties that are relevant to your chosen implementation.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see GenericObjectPool
+ * @see #createObjectPool
+ * @see #setMaxSize
+ * @see #setMaxIdle
+ * @see #setMinIdle
+ * @see #setMaxWait
+ */
+public class CommonsPoolServerSessionFactory extends AbstractPoolingServerSessionFactory {
+
+ private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
+
+ private int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
+
+ private long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
+
+ private long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+
+ private long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+
+ private final Map serverSessionPools = Collections.synchronizedMap(new HashMap(1));
+
+
+ /**
+ * Create a CommonsPoolServerSessionFactory with default settings.
+ * Default maximum size of the pool is 8.
+ * @see #setMaxSize
+ * @see GenericObjectPool#setMaxActive
+ */
+ public CommonsPoolServerSessionFactory() {
+ setMaxSize(GenericObjectPool.DEFAULT_MAX_ACTIVE);
+ }
+
+
+ /**
+ * Set the maximum number of idle ServerSessions in the pool.
+ * Default is 8.
+ * @see GenericObjectPool#setMaxIdle
+ */
+ public void setMaxIdle(int maxIdle) {
+ this.maxIdle = maxIdle;
+ }
+
+ /**
+ * Return the maximum number of idle ServerSessions in the pool.
+ */
+ public int getMaxIdle() {
+ return this.maxIdle;
+ }
+
+ /**
+ * Set the minimum number of idle ServerSessions in the pool.
+ * Default is 0.
+ * @see GenericObjectPool#setMinIdle
+ */
+ public void setMinIdle(int minIdle) {
+ this.minIdle = minIdle;
+ }
+
+ /**
+ * Return the minimum number of idle ServerSessions in the pool.
+ */
+ public int getMinIdle() {
+ return this.minIdle;
+ }
+
+ /**
+ * Set the maximum waiting time for fetching an ServerSession from the pool.
+ * Default is -1, waiting forever.
+ * @see GenericObjectPool#setMaxWait
+ */
+ public void setMaxWait(long maxWait) {
+ this.maxWait = maxWait;
+ }
+
+ /**
+ * Return the maximum waiting time for fetching a ServerSession from the pool.
+ */
+ public long getMaxWait() {
+ return this.maxWait;
+ }
+
+ /**
+ * Set the time between eviction runs that check idle ServerSessions
+ * whether they have been idle for too long or have become invalid.
+ * Default is -1, not performing any eviction.
+ * @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
+ */
+ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+
+ /**
+ * Return the time between eviction runs that check idle ServerSessions.
+ */
+ public long getTimeBetweenEvictionRunsMillis() {
+ return this.timeBetweenEvictionRunsMillis;
+ }
+
+ /**
+ * Set the minimum time that an idle ServerSession can sit in the pool
+ * before it becomes subject to eviction. Default is 1800000 (30 minutes).
+ *
Note that eviction runs need to be performed to take this
+ * setting into effect.
+ * @see #setTimeBetweenEvictionRunsMillis
+ * @see GenericObjectPool#setMinEvictableIdleTimeMillis
+ */
+ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ }
+
+ /**
+ * Return the minimum time that an idle ServerSession can sit in the pool.
+ */
+ public long getMinEvictableIdleTimeMillis() {
+ return this.minEvictableIdleTimeMillis;
+ }
+
+
+ /**
+ * Returns a ServerSession from the pool, creating a new pool for the given
+ * session manager if necessary.
+ * @see #createObjectPool
+ */
+ public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
+ ObjectPool pool = null;
+ synchronized (this.serverSessionPools) {
+ pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
+ if (pool == null) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Creating Commons ServerSession pool for: " + sessionManager);
+ }
+ pool = createObjectPool(sessionManager);
+ this.serverSessionPools.put(sessionManager, pool);
+ }
+ }
+ try {
+ return (ServerSession) pool.borrowObject();
+ }
+ catch (Exception ex) {
+ JMSException jmsEx = new JMSException("Failed to borrow ServerSession from pool");
+ jmsEx.setLinkedException(ex);
+ throw jmsEx;
+ }
+ }
+
+ /**
+ * Subclasses can override this if they want to return a specific Commons pool.
+ * They should apply any configuration properties to the pool here.
+ *
Default is a GenericObjectPool instance with the given pool size.
+ * @param sessionManager the session manager to use for
+ * creating and executing new listener sessions
+ * @return an empty Commons ObjectPool.
+ * @see org.apache.commons.pool.impl.GenericObjectPool
+ * @see #setMaxSize
+ */
+ protected ObjectPool createObjectPool(ListenerSessionManager sessionManager) {
+ GenericObjectPool pool = new GenericObjectPool(createPoolableObjectFactory(sessionManager));
+ pool.setMaxActive(getMaxSize());
+ pool.setMaxIdle(getMaxIdle());
+ pool.setMinIdle(getMinIdle());
+ pool.setMaxWait(getMaxWait());
+ pool.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
+ pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
+ return pool;
+ }
+
+ /**
+ * Create a Commons PoolableObjectFactory adapter for the given session manager.
+ * Calls createServerSession and destroyServerSession
+ * as defined by the AbstractPoolingServerSessionFactory class.
+ * @param sessionManager the session manager to use for
+ * creating and executing new listener sessions
+ * @return the Commons PoolableObjectFactory
+ * @see #createServerSession
+ * @see #destroyServerSession
+ */
+ protected PoolableObjectFactory createPoolableObjectFactory(final ListenerSessionManager sessionManager) {
+ return new PoolableObjectFactory() {
+ public Object makeObject() throws JMSException {
+ return createServerSession(sessionManager);
+ }
+ public void destroyObject(Object obj) {
+ destroyServerSession((ServerSession) obj);
+ }
+ public boolean validateObject(Object obj) {
+ return true;
+ }
+ public void activateObject(Object obj) {
+ }
+ public void passivateObject(Object obj) {
+ }
+ };
+ }
+
+ /**
+ * Returns the given ServerSession, which just finished an execution
+ * of its listener, back to the pool.
+ */
+ protected void serverSessionFinished(ServerSession serverSession, ListenerSessionManager sessionManager) {
+ ObjectPool pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
+ if (pool == null) {
+ throw new IllegalStateException("No pool found for session manager [" + sessionManager + "]");
+ }
+ try {
+ pool.returnObject(serverSession);
+ }
+ catch (Exception ex) {
+ logger.error("Failed to return ServerSession to pool", ex);
+ }
+ }
+
+ /**
+ * Closes and removes the pool for the given session manager.
+ */
+ public void close(ListenerSessionManager sessionManager) {
+ ObjectPool pool = (ObjectPool) this.serverSessionPools.remove(sessionManager);
+ if (pool != null) {
+ try {
+ pool.close();
+ }
+ catch (Exception ex) {
+ logger.error("Failed to close ServerSession pool", ex);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ListenerSessionManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/ListenerSessionManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ListenerSessionManager.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+/**
+ * SPI interface for creating and executing JMS Sessions,
+ * pre-populated with a specific MessageListener.
+ * Implemented by ServerSessionMessageListenerContainer,
+ * accessed by ServerSessionFactory implementations.
+ *
+ *
Effectively, an instance that implements this interface
+ * represents a message listener container for a specific
+ * listener and destination.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see ServerSessionFactory
+ * @see ServerSessionMessageListenerContainer
+ */
+public interface ListenerSessionManager {
+
+ /**
+ * Create a new JMS Session, pre-populated with this manager's
+ * MessageListener.
+ * @return the new JMS Session
+ * @throws JMSException if Session creation failed
+ * @see javax.jms.Session#setMessageListener(javax.jms.MessageListener)
+ */
+ Session createListenerSession() throws JMSException;
+
+ /**
+ * Execute the given JMS Session, triggering its MessageListener
+ * with pre-loaded messages.
+ * @param session the JMS Session to invoke
+ * @see javax.jms.Session#run()
+ */
+ void executeListenerSession(Session session);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionFactory.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.JMSException;
+import javax.jms.ServerSession;
+
+import org.springframework.jms.listener.serversession.ListenerSessionManager;
+
+/**
+ * SPI interface to be implemented by components that manage
+ * JMS ServerSessions. Usually, but not necessarily, an implementation
+ * of this interface will hold a pool of ServerSessions.
+ *
+ *
The passed-in ListenerSessionManager has to be used for creating
+ * and executing JMS Sessions. This session manager is responsible for
+ * registering a MessageListener with all Sessions that it creates.
+ * Consequently, the ServerSessionFactory implementation has to
+ * concentrate on the actual lifecycle (e.g. pooling) of JMS Sessions,
+ * but is not concerned about Session creation or execution.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see org.springframework.jms.listener.serversession.ListenerSessionManager
+ * @see org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer
+ */
+public interface ServerSessionFactory {
+
+ /**
+ * Retrieve a JMS ServerSession for the given session manager.
+ * @param sessionManager the session manager to use for
+ * creating and executing new listener sessions
+ * (implicitly indicating the target listener to invoke)
+ * @return the JMS ServerSession
+ * @throws JMSException if retrieval failed
+ */
+ ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException;
+
+ /**
+ * Close all ServerSessions for the given session manager.
+ * @param sessionManager the session manager used for
+ * creating and executing new listener sessions
+ * (implicitly indicating the target listener)
+ */
+ void close(ListenerSessionManager sessionManager);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionConsumer;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.ServerSession;
+import javax.jms.ServerSessionPool;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.springframework.jms.listener.AbstractMessageListenerContainer;
+import org.springframework.jms.support.JmsUtils;
+
+/**
+ * Message listener container that builds on the {@link javax.jms.ServerSessionPool}
+ * SPI, creating JMS ServerSession instances through a pluggable
+ * {@link ServerSessionFactory}.
+ *
+ *
NOTE: This class requires a JMS 1.1+ provider, because it builds on the
+ * domain-independent API. Use the {@link ServerSessionMessageListenerContainer102}
+ * subclass for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.
+ *
+ *
The default ServerSessionFactory is a {@link SimpleServerSessionFactory},
+ * which will create a new ServerSession for each listener execution.
+ * Consider specifying a {@link CommonsPoolServerSessionFactory} to reuse JMS
+ * Sessions and/or to limit the number of concurrent ServerSession executions.
+ *
+ *
See the {@link AbstractMessageListenerContainer} javadoc for details
+ * on acknowledge modes and other configuration options.
+ *
+ *
This is an 'advanced' (special-purpose) message listener container.
+ * For a simpler message listener container, in particular when using
+ * a JMS provider without ServerSessionPool support, consider using
+ * {@link org.springframework.jms.listener.SimpleMessageListenerContainer}.
+ * For a general one-stop shop that is nevertheless very flexible, consider
+ * {@link org.springframework.jms.listener.DefaultMessageListenerContainer}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see org.springframework.jms.listener.SimpleMessageListenerContainer
+ * @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
+ */
+public class ServerSessionMessageListenerContainer extends AbstractMessageListenerContainer
+ implements ListenerSessionManager {
+
+ private ServerSessionFactory serverSessionFactory = new SimpleServerSessionFactory();
+
+ private int maxMessagesPerTask = 1;
+
+ private ConnectionConsumer consumer;
+
+
+ /**
+ * Set the Spring ServerSessionFactory to use.
+ *
Default is a plain SimpleServerSessionFactory.
+ * Consider using a CommonsPoolServerSessionFactory to reuse JMS Sessions
+ * and/or to limit the number of concurrent ServerSession executions.
+ * @see SimpleServerSessionFactory
+ * @see CommonsPoolServerSessionFactory
+ */
+ public void setServerSessionFactory(ServerSessionFactory serverSessionFactory) {
+ this.serverSessionFactory =
+ (serverSessionFactory != null ? serverSessionFactory : new SimpleServerSessionFactory());
+ }
+
+ /**
+ * Return the Spring ServerSessionFactory to use.
+ */
+ protected ServerSessionFactory getServerSessionFactory() {
+ return this.serverSessionFactory;
+ }
+
+ /**
+ * Set the maximum number of messages to load into a JMS Session.
+ * Default is 1.
+ *
See the corresponding JMS createConnectionConsumer
+ * argument for details.
+ * @see javax.jms.Connection#createConnectionConsumer
+ */
+ public void setMaxMessagesPerTask(int maxMessagesPerTask) {
+ this.maxMessagesPerTask = maxMessagesPerTask;
+ }
+
+ /**
+ * Return the maximum number of messages to load into a JMS Session.
+ */
+ protected int getMaxMessagesPerTask() {
+ return this.maxMessagesPerTask;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Implementation of AbstractMessageListenerContainer's template methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Always use a shared JMS Connection.
+ */
+ protected final boolean sharedConnectionEnabled() {
+ return true;
+ }
+
+ /**
+ * Creates a JMS ServerSessionPool for the specified listener and registers
+ * it with a JMS ConnectionConsumer for the specified destination.
+ * @see #createServerSessionPool
+ * @see #createConsumer
+ */
+ protected void doInitialize() throws JMSException {
+ establishSharedConnection();
+
+ Connection con = getSharedConnection();
+ Destination destination = getDestination();
+ if (destination == null) {
+ Session session = createSession(con);
+ try {
+ destination = resolveDestinationName(session, getDestinationName());
+ }
+ finally {
+ JmsUtils.closeSession(session);
+ }
+ }
+ ServerSessionPool pool = createServerSessionPool();
+ this.consumer = createConsumer(con, destination, pool);
+ }
+
+ /**
+ * Create a JMS ServerSessionPool for the specified message listener,
+ * via this container's ServerSessionFactory.
+ *
This message listener container implements the ListenerSessionManager
+ * interface, hence can be passed to the ServerSessionFactory itself.
+ * @return the ServerSessionPool
+ * @throws JMSException if creation of the ServerSessionPool failed
+ * @see #setServerSessionFactory
+ * @see ServerSessionFactory#getServerSession(ListenerSessionManager)
+ */
+ protected ServerSessionPool createServerSessionPool() throws JMSException {
+ return new ServerSessionPool() {
+ public ServerSession getServerSession() throws JMSException {
+ logger.debug("JMS ConnectionConsumer requests ServerSession");
+ return getServerSessionFactory().getServerSession(ServerSessionMessageListenerContainer.this);
+ }
+ };
+ }
+
+ /**
+ * Return the JMS ConnectionConsumer used by this message listener container.
+ * Available after initialization.
+ */
+ protected final ConnectionConsumer getConsumer() {
+ return this.consumer;
+ }
+
+ /**
+ * Close the JMS ServerSessionPool for the specified message listener,
+ * via this container's ServerSessionFactory, and subsequently also
+ * this container's JMS ConnectionConsumer.
+ *
This message listener container implements the ListenerSessionManager
+ * interface, hence can be passed to the ServerSessionFactory itself.
+ * @see #setServerSessionFactory
+ * @see ServerSessionFactory#getServerSession(ListenerSessionManager)
+ */
+ protected void doShutdown() throws JMSException {
+ logger.debug("Closing ServerSessionFactory");
+ getServerSessionFactory().close(this);
+ logger.debug("Closing JMS ConnectionConsumer");
+ this.consumer.close();
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Implementation of the ListenerSessionManager interface
+ //-------------------------------------------------------------------------
+
+ /**
+ * Create a JMS Session with the specified listener registered.
+ * Listener execution is delegated to the executeListener method.
+ *
Default implementation simply calls setMessageListener
+ * on a newly created JMS Session, according to the JMS specification's
+ * ServerSessionPool section.
+ * @return the JMS Session
+ * @throws JMSException if thrown by JMS API methods
+ * @see #executeListener
+ */
+ public Session createListenerSession() throws JMSException {
+ final Session session = createSession(getSharedConnection());
+
+ session.setMessageListener(new MessageListener() {
+ public void onMessage(Message message) {
+ executeListener(session, message);
+ }
+ });
+
+ return session;
+ }
+
+ /**
+ * Execute the given JMS Session, triggering invocation
+ * of its listener.
+ *
Default implementation simply calls run()
+ * on the JMS Session, according to the JMS specification's
+ * ServerSessionPool section.
+ * @param session the JMS Session to execute
+ */
+ public void executeListenerSession(Session session) {
+ session.run();
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Create a JMS ConnectionConsumer for the given Connection.
+ *
This implementation uses JMS 1.1 API.
+ * @param con the JMS Connection to create a Session for
+ * @param destination the JMS Destination to listen to
+ * @param pool the ServerSessionpool to use
+ * @return the new JMS Session
+ * @throws JMSException if thrown by JMS API methods
+ */
+ protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
+ throws JMSException {
+
+ if (isSubscriptionDurable() && destination instanceof Topic) {
+ return con.createDurableConnectionConsumer(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
+ }
+ else {
+ return con.createConnectionConsumer(destination, getMessageSelector(), pool, getMaxMessagesPerTask());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/ServerSessionMessageListenerContainer102.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionConsumer;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.ServerSessionPool;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+/**
+ * A subclass of {@link ServerSessionMessageListenerContainer} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like ServerSessionMessageListenerContainer itself.
+ *
+ *
This class can be used for JMS 1.0.2 providers, offering the same facility as
+ * ServerSessionMessageListenerContainer does for JMS 1.1 providers.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ */
+public class ServerSessionMessageListenerContainer102 extends ServerSessionMessageListenerContainer {
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Connection createConnection() throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
+ }
+ else {
+ return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
+ throws JMSException {
+
+ if (isPubSubDomain()) {
+ if (isSubscriptionDurable()) {
+ return ((TopicConnection) con).createDurableConnectionConsumer(
+ (Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
+ }
+ else {
+ return ((TopicConnection) con).createConnectionConsumer(
+ (Topic) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
+ }
+ }
+ else {
+ return ((QueueConnection) con).createConnectionConsumer(
+ (Queue) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to use JMS 1.0.2 API.
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (isPubSubDomain()) {
+ return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ else {
+ return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+ }
+
+ /**
+ * This implementation overrides the superclass method to avoid using
+ * JMS 1.1's Session getAcknowledgeMode() method.
+ * The best we can do here is to check the setting on the listener container.
+ */
+ protected boolean isClientAcknowledge(Session session) throws JMSException {
+ return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/SimpleServerSessionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/SimpleServerSessionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/SimpleServerSessionFactory.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2002-2008 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.jms.listener.serversession;
+
+import javax.jms.JMSException;
+import javax.jms.ServerSession;
+import javax.jms.Session;
+
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * The simplest possible implementation of the ServerSessionFactory SPI:
+ * creating a new ServerSession with a new JMS Session every time.
+ * This is the default used by ServerSessionMessageListenerContainer.
+ *
+ *
The execution of a ServerSession (and its MessageListener) gets delegated
+ * to a TaskExecutor. By default, a SimpleAsyncTaskExecutor will be used,
+ * creating a new Thread for every execution attempt. Alternatives are a
+ * TimerTaskExecutor, sharing a single Thread for the execution of all
+ * ServerSessions, or a TaskExecutor implementation backed by a thread pool.
+ *
+ *
To reuse JMS Sessions and/or to limit the number of concurrent
+ * ServerSession executions, consider using a pooling ServerSessionFactory:
+ * for example, CommonsPoolServerSessionFactory.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
+ * and JmsMessageEndpointManager. To be removed in Spring 3.0.
+ * @see org.springframework.core.task.TaskExecutor
+ * @see org.springframework.core.task.SimpleAsyncTaskExecutor
+ * @see org.springframework.scheduling.timer.TimerTaskExecutor
+ * @see CommonsPoolServerSessionFactory
+ * @see ServerSessionMessageListenerContainer
+ */
+public class SimpleServerSessionFactory implements ServerSessionFactory {
+
+ /**
+ * Default thread name prefix: "SimpleServerSessionFactory-".
+ */
+ public static final String DEFAULT_THREAD_NAME_PREFIX =
+ ClassUtils.getShortName(SimpleServerSessionFactory.class) + "-";
+
+
+ private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(DEFAULT_THREAD_NAME_PREFIX);
+
+
+ /**
+ * Specify the TaskExecutor to use for executing ServerSessions
+ * (and consequently, the underlying MessageListener).
+ *
Default is a SimpleAsyncTaskExecutor, creating a new Thread for
+ * every execution attempt. Alternatives are a TimerTaskExecutor,
+ * sharing a single Thread for the execution of all ServerSessions,
+ * or a TaskExecutor implementation backed by a thread pool.
+ * @see org.springframework.core.task.SimpleAsyncTaskExecutor
+ * @see org.springframework.scheduling.timer.TimerTaskExecutor
+ */
+ public void setTaskExecutor(TaskExecutor taskExecutor) {
+ Assert.notNull(taskExecutor, "taskExecutor is required");
+ this.taskExecutor = taskExecutor;
+ }
+
+ /**
+ * Return the TaskExecutor to use for executing ServerSessions.
+ */
+ protected TaskExecutor getTaskExecutor() {
+ return taskExecutor;
+ }
+
+
+ /**
+ * Creates a new SimpleServerSession with a new JMS Session
+ * for every call.
+ */
+ public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
+ return new SimpleServerSession(sessionManager);
+ }
+
+ /**
+ * This implementation is empty, as there is no state held for
+ * each ListenerSessionManager.
+ */
+ public void close(ListenerSessionManager sessionManager) {
+ }
+
+
+ /**
+ * ServerSession implementation that simply creates a new
+ * JMS Session and executes it via the specified TaskExecutor.
+ */
+ private class SimpleServerSession implements ServerSession {
+
+ private final ListenerSessionManager sessionManager;
+
+ private final Session session;
+
+ public SimpleServerSession(ListenerSessionManager sessionManager) throws JMSException {
+ this.sessionManager = sessionManager;
+ this.session = sessionManager.createListenerSession();
+ }
+
+ public Session getSession() {
+ return session;
+ }
+
+ public void start() {
+ getTaskExecutor().execute(new Runnable() {
+ public void run() {
+ try {
+ sessionManager.executeListenerSession(session);
+ }
+ finally {
+ JmsUtils.closeSession(session);
+ }
+ }
+ });
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/listener/serversession/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/listener/serversession/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/listener/serversession/package.html 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+This package contains the ServerSessionMessageListenerContainer implementation,
+based on the standard JMS ServerSessionPool API.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2002-2007 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.jms.remoting;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jms.connection.ConnectionFactoryUtils;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.converter.MessageConverter;
+import org.springframework.jms.support.converter.SimpleMessageConverter;
+import org.springframework.jms.support.destination.DestinationResolver;
+import org.springframework.jms.support.destination.DynamicDestinationResolver;
+import org.springframework.remoting.RemoteAccessException;
+import org.springframework.remoting.RemoteInvocationFailureException;
+import org.springframework.remoting.support.DefaultRemoteInvocationFactory;
+import org.springframework.remoting.support.RemoteInvocation;
+import org.springframework.remoting.support.RemoteInvocationFactory;
+import org.springframework.remoting.support.RemoteInvocationResult;
+
+/**
+ * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a
+ * JMS-based remote service.
+ *
+ *
Serializes remote invocation objects and deserializes remote invocation
+ * result objects. Uses Java serialization just like RMI, but with the JMS
+ * provider as communication infrastructure.
+ *
+ *
To be configured with a {@link javax.jms.QueueConnectionFactory} and a
+ * target queue (either as {@link javax.jms.Queue} reference or as queue name).
+ *
+ *
Thanks to James Strachan for the original prototype that this
+ * JMS invoker mechanism was inspired by!
+ *
+ * @author Juergen Hoeller
+ * @author James Strachan
+ * @since 2.0
+ * @see #setConnectionFactory
+ * @see #setQueue
+ * @see #setQueueName
+ * @see org.springframework.jms.remoting.JmsInvokerServiceExporter
+ * @see org.springframework.jms.remoting.JmsInvokerProxyFactoryBean
+ */
+public class JmsInvokerClientInterceptor implements MethodInterceptor, InitializingBean {
+
+ private ConnectionFactory connectionFactory;
+
+ private Object queue;
+
+ private DestinationResolver destinationResolver = new DynamicDestinationResolver();
+
+ private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory();
+
+ private MessageConverter messageConverter = new SimpleMessageConverter();
+
+ private long receiveTimeout = 0;
+
+
+ /**
+ * Set the QueueConnectionFactory to use for obtaining JMS QueueConnections.
+ */
+ public void setConnectionFactory(ConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ }
+
+ /**
+ * Return the QueueConnectionFactory to use for obtaining JMS QueueConnections.
+ */
+ protected ConnectionFactory getConnectionFactory() {
+ return this.connectionFactory;
+ }
+
+ /**
+ * Set the target Queue to send invoker requests to.
+ */
+ public void setQueue(Queue queue) {
+ this.queue = queue;
+ }
+
+ /**
+ * Set the name of target queue to send invoker requests to.
+ * The specified name will be dynamically resolved via the
+ * {@link #setDestinationResolver DestinationResolver}.
+ */
+ public void setQueueName(String queueName) {
+ this.queue = queueName;
+ }
+
+ /**
+ * Set the DestinationResolver that is to be used to resolve Queue
+ * references for this accessor.
+ *
The default resolver is a DynamicDestinationResolver. Specify a
+ * JndiDestinationResolver for resolving destination names as JNDI locations.
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.destination.JndiDestinationResolver
+ */
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ this.destinationResolver =
+ (destinationResolver != null ? destinationResolver : new DynamicDestinationResolver());
+ }
+
+ /**
+ * Set the RemoteInvocationFactory to use for this accessor.
+ * Default is a {@link org.springframework.remoting.support.DefaultRemoteInvocationFactory}.
+ *
A custom invocation factory can add further context information
+ * to the invocation, for example user credentials.
+ */
+ public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) {
+ this.remoteInvocationFactory =
+ (remoteInvocationFactory != null ? remoteInvocationFactory : new DefaultRemoteInvocationFactory());
+ }
+
+ /**
+ * Specify the MessageConverter to use for turning
+ * {@link org.springframework.remoting.support.RemoteInvocation}
+ * objects into request messages, as well as response messages into
+ * {@link org.springframework.remoting.support.RemoteInvocationResult} objects.
+ *
Default is a {@link org.springframework.jms.support.converter.SimpleMessageConverter},
+ * using a standard JMS {@link javax.jms.ObjectMessage} for each invocation /
+ * invocation result object.
+ *
Custom implementations may generally adapt Serializables into
+ * special kinds of messages, or might be specifically tailored for
+ * translating RemoteInvocation(Result)s into specific kinds of messages.
+ */
+ public void setMessageConverter(MessageConverter messageConverter) {
+ this.messageConverter = (messageConverter != null ? messageConverter : new SimpleMessageConverter());
+ }
+
+ /**
+ * Set the timeout to use for receiving the response message for a request
+ * (in milliseconds).
+ *
The default is 0, which indicates a blocking receive without timeout.
+ * @see javax.jms.MessageConsumer#receive(long)
+ * @see javax.jms.MessageConsumer#receive()
+ */
+ public void setReceiveTimeout(long receiveTimeout) {
+ this.receiveTimeout = receiveTimeout;
+ }
+
+ /**
+ * Return the timeout to use for receiving the response message for a request
+ * (in milliseconds).
+ */
+ protected long getReceiveTimeout() {
+ return this.receiveTimeout;
+ }
+
+
+ public void afterPropertiesSet() {
+ if (getConnectionFactory() == null) {
+ throw new IllegalArgumentException("Property 'connectionFactory' is required");
+ }
+ if (this.queue == null) {
+ throw new IllegalArgumentException("'queue' or 'queueName' is required");
+ }
+ }
+
+
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+ if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
+ return "JMS invoker proxy for queue [" + this.queue + "]";
+ }
+
+ RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
+ RemoteInvocationResult result = null;
+ try {
+ result = executeRequest(invocation);
+ }
+ catch (JMSException ex) {
+ throw convertJmsInvokerAccessException(ex);
+ }
+ try {
+ return recreateRemoteInvocationResult(result);
+ }
+ catch (Throwable ex) {
+ if (result.hasInvocationTargetException()) {
+ throw ex;
+ }
+ else {
+ throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +
+ "] failed in JMS invoker remote service at queue [" + this.queue + "]", ex);
+ }
+ }
+ }
+
+ /**
+ * Create a new RemoteInvocation object for the given AOP method invocation.
+ * The default implementation delegates to the RemoteInvocationFactory.
+ *
Can be overridden in subclasses to provide custom RemoteInvocation
+ * subclasses, containing additional invocation parameters like user credentials.
+ * Note that it is preferable to use a custom RemoteInvocationFactory which
+ * is a reusable strategy.
+ * @param methodInvocation the current AOP method invocation
+ * @return the RemoteInvocation object
+ * @see RemoteInvocationFactory#createRemoteInvocation
+ */
+ protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
+ return this.remoteInvocationFactory.createRemoteInvocation(methodInvocation);
+ }
+
+ /**
+ * Execute the given remote invocation, sending an invoker request message
+ * to this accessor's target queue and waiting for a corresponding response.
+ * @param invocation the RemoteInvocation to execute
+ * @return the RemoteInvocationResult object
+ * @throws JMSException in case of JMS failure
+ * @see #doExecuteRequest
+ */
+ protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws JMSException {
+ Connection con = createConnection();
+ Session session = null;
+ try {
+ session = createSession(con);
+ Queue queueToUse = resolveQueue(session);
+ Message requestMessage = createRequestMessage(session, invocation);
+ con.start();
+ Message responseMessage = doExecuteRequest(session, queueToUse, requestMessage);
+ return extractInvocationResult(responseMessage);
+ }
+ finally {
+ JmsUtils.closeSession(session);
+ ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory(), true);
+ }
+ }
+
+ /**
+ * Create a new JMS Connection for this JMS invoker,
+ * ideally a javax.jms.QueueConnection.
+ *
The default implementation uses the
+ * javax.jms.QueueConnectionFactory API if available,
+ * falling back to a standard JMS 1.1 ConnectionFactory otherwise.
+ * This is necessary for working with generic JMS 1.1 connection pools
+ * (such as ActiveMQ's org.apache.activemq.pool.PooledConnectionFactory).
+ */
+ protected Connection createConnection() throws JMSException {
+ ConnectionFactory cf = getConnectionFactory();
+ if (cf instanceof QueueConnectionFactory) {
+ return ((QueueConnectionFactory) cf).createQueueConnection();
+ }
+ else {
+ return cf.createConnection();
+ }
+ }
+
+ /**
+ * Create a new JMS Session for this JMS invoker,
+ * ideally a javax.jms.QueueSession.
+ *
The default implementation uses the
+ * javax.jms.QueueConnection API if available,
+ * falling back to a standard JMS 1.1 Connection otherwise.
+ * This is necessary for working with generic JMS 1.1 connection pools
+ * (such as ActiveMQ's org.apache.activemq.pool.PooledConnectionFactory).
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ if (con instanceof QueueConnection) {
+ return ((QueueConnection) con).createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+ else {
+ return con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+ }
+
+ /**
+ * Resolve this accessor's target queue.
+ * @param session the current JMS Session
+ * @return the resolved target Queue
+ * @throws JMSException if resolution failed
+ */
+ protected Queue resolveQueue(Session session) throws JMSException {
+ if (this.queue instanceof Queue) {
+ return (Queue) this.queue;
+ }
+ else if (this.queue instanceof String) {
+ return resolveQueueName(session, (String) this.queue);
+ }
+ else {
+ throw new javax.jms.IllegalStateException(
+ "Queue object [" + this.queue + "] is neither a [javax.jms.Queue] nor a queue name String");
+ }
+ }
+
+ /**
+ * Resolve the given queue name into a JMS {@link javax.jms.Queue},
+ * via this accessor's {@link DestinationResolver}.
+ * @param session the current JMS Session
+ * @param queueName the name of the queue
+ * @return the located Queue
+ * @throws JMSException if resolution failed
+ * @see #setDestinationResolver
+ */
+ protected Queue resolveQueueName(Session session, String queueName) throws JMSException {
+ return (Queue) this.destinationResolver.resolveDestinationName(session, queueName, false);
+ }
+
+ /**
+ * Create the invoker request message.
+ *
The default implementation creates a JMS ObjectMessage
+ * for the given RemoteInvocation object.
+ * @param session the current JMS Session
+ * @param invocation the remote invocation to send
+ * @return the JMS Message to send
+ * @throws JMSException if the message could not be created
+ */
+ protected Message createRequestMessage(Session session, RemoteInvocation invocation) throws JMSException {
+ return this.messageConverter.toMessage(invocation, session);
+ }
+
+ /**
+ * Actually execute the given request, sending the invoker request message
+ * to the specified target queue and waiting for a corresponding response.
+ *
The default implementation is based on standard JMS send/receive,
+ * using a {@link javax.jms.TemporaryQueue} for receiving the response.
+ * @param session the JMS Session to use
+ * @param queue the resolved target Queue to send to
+ * @param requestMessage the JMS Message to send
+ * @return the RemoteInvocationResult object
+ * @throws JMSException in case of JMS failure
+ */
+ protected Message doExecuteRequest(Session session, Queue queue, Message requestMessage) throws JMSException {
+ TemporaryQueue responseQueue = null;
+ MessageProducer producer = null;
+ MessageConsumer consumer = null;
+ try {
+ if (session instanceof QueueSession) {
+ // Perform all calls on QueueSession reference for JMS 1.0.2 compatibility...
+ QueueSession queueSession = (QueueSession) session;
+ responseQueue = queueSession.createTemporaryQueue();
+ QueueSender sender = queueSession.createSender(queue);
+ producer = sender;
+ consumer = queueSession.createReceiver(responseQueue);
+ requestMessage.setJMSReplyTo(responseQueue);
+ sender.send(requestMessage);
+ }
+ else {
+ // Standard JMS 1.1 API usage...
+ responseQueue = session.createTemporaryQueue();
+ producer = session.createProducer(queue);
+ consumer = session.createConsumer(responseQueue);
+ requestMessage.setJMSReplyTo(responseQueue);
+ producer.send(requestMessage);
+ }
+ long timeout = getReceiveTimeout();
+ return (timeout > 0 ? consumer.receive(timeout) : consumer.receive());
+ }
+ finally {
+ JmsUtils.closeMessageConsumer(consumer);
+ JmsUtils.closeMessageProducer(producer);
+ if (responseQueue != null) {
+ responseQueue.delete();
+ }
+ }
+ }
+
+ /**
+ * Extract the invocation result from the response message.
+ *
The default implementation expects a JMS ObjectMessage carrying
+ * a RemoteInvocationResult object. If an invalid response message is
+ * encountered, the onInvalidResponse callback gets invoked.
+ * @param responseMessage the response message
+ * @return the invocation result
+ * @throws JMSException is thrown if a JMS exception occurs
+ * @see #onInvalidResponse
+ */
+ protected RemoteInvocationResult extractInvocationResult(Message responseMessage) throws JMSException {
+ Object content = this.messageConverter.fromMessage(responseMessage);
+ if (content instanceof RemoteInvocationResult) {
+ return (RemoteInvocationResult) content;
+ }
+ return onInvalidResponse(responseMessage);
+ }
+
+ /**
+ * Callback that is invoked by extractInvocationResult
+ * when it encounters an invalid response message.
+ *
The default implementation throws a MessageFormatException.
+ * @param responseMessage the invalid response message
+ * @return an alternative invocation result that should be
+ * returned to the caller (if desired)
+ * @throws JMSException if the invalid response should lead
+ * to an infrastructure exception propagated to the caller
+ * @see #extractInvocationResult
+ */
+ protected RemoteInvocationResult onInvalidResponse(Message responseMessage) throws JMSException {
+ throw new MessageFormatException("Invalid response message: " + responseMessage);
+ }
+
+ /**
+ * Recreate the invocation result contained in the given RemoteInvocationResult
+ * object. The default implementation calls the default recreate method.
+ *
Can be overridden in subclass to provide custom recreation, potentially
+ * processing the returned result object.
+ * @param result the RemoteInvocationResult to recreate
+ * @return a return value if the invocation result is a successful return
+ * @throws Throwable if the invocation result is an exception
+ * @see org.springframework.remoting.support.RemoteInvocationResult#recreate()
+ */
+ protected Object recreateRemoteInvocationResult(RemoteInvocationResult result) throws Throwable {
+ return result.recreate();
+ }
+
+ /**
+ * Convert the given JMS invoker access exception to an appropriate
+ * Spring RemoteAccessException.
+ * @param ex the exception to convert
+ * @return the RemoteAccessException to throw
+ */
+ protected RemoteAccessException convertJmsInvokerAccessException(JMSException ex) {
+ throw new RemoteAccessException("Could not access JMS invoker queue [" + this.queue + "]", ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java 17 Aug 2012 15:15:31 -0000 1.1
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2007 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.jms.remoting;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.util.ClassUtils;
+
+/**
+ * FactoryBean for JMS invoker proxies. Exposes the proxied service for use
+ * as a bean reference, using the specified service interface.
+ *
+ *
Serializes remote invocation objects and deserializes remote invocation
+ * result objects. Uses Java serialization just like RMI, but with the JMS
+ * provider as communication infrastructure.
+ *
+ *
To be configured with a {@link javax.jms.QueueConnectionFactory} and a
+ * target queue (either as {@link javax.jms.Queue} reference or as queue name).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setConnectionFactory
+ * @see #setQueueName
+ * @see #setServiceInterface
+ * @see org.springframework.jms.remoting.JmsInvokerClientInterceptor
+ * @see org.springframework.jms.remoting.JmsInvokerServiceExporter
+ */
+public class JmsInvokerProxyFactoryBean extends JmsInvokerClientInterceptor
+ implements FactoryBean, BeanClassLoaderAware {
+
+ private Class serviceInterface;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private Object serviceProxy;
+
+
+ /**
+ * Set the interface that the proxy must implement.
+ * @param serviceInterface the interface that the proxy must implement
+ * @throws IllegalArgumentException if the supplied serviceInterface
+ * is null, or if the supplied serviceInterface
+ * is not an interface type
+ */
+ public void setServiceInterface(Class serviceInterface) {
+ if (serviceInterface == null || !serviceInterface.isInterface()) {
+ throw new IllegalArgumentException("'serviceInterface' must be an interface");
+ }
+ this.serviceInterface = serviceInterface;
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ public void afterPropertiesSet() {
+ super.afterPropertiesSet();
+ if (this.serviceInterface == null) {
+ throw new IllegalArgumentException("Property 'serviceInterface' is required");
+ }
+ this.serviceProxy = new ProxyFactory(this.serviceInterface, this).getProxy(this.beanClassLoader);
+ }
+
+
+ public Object getObject() {
+ return this.serviceProxy;
+ }
+
+ public Class getObjectType() {
+ return this.serviceInterface;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerServiceExporter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerServiceExporter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/remoting/JmsInvokerServiceExporter.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2002-2008 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.jms.remoting;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jms.listener.SessionAwareMessageListener;
+import org.springframework.jms.support.JmsUtils;
+import org.springframework.jms.support.converter.MessageConverter;
+import org.springframework.jms.support.converter.SimpleMessageConverter;
+import org.springframework.remoting.support.RemoteInvocation;
+import org.springframework.remoting.support.RemoteInvocationBasedExporter;
+import org.springframework.remoting.support.RemoteInvocationResult;
+
+/**
+ * JMS message listener that exports the specified service bean as a
+ * JMS service endpoint, accessible via a JMS invoker proxy.
+ *
+ *
Note that this class implements Spring's
+ * {@link org.springframework.jms.listener.SessionAwareMessageListener}
+ * interface, since it requires access to the active JMS Session.
+ * Hence, this class can only be used with message listener containers
+ * which support the SessionAwareMessageListener interface (e.g. Spring's
+ * {@link org.springframework.jms.listener.DefaultMessageListenerContainer}).
+ *
+ *
Thanks to James Strachan for the original prototype that this
+ * JMS invoker mechanism was inspired by!
+ *
+ * @author Juergen Hoeller
+ * @author James Strachan
+ * @since 2.0
+ * @see JmsInvokerClientInterceptor
+ * @see JmsInvokerProxyFactoryBean
+ */
+public class JmsInvokerServiceExporter extends RemoteInvocationBasedExporter
+ implements SessionAwareMessageListener, InitializingBean {
+
+ private MessageConverter messageConverter = new SimpleMessageConverter();
+
+ private boolean ignoreInvalidRequests = true;
+
+ private Object proxy;
+
+
+ /**
+ * Specify the MessageConverter to use for turning request messages into
+ * {@link org.springframework.remoting.support.RemoteInvocation} objects,
+ * as well as {@link org.springframework.remoting.support.RemoteInvocationResult}
+ * objects into response messages.
+ *
Default is a {@link org.springframework.jms.support.converter.SimpleMessageConverter},
+ * using a standard JMS {@link javax.jms.ObjectMessage} for each invocation /
+ * invocation result object.
+ *
Custom implementations may generally adapt Serializables into
+ * special kinds of messages, or might be specifically tailored for
+ * translating RemoteInvocation(Result)s into specific kinds of messages.
+ */
+ public void setMessageConverter(MessageConverter messageConverter) {
+ this.messageConverter = (messageConverter != null ? messageConverter : new SimpleMessageConverter());
+ }
+
+ /**
+ * Set whether invalidly formatted messages should be discarded.
+ * Default is "true".
+ *
Switch this flag to "false" to throw an exception back to the
+ * listener container. This will typically lead to redelivery of
+ * the message, which is usually undesirable - since the message
+ * content will be the same (that is, still invalid).
+ */
+ public void setIgnoreInvalidRequests(boolean ignoreInvalidRequests) {
+ this.ignoreInvalidRequests = ignoreInvalidRequests;
+ }
+
+ public void afterPropertiesSet() {
+ this.proxy = getProxyForService();
+ }
+
+
+ public void onMessage(Message requestMessage, Session session) throws JMSException {
+ RemoteInvocation invocation = readRemoteInvocation(requestMessage);
+ if (invocation != null) {
+ RemoteInvocationResult result = invokeAndCreateResult(invocation, this.proxy);
+ writeRemoteInvocationResult(requestMessage, session, result);
+ }
+ }
+
+ /**
+ * Read a RemoteInvocation from the given JMS message.
+ * @param requestMessage current request message
+ * @return the RemoteInvocation object (or null
+ * in case of an invalid message that will simply be ignored)
+ * @throws javax.jms.JMSException in case of message access failure
+ */
+ protected RemoteInvocation readRemoteInvocation(Message requestMessage) throws JMSException {
+ Object content = this.messageConverter.fromMessage(requestMessage);
+ if (content instanceof RemoteInvocation) {
+ return (RemoteInvocation) content;
+ }
+ return onInvalidRequest(requestMessage);
+ }
+
+
+ /**
+ * Send the given RemoteInvocationResult as a JMS message to the originator.
+ * @param requestMessage current request message
+ * @param session the JMS Session to use
+ * @param result the RemoteInvocationResult object
+ * @throws javax.jms.JMSException if thrown by trying to send the message
+ */
+ protected void writeRemoteInvocationResult(
+ Message requestMessage, Session session, RemoteInvocationResult result) throws JMSException {
+
+ Message response = createResponseMessage(requestMessage, session, result);
+ MessageProducer producer = session.createProducer(requestMessage.getJMSReplyTo());
+ try {
+ producer.send(response);
+ }
+ finally {
+ JmsUtils.closeMessageProducer(producer);
+ }
+ }
+
+ /**
+ * Create the invocation result response message.
+ *
The default implementation creates a JMS ObjectMessage for the given
+ * RemoteInvocationResult object. It sets the response's correlation id
+ * to the request message's correlation id, if any; otherwise to the
+ * request message id.
+ * @param request the original request message
+ * @param session the JMS session to use
+ * @param result the invocation result
+ * @return the message response to send
+ * @throws javax.jms.JMSException if creating the messsage failed
+ */
+ protected Message createResponseMessage(Message request, Session session, RemoteInvocationResult result)
+ throws JMSException {
+
+ Message response = this.messageConverter.toMessage(result, session);
+ String correlation = request.getJMSCorrelationID();
+ if (correlation == null) {
+ correlation = request.getJMSMessageID();
+ }
+ response.setJMSCorrelationID(correlation);
+ return response;
+ }
+
+ /**
+ * Callback that is invoked by {@link #readRemoteInvocation}
+ * when it encounters an invalid request message.
+ *
The default implementation either discards the invalid message or
+ * throws a MessageFormatException - according to the "ignoreInvalidRequests"
+ * flag, which is set to "true" (that is, discard invalid messages) by default.
+ * @param requestMessage the invalid request message
+ * @return the RemoteInvocation to expose for the invalid request (typically
+ * null in case of an invalid message that will simply be ignored)
+ * @throws javax.jms.JMSException in case of the invalid request supposed
+ * to lead to an exception (instead of ignoring it)
+ * @see #readRemoteInvocation
+ * @see #setIgnoreInvalidRequests
+ */
+ protected RemoteInvocation onInvalidRequest(Message requestMessage) throws JMSException {
+ if (this.ignoreInvalidRequests) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Invalid request message will be discarded: " + requestMessage);
+ }
+ return null;
+ }
+ else {
+ throw new MessageFormatException("Invalid request message: " + requestMessage);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/remoting/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/remoting/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/remoting/package.html 17 Aug 2012 15:15:31 -0000 1.1
@@ -0,0 +1,11 @@
+
+
+
+Remoting classes for transparent Java-to-Java remoting via a JMS provider.
+
+
Allows the target service to be load-balanced across a number of queue
+receivers, and provides a level of indirection between the client and the
+service: They only need to agree on a queue name and a service interface.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/support/JmsAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/JmsAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/JmsAccessor.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2002-2008 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.jms.support;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.Constants;
+import org.springframework.jms.JmsException;
+
+/**
+ * Base class for {@link org.springframework.jms.core.JmsTemplate} and other
+ * JMS-accessing gateway helpers, defining common properties such as the
+ * JMS {@link ConnectionFactory} to operate on. The subclass
+ * {@link org.springframework.jms.support.destination.JmsDestinationAccessor}
+ * adds further, destination-related properties.
+ *
+ *
Not intended to be used directly.
+ * See {@link org.springframework.jms.core.JmsTemplate}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jms.support.destination.JmsDestinationAccessor
+ * @see org.springframework.jms.core.JmsTemplate
+ */
+public abstract class JmsAccessor implements InitializingBean {
+
+ /** Constants instance for javax.jms.Session */
+ private static final Constants sessionConstants = new Constants(Session.class);
+
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private ConnectionFactory connectionFactory;
+
+ private boolean sessionTransacted = false;
+
+ private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE;
+
+
+ /**
+ * Set the ConnectionFactory to use for obtaining JMS {@link Connection Connections}.
+ */
+ public void setConnectionFactory(ConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ }
+
+ /**
+ * Return the ConnectionFactory that this accessor uses for obtaining
+ * JMS {@link Connection Connections}.
+ */
+ public ConnectionFactory getConnectionFactory() {
+ return this.connectionFactory;
+ }
+
+ /**
+ * Set the transaction mode that is used when creating a JMS {@link Session}.
+ * Default is "false".
+ *
Note that within a JTA transaction, the parameters passed to
+ * create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)
+ * method are not taken into account. Depending on the J2EE transaction context,
+ * the container makes its own decisions on these values. Analogously, these
+ * parameters are not taken into account within a locally managed transaction
+ * either, since the accessor operates on an existing JMS Session in this case.
+ *
Setting this flag to "true" will use a short local JMS transaction
+ * when running outside of a managed transaction, and a synchronized local
+ * JMS transaction in case of a managed transaction (other than an XA
+ * transaction) being present. The latter has the effect of a local JMS
+ * transaction being managed alongside the main transaction (which might
+ * be a native JDBC transaction), with the JMS transaction committing
+ * right after the main transaction.
+ * @see javax.jms.Connection#createSession(boolean, int)
+ */
+ public void setSessionTransacted(boolean sessionTransacted) {
+ this.sessionTransacted = sessionTransacted;
+ }
+
+ /**
+ * Return whether the JMS {@link Session sessions} used by this
+ * accessor are supposed to be transacted.
+ * @see #setSessionTransacted(boolean)
+ */
+ public boolean isSessionTransacted() {
+ return this.sessionTransacted;
+ }
+
+ /**
+ * Set the JMS acknowledgement mode by the name of the corresponding constant
+ * in the JMS {@link Session} interface, e.g. "CLIENT_ACKNOWLEDGE".
+ *
If you want to use vendor-specific extensions to the acknowledgment mode,
+ * use {@link #setSessionAcknowledgeModeName(String)} instead.
+ * @param constantName the name of the {@link Session} acknowledge mode constant
+ * @see javax.jms.Session#AUTO_ACKNOWLEDGE
+ * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
+ * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
+ * @see javax.jms.Connection#createSession(boolean, int)
+ */
+ public void setSessionAcknowledgeModeName(String constantName) {
+ setSessionAcknowledgeMode(sessionConstants.asNumber(constantName).intValue());
+ }
+
+ /**
+ * Set the JMS acknowledgement mode that is used when creating a JMS
+ * {@link Session} to send a message.
+ *
Default is {@link Session#AUTO_ACKNOWLEDGE}.
+ *
Vendor-specific extensions to the acknowledgment mode can be set here as well.
+ *
Note that that inside an EJB the parameters to
+ * create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) method
+ * are not taken into account. Depending on the transaction context in the EJB,
+ * the container makes its own decisions on these values. See section 17.3.5
+ * of the EJB spec.
+ * @param sessionAcknowledgeMode the acknowledgement mode constant
+ * @see javax.jms.Session#AUTO_ACKNOWLEDGE
+ * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
+ * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
+ * @see javax.jms.Connection#createSession(boolean, int)
+ */
+ public void setSessionAcknowledgeMode(int sessionAcknowledgeMode) {
+ this.sessionAcknowledgeMode = sessionAcknowledgeMode;
+ }
+
+ /**
+ * Return the acknowledgement mode for JMS {@link Session sessions}.
+ */
+ public int getSessionAcknowledgeMode() {
+ return this.sessionAcknowledgeMode;
+ }
+
+ public void afterPropertiesSet() {
+ if (getConnectionFactory() == null) {
+ throw new IllegalArgumentException("Property 'connectionFactory' is required");
+ }
+ }
+
+
+ /**
+ * Convert the specified checked {@link javax.jms.JMSException JMSException} to
+ * a Spring runtime {@link org.springframework.jms.JmsException JmsException}
+ * equivalent.
+ *
The default implementation delegates to the
+ * {@link org.springframework.jms.support.JmsUtils#convertJmsAccessException} method.
+ * @param ex the original checked {@link JMSException} to convert
+ * @return the Spring runtime {@link JmsException} wrapping ex
+ * @see org.springframework.jms.support.JmsUtils#convertJmsAccessException
+ */
+ protected JmsException convertJmsAccessException(JMSException ex) {
+ return JmsUtils.convertJmsAccessException(ex);
+ }
+
+
+ //-------------------------------------------------------------------------
+ // JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
+ //-------------------------------------------------------------------------
+
+ /**
+ * Create a JMS Connection via this template's ConnectionFactory.
+ *
This implementation uses JMS 1.1 API.
+ * @return the new JMS Connection
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.ConnectionFactory#createConnection()
+ */
+ protected Connection createConnection() throws JMSException {
+ return getConnectionFactory().createConnection();
+ }
+
+ /**
+ * Create a JMS Session for the given Connection.
+ *
This implementation uses JMS 1.1 API.
+ * @param con the JMS Connection to create a Session for
+ * @return the new JMS Session
+ * @throws JMSException if thrown by JMS API methods
+ * @see javax.jms.Connection#createSession(boolean, int)
+ */
+ protected Session createSession(Connection con) throws JMSException {
+ return con.createSession(isSessionTransacted(), getSessionAcknowledgeMode());
+ }
+
+ /**
+ * Determine whether the given Session is in client acknowledge mode.
+ *
This implementation uses JMS 1.1 API.
+ * @param session the JMS Session to check
+ * @return whether the given Session is in client acknowledge mode
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ * @see javax.jms.Session#getAcknowledgeMode()
+ * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
+ */
+ protected boolean isClientAcknowledge(Session session) throws JMSException {
+ return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/JmsUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/JmsUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/JmsUtils.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2002-2008 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.jms.support;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueRequestor;
+import javax.jms.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.jms.InvalidClientIDException;
+import org.springframework.jms.InvalidDestinationException;
+import org.springframework.jms.InvalidSelectorException;
+import org.springframework.jms.JmsException;
+import org.springframework.jms.JmsSecurityException;
+import org.springframework.jms.MessageEOFException;
+import org.springframework.jms.MessageFormatException;
+import org.springframework.jms.MessageNotReadableException;
+import org.springframework.jms.MessageNotWriteableException;
+import org.springframework.jms.ResourceAllocationException;
+import org.springframework.jms.TransactionInProgressException;
+import org.springframework.jms.TransactionRolledBackException;
+import org.springframework.jms.UncategorizedJmsException;
+import org.springframework.util.Assert;
+
+/**
+ * Generic utility methods for working with JMS. Mainly for internal use
+ * within the framework, but also useful for custom JMS access code.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ */
+public abstract class JmsUtils {
+
+ private static final Log logger = LogFactory.getLog(JmsUtils.class);
+
+
+ /**
+ * Close the given JMS Connection and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param con the JMS Connection to close (may be null)
+ */
+ public static void closeConnection(Connection con) {
+ closeConnection(con, false);
+ }
+
+ /**
+ * Close the given JMS Connection and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param con the JMS Connection to close (may be null)
+ * @param stop whether to call stop() before closing
+ */
+ public static void closeConnection(Connection con, boolean stop) {
+ if (con != null) {
+ try {
+ if (stop) {
+ try {
+ con.stop();
+ }
+ finally {
+ con.close();
+ }
+ }
+ else {
+ con.close();
+ }
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ logger.debug("Ignoring Connection state exception - assuming already closed: " + ex);
+ }
+ catch (JMSException ex) {
+ logger.debug("Could not close JMS Connection", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.debug("Unexpected exception on closing JMS Connection", ex);
+ }
+ }
+ }
+
+ /**
+ * Close the given JMS Session and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param session the JMS Session to close (may be null)
+ */
+ public static void closeSession(Session session) {
+ if (session != null) {
+ try {
+ session.close();
+ }
+ catch (JMSException ex) {
+ logger.trace("Could not close JMS Session", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.trace("Unexpected exception on closing JMS Session", ex);
+ }
+ }
+ }
+
+ /**
+ * Close the given JMS MessageProducer and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param producer the JMS MessageProducer to close (may be null)
+ */
+ public static void closeMessageProducer(MessageProducer producer) {
+ if (producer != null) {
+ try {
+ producer.close();
+ }
+ catch (JMSException ex) {
+ logger.trace("Could not close JMS MessageProducer", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.trace("Unexpected exception on closing JMS MessageProducer", ex);
+ }
+ }
+ }
+
+ /**
+ * Close the given JMS MessageConsumer and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param consumer the JMS MessageConsumer to close (may be null)
+ */
+ public static void closeMessageConsumer(MessageConsumer consumer) {
+ if (consumer != null) {
+ // Clear interruptions to ensure that the consumer closes successfully...
+ // (working around misbehaving JMS providers such as ActiveMQ)
+ boolean wasInterrupted = Thread.interrupted();
+ try {
+ consumer.close();
+ }
+ catch (JMSException ex) {
+ logger.trace("Could not close JMS MessageConsumer", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.trace("Unexpected exception on closing JMS MessageConsumer", ex);
+ }
+ finally {
+ if (wasInterrupted) {
+ // Reset the interrupted flag as it was before.
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * Close the given JMS QueueBrowser and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param browser the JMS QueueBrowser to close (may be null)
+ */
+ public static void closeQueueBrowser(QueueBrowser browser) {
+ if (browser != null) {
+ try {
+ browser.close();
+ }
+ catch (JMSException ex) {
+ logger.trace("Could not close JMS QueueBrowser", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.trace("Unexpected exception on closing JMS QueueBrowser", ex);
+ }
+ }
+ }
+
+ /**
+ * Close the given JMS QueueRequestor and ignore any thrown exception.
+ * This is useful for typical finally blocks in manual JMS code.
+ * @param requestor the JMS QueueRequestor to close (may be null)
+ */
+ public static void closeQueueRequestor(QueueRequestor requestor) {
+ if (requestor != null) {
+ try {
+ requestor.close();
+ }
+ catch (JMSException ex) {
+ logger.trace("Could not close JMS QueueRequestor", ex);
+ }
+ catch (Throwable ex) {
+ // We don't trust the JMS provider: It might throw RuntimeException or Error.
+ logger.trace("Unexpected exception on closing JMS QueueRequestor", ex);
+ }
+ }
+ }
+
+ /**
+ * Commit the Session if not within a JTA transaction.
+ * @param session the JMS Session to commit
+ * @throws JMSException if committing failed
+ */
+ public static void commitIfNecessary(Session session) throws JMSException {
+ Assert.notNull(session, "Session must not be null");
+ try {
+ session.commit();
+ }
+ catch (javax.jms.TransactionInProgressException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ }
+
+ /**
+ * Rollback the Session if not within a JTA transaction.
+ * @param session the JMS Session to rollback
+ * @throws JMSException if committing failed
+ */
+ public static void rollbackIfNecessary(Session session) throws JMSException {
+ Assert.notNull(session, "Session must not be null");
+ try {
+ session.rollback();
+ }
+ catch (javax.jms.TransactionInProgressException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ catch (javax.jms.IllegalStateException ex) {
+ // Ignore -> can only happen in case of a JTA transaction.
+ }
+ }
+
+ /**
+ * Build a descriptive exception message for the given JMSException,
+ * incorporating a linked exception's message if appropriate.
+ * @param ex the JMSException to build a message for
+ * @return the descriptive message String
+ * @see javax.jms.JMSException#getLinkedException()
+ */
+ public static String buildExceptionMessage(JMSException ex) {
+ String message = ex.getMessage();
+ Exception linkedEx = ex.getLinkedException();
+ if (linkedEx != null && message.indexOf(linkedEx.getMessage()) == -1) {
+ message = message + "; nested exception is " + linkedEx;
+ }
+ return message;
+ }
+
+ /**
+ * Convert the specified checked {@link javax.jms.JMSException JMSException} to a
+ * Spring runtime {@link org.springframework.jms.JmsException JmsException} equivalent.
+ * @param ex the original checked JMSException to convert
+ * @return the Spring runtime JmsException wrapping the given exception
+ */
+ public static JmsException convertJmsAccessException(JMSException ex) {
+ Assert.notNull(ex, "JMSException must not be null");
+
+ if (ex instanceof javax.jms.IllegalStateException) {
+ return new org.springframework.jms.IllegalStateException((javax.jms.IllegalStateException) ex);
+ }
+ if (ex instanceof javax.jms.InvalidClientIDException) {
+ return new InvalidClientIDException((javax.jms.InvalidClientIDException) ex);
+ }
+ if (ex instanceof javax.jms.InvalidDestinationException) {
+ return new InvalidDestinationException((javax.jms.InvalidDestinationException) ex);
+ }
+ if (ex instanceof javax.jms.InvalidSelectorException) {
+ return new InvalidSelectorException((javax.jms.InvalidSelectorException) ex);
+ }
+ if (ex instanceof javax.jms.JMSSecurityException) {
+ return new JmsSecurityException((javax.jms.JMSSecurityException) ex);
+ }
+ if (ex instanceof javax.jms.MessageEOFException) {
+ return new MessageEOFException((javax.jms.MessageEOFException) ex);
+ }
+ if (ex instanceof javax.jms.MessageFormatException) {
+ return new MessageFormatException((javax.jms.MessageFormatException) ex);
+ }
+ if (ex instanceof javax.jms.MessageNotReadableException) {
+ return new MessageNotReadableException((javax.jms.MessageNotReadableException) ex);
+ }
+ if (ex instanceof javax.jms.MessageNotWriteableException) {
+ return new MessageNotWriteableException((javax.jms.MessageNotWriteableException) ex);
+ }
+ if (ex instanceof javax.jms.ResourceAllocationException) {
+ return new ResourceAllocationException((javax.jms.ResourceAllocationException) ex);
+ }
+ if (ex instanceof javax.jms.TransactionInProgressException) {
+ return new TransactionInProgressException((javax.jms.TransactionInProgressException) ex);
+ }
+ if (ex instanceof javax.jms.TransactionRolledBackException) {
+ return new TransactionRolledBackException((javax.jms.TransactionRolledBackException) ex);
+ }
+
+ // fallback
+ return new UncategorizedJmsException(ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/package.html 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+This package provides generic JMS support classes,
+to be used by higher-level classes like JmsTemplate.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConversionException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConversionException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConversionException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2006 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.jms.support.converter;
+
+import org.springframework.jms.JmsException;
+
+/**
+ * Thrown by {@link MessageConverter} implementations when the conversion
+ * of an object to/from a {@link javax.jms.Message} fails.
+ *
+ * @author Mark Pollack
+ * @since 1.1
+ * @see MessageConverter
+ */
+public class MessageConversionException extends JmsException {
+
+ /**
+ * Create a new MessageConversionException.
+ * @param msg the detail message
+ */
+ public MessageConversionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new MessageConversionException.
+ * @param msg the detail message
+ * @param cause the root cause (if any)
+ */
+ public MessageConversionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConverter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConverter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/converter/MessageConverter.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2002-2007 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.jms.support.converter;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+/**
+ * Strategy interface that specifies a converter between Java objects and JMS messages.
+ *
+ *
Check out {@link SimpleMessageConverter} for a default implementation,
+ * converting between the 'standard' message payloads and JMS Message types.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see org.springframework.jms.core.JmsTemplate#setMessageConverter
+ * @see org.springframework.jms.listener.adapter.MessageListenerAdapter#setMessageConverter
+ * @see org.springframework.jms.remoting.JmsInvokerClientInterceptor#setMessageConverter
+ * @see org.springframework.jms.remoting.JmsInvokerServiceExporter#setMessageConverter
+ */
+public interface MessageConverter {
+
+ /**
+ * Convert a Java object to a JMS Message using the supplied session
+ * to create the message object.
+ * @param object the object to convert
+ * @param session the Session to use for creating a JMS Message
+ * @return the JMS Message
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ * @throws MessageConversionException in case of conversion failure
+ */
+ Message toMessage(Object object, Session session) throws JMSException, MessageConversionException;
+
+ /**
+ * Convert from a JMS Message to a Java object.
+ * @param message the message to convert
+ * @return the converted Java object
+ * @throws javax.jms.JMSException if thrown by JMS API methods
+ * @throws MessageConversionException in case of conversion failure
+ */
+ Object fromMessage(Message message) throws JMSException, MessageConversionException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2002-2008 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.jms.support.converter;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.springframework.util.ObjectUtils;
+
+/**
+ * A simple message converter which is able to handle TextMessages, BytesMessages,
+ * MapMessages, and ObjectMessages. Used as default conversion strategy
+ * by {@link org.springframework.jms.core.JmsTemplate}, for
+ * convertAndSend and receiveAndConvert operations.
+ *
+ *
Converts a String to a {@link javax.jms.TextMessage}, a byte array to a
+ * {@link javax.jms.BytesMessage}, a Map to a {@link javax.jms.MapMessage}, and
+ * a Serializable object to a {@link javax.jms.ObjectMessage} (or vice versa).
+ *
+ *
This converter implementation works for both JMS 1.1 and JMS 1.0.2,
+ * except when extracting a byte array from a BytesMessage. So for converting
+ * BytesMessages with a JMS 1.0.2 provider, use {@link SimpleMessageConverter102}.
+ * (As you would expect, {@link org.springframework.jms.core.JmsTemplate102}
+ * uses SimpleMessageConverter102 as default.)
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see org.springframework.jms.core.JmsTemplate#convertAndSend
+ * @see org.springframework.jms.core.JmsTemplate#receiveAndConvert
+ */
+public class SimpleMessageConverter implements MessageConverter {
+
+ /**
+ * This implementation creates a TextMessage for a String, a
+ * BytesMessage for a byte array, a MapMessage for a Map,
+ * and an ObjectMessage for a Serializable object.
+ * @see #createMessageForString
+ * @see #createMessageForByteArray
+ * @see #createMessageForMap
+ * @see #createMessageForSerializable
+ */
+ public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
+ if (object instanceof Message) {
+ return (Message) object;
+ }
+ else if (object instanceof String) {
+ return createMessageForString((String) object, session);
+ }
+ else if (object instanceof byte[]) {
+ return createMessageForByteArray((byte[]) object, session);
+ }
+ else if (object instanceof Map) {
+ return createMessageForMap((Map) object, session);
+ }
+ else if (object instanceof Serializable) {
+ return createMessageForSerializable(((Serializable) object), session);
+ }
+ else {
+ throw new MessageConversionException("Cannot convert object of type [" +
+ ObjectUtils.nullSafeClassName(object) + "] to JMS message. Supported message " +
+ "payloads are: String, byte array, Map, Serializable object.");
+ }
+ }
+
+ /**
+ * This implementation converts a TextMessage back to a String, a
+ * ByteMessage back to a byte array, a MapMessage back to a Map,
+ * and an ObjectMessage back to a Serializable object. Returns
+ * the plain Message object in case of an unknown message type.
+ * @see #extractStringFromMessage
+ * @see #extractByteArrayFromMessage
+ * @see #extractMapFromMessage
+ * @see #extractSerializableFromMessage
+ */
+ public Object fromMessage(Message message) throws JMSException, MessageConversionException {
+ if (message instanceof TextMessage) {
+ return extractStringFromMessage((TextMessage) message);
+ }
+ else if (message instanceof BytesMessage) {
+ return extractByteArrayFromMessage((BytesMessage) message);
+ }
+ else if (message instanceof MapMessage) {
+ return extractMapFromMessage((MapMessage) message);
+ }
+ else if (message instanceof ObjectMessage) {
+ return extractSerializableFromMessage((ObjectMessage) message);
+ }
+ else {
+ return message;
+ }
+ }
+
+
+ /**
+ * Create a JMS TextMessage for the given String.
+ * @param text the String to convert
+ * @param session current JMS session
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @see javax.jms.Session#createTextMessage
+ */
+ protected TextMessage createMessageForString(String text, Session session) throws JMSException {
+ return session.createTextMessage(text);
+ }
+
+ /**
+ * Create a JMS BytesMessage for the given byte array.
+ * @param bytes the byyte array to convert
+ * @param session current JMS session
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @see javax.jms.Session#createBytesMessage
+ */
+ protected BytesMessage createMessageForByteArray(byte[] bytes, Session session) throws JMSException {
+ BytesMessage message = session.createBytesMessage();
+ message.writeBytes(bytes);
+ return message;
+ }
+
+ /**
+ * Create a JMS MapMessage for the given Map.
+ * @param map the Map to convert
+ * @param session current JMS session
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @see javax.jms.Session#createMapMessage
+ */
+ protected MapMessage createMessageForMap(Map map, Session session) throws JMSException {
+ MapMessage message = session.createMapMessage();
+ for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ if (!(entry.getKey() instanceof String)) {
+ throw new MessageConversionException("Cannot convert non-String key of type [" +
+ ObjectUtils.nullSafeClassName(entry.getKey()) + "] to JMS MapMessage entry");
+ }
+ message.setObject((String) entry.getKey(), entry.getValue());
+ }
+ return message;
+ }
+
+ /**
+ * Create a JMS ObjectMessage for the given Serializable object.
+ * @param object the Serializable object to convert
+ * @param session current JMS session
+ * @return the resulting message
+ * @throws JMSException if thrown by JMS methods
+ * @see javax.jms.Session#createObjectMessage
+ */
+ protected ObjectMessage createMessageForSerializable(Serializable object, Session session) throws JMSException {
+ return session.createObjectMessage(object);
+ }
+
+
+ /**
+ * Extract a String from the given TextMessage.
+ * @param message the message to convert
+ * @return the resulting String
+ * @throws JMSException if thrown by JMS methods
+ */
+ protected String extractStringFromMessage(TextMessage message) throws JMSException {
+ return message.getText();
+ }
+
+ /**
+ * Extract a byte array from the given {@link BytesMessage}.
+ * @param message the message to convert
+ * @return the resulting byte array
+ * @throws JMSException if thrown by JMS methods
+ */
+ protected byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
+ byte[] bytes = new byte[(int) message.getBodyLength()];
+ message.readBytes(bytes);
+ return bytes;
+ }
+
+ /**
+ * Extract a Map from the given {@link MapMessage}.
+ * @param message the message to convert
+ * @return the resulting Map
+ * @throws JMSException if thrown by JMS methods
+ */
+ protected Map extractMapFromMessage(MapMessage message) throws JMSException {
+ Map map = new HashMap();
+ Enumeration en = message.getMapNames();
+ while (en.hasMoreElements()) {
+ String key = (String) en.nextElement();
+ map.put(key, message.getObject(key));
+ }
+ return map;
+ }
+
+ /**
+ * Extract a Serializable object from the given {@link ObjectMessage}.
+ * @param message the message to convert
+ * @return the resulting Serializable object
+ * @throws JMSException if thrown by JMS methods
+ */
+ protected Serializable extractSerializableFromMessage(ObjectMessage message) throws JMSException {
+ return message.getObject();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter102.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter102.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/converter/SimpleMessageConverter102.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2002-2007 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.jms.support.converter;
+
+import java.io.ByteArrayOutputStream;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+
+/**
+ * A subclass of {@link SimpleMessageConverter} for the JMS 1.0.2 specification,
+ * not relying on JMS 1.1 methods like SimpleMessageConverter itself.
+ * This class can be used for JMS 1.0.2 providers, offering the same functionality
+ * as SimpleMessageConverter does for JMS 1.1 providers.
+ *
+ *
The only difference to the default SimpleMessageConverter is that BytesMessage
+ * is handled differently: namely, without using the getBodyLength()
+ * method which has been introduced in JMS 1.1 and is therefore not available on a
+ * JMS 1.0.2 provider.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.1
+ * @see javax.jms.BytesMessage#getBodyLength()
+ */
+public class SimpleMessageConverter102 extends SimpleMessageConverter {
+
+ public static final int BUFFER_SIZE = 4096;
+
+
+ /**
+ * Overrides superclass method to copy bytes from the message into a
+ * ByteArrayOutputStream, using a buffer, to avoid using the
+ * getBodyLength() method which has been introduced in
+ * JMS 1.1 and is therefore not available on a JMS 1.0.2 provider.
+ * @see javax.jms.BytesMessage#getBodyLength()
+ */
+ protected byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(BUFFER_SIZE);
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bufferCount = -1;
+ while ((bufferCount = message.readBytes(buffer)) >= 0) {
+ baos.write(buffer, 0, bufferCount);
+ if (bufferCount < BUFFER_SIZE) {
+ break;
+ }
+ }
+ return baos.toByteArray();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/converter/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/converter/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/converter/package.html 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides a MessageConverter abstraction to convert
+between Java objects and JMS messages.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/BeanFactoryDestinationResolver.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2007 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.jms.support.destination;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.util.Assert;
+
+/**
+ * {@link DestinationResolver} implementation based on a Spring {@link BeanFactory}.
+ *
+ *
Will lookup Spring managed beans identified by bean name,
+ * expecting them to be of type javax.jms.Destination.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see org.springframework.beans.factory.BeanFactory
+ */
+public class BeanFactoryDestinationResolver implements DestinationResolver, BeanFactoryAware {
+
+ private BeanFactory beanFactory;
+
+
+ /**
+ * Create a new instance of the {@link BeanFactoryDestinationResolver} class.
+ *
The BeanFactory to access must be set via setBeanFactory.
+ * @see #setBeanFactory
+ */
+ public BeanFactoryDestinationResolver() {
+ }
+
+ /**
+ * Create a new instance of the {@link BeanFactoryDestinationResolver} class.
+ *
Use of this constructor is redundant if this object is being created
+ * by a Spring IoC container, as the supplied {@link BeanFactory} will be
+ * replaced by the {@link BeanFactory} that creates it (c.f. the
+ * {@link BeanFactoryAware} contract). So only use this constructor if you
+ * are using this class outside the context of a Spring IoC container.
+ * @param beanFactory the bean factory to be used to lookup {@link javax.jms.Destination Destinatiosn}
+ */
+ public BeanFactoryDestinationResolver(BeanFactory beanFactory) {
+ Assert.notNull(beanFactory, "BeanFactory is required");
+ this.beanFactory = beanFactory;
+ }
+
+
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+
+ public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
+ throws JMSException {
+
+ Assert.state(this.beanFactory != null, "BeanFactory is required");
+ try {
+ return (Destination) this.beanFactory.getBean(destinationName, Destination.class);
+ }
+ catch (BeansException ex) {
+ throw new DestinationResolutionException(
+ "Failed to look up Destinaton bean with name '" + destinationName + "'", ex);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/CachingDestinationResolver.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/CachingDestinationResolver.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/CachingDestinationResolver.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2006 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.jms.support.destination;
+
+/**
+ * Extension of the DestinationResolver interface,
+ * exposing methods for clearing the cache.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public interface CachingDestinationResolver extends DestinationResolver {
+
+ /**
+ * Remove the destination with the given name from the cache
+ * (if cached by this resolver in the first place).
+ *
To be called if access to the specified destination failed,
+ * assuming that the JMS Destination object might have become invalid.
+ * @param destinationName the name of the destination
+ */
+ void removeFromCache(String destinationName);
+
+ /**
+ * Clear the entire destination cache.
+ *
To be called in case of general JMS provider failure.
+ */
+ void clearCache();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolutionException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolutionException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolutionException.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2006 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.jms.support.destination;
+
+import org.springframework.jms.JmsException;
+
+/**
+ * Thrown by a DestinationResolver when it cannot resolve a destination name.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see DestinationResolver
+ */
+public class DestinationResolutionException extends JmsException {
+
+ /**
+ * Create a new DestinationResolutionException.
+ * @param msg the detail message
+ */
+ public DestinationResolutionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new DestinationResolutionException.
+ * @param msg the detail message
+ * @param cause the root cause (if any)
+ */
+ public DestinationResolutionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolver.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolver.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/DestinationResolver.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2002-2007 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.jms.support.destination;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+/**
+ * Strategy interface for resolving JMS destinations.
+ *
+ *
Used by {@link org.springframework.jms.core.JmsTemplate} for resolving
+ * destination names from simple {@link String Strings} to actual
+ * {@link Destination} implementation instances.
+ *
+ *
The default {@link DestinationResolver} implementation used by
+ * {@link org.springframework.jms.core.JmsTemplate} instances is the
+ * {@link DynamicDestinationResolver} class. Consider using the
+ * {@link JndiDestinationResolver} for more advanced scenarios.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see org.springframework.jms.core.JmsTemplate#setDestinationResolver
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.destination.JndiDestinationResolver
+ */
+public interface DestinationResolver {
+
+ /**
+ * Resolve the given destination name, either as located resource
+ * or as dynamic destination.
+ * @param session the current JMS Session
+ * (may be null if the resolver implementation is able to work without it)
+ * @param destinationName the name of the destination
+ * @param pubSubDomain true if the domain is pub-sub, false if P2P
+ * @return the JMS destination (either a topic or a queue)
+ * @throws javax.jms.JMSException if the JMS Session failed to resolve the destination
+ * @throws DestinationResolutionException in case of general destination resolution failure
+ */
+ Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
+ throws JMSException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/DynamicDestinationResolver.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/DynamicDestinationResolver.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/DynamicDestinationResolver.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-2006 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.jms.support.destination;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicSession;
+
+import org.springframework.util.Assert;
+
+/**
+ * Simple {@link DestinationResolver} implementation resolving destination names
+ * as dynamic destinations.
+ *
+ *
This implementation will work on both JMS 1.1 and JMS 1.0.2,
+ * because it uses the {@link javax.jms.QueueSession} or {@link javax.jms.TopicSession}
+ * methods if possible, falling back to JMS 1.1's generic {@link javax.jms.Session}
+ * methods.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see javax.jms.QueueSession#createQueue
+ * @see javax.jms.TopicSession#createTopic
+ * @see javax.jms.Session#createQueue
+ * @see javax.jms.Session#createTopic
+ */
+public class DynamicDestinationResolver implements DestinationResolver {
+
+ /**
+ * Resolve the specified destination name as a dynamic destination.
+ * @param session the current JMS Session
+ * @param destinationName the name of the destination
+ * @param pubSubDomain true if the domain is pub-sub, false if P2P
+ * @return the JMS destination (either a topic or a queue)
+ * @throws javax.jms.JMSException if resolution failed
+ * @see #resolveTopic(javax.jms.Session, String)
+ * @see #resolveQueue(javax.jms.Session, String)
+ */
+ public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
+ throws JMSException {
+
+ Assert.notNull(session, "Session must not be null");
+ Assert.notNull(destinationName, "Destination name must not be null");
+ if (pubSubDomain) {
+ return resolveTopic(session, destinationName);
+ }
+ else {
+ return resolveQueue(session, destinationName);
+ }
+ }
+
+
+ /**
+ * Resolve the given destination name to a {@link Topic}.
+ * @param session the current JMS Session
+ * @param topicName the name of the desired {@link Topic}
+ * @return the JMS {@link Topic}
+ * @throws javax.jms.JMSException if resolution failed
+ * @see Session#createTopic(String)
+ */
+ protected Topic resolveTopic(Session session, String topicName) throws JMSException {
+ if (session instanceof TopicSession) {
+ // Cast to TopicSession: will work on both JMS 1.1 and 1.0.2
+ return ((TopicSession) session).createTopic(topicName);
+ }
+ else {
+ // Fall back to generic JMS Session: will only work on JMS 1.1
+ return session.createTopic(topicName);
+ }
+ }
+
+ /**
+ * Resolve the given destination name to a {@link Queue}.
+ * @param session the current JMS Session
+ * @param queueName the name of the desired {@link Queue}
+ * @return the JMS {@link Queue}
+ * @throws javax.jms.JMSException if resolution failed
+ * @see Session#createQueue(String)
+ */
+ protected Queue resolveQueue(Session session, String queueName) throws JMSException {
+ if (session instanceof QueueSession) {
+ // Cast to QueueSession: will work on both JMS 1.1 and 1.0.2
+ return ((QueueSession) session).createQueue(queueName);
+ }
+ else {
+ // Fall back to generic JMS Session: will only work on JMS 1.1
+ return session.createQueue(queueName);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/JmsDestinationAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/JmsDestinationAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/JmsDestinationAccessor.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2002-2007 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.jms.support.destination;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.springframework.jms.support.JmsAccessor;
+import org.springframework.util.Assert;
+
+/**
+ * Base class for {@link org.springframework.jms.core.JmsTemplate} and other
+ * JMS-accessing gateway helpers, adding destination-related properties to
+ * {@link JmsAccessor JmsAccessor's} common properties.
+ *
+ *
Not intended to be used directly.
+ * See {@link org.springframework.jms.core.JmsTemplate}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2.5
+ * @see org.springframework.jms.support.JmsAccessor
+ * @see org.springframework.jms.core.JmsTemplate
+ */
+public abstract class JmsDestinationAccessor extends JmsAccessor {
+
+ private DestinationResolver destinationResolver = new DynamicDestinationResolver();
+
+ private boolean pubSubDomain = false;
+
+
+ /**
+ * Set the {@link DestinationResolver} that is to be used to resolve
+ * {@link javax.jms.Destination} references for this accessor.
+ *
The default resolver is a DynamicDestinationResolver. Specify a
+ * JndiDestinationResolver for resolving destination names as JNDI locations.
+ * @see org.springframework.jms.support.destination.DynamicDestinationResolver
+ * @see org.springframework.jms.support.destination.JndiDestinationResolver
+ */
+ public void setDestinationResolver(DestinationResolver destinationResolver) {
+ Assert.notNull(destinationResolver, "'destinationResolver' must not be null");
+ this.destinationResolver = destinationResolver;
+ }
+
+ /**
+ * Return the DestinationResolver for this accessor (never null).
+ */
+ public DestinationResolver getDestinationResolver() {
+ return this.destinationResolver;
+ }
+
+ /**
+ * Configure the destination accessor with knowledge of the JMS domain used.
+ * Default is Point-to-Point (Queues).
+ *
For JMS 1.0.2 based accessors, this tells the JMS provider which class hierarchy
+ * to use in the implementation of its operations. For JMS 1.1 based accessors, this
+ * setting does usually not affect operations. However, for both JMS versions, this
+ * setting tells what type of destination to resolve if dynamic destinations are enabled.
+ * @param pubSubDomain "true" for the Publish/Subscribe domain ({@link javax.jms.Topic Topics}),
+ * "false" for the Point-to-Point domain ({@link javax.jms.Queue Queues})
+ * @see #setDestinationResolver
+ */
+ public void setPubSubDomain(boolean pubSubDomain) {
+ this.pubSubDomain = pubSubDomain;
+ }
+
+ /**
+ * Return whether the Publish/Subscribe domain ({@link javax.jms.Topic Topics}) is used.
+ * Otherwise, the Point-to-Point domain ({@link javax.jms.Queue Queues}) is used.
+ */
+ public boolean isPubSubDomain() {
+ return this.pubSubDomain;
+ }
+
+
+ /**
+ * Resolve the given destination name into a JMS {@link Destination},
+ * via this accessor's {@link DestinationResolver}.
+ * @param session the current JMS {@link Session}
+ * @param destinationName the name of the destination
+ * @return the located {@link Destination}
+ * @throws javax.jms.JMSException if resolution failed
+ * @see #setDestinationResolver
+ */
+ protected Destination resolveDestinationName(Session session, String destinationName) throws JMSException {
+ return getDestinationResolver().resolveDestinationName(session, destinationName, isPubSubDomain());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/JndiDestinationResolver.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/JndiDestinationResolver.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/JndiDestinationResolver.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2002-2007 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.jms.support.destination;
+
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.naming.NamingException;
+
+import org.springframework.core.CollectionFactory;
+import org.springframework.jndi.JndiLocatorSupport;
+import org.springframework.util.Assert;
+
+/**
+ * {@link DestinationResolver} implementation which interprets destination names
+ * as JNDI locations (with a configurable fallback strategy).
+ *
+ *
Allows for customizing the JNDI environment if necessary, for example
+ * specifying appropriate JNDI environment properties.
+ *
+ *
Dynamic queues and topics get cached by destination name. As a consequence,
+ * you need to use unique destination names across both queues and topics.
+ * Caching can be turned off through the {@link #setCache "cache"} flag.
+ *
+ *
Note that the fallback to resolution of dynamic destinations
+ * is turned off by default. Switch the
+ * {@link #setFallbackToDynamicDestination "fallbackToDynamicDestination"}
+ * flag on to enable this functionality.
+ *
+ * @author Mark Pollack
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setJndiTemplate
+ * @see #setJndiEnvironment
+ * @see #setCache
+ * @see #setFallbackToDynamicDestination
+ */
+public class JndiDestinationResolver extends JndiLocatorSupport implements CachingDestinationResolver {
+
+ private boolean cache = true;
+
+ private boolean fallbackToDynamicDestination = false;
+
+ private DestinationResolver dynamicDestinationResolver = new DynamicDestinationResolver();
+
+ private final Map destinationCache = CollectionFactory.createConcurrentMapIfPossible(16);
+
+
+ /**
+ * Set whether to cache resolved destinations. Default is "true".
+ *
This flag can be turned off to re-lookup a destination for each operation,
+ * which allows for hot restarting of destinations. This is mainly useful
+ * during development.
+ *
Note that dynamic queues and topics get cached by destination name.
+ * As a consequence, you need to use unique destination names across both
+ * queues and topics.
+ */
+ public void setCache(boolean cache) {
+ this.cache = cache;
+ }
+
+ /**
+ * Set whether this resolver is supposed to create dynamic destinations
+ * if the destination name is not found in JNDI. Default is "false".
+ *
Turn this flag on to enable transparent fallback to dynamic destinations.
+ * @see #setDynamicDestinationResolver
+ */
+ public void setFallbackToDynamicDestination(boolean fallbackToDynamicDestination) {
+ this.fallbackToDynamicDestination = fallbackToDynamicDestination;
+ }
+
+ /**
+ * Set the {@link DestinationResolver} to use when falling back to dynamic
+ * destinations.
+ *
The default is Spring's standard {@link DynamicDestinationResolver}.
+ * @see #setFallbackToDynamicDestination
+ * @see DynamicDestinationResolver
+ */
+ public void setDynamicDestinationResolver(DestinationResolver dynamicDestinationResolver) {
+ this.dynamicDestinationResolver = dynamicDestinationResolver;
+ }
+
+
+ public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
+ throws JMSException {
+
+ Assert.notNull(destinationName, "Destination name must not be null");
+ Destination dest = (Destination) this.destinationCache.get(destinationName);
+ if (dest != null) {
+ validateDestination(dest, destinationName, pubSubDomain);
+ }
+ else {
+ try {
+ dest = (Destination) lookup(destinationName, Destination.class);
+ validateDestination(dest, destinationName, pubSubDomain);
+ }
+ catch (NamingException ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Destination [" + destinationName + "] not found in JNDI", ex);
+ }
+ if (this.fallbackToDynamicDestination) {
+ dest = this.dynamicDestinationResolver.resolveDestinationName(session, destinationName, pubSubDomain);
+ }
+ else {
+ throw new DestinationResolutionException(
+ "Destination [" + destinationName + "] not found in JNDI", ex);
+ }
+ }
+ if (this.cache) {
+ this.destinationCache.put(destinationName, dest);
+ }
+ }
+ return dest;
+ }
+
+ /**
+ * Validate the given Destination object, checking whether it matches
+ * the expected type.
+ * @param destination the Destination object to validate
+ * @param destinationName the name of the destination
+ * @param pubSubDomain true if a Topic is expected,
+ * false in case of a Queue
+ */
+ protected void validateDestination(Destination destination, String destinationName, boolean pubSubDomain) {
+ Class targetClass = Queue.class;
+ if (pubSubDomain) {
+ targetClass = Topic.class;
+ }
+ if (!targetClass.isInstance(destination)) {
+ throw new DestinationResolutionException(
+ "Destination [" + destinationName + "] is not of expected type [" + targetClass.getName() + "]");
+ }
+ }
+
+
+ public void removeFromCache(String destinationName) {
+ this.destinationCache.remove(destinationName);
+ }
+
+ public void clearCache() {
+ this.destinationCache.clear();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jms/support/destination/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jms/support/destination/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jms/support/destination/package.html 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,7 @@
+
+
+
+Support classes for Spring's JMS framework.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/JmxException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/JmxException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/JmxException.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2006 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.jmx;
+
+import org.springframework.core.NestedRuntimeException;
+
+/**
+ * General base exception to be thrown on JMX errors.
+ * Unchecked since JMX failures are usually fatal.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public class JmxException extends NestedRuntimeException {
+
+ /**
+ * Constructor for JmxException.
+ * @param msg the detail message
+ */
+ public JmxException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for JmxException.
+ * @param msg the detail message
+ * @param cause the root cause (usually a raw JMX API exception)
+ */
+ public JmxException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/MBeanServerNotFoundException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/MBeanServerNotFoundException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/MBeanServerNotFoundException.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2006 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.jmx;
+
+/**
+ * Exception thrown when we cannot locate an instance of an MBeanServer,
+ * or when more than one instance is found.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jmx.support.JmxUtils#locateMBeanServer
+ */
+public class MBeanServerNotFoundException extends JmxException {
+
+ /**
+ * Create a new MBeanServerNotFoundException with the
+ * supplied error message.
+ * @param msg the error message
+ */
+ public MBeanServerNotFoundException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new MBeanServerNotFoundException with the
+ * specified error message and root cause.
+ * @param msg the error message
+ * @param cause the root cause
+ */
+ public MBeanServerNotFoundException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/package.html 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+This package contains Spring's JMX support, which includes registration of
+Spring-managed beans as JMX MBeans as well as access to remote JMX MBeans.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/access/ConnectorDelegate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/ConnectorDelegate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/ConnectorDelegate.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.jmx.MBeanServerNotFoundException;
+import org.springframework.jmx.support.JmxUtils;
+
+/**
+ * Internal helper class for managing a JMX connector.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.2
+ */
+class ConnectorDelegate {
+
+ private final static Log logger = LogFactory.getLog(ConnectorDelegate.class);
+
+ private JMXConnector connector;
+
+
+ /**
+ * Connects to the remote MBeanServer using the configured JMXServiceURL:
+ * to the specified JMX service, or to a local MBeanServer if no service URL specified.
+ * @param serviceUrl the JMX service URL to connect to (may be null)
+ * @param environment the JMX environment for the connector (may be null)
+ * @param agentId the local JMX MBeanServer's agent id (may be null)
+ */
+ public MBeanServerConnection connect(JMXServiceURL serviceUrl, Map environment, String agentId)
+ throws MBeanServerNotFoundException {
+
+ if (serviceUrl != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Connecting to remote MBeanServer at URL [" + serviceUrl + "]");
+ }
+ try {
+ this.connector = JMXConnectorFactory.connect(serviceUrl, environment);
+ return this.connector.getMBeanServerConnection();
+ }
+ catch (IOException ex) {
+ throw new MBeanServerNotFoundException("Could not connect to remote MBeanServer [" + serviceUrl + "]", ex);
+ }
+ }
+ else {
+ logger.debug("Attempting to locate local MBeanServer");
+ return JmxUtils.locateMBeanServer(agentId);
+ }
+ }
+
+ /**
+ * Closes any JMXConnector that may be managed by this interceptor.
+ */
+ public void close() {
+ if (this.connector != null) {
+ try {
+ this.connector.close();
+ }
+ catch (IOException ex) {
+ logger.debug("Could not close JMX connector", ex);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/InvalidInvocationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/InvalidInvocationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/InvalidInvocationException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import javax.management.JMRuntimeException;
+
+/**
+ * Thrown when trying to invoke an operation on a proxy that is not exposed
+ * by the proxied MBean resource's management interface.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanClientInterceptor
+ */
+public class InvalidInvocationException extends JMRuntimeException {
+
+ /**
+ * Create a new InvalidInvocationException with the supplied
+ * error message.
+ * @param msg the detail message
+ */
+ public InvalidInvocationException(String msg) {
+ super(msg);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/InvocationFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/InvocationFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/InvocationFailureException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Thrown when an invocation on an MBean resource failed with an exception (either
+ * a reflection exception or an exception thrown by the target method itself).
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanClientInterceptor
+ */
+public class InvocationFailureException extends JmxException {
+
+ /**
+ * Create a new InvocationFailureException with the supplied
+ * error message.
+ * @param msg the detail message
+ */
+ public InvocationFailureException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new InvocationFailureException with the
+ * specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public InvocationFailureException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/MBeanClientInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/MBeanClientInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/MBeanClientInterceptor.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,600 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.Attribute;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.JMException;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
+import javax.management.RuntimeOperationsException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import javax.management.remote.JMXServiceURL;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.JdkVersion;
+import org.springframework.jmx.support.JmxUtils;
+import org.springframework.jmx.support.ObjectNameManager;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * {@link org.aopalliance.intercept.MethodInterceptor} that routes calls to an
+ * MBean running on the supplied MBeanServerConnection.
+ * Works for both local and remote MBeanServerConnections.
+ *
+ *
By default, the MBeanClientInterceptor will connect to the
+ * MBeanServer and cache MBean metadata at startup. This can
+ * be undesirable when running against a remote MBeanServer
+ * that may not be running when the application starts. Through setting the
+ * {@link #setConnectOnStartup(boolean) connectOnStartup} property to "false",
+ * you can defer this process until the first invocation against the proxy.
+ *
+ *
Requires JMX 1.2's MBeanServerConnection feature.
+ * As a consequence, this class will not work on JMX 1.0.
+ *
+ *
This functionality is usually used through {@link MBeanProxyFactoryBean}.
+ * See the javadoc of that class for more information.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanProxyFactoryBean
+ * @see #setConnectOnStartup
+ */
+public class MBeanClientInterceptor
+ implements MethodInterceptor, BeanClassLoaderAware, InitializingBean, DisposableBean {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private MBeanServerConnection server;
+
+ private JMXServiceURL serviceUrl;
+
+ private Map environment;
+
+ private String agentId;
+
+ private boolean connectOnStartup = true;
+
+ private boolean refreshOnConnectFailure = false;
+
+ private ObjectName objectName;
+
+ private boolean useStrictCasing = true;
+
+ private Class managementInterface;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private final ConnectorDelegate connector = new ConnectorDelegate();
+
+ private MBeanServerConnection serverToUse;
+
+ private MBeanServerInvocationHandler invocationHandler;
+
+ private Map allowedAttributes;
+
+ private Map allowedOperations;
+
+ private final Map signatureCache = new HashMap();
+
+ private final Object preparationMonitor = new Object();
+
+
+ /**
+ * Set the MBeanServerConnection used to connect to the
+ * MBean which all invocations are routed to.
+ */
+ public void setServer(MBeanServerConnection server) {
+ this.server = server;
+ }
+
+ /**
+ * Set the service URL of the remote MBeanServer.
+ */
+ public void setServiceUrl(String url) throws MalformedURLException {
+ this.serviceUrl = new JMXServiceURL(url);
+ }
+
+ /**
+ * Specify the environment for the JMX connector.
+ * @see javax.management.remote.JMXConnectorFactory#connect(javax.management.remote.JMXServiceURL, java.util.Map)
+ */
+ public void setEnvironment(Map environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Allow Map access to the environment to be set for the connector,
+ * with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via
+ * "environment[myKey]". This is particularly useful for
+ * adding or overriding entries in child bean definitions.
+ */
+ public Map getEnvironment() {
+ return this.environment;
+ }
+
+ /**
+ * Set the agent id of the MBeanServer to locate.
+ *
Default is none. If specified, this will result in an
+ * attempt being made to locate the attendant MBeanServer, unless
+ * the {@link #setServiceUrl "serviceUrl"} property has been set.
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ /**
+ * Set whether or not the proxy should connect to the MBeanServer
+ * at creation time ("true") or the first time it is invoked ("false").
+ * Default is "true".
+ */
+ public void setConnectOnStartup(boolean connectOnStartup) {
+ this.connectOnStartup = connectOnStartup;
+ }
+
+ /**
+ * Set whether to refresh the MBeanServer connection on connect failure.
+ * Default is "false".
+ *
Can be turned on to allow for hot restart of the JMX server,
+ * automatically reconnecting and retrying in case of an IOException.
+ */
+ public void setRefreshOnConnectFailure(boolean refreshOnConnectFailure) {
+ this.refreshOnConnectFailure = refreshOnConnectFailure;
+ }
+
+ /**
+ * Set the ObjectName of the MBean which calls are routed to,
+ * as ObjectName instance or as String.
+ */
+ public void setObjectName(Object objectName) throws MalformedObjectNameException {
+ this.objectName = ObjectNameManager.getInstance(objectName);
+ }
+
+ /**
+ * Set whether to use strict casing for attributes. Enabled by default.
+ *
When using strict casing, a JavaBean property with a getter such as
+ * getFoo() translates to an attribute called Foo.
+ * With strict casing disabled, getFoo() would translate to just
+ * foo.
+ */
+ public void setUseStrictCasing(boolean useStrictCasing) {
+ this.useStrictCasing = useStrictCasing;
+ }
+
+ /**
+ * Set the management interface of the target MBean, exposing bean property
+ * setters and getters for MBean attributes and conventional Java methods
+ * for MBean operations.
+ */
+ public void setManagementInterface(Class managementInterface) {
+ this.managementInterface = managementInterface;
+ }
+
+ /**
+ * Return the management interface of the target MBean,
+ * or null if none specified.
+ */
+ protected final Class getManagementInterface() {
+ return this.managementInterface;
+ }
+
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ this.beanClassLoader = beanClassLoader;
+ }
+
+
+ /**
+ * Prepares the MBeanServerConnection if the "connectOnStartup"
+ * is turned on (which it is by default).
+ */
+ public void afterPropertiesSet() {
+ if (this.server != null && this.refreshOnConnectFailure) {
+ throw new IllegalArgumentException("'refreshOnConnectFailure' does not work when setting " +
+ "a 'server' reference. Prefer 'serviceUrl' etc instead.");
+ }
+ if (this.connectOnStartup) {
+ prepare();
+ }
+ }
+
+ /**
+ * Ensures that an MBeanServerConnection is configured and attempts
+ * to detect a local connection if one is not supplied.
+ */
+ public void prepare() {
+ synchronized (this.preparationMonitor) {
+ if (this.server != null) {
+ this.serverToUse = this.server;
+ }
+ else {
+ this.serverToUse = null;
+ this.serverToUse = this.connector.connect(this.serviceUrl, this.environment, this.agentId);
+ }
+ this.invocationHandler = null;
+ if (this.useStrictCasing) {
+ // Use the JDK's own MBeanServerInvocationHandler,
+ // in particular for native MXBean support on Java 6.
+ if (JdkVersion.isAtLeastJava16()) {
+ this.invocationHandler =
+ new MBeanServerInvocationHandler(this.serverToUse, this.objectName,
+ (this.managementInterface != null && JMX.isMXBeanInterface(this.managementInterface)));
+ }
+ else {
+ this.invocationHandler = new MBeanServerInvocationHandler(this.serverToUse, this.objectName);
+ }
+ }
+ else {
+ // Non-strict casing can only be achieved through custom
+ // invocation handling. Only partial MXBean support available!
+ retrieveMBeanInfo();
+ }
+ }
+ }
+ /**
+ * Loads the management interface info for the configured MBean into the caches.
+ * This information is used by the proxy when determining whether an invocation matches
+ * a valid operation or attribute on the management interface of the managed resource.
+ */
+ private void retrieveMBeanInfo() throws MBeanInfoRetrievalException {
+ try {
+ MBeanInfo info = this.serverToUse.getMBeanInfo(this.objectName);
+
+ MBeanAttributeInfo[] attributeInfo = info.getAttributes();
+ this.allowedAttributes = new HashMap(attributeInfo.length);
+ for (int x = 0; x < attributeInfo.length; x++) {
+ this.allowedAttributes.put(attributeInfo[x].getName(), attributeInfo[x]);
+ }
+
+ MBeanOperationInfo[] operationInfo = info.getOperations();
+ this.allowedOperations = new HashMap(operationInfo.length);
+ for (int x = 0; x < operationInfo.length; x++) {
+ MBeanOperationInfo opInfo = operationInfo[x];
+ Class[] paramTypes = JmxUtils.parameterInfoToTypes(opInfo.getSignature(), this.beanClassLoader);
+ this.allowedOperations.put(new MethodCacheKey(opInfo.getName(), paramTypes), opInfo);
+ }
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MBeanInfoRetrievalException("Unable to locate class specified in method signature", ex);
+ }
+ catch (IntrospectionException ex) {
+ throw new MBeanInfoRetrievalException("Unable to obtain MBean info for bean [" + this.objectName + "]", ex);
+ }
+ catch (InstanceNotFoundException ex) {
+ // if we are this far this shouldn't happen, but...
+ throw new MBeanInfoRetrievalException("Unable to obtain MBean info for bean [" + this.objectName +
+ "]: it is likely that this bean was unregistered during the proxy creation process",
+ ex);
+ }
+ catch (ReflectionException ex) {
+ throw new MBeanInfoRetrievalException("Unable to read MBean info for bean [ " + this.objectName + "]", ex);
+ }
+ catch (IOException ex) {
+ throw new MBeanInfoRetrievalException("An IOException occurred when communicating with the " +
+ "MBeanServer. It is likely that you are communicating with a remote MBeanServer. " +
+ "Check the inner exception for exact details.", ex);
+ }
+ }
+
+ /**
+ * Return whether this client interceptor has already been prepared,
+ * i.e. has already looked up the server and cached all metadata.
+ */
+ protected boolean isPrepared() {
+ synchronized (this.preparationMonitor) {
+ return (this.serverToUse != null);
+ }
+ }
+
+
+ /**
+ * Route the invocation to the configured managed resource..
+ * @param invocation the MethodInvocation to re-route
+ * @return the value returned as a result of the re-routed invocation
+ * @throws Throwable an invocation error propagated to the user
+ * @see #doInvoke
+ * @see #handleConnectFailure
+ */
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ // Lazily connect to MBeanServer if necessary.
+ synchronized (this.preparationMonitor) {
+ if (!isPrepared()) {
+ prepare();
+ }
+ }
+ try {
+ return doInvoke(invocation);
+ }
+ catch (MBeanConnectFailureException ex) {
+ return handleConnectFailure(invocation, ex);
+ }
+ catch (IOException ex) {
+ return handleConnectFailure(invocation, ex);
+ }
+ }
+
+ /**
+ * Refresh the connection and retry the MBean invocation if possible.
+ *
If not configured to refresh on connect failure, this method
+ * simply rethrows the original exception.
+ * @param invocation the invocation that failed
+ * @param ex the exception raised on remote invocation
+ * @return the result value of the new invocation, if succeeded
+ * @throws Throwable an exception raised by the new invocation,
+ * if it failed as well
+ * @see #setRefreshOnConnectFailure
+ * @see #doInvoke
+ */
+ protected Object handleConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable {
+ if (this.refreshOnConnectFailure) {
+ String msg = "Could not connect to JMX server - retrying";
+ if (logger.isDebugEnabled()) {
+ logger.warn(msg, ex);
+ }
+ else if (logger.isWarnEnabled()) {
+ logger.warn(msg);
+ }
+ prepare();
+ return doInvoke(invocation);
+ }
+ else {
+ throw ex;
+ }
+ }
+
+ /**
+ * Route the invocation to the configured managed resource. Correctly routes JavaBean property
+ * access to MBeanServerConnection.get/setAttribute and method invocation to
+ * MBeanServerConnection.invoke.
+ * @param invocation the MethodInvocation to re-route
+ * @return the value returned as a result of the re-routed invocation
+ * @throws Throwable an invocation error propagated to the user
+ */
+ protected Object doInvoke(MethodInvocation invocation) throws Throwable {
+ Method method = invocation.getMethod();
+ try {
+ Object result = null;
+ if (this.invocationHandler != null) {
+ result = this.invocationHandler.invoke(invocation.getThis(), method, invocation.getArguments());
+ }
+ else {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ result = invokeAttribute(pd, invocation);
+ }
+ else {
+ result = invokeOperation(method, invocation.getArguments());
+ }
+ }
+ return convertResultValueIfNecessary(result, method.getReturnType());
+ }
+ catch (MBeanException ex) {
+ throw ex.getTargetException();
+ }
+ catch (RuntimeMBeanException ex) {
+ throw ex.getTargetException();
+ }
+ catch (RuntimeErrorException ex) {
+ throw ex.getTargetError();
+ }
+ catch (RuntimeOperationsException ex) {
+ // This one is only thrown by the JMX 1.2 RI, not by the JDK 1.5 JMX code.
+ RuntimeException rex = ex.getTargetException();
+ if (rex instanceof RuntimeMBeanException) {
+ throw ((RuntimeMBeanException) rex).getTargetException();
+ }
+ else if (rex instanceof RuntimeErrorException) {
+ throw ((RuntimeErrorException) rex).getTargetError();
+ }
+ else {
+ throw rex;
+ }
+ }
+ catch (OperationsException ex) {
+ if (ReflectionUtils.declaresException(method, ex.getClass())) {
+ throw ex;
+ }
+ else {
+ throw new InvalidInvocationException(ex.getMessage());
+ }
+ }
+ catch (JMException ex) {
+ if (ReflectionUtils.declaresException(method, ex.getClass())) {
+ throw ex;
+ }
+ else {
+ throw new InvocationFailureException("JMX access failed", ex);
+ }
+ }
+ catch (IOException ex) {
+ if (ReflectionUtils.declaresException(method, ex.getClass())) {
+ throw ex;
+ }
+ else {
+ throw new MBeanConnectFailureException("I/O failure during JMX access", ex);
+ }
+ }
+ }
+
+ private Object invokeAttribute(PropertyDescriptor pd, MethodInvocation invocation)
+ throws JMException, IOException {
+
+ String attributeName = JmxUtils.getAttributeName(pd, this.useStrictCasing);
+ MBeanAttributeInfo inf = (MBeanAttributeInfo) this.allowedAttributes.get(attributeName);
+ // If no attribute is returned, we know that it is not defined in the
+ // management interface.
+ if (inf == null) {
+ throw new InvalidInvocationException(
+ "Attribute '" + pd.getName() + "' is not exposed on the management interface");
+ }
+ if (invocation.getMethod().equals(pd.getReadMethod())) {
+ if (inf.isReadable()) {
+ return this.serverToUse.getAttribute(this.objectName, attributeName);
+ }
+ else {
+ throw new InvalidInvocationException("Attribute '" + attributeName + "' is not readable");
+ }
+ }
+ else if (invocation.getMethod().equals(pd.getWriteMethod())) {
+ if (inf.isWritable()) {
+ this.serverToUse.setAttribute(this.objectName, new Attribute(attributeName, invocation.getArguments()[0]));
+ return null;
+ }
+ else {
+ throw new InvalidInvocationException("Attribute '" + attributeName + "' is not writable");
+ }
+ }
+ else {
+ throw new IllegalStateException(
+ "Method [" + invocation.getMethod() + "] is neither a bean property getter nor a setter");
+ }
+ }
+
+ /**
+ * Routes a method invocation (not a property get/set) to the corresponding
+ * operation on the managed resource.
+ * @param method the method corresponding to operation on the managed resource.
+ * @param args the invocation arguments
+ * @return the value returned by the method invocation.
+ */
+ private Object invokeOperation(Method method, Object[] args) throws JMException, IOException {
+ MethodCacheKey key = new MethodCacheKey(method.getName(), method.getParameterTypes());
+ MBeanOperationInfo info = (MBeanOperationInfo) this.allowedOperations.get(key);
+ if (info == null) {
+ throw new InvalidInvocationException("Operation '" + method.getName() +
+ "' is not exposed on the management interface");
+ }
+ String[] signature = null;
+ synchronized (this.signatureCache) {
+ signature = (String[]) this.signatureCache.get(method);
+ if (signature == null) {
+ signature = JmxUtils.getMethodSignature(method);
+ this.signatureCache.put(method, signature);
+ }
+ }
+ return this.serverToUse.invoke(this.objectName, method.getName(), args, signature);
+ }
+
+ /**
+ * Convert the given result object (from attribute access or operation invocation)
+ * to the specified target class for returning from the proxy method.
+ * @param result the result object as returned by the MBeanServer
+ * @param targetClass the result type of the proxy method that's been invoked
+ * @return the converted result object, or the passed-in object if no conversion
+ * is necessary
+ */
+ protected Object convertResultValueIfNecessary(Object result, Class targetClass) {
+ try {
+ if (result == null) {
+ return null;
+ }
+ if (ClassUtils.isAssignableValue(targetClass, result)) {
+ return result;
+ }
+ if (result instanceof CompositeData) {
+ Method fromMethod = targetClass.getMethod("from", new Class[] {CompositeData.class});
+ return ReflectionUtils.invokeMethod(fromMethod, null, new Object[] {result});
+ }
+ else if (result instanceof TabularData) {
+ Method fromMethod = targetClass.getMethod("from", new Class[] {TabularData.class});
+ return ReflectionUtils.invokeMethod(fromMethod, null, new Object[] {result});
+ }
+ else {
+ throw new InvocationFailureException(
+ "Incompatible result value [" + result + "] for target type [" + targetClass.getName() + "]");
+ }
+ }
+ catch (NoSuchMethodException ex) {
+ throw new InvocationFailureException(
+ "Could not obtain 'find(CompositeData)' / 'find(TabularData)' method on target type [" +
+ targetClass.getName() + "] for conversion of MXBean data structure [" + result + "]");
+ }
+ }
+
+ public void destroy() {
+ this.connector.close();
+ }
+
+
+ /**
+ * Simple wrapper class around a method name and its signature.
+ * Used as the key when caching methods.
+ */
+ private static class MethodCacheKey {
+
+ private final String name;
+
+ private final Class[] parameterTypes;
+
+ /**
+ * Create a new instance of MethodCacheKey with the supplied
+ * method name and parameter list.
+ * @param name the name of the method
+ * @param parameterTypes the arguments in the method signature
+ */
+ public MethodCacheKey(String name, Class[] parameterTypes) {
+ this.name = name;
+ this.parameterTypes = (parameterTypes != null ? parameterTypes : new Class[0]);
+ }
+
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ MethodCacheKey otherKey = (MethodCacheKey) other;
+ return (this.name.equals(otherKey.name) && Arrays.equals(this.parameterTypes, otherKey.parameterTypes));
+ }
+
+ public int hashCode() {
+ return this.name.hashCode();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/MBeanConnectFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/MBeanConnectFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/MBeanConnectFailureException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Thrown when an invocation failed because of an I/O problem on the
+ * MBeanServerConnection.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.6
+ * @see MBeanClientInterceptor
+ */
+public class MBeanConnectFailureException extends JmxException {
+
+ /**
+ * Create a new MBeanConnectFailureException
+ * with the specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public MBeanConnectFailureException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/MBeanInfoRetrievalException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/MBeanInfoRetrievalException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/MBeanInfoRetrievalException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002-2006 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.jmx.access;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Thrown if an exception is encountered when trying to retrieve
+ * MBean metadata.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanClientInterceptor
+ * @see MBeanProxyFactoryBean
+ */
+public class MBeanInfoRetrievalException extends JmxException {
+
+ /**
+ * Create a new MBeanInfoRetrievalException with the
+ * specified error message.
+ * @param msg the detail message
+ */
+ public MBeanInfoRetrievalException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new MBeanInfoRetrievalException with the
+ * specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public MBeanInfoRetrievalException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/MBeanProxyFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/MBeanProxyFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/MBeanProxyFactoryBean.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2002-2007 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.jmx.access;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.MBeanServerNotFoundException;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Creates a proxy to a managed resource running either locally or remotely.
+ * The "proxyInterface" property defines the interface that the generated
+ * proxy is supposed to implement. This interface should define methods and
+ * properties that correspond to operations and attributes in the management
+ * interface of the resource you wish to proxy.
+ *
+ *
There is no need for the managed resource to implement the proxy interface,
+ * although you may find it convenient to do. It is not required that every
+ * operation and attribute in the management interface is matched by a
+ * corresponding property or method in the proxy interface.
+ *
+ *
Attempting to invoke or access any method or property on the proxy
+ * interface that does not correspond to the management interface will lead
+ * to an InvalidInvocationException.
+ *
+ *
Requires JMX 1.2's MBeanServerConnection feature.
+ * As a consequence, this class will not work on JMX 1.0.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanClientInterceptor
+ * @see InvalidInvocationException
+ */
+public class MBeanProxyFactoryBean extends MBeanClientInterceptor
+ implements FactoryBean, BeanClassLoaderAware, InitializingBean {
+
+ private Class proxyInterface;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private Object mbeanProxy;
+
+
+ /**
+ * Set the interface that the generated proxy will implement.
+ *
This will usually be a management interface that matches the target MBean,
+ * exposing bean property setters and getters for MBean attributes and
+ * conventional Java methods for MBean operations.
+ * @see #setObjectName
+ */
+ public void setProxyInterface(Class proxyInterface) {
+ this.proxyInterface = proxyInterface;
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ /**
+ * Checks that the proxyInterface has been specified and then
+ * generates the proxy for the target MBean.
+ */
+ public void afterPropertiesSet() throws MBeanServerNotFoundException, MBeanInfoRetrievalException {
+ super.afterPropertiesSet();
+
+ if (this.proxyInterface == null) {
+ this.proxyInterface = getManagementInterface();
+ if (this.proxyInterface == null) {
+ throw new IllegalArgumentException("Property 'proxyInterface' or 'managementInterface' is required");
+ }
+ }
+ else {
+ if (getManagementInterface() == null) {
+ setManagementInterface(this.proxyInterface);
+ }
+ }
+ this.mbeanProxy = new ProxyFactory(this.proxyInterface, this).getProxy(this.beanClassLoader);
+ }
+
+
+ public Object getObject() {
+ return this.mbeanProxy;
+ }
+
+ public Class getObjectType() {
+ return this.proxyInterface;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/NotificationListenerRegistrar.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/NotificationListenerRegistrar.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/NotificationListenerRegistrar.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2002-2008 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.jmx.access;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.JmxException;
+import org.springframework.jmx.MBeanServerNotFoundException;
+import org.springframework.jmx.support.NotificationListenerHolder;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Registrar object that associates a specific {@link javax.management.NotificationListener}
+ * with one or more MBeans in an {@link javax.management.MBeanServer}
+ * (typically via a {@link javax.management.MBeanServerConnection}).
+ *
+ *
Requires JMX 1.2's MBeanServerConnection feature.
+ * As a consequence, this class will not work on JMX 1.0.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.2
+ * @see #setServer
+ * @see #setMappedObjectNames
+ * @see #setNotificationListener
+ */
+public class NotificationListenerRegistrar extends NotificationListenerHolder
+ implements InitializingBean, DisposableBean {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private MBeanServerConnection server;
+
+ private JMXServiceURL serviceUrl;
+
+ private Map environment;
+
+ private String agentId;
+
+ private final ConnectorDelegate connector = new ConnectorDelegate();
+
+ private ObjectName[] actualObjectNames;
+
+
+ /**
+ * Set the MBeanServerConnection used to connect to the
+ * MBean which all invocations are routed to.
+ */
+ public void setServer(MBeanServerConnection server) {
+ this.server = server;
+ }
+
+ /**
+ * Specify the environment for the JMX connector.
+ * @see javax.management.remote.JMXConnectorFactory#connect(javax.management.remote.JMXServiceURL, java.util.Map)
+ */
+ public void setEnvironment(Map environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Allow Map access to the environment to be set for the connector,
+ * with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via
+ * "environment[myKey]". This is particularly useful for
+ * adding or overriding entries in child bean definitions.
+ */
+ public Map getEnvironment() {
+ return this.environment;
+ }
+
+ /**
+ * Set the service URL of the remote MBeanServer.
+ */
+ public void setServiceUrl(String url) throws MalformedURLException {
+ this.serviceUrl = new JMXServiceURL(url);
+ }
+
+ /**
+ * Set the agent id of the MBeanServer to locate.
+ *
Default is none. If specified, this will result in an
+ * attempt being made to locate the attendant MBeanServer, unless
+ * the {@link #setServiceUrl "serviceUrl"} property has been set.
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+
+ public void afterPropertiesSet() {
+ if (getNotificationListener() == null) {
+ throw new IllegalArgumentException("Property 'notificationListener' is required");
+ }
+ if (CollectionUtils.isEmpty(this.mappedObjectNames)) {
+ throw new IllegalArgumentException("Property 'mappedObjectName' is required");
+ }
+ prepare();
+ }
+
+ /**
+ * Registers the specified NotificationListener.
+ *
Ensures that an MBeanServerConnection is configured and attempts
+ * to detect a local connection if one is not supplied.
+ */
+ public void prepare() {
+ if (this.server == null) {
+ this.server = this.connector.connect(this.serviceUrl, this.environment, this.agentId);
+ }
+ try {
+ this.actualObjectNames = getResolvedObjectNames();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Registering NotificationListener for MBeans " + Arrays.asList(this.actualObjectNames));
+ }
+ for (int i = 0; i < this.actualObjectNames.length; i++) {
+ this.server.addNotificationListener(this.actualObjectNames[i],
+ getNotificationListener(), getNotificationFilter(), getHandback());
+ }
+ }
+ catch (IOException ex) {
+ throw new MBeanServerNotFoundException(
+ "Could not connect to remote MBeanServer at URL [" + this.serviceUrl + "]", ex);
+ }
+ catch (Exception ex) {
+ throw new JmxException("Unable to register NotificationListener", ex);
+ }
+ }
+
+ /**
+ * Unregisters the specified NotificationListener.
+ */
+ public void destroy() {
+ try {
+ if (this.actualObjectNames != null) {
+ for (int i = 0; i < this.actualObjectNames.length; i++) {
+ try {
+ this.server.removeNotificationListener(this.actualObjectNames[i],
+ getNotificationListener(), getNotificationFilter(), getHandback());
+ }
+ catch (Exception ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Unable to unregister NotificationListener", ex);
+ }
+ }
+ }
+ }
+ }
+ finally {
+ this.connector.close();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/access/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/access/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/access/package.html 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,7 @@
+
+
+
+Provides support for accessing remote MBean resources. Requires JMX 1.2 or above.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2006 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.jmx.export;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Exception thrown in case of failure when exporting an MBean.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see MBeanExportOperations
+ */
+public class MBeanExportException extends JmxException {
+
+ /**
+ * Create a new MBeanExportException with the
+ * specified error message.
+ * @param msg the detail message
+ */
+ public MBeanExportException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new MBeanExportException with the
+ * specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public MBeanExportException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExportOperations.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2002-2005 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.jmx.export;
+
+import javax.management.ObjectName;
+
+/**
+ * Interface that defines the set of MBean export operations that are intended to be
+ * accessed by application developers during application runtime.
+ *
+ *
This interface should be used to export application resources to JMX using Spring's
+ * management interface generation capabilties and, optionally, it's {@link ObjectName}
+ * generation capabilities.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see MBeanExporter
+ */
+public interface MBeanExportOperations {
+
+ /**
+ * Register the supplied resource with JMX. If the resource is not a valid MBean already,
+ * Spring will generate a management interface for it. The exact interface generated will
+ * depend on the implementation and its configuration. This call also generates an
+ * {@link ObjectName} for the managed resource and returns this to the caller.
+ * @param managedResource the resource to expose via JMX
+ * @return the {@link ObjectName} under which the resource was exposed
+ * @throws MBeanExportException if Spring is unable to generate an {@link ObjectName}
+ * or register the MBean
+ */
+ ObjectName registerManagedResource(Object managedResource) throws MBeanExportException;
+
+ /**
+ * Register the supplied resource with JMX. If the resource is not a valid MBean already,
+ * Spring will generate a management interface for it. The exact interface generated will
+ * depend on the implementation and its configuration.
+ * @param managedResource the resource to expose via JMX
+ * @param objectName the {@link ObjectName} under which to expose the resource
+ * @throws MBeanExportException if Spring is unable to register the MBean
+ */
+ void registerManagedResource(Object managedResource, ObjectName objectName) throws MBeanExportException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporter.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,1091 @@
+/*
+ * Copyright 2002-2008 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.jmx.export;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.DynamicMBean;
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import javax.management.modelmbean.ModelMBean;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.RequiredModelMBean;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.aop.target.LazyInitTargetSource;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.core.Constants;
+import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler;
+import org.springframework.jmx.export.assembler.MBeanInfoAssembler;
+import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler;
+import org.springframework.jmx.export.naming.KeyNamingStrategy;
+import org.springframework.jmx.export.naming.ObjectNamingStrategy;
+import org.springframework.jmx.export.naming.SelfNaming;
+import org.springframework.jmx.export.notification.ModelMBeanNotificationPublisher;
+import org.springframework.jmx.export.notification.NotificationPublisherAware;
+import org.springframework.jmx.support.JmxUtils;
+import org.springframework.jmx.support.MBeanRegistrationSupport;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * JMX exporter that allows for exposing any Spring-managed bean
+ * to a JMX MBeanServer, without the need to define any
+ * JMX-specific information in the bean classes.
+ *
+ *
If the bean implements one of the JMX management interfaces,
+ * then MBeanExporter can simply register the MBean with the server
+ * automatically, through its autodetection process.
+ *
+ *
If the bean does not implement one of the JMX management interfaces,
+ * then MBeanExporter will create the management information using the
+ * supplied {@link MBeanInfoAssembler} implementation.
+ *
+ *
A list of {@link MBeanExporterListener MBeanExporterListeners}
+ * can be registered via the
+ * {@link #setListeners(MBeanExporterListener[]) listeners} property,
+ * allowing application code to be notified of MBean registration and
+ * unregistration events.
+ *
+ *
This exporter is compatible with JMX 1.0 or higher for its basic
+ * functionality. However, for adapting AOP proxies where the target
+ * bean is a native MBean, JMX 1.2 is required. As of Spring 2.5,
+ * this class also autodetects and exports JDK 1.6 MXBeans.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @author Rick Evans
+ * @author Mark Fisher
+ * @since 1.2
+ * @see #setBeans
+ * @see #setAutodetect
+ * @see #setAssembler
+ * @see #setListeners
+ * @see org.springframework.jmx.export.assembler.MBeanInfoAssembler
+ * @see MBeanExporterListener
+ */
+public class MBeanExporter extends MBeanRegistrationSupport
+ implements MBeanExportOperations, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
+
+ /**
+ * Autodetection mode indicating that no autodetection should be used.
+ */
+ public static final int AUTODETECT_NONE = 0;
+
+ /**
+ * Autodetection mode indicating that only valid MBeans should be autodetected.
+ */
+ public static final int AUTODETECT_MBEAN = 1;
+
+ /**
+ * Autodetection mode indicating that only the {@link MBeanInfoAssembler} should be able
+ * to autodetect beans.
+ */
+ public static final int AUTODETECT_ASSEMBLER = 2;
+
+ /**
+ * Autodetection mode indicating that all autodetection mechanisms should be used.
+ */
+ public static final int AUTODETECT_ALL = AUTODETECT_MBEAN | AUTODETECT_ASSEMBLER;
+
+
+ /**
+ * Wildcard used to map a {@link javax.management.NotificationListener}
+ * to all MBeans registered by the MBeanExporter.
+ */
+ private static final String WILDCARD = "*";
+
+ /** Constant for the JMX mr_type "ObjectReference" */
+ private static final String MR_TYPE_OBJECT_REFERENCE = "ObjectReference";
+
+ /** Prefix for the autodetect constants defined in this class */
+ private static final String CONSTANT_PREFIX_AUTODETECT = "AUTODETECT_";
+
+
+ /** Constants instance for this class */
+ private static final Constants constants = new Constants(MBeanExporter.class);
+
+ /** The beans to be exposed as JMX managed resources, with JMX names as keys */
+ private Map beans;
+
+ /** The autodetect mode to use for this MBeanExporter */
+ private Integer autodetectMode;
+
+ /** Whether to eagerly init candidate beans when autodetecting MBeans */
+ private boolean allowEagerInit = false;
+
+ /** Indicates whether Spring should modify generated ObjectNames */
+ private boolean ensureUniqueRuntimeObjectNames = true;
+
+ /** Indicates whether Spring should expose the managed resource ClassLoader in the MBean */
+ private boolean exposeManagedResourceClassLoader = true;
+
+ /** A set of bean names that should be excluded from autodetection */
+ private Set excludedBeans;
+
+ /** The MBeanExporterListeners registered with this exporter. */
+ private MBeanExporterListener[] listeners;
+
+ /** The NotificationListeners to register for the MBeans registered by this exporter */
+ private NotificationListenerBean[] notificationListeners;
+
+ /** Map of actually registered NotificationListeners */
+ private final Map registeredNotificationListeners = new LinkedHashMap();
+
+ /** Stores the MBeanInfoAssembler to use for this exporter */
+ private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();
+
+ /** The strategy to use for creating ObjectNames for an object */
+ private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();
+
+ /** Stores the ClassLoader to use for generating lazy-init proxies */
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ /** Stores the BeanFactory for use in autodetection process */
+ private ListableBeanFactory beanFactory;
+
+
+ /**
+ * Supply a Map of beans to be registered with the JMX
+ * MBeanServer.
+ *
The String keys are the basis for the creation of JMX object names.
+ * By default, a JMX ObjectName will be created straight
+ * from the given key. This can be customized through specifying a
+ * custom NamingStrategy.
+ *
Both bean instances and bean names are allowed as values.
+ * Bean instances are typically linked in through bean references.
+ * Bean names will be resolved as beans in the current factory, respecting
+ * lazy-init markers (that is, not triggering initialization of such beans).
+ * @param beans Map with JMX names as keys and bean instances or bean names
+ * as values
+ * @see #setNamingStrategy
+ * @see org.springframework.jmx.export.naming.KeyNamingStrategy
+ * @see javax.management.ObjectName#ObjectName(String)
+ */
+ public void setBeans(Map beans) {
+ this.beans = beans;
+ }
+
+ /**
+ * Set whether to autodetect MBeans in the bean factory that this exporter
+ * runs in. Will also ask an AutodetectCapableMBeanInfoAssembler
+ * if available.
+ *
This feature is turned off by default. Explicitly specify
+ * true here to enable autodetection.
+ * @see #setAssembler
+ * @see AutodetectCapableMBeanInfoAssembler
+ * @see #isMBean
+ */
+ public void setAutodetect(boolean autodetect) {
+ this.autodetectMode = new Integer(autodetect ? AUTODETECT_ALL : AUTODETECT_NONE);
+ }
+
+ /**
+ * Set the autodetection mode to use.
+ * @exception IllegalArgumentException if the supplied value is not
+ * one of the AUTODETECT_ constants
+ * @see #setAutodetectModeName(String)
+ * @see #AUTODETECT_ALL
+ * @see #AUTODETECT_ASSEMBLER
+ * @see #AUTODETECT_MBEAN
+ * @see #AUTODETECT_NONE
+ */
+ public void setAutodetectMode(int autodetectMode) {
+ if (!constants.getValues(CONSTANT_PREFIX_AUTODETECT).contains(new Integer(autodetectMode))) {
+ throw new IllegalArgumentException("Only values of autodetect constants allowed");
+ }
+ this.autodetectMode = new Integer(autodetectMode);
+ }
+
+ /**
+ * Set the autodetection mode to use by name.
+ * @exception IllegalArgumentException if the supplied value is not resolvable
+ * to one of the AUTODETECT_ constants or is null
+ * @see #setAutodetectMode(int)
+ * @see #AUTODETECT_ALL
+ * @see #AUTODETECT_ASSEMBLER
+ * @see #AUTODETECT_MBEAN
+ * @see #AUTODETECT_NONE
+ */
+ public void setAutodetectModeName(String constantName) {
+ if (constantName == null || !constantName.startsWith(CONSTANT_PREFIX_AUTODETECT)) {
+ throw new IllegalArgumentException("Only autodetect constants allowed");
+ }
+ this.autodetectMode = (Integer) constants.asNumber(constantName);
+ }
+
+ /**
+ * Specify whether to allow eager initialization of candidate beans
+ * when autodetecting MBeans in the Spring application context.
+ *
Default is "false", respecting lazy-init flags on bean definitions.
+ * Switch this to "true" in order to search lazy-init beans as well,
+ * including FactoryBean-produced objects that haven't been initialized yet.
+ */
+ public void setAllowEagerInit(boolean allowEagerInit) {
+ this.allowEagerInit = allowEagerInit;
+ }
+
+ /**
+ * Set the implementation of the MBeanInfoAssembler interface to use
+ * for this exporter. Default is a SimpleReflectiveMBeanInfoAssembler.
+ *
The passed-in assembler can optionally implement the
+ * AutodetectCapableMBeanInfoAssembler interface, which enables it
+ * to participate in the exporter's MBean autodetection process.
+ * @see org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler
+ * @see org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
+ * @see #setAutodetect
+ */
+ public void setAssembler(MBeanInfoAssembler assembler) {
+ this.assembler = assembler;
+ }
+
+ /**
+ * Set the implementation of the ObjectNamingStrategy interface
+ * to use for this exporter. Default is a KeyNamingStrategy.
+ * @see org.springframework.jmx.export.naming.KeyNamingStrategy
+ * @see org.springframework.jmx.export.naming.MetadataNamingStrategy
+ */
+ public void setNamingStrategy(ObjectNamingStrategy namingStrategy) {
+ this.namingStrategy = namingStrategy;
+ }
+
+ /**
+ * Set the MBeanExporterListeners that should be notified
+ * of MBean registration and unregistration events.
+ * @see MBeanExporterListener
+ */
+ public void setListeners(MBeanExporterListener[] listeners) {
+ this.listeners = listeners;
+ }
+
+ /**
+ * Set the list of names for beans that should be excluded from autodetection.
+ */
+ public void setExcludedBeans(String[] excludedBeans) {
+ this.excludedBeans = (excludedBeans != null ? new HashSet(Arrays.asList(excludedBeans)) : null);
+ }
+
+ /**
+ * Indicates whether Spring should ensure that {@link ObjectName ObjectNames}
+ * generated by the configured {@link ObjectNamingStrategy} for
+ * runtime-registered MBeans should be modified to ensure uniqueness
+ * for every instance of a managed Class.
+ *
The default value is true.
+ * @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
+ */
+ public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
+ this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
+ }
+
+ /**
+ * Indicates whether or not the managed resource should be exposed on the
+ * {@link Thread#getContextClassLoader() thread context ClassLoader} before
+ * allowing any invocations on the MBean to occur.
+ *
The default value is true, exposing a {@link SpringModelMBean}
+ * which performs thread context ClassLoader management. Switch this flag off to
+ * expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
+ */
+ public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
+ this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
+ }
+
+ /**
+ * Set the {@link NotificationListenerBean NotificationListenerBeans}
+ * containing the
+ * {@link javax.management.NotificationListener NotificationListeners}
+ * that will be registered with the {@link MBeanServer}.
+ * @see #setNotificationListenerMappings(java.util.Map)
+ * @see NotificationListenerBean
+ */
+ public void setNotificationListeners(NotificationListenerBean[] notificationListeners) {
+ this.notificationListeners = notificationListeners;
+ }
+
+ /**
+ * Set the {@link NotificationListener NotificationListeners} to register
+ * with the {@link javax.management.MBeanServer}.
+ *
The key of each entry in the Map is a {@link String}
+ * representation of the {@link javax.management.ObjectName} or the bean
+ * name of the MBean the listener should be registered for. Specifying an
+ * asterisk (*) for a key will cause the listener to be
+ * associated with all MBeans registered by this class at startup time.
+ *
The value of each entry is the
+ * {@link javax.management.NotificationListener} to register. For more
+ * advanced options such as registering
+ * {@link javax.management.NotificationFilter NotificationFilters} and
+ * handback objects see {@link #setNotificationListeners(NotificationListenerBean[])}.
+ * @throws IllegalArgumentException if the supplied listeners {@link Map} is null.
+ */
+ public void setNotificationListenerMappings(Map listeners) {
+ Assert.notNull(listeners, "'listeners' must not be null");
+ List notificationListeners = new ArrayList(listeners.size());
+
+ for (Iterator iterator = listeners.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+
+ // Get the listener from the map value.
+ Object value = entry.getValue();
+ if (!(value instanceof NotificationListener)) {
+ throw new IllegalArgumentException(
+ "Map entry value [" + value + "] is not a NotificationListener");
+ }
+ NotificationListenerBean bean = new NotificationListenerBean((NotificationListener) value);
+
+ // Get the ObjectName from the map key.
+ Object key = entry.getKey();
+ if (key != null && !WILDCARD.equals(key)) {
+ // This listener is mapped to a specific ObjectName.
+ bean.setMappedObjectName(entry.getKey());
+ }
+
+ notificationListeners.add(bean);
+ }
+
+ this.notificationListeners = (NotificationListenerBean[])
+ notificationListeners.toArray(new NotificationListenerBean[notificationListeners.size()]);
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ /**
+ * This callback is only required for resolution of bean names in the
+ * {@link #setBeans(java.util.Map) "beans"} {@link Map} and for
+ * autodetection of MBeans (in the latter case, a
+ * ListableBeanFactory is required).
+ * @see #setBeans
+ * @see #setAutodetect
+ * @throws IllegalArgumentException if the supplied beanFactory is not a {@link ListableBeanFactory}.
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ if (beanFactory instanceof ListableBeanFactory) {
+ this.beanFactory = (ListableBeanFactory) beanFactory;
+ }
+ else {
+ logger.info("MBeanExporter not running in a ListableBeanFactory: Autodetection of MBeans not available.");
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Lifecycle in bean factory: automatically register/unregister beans
+ //---------------------------------------------------------------------
+
+ /**
+ * Start bean registration automatically when deployed in an
+ * ApplicationContext.
+ * @see #registerBeans()
+ */
+ public void afterPropertiesSet() {
+ // If no server was provided then try to find one. This is useful in an environment
+ // such as JDK 1.5, Tomcat or JBoss where there is already an MBeanServer loaded.
+ if (this.server == null) {
+ this.server = JmxUtils.locateMBeanServer();
+ }
+ try {
+ logger.info("Registering beans for JMX exposure on startup");
+ registerBeans();
+ registerNotificationListeners();
+ }
+ catch (RuntimeException ex) {
+ // Unregister beans already registered by this exporter.
+ unregisterNotificationListeners();
+ unregisterBeans();
+ throw ex;
+ }
+ }
+
+ /**
+ * Unregisters all beans that this exported has exposed via JMX
+ * when the enclosing ApplicationContext is destroyed.
+ */
+ public void destroy() {
+ logger.info("Unregistering JMX-exposed beans on shutdown");
+ unregisterNotificationListeners();
+ unregisterBeans();
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of MBeanExportOperations interface
+ //---------------------------------------------------------------------
+
+ public ObjectName registerManagedResource(Object managedResource) throws MBeanExportException {
+ Assert.notNull(managedResource, "Managed resource must not be null");
+ ObjectName objectName = null;
+ try {
+ objectName = getObjectName(managedResource, null);
+ if (this.ensureUniqueRuntimeObjectNames) {
+ objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
+ }
+ }
+ catch (Exception ex) {
+ throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
+ }
+ registerManagedResource(managedResource, objectName);
+ return objectName;
+ }
+
+ public void registerManagedResource(Object managedResource, ObjectName objectName) throws MBeanExportException {
+ Assert.notNull(managedResource, "Managed resource must not be null");
+ Assert.notNull(objectName, "ObjectName must not be null");
+ try {
+ if (isMBean(managedResource.getClass())) {
+ doRegister(managedResource, objectName);
+ }
+ else {
+ ModelMBean mbean = createAndConfigureMBean(managedResource, managedResource.getClass().getName());
+ doRegister(mbean, objectName);
+ injectNotificationPublisherIfNecessary(managedResource, mbean, objectName);
+ }
+ }
+ catch (JMException ex) {
+ throw new UnableToRegisterMBeanException(
+ "Unable to register MBean [" + managedResource + "] with object name [" + objectName + "]", ex);
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Exporter implementation
+ //---------------------------------------------------------------------
+
+ /**
+ * Registers the defined beans with the {@link MBeanServer}.
+ *
Each bean is exposed to the MBeanServer via a
+ * ModelMBean. The actual implemetation of the
+ * ModelMBean interface used depends on the implementation of
+ * the ModelMBeanProvider interface that is configured. By
+ * default the RequiredModelMBean class that is supplied with
+ * all JMX implementations is used.
+ *
The management interface produced for each bean is dependent on the
+ * MBeanInfoAssembler implementation being used. The
+ * ObjectName given to each bean is dependent on the
+ * implementation of the ObjectNamingStrategy interface being used.
+ */
+ protected void registerBeans() {
+ // The beans property may be null, for example if we are relying solely on autodetection.
+ if (this.beans == null) {
+ this.beans = new HashMap();
+ // Use AUTODETECT_ALL as default in no beans specified explicitly.
+ if (this.autodetectMode == null) {
+ this.autodetectMode = new Integer(AUTODETECT_ALL);
+ }
+ }
+
+ // Perform autodetection, if desired.
+ int mode = (this.autodetectMode != null ? this.autodetectMode.intValue() : AUTODETECT_NONE);
+ if (mode != AUTODETECT_NONE) {
+ if (this.beanFactory == null) {
+ throw new MBeanExportException("Cannot autodetect MBeans if not running in a BeanFactory");
+ }
+ if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
+ // Autodetect any beans that are already MBeans.
+ this.logger.debug("Autodetecting user-defined JMX MBeans");
+ autodetectMBeans();
+ }
+ // Allow the assembler a chance to vote for bean inclusion.
+ if ((mode == AUTODETECT_ASSEMBLER || mode == AUTODETECT_ALL) &&
+ this.assembler instanceof AutodetectCapableMBeanInfoAssembler) {
+ autodetectBeans((AutodetectCapableMBeanInfoAssembler) this.assembler);
+ }
+ }
+
+ if (!this.beans.isEmpty()) {
+ for (Iterator it = this.beans.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Assert.notNull(entry.getKey(), "Beans key must not be null");
+ String beanKey = entry.getKey().toString();
+ Object value = entry.getValue();
+ registerBeanNameOrInstance(value, beanKey);
+ }
+ }
+ }
+
+ /**
+ * Return whether the specified bean definition should be considered as lazy-init.
+ * @param beanFactory the bean factory that is supposed to contain the bean definition
+ * @param beanName the name of the bean to check
+ * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
+ * @see org.springframework.beans.factory.config.BeanDefinition#isLazyInit
+ */
+ protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, String beanName) {
+ if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
+ return false;
+ }
+ try {
+ BeanDefinition bd = ((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName);
+ return bd.isLazyInit();
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ // Probably a directly registered singleton.
+ return false;
+ }
+ }
+
+ /**
+ * Registers an individual bean with the {@link #setServer MBeanServer}.
+ *
This method is responsible for deciding how a bean
+ * should be exposed to the MBeanServer. Specifically, if the
+ * supplied mapValue is the name of a bean that is configured
+ * for lazy initialization, then a proxy to the resource is registered with
+ * the MBeanServer so that the the lazy load behavior is
+ * honored. If the bean is already an MBean then it will be registered
+ * directly with the MBeanServer without any intervention. For
+ * all other beans or bean names, the resource itself is registered with
+ * the MBeanServer directly.
+ * @param mapValue the value configured for this bean in the beans map;
+ * may be either the String name of a bean, or the bean itself
+ * @param beanKey the key associated with this bean in the beans map
+ * @return the ObjectName under which the resource was registered
+ * @throws MBeanExportException if the export failed
+ * @see #setBeans
+ * @see #registerBeanInstance
+ * @see #registerLazyInit
+ */
+ protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException {
+ try {
+ if (mapValue instanceof String) {
+ // Bean name pointing to a potentially lazy-init bean in the factory.
+ if (this.beanFactory == null) {
+ throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory");
+ }
+ String beanName = (String) mapValue;
+ if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) {
+ ObjectName objectName = registerLazyInit(beanName, beanKey);
+ replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
+ return objectName;
+ }
+ else {
+ Object bean = this.beanFactory.getBean(beanName);
+ ObjectName objectName = registerBeanInstance(bean, beanKey);
+ replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
+ return objectName;
+ }
+ }
+ else {
+ // Plain bean instance -> register it directly.
+ if (this.beanFactory != null) {
+ Map beansOfSameType = this.beanFactory.getBeansOfType(mapValue.getClass(), false, false);
+ for (Iterator iterator = beansOfSameType.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ if (entry.getValue() == mapValue) {
+ String beanName = (String) entry.getKey();
+ ObjectName objectName = registerBeanInstance(mapValue, beanKey);
+ replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
+ return objectName;
+ }
+ }
+ }
+ return registerBeanInstance(mapValue, beanKey);
+ }
+ }
+ catch (Exception ex) {
+ throw new UnableToRegisterMBeanException(
+ "Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
+ }
+ }
+
+ /**
+ * Replaces any bean names used as keys in the NotificationListener
+ * mappings with their corresponding ObjectName values.
+ * @param beanName the name of the bean to be registered
+ * @param objectName the ObjectName under which the bean will be registered
+ * with the MBeanServer
+ */
+ private void replaceNotificationListenerBeanNameKeysIfNecessary(String beanName, ObjectName objectName) {
+ if (this.notificationListeners != null) {
+ for (int i = 0; i < this.notificationListeners.length; i++) {
+ this.notificationListeners[i].replaceObjectName(beanName, objectName);
+ }
+ }
+ }
+
+ /**
+ * Registers an existing MBean or an MBean adapter for a plain bean
+ * with the MBeanServer.
+ * @param bean the bean to register, either an MBean or a plain bean
+ * @param beanKey the key associated with this bean in the beans map
+ * @return the ObjectName under which the bean was registered
+ * with the MBeanServer
+ */
+ private ObjectName registerBeanInstance(Object bean, String beanKey) throws JMException {
+ ObjectName objectName = getObjectName(bean, beanKey);
+ Object mbeanToExpose = null;
+ if (isMBean(bean.getClass())) {
+ mbeanToExpose = bean;
+ }
+ else {
+ DynamicMBean adaptedBean = adaptMBeanIfPossible(bean);
+ if (adaptedBean != null) {
+ mbeanToExpose = adaptedBean;
+ }
+ }
+ if (mbeanToExpose != null) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Located MBean '" + beanKey + "': registering with JMX server as MBean [" +
+ objectName + "]");
+ }
+ doRegister(mbeanToExpose, objectName);
+ }
+ else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Located managed bean '" + beanKey + "': registering with JMX server as MBean [" +
+ objectName + "]");
+ }
+ ModelMBean mbean = createAndConfigureMBean(bean, beanKey);
+ doRegister(mbean, objectName);
+ injectNotificationPublisherIfNecessary(bean, mbean, objectName);
+ }
+ return objectName;
+ }
+
+ /**
+ * Registers beans that are configured for lazy initialization with the
+ * MBeanServer indirectly through a proxy.
+ * @param beanName the name of the bean in the BeanFactory
+ * @param beanKey the key associated with this bean in the beans map
+ * @return the ObjectName under which the bean was registered
+ * with the MBeanServer
+ */
+ private ObjectName registerLazyInit(String beanName, String beanKey) throws JMException {
+ ProxyFactory proxyFactory = new ProxyFactory();
+ proxyFactory.setProxyTargetClass(true);
+ proxyFactory.setFrozen(true);
+
+ if (isMBean(this.beanFactory.getType(beanName))) {
+ // A straight MBean... Let's create a simple lazy-init CGLIB proxy for it.
+ LazyInitTargetSource targetSource = new LazyInitTargetSource();
+ targetSource.setTargetBeanName(beanName);
+ targetSource.setBeanFactory(this.beanFactory);
+ proxyFactory.setTargetSource(targetSource);
+
+ Object proxy = proxyFactory.getProxy(this.beanClassLoader);
+ ObjectName objectName = getObjectName(proxy, beanKey);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Located MBean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
+ objectName + "]");
+ }
+ doRegister(proxy, objectName);
+ return objectName;
+ }
+
+ else {
+ // A simple bean... Let's create a lazy-init ModelMBean proxy with notification support.
+ NotificationPublisherAwareLazyTargetSource targetSource = new NotificationPublisherAwareLazyTargetSource();
+ targetSource.setTargetBeanName(beanName);
+ targetSource.setBeanFactory(this.beanFactory);
+ proxyFactory.setTargetSource(targetSource);
+
+ Object proxy = proxyFactory.getProxy(this.beanClassLoader);
+ ObjectName objectName = getObjectName(proxy, beanKey);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Located simple bean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
+ objectName + "]");
+ }
+ ModelMBean mbean = createAndConfigureMBean(proxy, beanKey);
+ targetSource.setModelMBean(mbean);
+ targetSource.setObjectName(objectName);
+ doRegister(mbean, objectName);
+ return objectName;
+ }
+ }
+
+ /**
+ * Retrieve the ObjectName for a bean.
+ *
If the bean implements the SelfNaming interface, then the
+ * ObjectName will be retrieved using SelfNaming.getObjectName().
+ * Otherwise, the configured ObjectNamingStrategy is used.
+ * @param bean the name of the bean in the BeanFactory
+ * @param beanKey the key associated with the bean in the beans map
+ * @return the ObjectName for the supplied bean
+ * @throws javax.management.MalformedObjectNameException
+ * if the retrieved ObjectName is malformed
+ */
+ protected ObjectName getObjectName(Object bean, String beanKey) throws MalformedObjectNameException {
+ if (bean instanceof SelfNaming) {
+ return ((SelfNaming) bean).getObjectName();
+ }
+ else {
+ return this.namingStrategy.getObjectName(bean, beanKey);
+ }
+ }
+
+ /**
+ * Determine whether the given bean class qualifies as an MBean as-is.
+ *
The default implementation delegates to {@link JmxUtils#isMBean},
+ * which checks for {@link javax.management.DynamicMBean} classes as well
+ * as classes with corresponding "*MBean" interface (Standard MBeans)
+ * or corresponding "*MXBean" interface (Java 6 MXBeans).
+ * @param beanClass the bean class to analyze
+ * @return whether the class qualifies as an MBean
+ * @see org.springframework.jmx.support.JmxUtils#isMBean(Class)
+ */
+ protected boolean isMBean(Class beanClass) {
+ return JmxUtils.isMBean(beanClass);
+ }
+
+ /**
+ * Build an adapted MBean for the given bean instance, if possible.
+ *
The default implementation builds a JMX 1.2 StandardMBean
+ * for the target's MBean/MXBean interface in case of an AOP proxy,
+ * delegating the interface's management operations to the proxy.
+ * @param bean the original bean instance
+ * @return the adapted MBean, or null if not possible
+ */
+ protected DynamicMBean adaptMBeanIfPossible(Object bean) throws JMException {
+ Class targetClass = AopUtils.getTargetClass(bean);
+ if (targetClass != bean.getClass()) {
+ Class ifc = JmxUtils.getMXBeanInterface(targetClass);
+ if (ifc != null) {
+ if (!(ifc.isInstance(bean))) {
+ throw new NotCompliantMBeanException("Managed bean [" + bean +
+ "] has a target class with an MXBean interface but does not expose it in the proxy");
+ }
+ return new StandardMBean(bean, ifc, true);
+ }
+ else {
+ ifc = JmxUtils.getMBeanInterface(targetClass);
+ if (ifc != null) {
+ if (!(ifc.isInstance(bean))) {
+ throw new NotCompliantMBeanException("Managed bean [" + bean +
+ "] has a target class with an MBean interface but does not expose it in the proxy");
+ }
+ return new StandardMBean(bean, ifc);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates an MBean that is configured with the appropriate management
+ * interface for the supplied managed resource.
+ * @param managedResource the resource that is to be exported as an MBean
+ * @param beanKey the key associated with the managed bean
+ * @see #createModelMBean()
+ * @see #getMBeanInfo(Object, String)
+ */
+ protected ModelMBean createAndConfigureMBean(Object managedResource, String beanKey)
+ throws MBeanExportException {
+ try {
+ ModelMBean mbean = createModelMBean();
+ mbean.setModelMBeanInfo(getMBeanInfo(managedResource, beanKey));
+ mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
+ return mbean;
+ }
+ catch (Exception ex) {
+ throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
+ managedResource + "] with key '" + beanKey + "'", ex);
+ }
+ }
+
+ /**
+ * Create an instance of a class that implements ModelMBean.
+ *
This method is called to obtain a ModelMBean instance to
+ * use when registering a bean. This method is called once per bean during the
+ * registration phase and must return a new instance of ModelMBean
+ * @return a new instance of a class that implements ModelMBean
+ * @throws javax.management.MBeanException if creation of the ModelMBean failed
+ */
+ protected ModelMBean createModelMBean() throws MBeanException {
+ return (this.exposeManagedResourceClassLoader ? new SpringModelMBean() : new RequiredModelMBean());
+ }
+
+ /**
+ * Gets the ModelMBeanInfo for the bean with the supplied key
+ * and of the supplied type.
+ */
+ private ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException {
+ ModelMBeanInfo info = this.assembler.getMBeanInfo(managedBean, beanKey);
+ if (logger.isWarnEnabled() && ObjectUtils.isEmpty(info.getAttributes()) &&
+ ObjectUtils.isEmpty(info.getOperations())) {
+ logger.warn("Bean with key '" + beanKey +
+ "' has been registered as an MBean but has no exposed attributes or operations");
+ }
+ return info;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Autodetection process
+ //---------------------------------------------------------------------
+
+ /**
+ * Invoked when using an AutodetectCapableMBeanInfoAssembler.
+ * Gives the assembler the opportunity to add additional beans from the
+ * BeanFactory to the list of beans to be exposed via JMX.
+ *
This implementation prevents a bean from being added to the list
+ * automatically if it has already been added manually, and it prevents
+ * certain internal classes from being registered automatically.
+ */
+ private void autodetectBeans(final AutodetectCapableMBeanInfoAssembler assembler) {
+ autodetect(new AutodetectCallback() {
+ public boolean include(Class beanClass, String beanName) {
+ return assembler.includeBean(beanClass, beanName);
+ }
+ });
+ }
+
+ /**
+ * Attempts to detect any beans defined in the ApplicationContext that are
+ * valid MBeans and registers them automatically with the MBeanServer.
+ */
+ private void autodetectMBeans() {
+ autodetect(new AutodetectCallback() {
+ public boolean include(Class beanClass, String beanName) {
+ return isMBean(beanClass);
+ }
+ });
+ }
+
+ /**
+ * Performs the actual autodetection process, delegating to an
+ * AutodetectCallback instance to vote on the inclusion of a
+ * given bean.
+ * @param callback the AutodetectCallback to use when deciding
+ * whether to include a bean or not
+ */
+ private void autodetect(AutodetectCallback callback) {
+ String[] beanNames = this.beanFactory.getBeanNamesForType(Object.class, true, this.allowEagerInit);
+ for (int i = 0; i < beanNames.length; i++) {
+ String beanName = beanNames[i];
+ if (!isExcluded(beanName)) {
+ Class beanClass = this.beanFactory.getType(beanName);
+ if (beanClass != null && callback.include(beanClass, beanName)) {
+ boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName);
+ Object beanInstance = (!lazyInit ? this.beanFactory.getBean(beanName) : null);
+ if (!this.beans.containsValue(beanName) &&
+ (beanInstance == null || !CollectionUtils.containsInstance(this.beans.values(), beanInstance))) {
+ // Not already registered for JMX exposure.
+ this.beans.put(beanName, (beanInstance != null ? beanInstance : beanName));
+ if (logger.isInfoEnabled()) {
+ logger.info("Bean with name '" + beanName + "' has been autodetected for JMX exposure");
+ }
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Bean with name '" + beanName + "' is already registered for JMX exposure");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Indicates whether or not a particular bean name is present in the excluded beans list.
+ */
+ private boolean isExcluded(String beanName) {
+ return (this.excludedBeans != null && this.excludedBeans.contains(beanName));
+ }
+
+
+ //---------------------------------------------------------------------
+ // Notification and listener management
+ //---------------------------------------------------------------------
+
+ /**
+ * If the supplied managed resource implements the {@link NotificationPublisherAware} an instance of
+ * {@link org.springframework.jmx.export.notification.NotificationPublisher} is injected.
+ */
+ private void injectNotificationPublisherIfNecessary(
+ Object managedResource, ModelMBean modelMBean, ObjectName objectName) {
+
+ if (managedResource instanceof NotificationPublisherAware) {
+ ((NotificationPublisherAware) managedResource).setNotificationPublisher(
+ new ModelMBeanNotificationPublisher(modelMBean, objectName, managedResource));
+ }
+ }
+
+ /**
+ * Register the configured {@link NotificationListener NotificationListeners}
+ * with the {@link MBeanServer}.
+ */
+ private void registerNotificationListeners() throws MBeanExportException {
+ if (this.notificationListeners != null) {
+ for (int i = 0; i < this.notificationListeners.length; i++) {
+ NotificationListenerBean bean = this.notificationListeners[i];
+ try {
+ ObjectName[] mappedObjectNames = bean.getResolvedObjectNames();
+ if (mappedObjectNames == null) {
+ // Mapped to all MBeans registered by the MBeanExporter.
+ mappedObjectNames = getRegisteredObjectNames();
+ }
+ if (this.registeredNotificationListeners.put(bean, mappedObjectNames) == null) {
+ for (int j = 0; j < mappedObjectNames.length; j++) {
+ this.server.addNotificationListener(mappedObjectNames[j],
+ bean.getNotificationListener(), bean.getNotificationFilter(), bean.getHandback());
+ }
+ }
+ }
+ catch (Exception ex) {
+ throw new MBeanExportException("Unable to register NotificationListener", ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Unregister the configured {@link NotificationListener NotificationListeners}
+ * from the {@link MBeanServer}.
+ */
+ private void unregisterNotificationListeners() {
+ for (Iterator it = this.registeredNotificationListeners.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ NotificationListenerBean bean = (NotificationListenerBean) entry.getKey();
+ ObjectName[] mappedObjectNames = (ObjectName[]) entry.getValue();
+ for (int j = 0; j < mappedObjectNames.length; j++) {
+ try {
+ this.server.removeNotificationListener(mappedObjectNames[j],
+ bean.getNotificationListener(), bean.getNotificationFilter(), bean.getHandback());
+ }
+ catch (Exception ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Unable to unregister NotificationListener", ex);
+ }
+ }
+ }
+ }
+ this.registeredNotificationListeners.clear();
+ }
+
+ /**
+ * Called when an MBean is registered. Notifies all registered
+ * {@link MBeanExporterListener MBeanExporterListeners} of the registration event.
+ *
Please note that if an {@link MBeanExporterListener} throws a (runtime)
+ * exception when notified, this will essentially interrupt the notification process
+ * and any remaining listeners that have yet to be notified will not (obviously)
+ * receive the {@link MBeanExporterListener#mbeanRegistered(javax.management.ObjectName)}
+ * callback.
+ * @param objectName the ObjectName of the registered MBean
+ */
+ protected void onRegister(ObjectName objectName) {
+ notifyListenersOfRegistration(objectName);
+ }
+
+ /**
+ * Called when an MBean is unregistered. Notifies all registered
+ * {@link MBeanExporterListener MBeanExporterListeners} of the unregistration event.
+ *
Please note that if an {@link MBeanExporterListener} throws a (runtime)
+ * exception when notified, this will essentially interrupt the notification process
+ * and any remaining listeners that have yet to be notified will not (obviously)
+ * receive the {@link MBeanExporterListener#mbeanUnregistered(javax.management.ObjectName)}
+ * callback.
+ * @param objectName the ObjectName of the unregistered MBean
+ */
+ protected void onUnregister(ObjectName objectName) {
+ notifyListenersOfUnregistration(objectName);
+ }
+
+
+ /**
+ * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
+ * registration of the MBean identified by the supplied {@link ObjectName}.
+ */
+ private void notifyListenersOfRegistration(ObjectName objectName) {
+ if (this.listeners != null) {
+ for (int i = 0; i < this.listeners.length; i++) {
+ this.listeners[i].mbeanRegistered(objectName);
+ }
+ }
+ }
+
+ /**
+ * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
+ * unregistration of the MBean identified by the supplied {@link ObjectName}.
+ */
+ private void notifyListenersOfUnregistration(ObjectName objectName) {
+ if (this.listeners != null) {
+ for (int i = 0; i < this.listeners.length; i++) {
+ this.listeners[i].mbeanUnregistered(objectName);
+ }
+ }
+ }
+
+
+ //---------------------------------------------------------------------
+ // Inner classes for internal use
+ //---------------------------------------------------------------------
+
+ /**
+ * Internal callback interface for the autodetection process.
+ */
+ private static interface AutodetectCallback {
+
+ /**
+ * Called during the autodetection process to decide whether
+ * or not a bean should be included.
+ * @param beanClass the class of the bean
+ * @param beanName the name of the bean
+ */
+ boolean include(Class beanClass, String beanName);
+ }
+
+
+ /**
+ * Extension of {@link LazyInitTargetSource} that will inject a
+ * {@link org.springframework.jmx.export.notification.NotificationPublisher}
+ * into the lazy resource as it is created if required.
+ */
+ private class NotificationPublisherAwareLazyTargetSource extends LazyInitTargetSource {
+
+ private ModelMBean modelMBean;
+
+ private ObjectName objectName;
+
+ public void setModelMBean(ModelMBean modelMBean) {
+ this.modelMBean = modelMBean;
+ }
+
+ public void setObjectName(ObjectName objectName) {
+ this.objectName = objectName;
+ }
+
+ protected void postProcessTargetObject(Object targetObject) {
+ injectNotificationPublisherIfNecessary(targetObject, this.modelMBean, this.objectName);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporterListener.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporterListener.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/MBeanExporterListener.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-2008 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.jmx.export;
+
+import javax.management.ObjectName;
+
+/**
+ * A listener that allows application code to be notified when an MBean is
+ * registered and unregistered via an {@link MBeanExporter}.
+ *
+ * @author Rob Harrop
+ * @since 1.2.2
+ * @see org.springframework.jmx.export.MBeanExporter#setListeners
+ */
+public interface MBeanExporterListener {
+
+ /**
+ * Called by {@link MBeanExporter} after an MBean has been successfully
+ * registered with an {@link javax.management.MBeanServer}.
+ * @param objectName the ObjectName of the registered MBean
+ */
+ void mbeanRegistered(ObjectName objectName);
+
+ /**
+ * Called by {@link MBeanExporter} after an MBean has been successfully
+ * unregistered from an {@link javax.management.MBeanServer}.
+ * @param objectName the ObjectName of the unregistered MBean
+ */
+ void mbeanUnregistered(ObjectName objectName);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/NotificationListenerBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/NotificationListenerBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/NotificationListenerBean.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002-2008 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.jmx.export;
+
+import javax.management.NotificationListener;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.support.NotificationListenerHolder;
+
+/**
+ * Helper class that aggregates a {@link javax.management.NotificationListener},
+ * a {@link javax.management.NotificationFilter}, and an arbitrary handback
+ * object.
+ *
+ *
Also provides support for associating the encapsulated
+ * {@link javax.management.NotificationListener} with any number of
+ * MBeans from which it wishes to receive
+ * {@link javax.management.Notification Notifications} via the
+ * {@link #setMappedObjectNames mappedObjectNames} property.
+ *
+ *
Note: This class supports Spring bean names as
+ * {@link #setMappedObjectNames "mappedObjectNames"} as well, as alternative
+ * to specifying JMX object names. Note that only beans exported by the
+ * same {@link MBeanExporter} are supported for such bean names.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see MBeanExporter#setNotificationListeners
+ */
+public class NotificationListenerBean extends NotificationListenerHolder implements InitializingBean {
+
+ /**
+ * Create a new instance of the {@link NotificationListenerBean} class.
+ */
+ public NotificationListenerBean() {
+ }
+
+ /**
+ * Create a new instance of the {@link NotificationListenerBean} class.
+ * @param notificationListener the encapsulated listener
+ */
+ public NotificationListenerBean(NotificationListener notificationListener) {
+ setNotificationListener(notificationListener);
+ }
+
+
+ public void afterPropertiesSet() {
+ if (getNotificationListener() == null) {
+ throw new IllegalArgumentException("Property 'notificationListener' is required");
+ }
+ }
+
+ void replaceObjectName(Object originalName, Object newName) {
+ if (this.mappedObjectNames != null && this.mappedObjectNames.contains(originalName)) {
+ this.mappedObjectNames.remove(originalName);
+ this.mappedObjectNames.add(newName);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/SpringModelMBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/SpringModelMBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/SpringModelMBean.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2002-2007 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.jmx.export;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.RequiredModelMBean;
+
+/**
+ * Extension of the {@link RequiredModelMBean} class that ensures the
+ * {@link Thread#getContextClassLoader() thread context ClassLoader} is switched
+ * for the managed resource's {@link ClassLoader} before any invocations occur.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see RequiredModelMBean
+ */
+public class SpringModelMBean extends RequiredModelMBean {
+
+ /**
+ * Stores the {@link ClassLoader} to use for invocations. Defaults
+ * to the current thread {@link ClassLoader}.
+ */
+ private ClassLoader managedResourceClassLoader = Thread.currentThread().getContextClassLoader();
+
+
+ /**
+ * Construct a new SpringModelMBean instance with an empty {@link ModelMBeanInfo}.
+ * @see javax.management.modelmbean.RequiredModelMBean#RequiredModelMBean()
+ */
+ public SpringModelMBean() throws MBeanException, RuntimeOperationsException {
+ super();
+ }
+
+ /**
+ * Construct a new SpringModelMBean instance with the given {@link ModelMBeanInfo}.
+ * @see javax.management.modelmbean.RequiredModelMBean#RequiredModelMBean(ModelMBeanInfo)
+ */
+ public SpringModelMBean(ModelMBeanInfo mbi) throws MBeanException, RuntimeOperationsException {
+ super(mbi);
+ }
+
+
+ /**
+ * Sets managed resource to expose and stores its {@link ClassLoader}.
+ */
+ public void setManagedResource(Object managedResource, String managedResourceType)
+ throws MBeanException, InstanceNotFoundException, InvalidTargetObjectTypeException {
+
+ this.managedResourceClassLoader = managedResource.getClass().getClassLoader();
+ super.setManagedResource(managedResource, managedResourceType);
+ }
+
+
+ /**
+ * Switches the {@link Thread#getContextClassLoader() context ClassLoader} for the
+ * managed resources {@link ClassLoader} before allowing the invocation to occur.
+ * @see javax.management.modelmbean.ModelMBean#invoke
+ */
+ public Object invoke(String opName, Object[] opArgs, String[] sig)
+ throws MBeanException, ReflectionException {
+
+ ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(this.managedResourceClassLoader);
+ return super.invoke(opName, opArgs, sig);
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader(currentClassLoader);
+ }
+ }
+
+ /**
+ * Switches the {@link Thread#getContextClassLoader() context ClassLoader} for the
+ * managed resources {@link ClassLoader} before allowing the invocation to occur.
+ * @see javax.management.modelmbean.ModelMBean#getAttribute
+ */
+ public Object getAttribute(String attrName)
+ throws AttributeNotFoundException, MBeanException, ReflectionException {
+
+ ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(this.managedResourceClassLoader);
+ return super.getAttribute(attrName);
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader(currentClassLoader);
+ }
+ }
+
+ /**
+ * Switches the {@link Thread#getContextClassLoader() context ClassLoader} for the
+ * managed resources {@link ClassLoader} before allowing the invocation to occur.
+ * @see javax.management.modelmbean.ModelMBean#getAttributes
+ */
+ public AttributeList getAttributes(String[] attrNames) {
+ ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(this.managedResourceClassLoader);
+ return super.getAttributes(attrNames);
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader(currentClassLoader);
+ }
+ }
+
+ /**
+ * Switches the {@link Thread#getContextClassLoader() context ClassLoader} for the
+ * managed resources {@link ClassLoader} before allowing the invocation to occur.
+ * @see javax.management.modelmbean.ModelMBean#setAttribute
+ */
+ public void setAttribute(Attribute attribute)
+ throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+
+ ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(this.managedResourceClassLoader);
+ super.setAttribute(attribute);
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader(currentClassLoader);
+ }
+ }
+
+ /**
+ * Switches the {@link Thread#getContextClassLoader() context ClassLoader} for the
+ * managed resources {@link ClassLoader} before allowing the invocation to occur.
+ * @see javax.management.modelmbean.ModelMBean#setAttributes
+ */
+ public AttributeList setAttributes(AttributeList attributes) {
+ ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(this.managedResourceClassLoader);
+ return super.setAttributes(attributes);
+ }
+ finally {
+ Thread.currentThread().setContextClassLoader(currentClassLoader);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/UnableToRegisterMBeanException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/UnableToRegisterMBeanException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/UnableToRegisterMBeanException.java 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2006 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.jmx.export;
+
+/**
+ * Exception thrown when we are unable to register an MBean,
+ * for example because of a naming conflict.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ */
+public class UnableToRegisterMBeanException extends MBeanExportException {
+
+ /**
+ * Create a new UnableToRegisterMBeanException with the
+ * specified error message.
+ * @param msg the detail message
+ */
+ public UnableToRegisterMBeanException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new UnableToRegisterMBeanException with the
+ * specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root caus
+ */
+ public UnableToRegisterMBeanException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/package.html 17 Aug 2012 15:15:26 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+This package provides declarative creation and registration of
+Spring-managed beans as JMX MBeans.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.annotation;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.annotation.AnnotationBeanUtils;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.jmx.export.metadata.InvalidMetadataException;
+import org.springframework.jmx.export.metadata.JmxAttributeSource;
+import org.springframework.jmx.export.metadata.ManagedAttribute;
+import org.springframework.jmx.export.metadata.ManagedNotification;
+import org.springframework.jmx.export.metadata.ManagedOperation;
+import org.springframework.jmx.export.metadata.ManagedOperationParameter;
+import org.springframework.jmx.export.metadata.ManagedResource;
+import org.springframework.util.StringUtils;
+
+/**
+ * Implementation of the JmxAttributeSource interface that
+ * reads JDK 1.5+ annotations and exposes the corresponding attributes.
+ *
+ *
This is a direct alternative to AttributesJmxAttributeSource,
+ * which is able to read in source-level attributes via Commons Attributes.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jmx.export.annotation.ManagedResource
+ * @see org.springframework.jmx.export.annotation.ManagedAttribute
+ * @see org.springframework.jmx.export.annotation.ManagedOperation
+ * @see org.springframework.jmx.export.metadata.AttributesJmxAttributeSource
+ * @see org.springframework.metadata.commons.CommonsAttributes
+ */
+public class AnnotationJmxAttributeSource implements JmxAttributeSource {
+
+ public ManagedResource getManagedResource(Class beanClass) throws InvalidMetadataException {
+ org.springframework.jmx.export.annotation.ManagedResource ann =
+ ((Class>) beanClass).getAnnotation(org.springframework.jmx.export.annotation.ManagedResource.class);
+ if (ann == null) {
+ return null;
+ }
+ ManagedResource managedResource = new ManagedResource();
+ AnnotationBeanUtils.copyPropertiesToBean(ann, managedResource);
+ if (!"".equals(ann.value()) && !StringUtils.hasLength(managedResource.getObjectName())) {
+ managedResource.setObjectName(ann.value());
+ }
+ return managedResource;
+ }
+
+ public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
+ org.springframework.jmx.export.annotation.ManagedAttribute ann =
+ AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedAttribute.class);
+ if (ann == null) {
+ return null;
+ }
+ ManagedAttribute managedAttribute = new ManagedAttribute();
+ AnnotationBeanUtils.copyPropertiesToBean(ann, managedAttribute, "defaultValue");
+ if (ann.defaultValue().length() > 0) {
+ managedAttribute.setDefaultValue(ann.defaultValue());
+ }
+ return managedAttribute;
+ }
+
+ public ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ throw new InvalidMetadataException(
+ "The ManagedOperation attribute is not valid for JavaBean properties. Use ManagedAttribute instead.");
+ }
+
+ Annotation ann = AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedOperation.class);
+ if (ann == null) {
+ return null;
+ }
+
+ ManagedOperation op = new ManagedOperation();
+ AnnotationBeanUtils.copyPropertiesToBean(ann, op);
+ return op;
+ }
+
+ public ManagedOperationParameter[] getManagedOperationParameters(Method method)
+ throws InvalidMetadataException {
+
+ ManagedOperationParameters params = AnnotationUtils.getAnnotation(method, ManagedOperationParameters.class);
+ ManagedOperationParameter[] result = null;
+ if (params == null) {
+ result = new ManagedOperationParameter[0];
+ }
+ else {
+ Annotation[] paramData = params.value();
+ result = new ManagedOperationParameter[paramData.length];
+ for (int i = 0; i < paramData.length; i++) {
+ Annotation annotation = paramData[i];
+ ManagedOperationParameter managedOperationParameter = new ManagedOperationParameter();
+ AnnotationBeanUtils.copyPropertiesToBean(annotation, managedOperationParameter);
+ result[i] = managedOperationParameter;
+ }
+ }
+ return result;
+ }
+
+ public ManagedNotification[] getManagedNotifications(Class clazz) throws InvalidMetadataException {
+ ManagedNotifications notificationsAnn = (ManagedNotifications) clazz.getAnnotation(ManagedNotifications.class);
+ if(notificationsAnn == null) {
+ return new ManagedNotification[0];
+ }
+ Annotation[] notifications = notificationsAnn.value();
+ ManagedNotification[] result = new ManagedNotification[notifications.length];
+ for (int i = 0; i < notifications.length; i++) {
+ Annotation notification = notifications[i];
+
+ ManagedNotification managedNotification = new ManagedNotification();
+ AnnotationBeanUtils.copyPropertiesToBean(notification, managedNotification);
+ result[i] = managedNotification;
+ }
+ return result;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationMBeanExporter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationMBeanExporter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/AnnotationMBeanExporter.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.annotation;
+
+import org.springframework.jmx.export.MBeanExporter;
+import org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler;
+import org.springframework.jmx.export.naming.MetadataNamingStrategy;
+
+/**
+ * Convenient subclass of Spring's standard {@link MBeanExporter},
+ * activating Java 5 annotation usage for JMX exposure of Spring beans:
+ * {@link ManagedResource}, {@link ManagedAttribute}, {@link ManagedOperation}, etc.
+ *
+ *
Sets a {@link MetadataNamingStrategy} and a {@link MetadataMBeanInfoAssembler}
+ * with an {@link AnnotationJmxAttributeSource}, and activates the
+ * {@link #AUTODETECT_ALL} mode by default.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class AnnotationMBeanExporter extends MBeanExporter {
+
+ private final AnnotationJmxAttributeSource annotationSource =
+ new AnnotationJmxAttributeSource();
+
+ private final MetadataNamingStrategy metadataNamingStrategy =
+ new MetadataNamingStrategy(this.annotationSource);
+
+ private final MetadataMBeanInfoAssembler metadataAssembler =
+ new MetadataMBeanInfoAssembler(this.annotationSource);
+
+
+ public AnnotationMBeanExporter() {
+ setNamingStrategy(this.metadataNamingStrategy);
+ setAssembler(this.metadataAssembler);
+ setAutodetectMode(AUTODETECT_ALL);
+ }
+
+
+ /**
+ * Specify the default domain to be used for generating ObjectNames
+ * when no source-level metadata has been specified.
+ *
The default is to use the domain specified in the bean name
+ * (if the bean name follows the JMX ObjectName syntax); else,
+ * the package name of the managed bean class.
+ * @see MetadataNamingStrategy#setDefaultDomain
+ */
+ public void setDefaultDomain(String defaultDomain) {
+ this.metadataNamingStrategy.setDefaultDomain(defaultDomain);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedAttribute.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedAttribute.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedAttribute.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ method-level annotation that indicates to expose a given bean
+ * property as JMX attribute, corresponding to the ManagedAttribute attribute.
+ * Only valid when used on a JavaBean getter or setter.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.metadata.ManagedAttribute
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ManagedAttribute {
+
+ String defaultValue() default "";
+
+ String description() default "";
+
+ int currencyTimeLimit() default -1;
+
+ String persistPolicy() default "";
+
+ int persistPeriod() default -1;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotification.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotification.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotification.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ method-level annotation that indicates a JMX notification
+ * emitted by a bean.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see org.springframework.jmx.export.metadata.ManagedNotification
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface ManagedNotification {
+
+ String name();
+
+ String description() default "";
+
+ String[] notificationTypes();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotifications.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotifications.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedNotifications.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ method-level annotation that indicates JMX notifications emitted by
+ * a bean, containing multiple {@link ManagedNotification ManagedNotifications}
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface ManagedNotifications {
+
+ ManagedNotification[] value();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperation.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperation.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperation.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ method-level annotation that indicates to expose a given method
+ * as JMX operation, corresponding to the ManagedOperation attribute.
+ * Only valid when used on a method that is not a JavaBean getter or setter.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.metadata.ManagedOperation
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ManagedOperation {
+
+ String description() default "";
+
+ int currencyTimeLimit() default -1;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameter.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.annotation;
+
+/**
+ * JDK 1.5+ method-level annotation used to provide metadata about operation
+ * parameters, corresponding to a ManagedOperationParameter attribute.
+ * Used as part of a ManagedOperationParameters annotation.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see ManagedOperationParameters#value
+ * @see org.springframework.jmx.export.metadata.ManagedOperationParameter
+ */
+public @interface ManagedOperationParameter {
+
+ String name();
+
+ String description();
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameters.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameters.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedOperationParameters.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ method-level annotation used to provide metadata about
+ * operation parameters, corresponding to an array of
+ * ManagedOperationParameter attributes.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.metadata.ManagedOperationParameter
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ManagedOperationParameters {
+
+ ManagedOperationParameter[] value() default {};
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedResource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedResource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/ManagedResource.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JDK 1.5+ class-level annotation that indicates to register
+ * instances of a class with a JMX server, corresponding to
+ * the ManagedResource attribute.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jmx.export.metadata.ManagedResource
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ManagedResource {
+
+ /**
+ * The annotation value is equivalent to the objectName
+ * attribute, for simple default usage.
+ */
+ String value() default "";
+
+ String objectName() default "";
+
+ String description() default "";
+
+ int currencyTimeLimit() default -1;
+
+ boolean log() default false;
+
+ String logFile() default "";
+
+ String persistPolicy() default "";
+
+ int persistPeriod() default -1;
+
+ String persistName() default "";
+
+ String persistLocation() default "";
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/annotation/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/annotation/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/annotation/package.html 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
+JDK 1.5+ annotations for MBean exposure.
+Hooked into Spring's JMX export infrastructure
+via a special JmxAttributeSource implementation.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractConfigurableMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.assembler;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+
+import org.springframework.jmx.export.metadata.JmxMetadataUtils;
+import org.springframework.jmx.export.metadata.ManagedNotification;
+import org.springframework.util.StringUtils;
+
+/**
+ * Base class for MBeanInfoAssemblers that support configurable
+ * JMX notification behavior.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public abstract class AbstractConfigurableMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssembler {
+
+ private ModelMBeanNotificationInfo[] notificationInfos;
+
+ private final Map notificationInfoMappings = new HashMap();
+
+
+ public void setNotificationInfos(ManagedNotification[] notificationInfos) {
+ ModelMBeanNotificationInfo[] infos = new ModelMBeanNotificationInfo[notificationInfos.length];
+ for (int i = 0; i < notificationInfos.length; i++) {
+ ManagedNotification notificationInfo = notificationInfos[i];
+ infos[i] = JmxMetadataUtils.convertToModelMBeanNotificationInfo(notificationInfo);
+ }
+ this.notificationInfos = infos;
+ }
+
+ public void setNotificationInfoMappings(Map notificationInfoMappings) {
+ Iterator entries = notificationInfoMappings.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if (!(entry.getKey() instanceof String)) {
+ throw new IllegalArgumentException("Property [notificationInfoMappings] only accepts Strings for Map keys");
+ }
+ this.notificationInfoMappings.put(entry.getKey(), extractNotificationMetadata(entry.getValue()));
+ }
+ }
+
+
+ protected ModelMBeanNotificationInfo[] getNotificationInfo(Object managedBean, String beanKey) {
+ ModelMBeanNotificationInfo[] result = null;
+
+ if (StringUtils.hasText(beanKey)) {
+ result = (ModelMBeanNotificationInfo[]) this.notificationInfoMappings.get(beanKey);
+ }
+
+ if (result == null) {
+ result = this.notificationInfos;
+ }
+
+ return (result == null) ? new ModelMBeanNotificationInfo[0] : result;
+ }
+
+ private ModelMBeanNotificationInfo[] extractNotificationMetadata(Object mapValue) {
+ if (mapValue instanceof ManagedNotification) {
+ ManagedNotification mn = (ManagedNotification) mapValue;
+ return new ModelMBeanNotificationInfo[] {JmxMetadataUtils.convertToModelMBeanNotificationInfo(mn)};
+ }
+ else if (mapValue instanceof Collection) {
+ Collection col = (Collection) mapValue;
+ List result = new ArrayList();
+ for (Iterator iterator = col.iterator(); iterator.hasNext();) {
+ Object colValue = iterator.next();
+ if (!(colValue instanceof ManagedNotification)) {
+ throw new IllegalArgumentException(
+ "Property 'notificationInfoMappings' only accepts ManagedNotifications for Map values");
+ }
+ ManagedNotification mn = (ManagedNotification) colValue;
+ result.add(JmxMetadataUtils.convertToModelMBeanNotificationInfo(mn));
+ }
+ return (ModelMBeanNotificationInfo[]) result.toArray(new ModelMBeanNotificationInfo[result.size()]);
+ }
+ else {
+ throw new IllegalArgumentException(
+ "Property 'notificationInfoMappings' only accepts ManagedNotifications for Map values");
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.assembler;
+
+import javax.management.Descriptor;
+import javax.management.JMException;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanConstructorInfo;
+import javax.management.modelmbean.ModelMBeanInfo;
+import javax.management.modelmbean.ModelMBeanInfoSupport;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.jmx.support.JmxUtils;
+
+/**
+ * Abstract implementation of the MBeanInfoAssembler interface
+ * that encapsulates the creation of a ModelMBeanInfo instance
+ * but delegates the creation of metadata to subclasses.
+ *
+ *
This class offers two flavors of Class extraction from a managed bean
+ * instance: {@link #getTargetClass}, extracting the target class behind
+ * any kind of AOP proxy, and {@link #getClassToExpose}, returning the
+ * class or interface that will be searched for annotations and exposed
+ * to the JMX runtime.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ */
+public abstract class AbstractMBeanInfoAssembler implements MBeanInfoAssembler {
+
+ /**
+ * Create an instance of the ModelMBeanInfoSupport class supplied with all
+ * JMX implementations and populates the metadata through calls to the subclass.
+ * @param managedBean the bean that will be exposed (might be an AOP proxy)
+ * @param beanKey the key associated with the managed bean
+ * @return the populated ModelMBeanInfo instance
+ * @throws JMException in case of errors
+ * @see #getDescription(Object, String)
+ * @see #getAttributeInfo(Object, String)
+ * @see #getConstructorInfo(Object, String)
+ * @see #getOperationInfo(Object, String)
+ * @see #getNotificationInfo(Object, String)
+ * @see #populateMBeanDescriptor(javax.management.Descriptor, Object, String)
+ */
+ public ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException {
+ checkManagedBean(managedBean);
+ ModelMBeanInfo info = new ModelMBeanInfoSupport(
+ getClassName(managedBean, beanKey), getDescription(managedBean, beanKey),
+ getAttributeInfo(managedBean, beanKey), getConstructorInfo(managedBean, beanKey),
+ getOperationInfo(managedBean, beanKey), getNotificationInfo(managedBean, beanKey));
+ Descriptor desc = info.getMBeanDescriptor();
+ populateMBeanDescriptor(desc, managedBean, beanKey);
+ info.setMBeanDescriptor(desc);
+ return info;
+ }
+
+ /**
+ * Check the given bean instance, throwing an IllegalArgumentException
+ * if it is not eligible for exposure with this assembler.
+ *
Default implementation is empty, accepting every bean instance.
+ * @param managedBean the bean that will be exposed (might be an AOP proxy)
+ * @throws IllegalArgumentException the bean is not valid for exposure
+ */
+ protected void checkManagedBean(Object managedBean) throws IllegalArgumentException {
+ }
+
+ /**
+ * Return the actual bean class of the given bean instance.
+ * This is the class exposed to description-style JMX properties.
+ *
Default implementation returns the target class for an AOP proxy,
+ * and the plain bean class else.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @return the bean class to expose
+ * @see org.springframework.aop.framework.AopProxyUtils#getTargetClass
+ */
+ protected Class getTargetClass(Object managedBean) {
+ return AopUtils.getTargetClass(managedBean);
+ }
+
+ /**
+ * Return the class or interface to expose for the given bean.
+ * This is the class that will be searched for attributes and operations
+ * (for example, checked for annotations).
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @return the bean class to expose
+ * @see JmxUtils#getClassToExpose(Object)
+ */
+ protected Class getClassToExpose(Object managedBean) {
+ return JmxUtils.getClassToExpose(managedBean);
+ }
+
+ /**
+ * Return the class or interface to expose for the given bean class.
+ * This is the class that will be searched for attributes and operations
+ * @param beanClass the bean class (might be an AOP proxy class)
+ * @return the bean class to expose
+ * @see JmxUtils#getClassToExpose(Class)
+ */
+ protected Class getClassToExpose(Class beanClass) {
+ return JmxUtils.getClassToExpose(beanClass);
+ }
+
+ /**
+ * Get the class name of the MBean resource.
+ *
Default implementation returns a simple description for the MBean
+ * based on the class name.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the MBean description
+ * @throws JMException in case of errors
+ */
+ protected String getClassName(Object managedBean, String beanKey) throws JMException {
+ return getTargetClass(managedBean).getName();
+ }
+
+ /**
+ * Get the description of the MBean resource.
+ *
Default implementation returns a simple description for the MBean
+ * based on the class name.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @throws JMException in case of errors
+ */
+ protected String getDescription(Object managedBean, String beanKey) throws JMException {
+ String targetClassName = getTargetClass(managedBean).getName();
+ if (AopUtils.isAopProxy(managedBean)) {
+ return "Proxy for " + targetClassName;
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Called after the ModelMBeanInfo instance has been constructed but
+ * before it is passed to the MBeanExporter.
+ *
Subclasses can implement this method to add additional descriptors to the
+ * MBean metadata. Default implementation is empty.
+ * @param descriptor the Descriptor for the MBean resource.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @throws JMException in case of errors
+ */
+ protected void populateMBeanDescriptor(Descriptor descriptor, Object managedBean, String beanKey)
+ throws JMException {
+ }
+
+ /**
+ * Get the constructor metadata for the MBean resource. Subclasses should implement
+ * this method to return the appropriate metadata for all constructors that should
+ * be exposed in the management interface for the managed resource.
+ *
Default implementation returns an empty array of ModelMBeanConstructorInfo.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the constructor metadata
+ * @throws JMException in case of errors
+ */
+ protected ModelMBeanConstructorInfo[] getConstructorInfo(Object managedBean, String beanKey)
+ throws JMException {
+ return new ModelMBeanConstructorInfo[0];
+ }
+
+ /**
+ * Get the notification metadata for the MBean resource. Subclasses should implement
+ * this method to return the appropriate metadata for all notifications that should
+ * be exposed in the management interface for the managed resource.
+ *
Default implementation returns an empty array of ModelMBeanNotificationInfo.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the notification metadata
+ * @throws JMException in case of errors
+ */
+ protected ModelMBeanNotificationInfo[] getNotificationInfo(Object managedBean, String beanKey)
+ throws JMException {
+ return new ModelMBeanNotificationInfo[0];
+ }
+
+
+ /**
+ * Get the attribute metadata for the MBean resource. Subclasses should implement
+ * this method to return the appropriate metadata for all the attributes that should
+ * be exposed in the management interface for the managed resource.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the attribute metadata
+ * @throws JMException in case of errors
+ */
+ protected abstract ModelMBeanAttributeInfo[] getAttributeInfo(Object managedBean, String beanKey)
+ throws JMException;
+
+ /**
+ * Get the operation metadata for the MBean resource. Subclasses should implement
+ * this method to return the appropriate metadata for all operations that should
+ * be exposed in the management interface for the managed resource.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the operation metadata
+ * @throws JMException in case of errors
+ */
+ protected abstract ModelMBeanOperationInfo[] getOperationInfo(Object managedBean, String beanKey)
+ throws JMException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractReflectiveMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractReflectiveMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AbstractReflectiveMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.assembler;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.Descriptor;
+import javax.management.JMException;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+import javax.management.modelmbean.ModelMBeanOperationInfo;
+
+import org.springframework.aop.framework.AopProxyUtils;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.core.JdkVersion;
+import org.springframework.jmx.support.JmxUtils;
+
+/**
+ * Builds on the {@link AbstractMBeanInfoAssembler} superclass to
+ * add a basic algorithm for building metadata based on the
+ * reflective metadata of the MBean class.
+ *
+ *
The logic for creating MBean metadata from the reflective metadata
+ * is contained in this class, but this class makes no decisions as to
+ * which methods and properties are to be exposed. Instead it gives
+ * subclasses a chance to 'vote' on each property or method through
+ * the includeXXX methods.
+ *
+ *
Subclasses are also given the opportunity to populate attribute
+ * and operation metadata with additional descriptors once the metadata
+ * is assembled through the populateXXXDescriptor methods.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #includeOperation
+ * @see #includeReadAttribute
+ * @see #includeWriteAttribute
+ * @see #populateAttributeDescriptor
+ * @see #populateOperationDescriptor
+ */
+public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBeanInfoAssembler {
+
+ /**
+ * Identifies a getter method in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_GET_METHOD = "getMethod";
+
+ /**
+ * Identifies a setter method in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_SET_METHOD = "setMethod";
+
+ /**
+ * Constant identifier for the role field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_ROLE = "role";
+
+ /**
+ * Constant identifier for the getter role field value in a JMX {@link Descriptor}.
+ */
+ protected static final String ROLE_GETTER = "getter";
+
+ /**
+ * Constant identifier for the setter role field value in a JMX {@link Descriptor}.
+ */
+ protected static final String ROLE_SETTER = "setter";
+
+ /**
+ * Identifies an operation (method) in a JMX {@link Descriptor}.
+ */
+ protected static final String ROLE_OPERATION = "operation";
+
+ /**
+ * Constant identifier for the visibility field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_VISIBILITY = "visibility";
+
+ /**
+ * Lowest visibility, used for operations that correspond to
+ * accessors or mutators for attributes.
+ * @see #FIELD_VISIBILITY
+ */
+ protected static final Integer ATTRIBUTE_OPERATION_VISIBILITY = new Integer(4);
+
+ /**
+ * Constant identifier for the class field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_CLASS = "class";
+ /**
+ * Constant identifier for the log field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_LOG = "log";
+
+ /**
+ * Constant identifier for the logfile field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_LOG_FILE = "logFile";
+
+ /**
+ * Constant identifier for the currency time limit field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_CURRENCY_TIME_LIMIT = "currencyTimeLimit";
+
+ /**
+ * Constant identifier for the default field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_DEFAULT = "default";
+
+ /**
+ * Constant identifier for the persistPolicy field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_PERSIST_POLICY = "persistPolicy";
+
+ /**
+ * Constant identifier for the persistPeriod field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_PERSIST_PERIOD = "persistPeriod";
+
+ /**
+ * Constant identifier for the persistLocation field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_PERSIST_LOCATION = "persistLocation";
+
+ /**
+ * Constant identifier for the persistName field in a JMX {@link Descriptor}.
+ */
+ protected static final String FIELD_PERSIST_NAME = "persistName";
+
+
+ /**
+ * Default value for the JMX field "currencyTimeLimit".
+ */
+ private Integer defaultCurrencyTimeLimit;
+
+ /**
+ * Indicates whether or not strict casing is being used for attributes.
+ */
+ private boolean useStrictCasing = true;
+
+ private boolean exposeClassDescriptor = false;
+
+
+ /**
+ * Set the default for the JMX field "currencyTimeLimit".
+ * The default will usually indicate to never cache attribute values.
+ *
Default is none, not explicitly setting that field, as recommended by the
+ * JMX 1.2 specification. This should result in "never cache" behavior, always
+ * reading attribute values freshly (which corresponds to a "currencyTimeLimit"
+ * of -1 in JMX 1.2).
+ *
However, some JMX implementations (that do not follow the JMX 1.2 spec
+ * in that respect) might require an explicit value to be set here to get
+ * "never cache" behavior: for example, JBoss 3.2.x.
+ *
Note that the "currencyTimeLimit" value can also be specified on a
+ * managed attribute or operation. The default value will apply if not
+ * overridden with a "currencyTimeLimit" value >= 0 there:
+ * a metadata "currencyTimeLimit" value of -1 indicates
+ * to use the default; a value of 0 indicates to "always cache"
+ * and will be translated to Integer.MAX_VALUE; a positive
+ * value indicates the number of cache seconds.
+ * @see org.springframework.jmx.export.metadata.AbstractJmxAttribute#setCurrencyTimeLimit
+ * @see #applyCurrencyTimeLimit(javax.management.Descriptor, int)
+ */
+ public void setDefaultCurrencyTimeLimit(Integer defaultCurrencyTimeLimit) {
+ this.defaultCurrencyTimeLimit = defaultCurrencyTimeLimit;
+ }
+
+ /**
+ * Return default value for the JMX field "currencyTimeLimit", if any.
+ */
+ protected Integer getDefaultCurrencyTimeLimit() {
+ return this.defaultCurrencyTimeLimit;
+ }
+
+ /**
+ * Set whether to use strict casing for attributes. Enabled by default.
+ *
When using strict casing, a JavaBean property with a getter such as
+ * getFoo() translates to an attribute called Foo.
+ * With strict casing disabled, getFoo() would translate to just
+ * foo.
+ */
+ public void setUseStrictCasing(boolean useStrictCasing) {
+ this.useStrictCasing = useStrictCasing;
+ }
+
+ /**
+ * Return whether strict casing for attributes is enabled.
+ */
+ protected boolean isUseStrictCasing() {
+ return useStrictCasing;
+ }
+
+ /**
+ * Set whether to expose the JMX descriptor field "class" for managed operations.
+ * Default is "false", letting the JMX implementation determine the actual class
+ * through reflection.
+ *
Set this property to true for JMX implementations that
+ * require the "class" field to be specified, for example WebLogic's.
+ * In that case, Spring will expose the target class name there, in case of
+ * a plain bean instance or a CGLIB proxy. When encountering a JDK dynamic
+ * proxy, the first interface implemented by the proxy will be specified.
+ *
WARNING: Review your proxy definitions when exposing a JDK dynamic
+ * proxy through JMX, in particular with this property turned to true:
+ * the specified interface list should start with your management interface in
+ * this case, with all other interfaces following. In general, consider exposing
+ * your target bean directly or a CGLIB proxy for it instead.
+ * @see #getClassForDescriptor(Object)
+ */
+ public void setExposeClassDescriptor(boolean exposeClassDescriptor) {
+ this.exposeClassDescriptor = exposeClassDescriptor;
+ }
+
+ /**
+ * Return whether to expose the JMX descriptor field "class" for managed operations.
+ */
+ protected boolean isExposeClassDescriptor() {
+ return exposeClassDescriptor;
+ }
+
+
+ /**
+ * Iterate through all properties on the MBean class and gives subclasses
+ * the chance to vote on the inclusion of both the accessor and mutator.
+ * If a particular accessor or mutator is voted for inclusion, the appropriate
+ * metadata is assembled and passed to the subclass for descriptor population.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the attribute metadata
+ * @throws JMException in case of errors
+ * @see #populateAttributeDescriptor
+ */
+ protected ModelMBeanAttributeInfo[] getAttributeInfo(Object managedBean, String beanKey) throws JMException {
+ PropertyDescriptor[] props = BeanUtils.getPropertyDescriptors(getClassToExpose(managedBean));
+ List infos = new ArrayList();
+
+ for (int i = 0; i < props.length; i++) {
+ Method getter = props[i].getReadMethod();
+ if (getter != null && getter.getDeclaringClass() == Object.class) {
+ continue;
+ }
+ if (getter != null && !includeReadAttribute(getter, beanKey)) {
+ getter = null;
+ }
+
+ Method setter = props[i].getWriteMethod();
+ if (setter != null && !includeWriteAttribute(setter, beanKey)) {
+ setter = null;
+ }
+
+ if (getter != null || setter != null) {
+ // If both getter and setter are null, then this does not need exposing.
+ String attrName = JmxUtils.getAttributeName(props[i], isUseStrictCasing());
+ String description = getAttributeDescription(props[i], beanKey);
+ ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo(attrName, description, getter, setter);
+
+ Descriptor desc = info.getDescriptor();
+ if (getter != null) {
+ desc.setField(FIELD_GET_METHOD, getter.getName());
+ }
+ if (setter != null) {
+ desc.setField(FIELD_SET_METHOD, setter.getName());
+ }
+
+ populateAttributeDescriptor(desc, getter, setter, beanKey);
+ info.setDescriptor(desc);
+ infos.add(info);
+ }
+ }
+
+ return (ModelMBeanAttributeInfo[]) infos.toArray(new ModelMBeanAttributeInfo[infos.size()]);
+ }
+
+ /**
+ * Iterate through all methods on the MBean class and gives subclasses the chance
+ * to vote on their inclusion. If a particular method corresponds to the accessor
+ * or mutator of an attribute that is inclued in the managment interface, then
+ * the corresponding operation is exposed with the "role" descriptor
+ * field set to the appropriate value.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the operation metadata
+ * @see #populateOperationDescriptor
+ */
+ protected ModelMBeanOperationInfo[] getOperationInfo(Object managedBean, String beanKey) {
+ Method[] methods = getClassToExpose(managedBean).getMethods();
+ List infos = new ArrayList();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (JdkVersion.isAtLeastJava15() && method.isSynthetic()) {
+ continue;
+ }
+ if (method.getDeclaringClass().equals(Object.class)) {
+ continue;
+ }
+
+ ModelMBeanOperationInfo info = null;
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ if ((method.equals(pd.getReadMethod()) && includeReadAttribute(method, beanKey)) ||
+ (method.equals(pd.getWriteMethod()) && includeWriteAttribute(method, beanKey))) {
+ // Attributes need to have their methods exposed as
+ // operations to the JMX server as well.
+ info = createModelMBeanOperationInfo(method, pd.getName(), beanKey);
+ Descriptor desc = info.getDescriptor();
+ if (method.equals(pd.getReadMethod())) {
+ desc.setField(FIELD_ROLE, ROLE_GETTER);
+ }
+ else {
+ desc.setField(FIELD_ROLE, ROLE_SETTER);
+ }
+ desc.setField(FIELD_VISIBILITY, ATTRIBUTE_OPERATION_VISIBILITY);
+ if (isExposeClassDescriptor()) {
+ desc.setField(FIELD_CLASS, getClassForDescriptor(managedBean).getName());
+ }
+ info.setDescriptor(desc);
+ }
+ }
+ else if (includeOperation(method, beanKey)) {
+ info = createModelMBeanOperationInfo(method, method.getName(), beanKey);
+ Descriptor desc = info.getDescriptor();
+ desc.setField(FIELD_ROLE, ROLE_OPERATION);
+ if (isExposeClassDescriptor()) {
+ desc.setField(FIELD_CLASS, getClassForDescriptor(managedBean).getName());
+ }
+ populateOperationDescriptor(desc, method, beanKey);
+ info.setDescriptor(desc);
+ }
+
+ if (info != null) {
+ infos.add(info);
+ }
+ }
+
+ return (ModelMBeanOperationInfo[]) infos.toArray(new ModelMBeanOperationInfo[infos.size()]);
+ }
+
+ /**
+ * Creates an instance of ModelMBeanOperationInfo for the
+ * given method. Populates the parameter info for the operation.
+ * @param method the Method to create a ModelMBeanOperationInfo for
+ * @param name the name for the operation info
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the ModelMBeanOperationInfo
+ */
+ protected ModelMBeanOperationInfo createModelMBeanOperationInfo(Method method, String name, String beanKey) {
+ MBeanParameterInfo[] params = getOperationParameters(method, beanKey);
+ if (params.length == 0) {
+ return new ModelMBeanOperationInfo(getOperationDescription(method, beanKey), method);
+ }
+ else {
+ return new ModelMBeanOperationInfo(name,
+ getOperationDescription(method, beanKey),
+ getOperationParameters(method, beanKey),
+ method.getReturnType().getName(),
+ MBeanOperationInfo.UNKNOWN);
+ }
+ }
+
+ /**
+ * Return the class to be used for the JMX descriptor field "class".
+ * Only applied when the "exposeClassDescriptor" property is "true".
+ *
Default implementation returns the first implemented interface
+ * for a JDK proxy, and the target class else.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @return the class to expose in the descriptor field "class"
+ * @see #setExposeClassDescriptor
+ * @see #getClassToExpose(Class)
+ * @see org.springframework.aop.framework.AopProxyUtils#proxiedUserInterfaces(Object)
+ */
+ protected Class getClassForDescriptor(Object managedBean) {
+ if (AopUtils.isJdkDynamicProxy(managedBean)) {
+ return AopProxyUtils.proxiedUserInterfaces(managedBean)[0];
+ }
+ return getClassToExpose(managedBean);
+ }
+
+
+ /**
+ * Allows subclasses to vote on the inclusion of a particular attribute accessor.
+ * @param method the accessor Method
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return true if the accessor should be included in the management interface,
+ * otherwise false
+ */
+ protected abstract boolean includeReadAttribute(Method method, String beanKey);
+
+ /**
+ * Allows subclasses to vote on the inclusion of a particular attribute mutator.
+ * @param method the mutator Method.
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return true if the mutator should be included in the management interface,
+ * otherwise false
+ */
+ protected abstract boolean includeWriteAttribute(Method method, String beanKey);
+
+ /**
+ * Allows subclasses to vote on the inclusion of a particular operation.
+ * @param method the operation method
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return whether the operation should be included in the management interface
+ */
+ protected abstract boolean includeOperation(Method method, String beanKey);
+
+
+ /**
+ * Get the description for a particular attribute.
+ *
Default implementation returns a description for the operation
+ * that is the name of corresponding Method.
+ * @param propertyDescriptor the PropertyDescriptor for the attribute
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the description for the attribute
+ */
+ protected String getAttributeDescription(PropertyDescriptor propertyDescriptor, String beanKey) {
+ return propertyDescriptor.getDisplayName();
+ }
+
+ /**
+ * Get the description for a particular operation.
+ *
Default implementation returns a description for the operation
+ * that is the name of corresponding Method.
+ * @param method the operation method
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the description for the operation
+ */
+ protected String getOperationDescription(Method method, String beanKey) {
+ return method.getName();
+ }
+
+ /**
+ * Create parameter info for the given method. Default implementation
+ * returns an empty arry of MBeanParameterInfo.
+ * @param method the Method to get the parameter information for
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @return the MBeanParameterInfo array
+ */
+ protected MBeanParameterInfo[] getOperationParameters(Method method, String beanKey) {
+ return new MBeanParameterInfo[0];
+ }
+
+
+ /**
+ * Allows subclasses to add extra fields to the Descriptor for an
+ * MBean. Default implementation sets the currencyTimeLimit field to
+ * the specified "defaultCurrencyTimeLimit", if any (by default none).
+ * @param descriptor the Descriptor for the MBean resource.
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @see #setDefaultCurrencyTimeLimit(Integer)
+ * @see #applyDefaultCurrencyTimeLimit(javax.management.Descriptor)
+ */
+ protected void populateMBeanDescriptor(Descriptor descriptor, Object managedBean, String beanKey) {
+ applyDefaultCurrencyTimeLimit(descriptor);
+ }
+
+ /**
+ * Allows subclasses to add extra fields to the Descriptor for a particular
+ * attribute. Default implementation sets the currencyTimeLimit field to
+ * the specified "defaultCurrencyTimeLimit", if any (by default none).
+ * @param desc the attribute descriptor
+ * @param getter the accessor method for the attribute
+ * @param setter the mutator method for the attribute
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @see #setDefaultCurrencyTimeLimit(Integer)
+ * @see #applyDefaultCurrencyTimeLimit(javax.management.Descriptor)
+ */
+ protected void populateAttributeDescriptor(Descriptor desc, Method getter, Method setter, String beanKey) {
+ applyDefaultCurrencyTimeLimit(desc);
+ }
+
+ /**
+ * Allows subclasses to add extra fields to the Descriptor for a particular
+ * operation. Default implementation sets the currencyTimeLimit field to
+ * the specified "defaultCurrencyTimeLimit", if any (by default none).
+ * @param desc the operation descriptor
+ * @param method the method corresponding to the operation
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ * @see #setDefaultCurrencyTimeLimit(Integer)
+ * @see #applyDefaultCurrencyTimeLimit(javax.management.Descriptor)
+ */
+ protected void populateOperationDescriptor(Descriptor desc, Method method, String beanKey) {
+ applyDefaultCurrencyTimeLimit(desc);
+ }
+
+ /**
+ * Set the currencyTimeLimit field to the specified
+ * "defaultCurrencyTimeLimit", if any (by default none).
+ * @param desc the JMX attribute or operation descriptor
+ * @see #setDefaultCurrencyTimeLimit(Integer)
+ */
+ protected final void applyDefaultCurrencyTimeLimit(Descriptor desc) {
+ if (getDefaultCurrencyTimeLimit() != null) {
+ desc.setField(FIELD_CURRENCY_TIME_LIMIT, getDefaultCurrencyTimeLimit().toString());
+ }
+ }
+
+ /**
+ * Apply the given JMX "currencyTimeLimit" value to the given descriptor.
+ *
Default implementation sets a value >0 as-is (as number of cache seconds),
+ * turns a value of 0 into Integer.MAX_VALUE ("always cache")
+ * and sets the "defaultCurrencyTimeLimit" (if any, indicating "never cache") in case of
+ * a value <0. This follows the recommendation in the JMX 1.2 specification.
+ * @param desc the JMX attribute or operation descriptor
+ * @param currencyTimeLimit the "currencyTimeLimit" value to apply
+ * @see #setDefaultCurrencyTimeLimit(Integer)
+ * @see #applyDefaultCurrencyTimeLimit(javax.management.Descriptor)
+ */
+ protected void applyCurrencyTimeLimit(Descriptor desc, int currencyTimeLimit) {
+ if (currencyTimeLimit > 0) {
+ // number of cache seconds
+ desc.setField(FIELD_CURRENCY_TIME_LIMIT, Integer.toString(currencyTimeLimit));
+ }
+ else if (currencyTimeLimit == 0) {
+ // "always cache"
+ desc.setField(FIELD_CURRENCY_TIME_LIMIT, Integer.toString(Integer.MAX_VALUE));
+ }
+ else {
+ // "never cache"
+ applyDefaultCurrencyTimeLimit(desc);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AutodetectCapableMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/AutodetectCapableMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/AutodetectCapableMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.assembler;
+
+/**
+ * Extends the MBeanInfoAssembler to add autodetection logic.
+ * Implementations of this interface are given the opportunity by the
+ * MBeanExporter to include additional beans in the registration process.
+ *
+ *
The exact mechanism for deciding which beans to include is left to
+ * implementing classes.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public interface AutodetectCapableMBeanInfoAssembler extends MBeanInfoAssembler {
+
+ /**
+ * Indicate whether a particular bean should be included in the registration
+ * process, if it is not specified in the beans map of the
+ * MBeanExporter.
+ * @param beanClass the class of the bean (might be a proxy class)
+ * @param beanName the name of the bean in the bean factory
+ */
+ boolean includeBean(Class beanClass, String beanName);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/InterfaceBasedMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.assembler;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * Subclass of AbstractReflectiveMBeanInfoAssembler that allows for
+ * the management interface of a bean to be defined using arbitrary interfaces.
+ * Any methods or properties that are defined in those interfaces are exposed
+ * as MBean operations and attributes.
+ *
+ *
By default, this class votes on the inclusion of each operation or attribute
+ * based on the interfaces implemented by the bean class. However, you can supply an
+ * array of interfaces via the managedInterfaces property that will be
+ * used instead. If you have multiple beans and you wish each bean to use a different
+ * set of interfaces, then you can map bean keys (that is the name used to pass the
+ * bean to the MBeanExporter) to a list of interface names using the
+ * interfaceMappings property.
+ *
+ *
If you specify values for both interfaceMappings and
+ * managedInterfaces, Spring will attempt to find interfaces in the
+ * mappings first. If no interfaces for the bean are found, it will use the
+ * interfaces defined by managedInterfaces.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setManagedInterfaces
+ * @see #setInterfaceMappings
+ * @see MethodNameBasedMBeanInfoAssembler
+ * @see SimpleReflectiveMBeanInfoAssembler
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class InterfaceBasedMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler
+ implements BeanClassLoaderAware, InitializingBean {
+
+ /**
+ * Stores the array of interfaces to use for creating the management interface.
+ */
+ private Class[] managedInterfaces;
+
+ /**
+ * Stores the mappings of bean keys to an array of Classes.
+ */
+ private Properties interfaceMappings;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ /**
+ * Stores the mappings of bean keys to an array of Classes.
+ */
+ private Map resolvedInterfaceMappings;
+
+
+ /**
+ * Set the array of interfaces to use for creating the management info.
+ * These interfaces will be used for a bean if no entry corresponding to
+ * that bean is found in the interfaceMappings property.
+ * @param managedInterfaces an array of classes indicating the interfaces to use.
+ * Each entry MUST be an interface.
+ * @see #setInterfaceMappings
+ */
+ public void setManagedInterfaces(Class[] managedInterfaces) {
+ if (managedInterfaces != null) {
+ for (int x = 0; x < managedInterfaces.length; x++) {
+ if (!managedInterfaces[x].isInterface()) {
+ throw new IllegalArgumentException(
+ "Management interface [" + managedInterfaces[x].getName() + "] is no interface");
+ }
+ }
+ }
+ this.managedInterfaces = managedInterfaces;
+ }
+
+ /**
+ * Set the mappings of bean keys to a comma-separated list of interface names.
+ * The property key should match the bean key and the property value should match
+ * the list of interface names. When searching for interfaces for a bean, Spring
+ * will check these mappings first.
+ * @param mappings the mappins of bean keys to interface names
+ */
+ public void setInterfaceMappings(Properties mappings) {
+ this.interfaceMappings = mappings;
+ }
+
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ this.beanClassLoader = beanClassLoader;
+ }
+
+
+ public void afterPropertiesSet() {
+ if (this.interfaceMappings != null) {
+ this.resolvedInterfaceMappings = resolveInterfaceMappings(this.interfaceMappings);
+ }
+ }
+
+ /**
+ * Resolve the given interface mappings, turning class names into Class objects.
+ * @param mappings the specified interface mappings
+ * @return the resolved interface mappings (with Class objects as values)
+ */
+ private Map resolveInterfaceMappings(Properties mappings) {
+ Map resolvedMappings = new HashMap(mappings.size());
+ for (Enumeration en = mappings.propertyNames(); en.hasMoreElements();) {
+ String beanKey = (String) en.nextElement();
+ String[] classNames = StringUtils.commaDelimitedListToStringArray(mappings.getProperty(beanKey));
+ Class[] classes = resolveClassNames(classNames, beanKey);
+ resolvedMappings.put(beanKey, classes);
+ }
+ return resolvedMappings;
+ }
+
+ /**
+ * Resolve the given class names into Class objects.
+ * @param classNames the class names to resolve
+ * @param beanKey the bean key that the class names are associated with
+ * @return the resolved Class
+ */
+ private Class[] resolveClassNames(String[] classNames, String beanKey) {
+ Class[] classes = new Class[classNames.length];
+ for (int x = 0; x < classes.length; x++) {
+ Class cls = ClassUtils.resolveClassName(classNames[x].trim(), this.beanClassLoader);
+ if (!cls.isInterface()) {
+ throw new IllegalArgumentException(
+ "Class [" + classNames[x] + "] mapped to bean key [" + beanKey + "] is no interface");
+ }
+ classes[x] = cls;
+ }
+ return classes;
+ }
+
+
+ /**
+ * Check to see if the Method is declared in
+ * one of the configured interfaces and that it is public.
+ * @param method the accessor Method.
+ * @param beanKey the key associated with the MBean in the
+ * beansMap.
+ * @return true if the Method is declared in one of the
+ * configured interfaces, otherwise false.
+ */
+ protected boolean includeReadAttribute(Method method, String beanKey) {
+ return isPublicInInterface(method, beanKey);
+ }
+
+ /**
+ * Check to see if the Method is declared in
+ * one of the configured interfaces and that it is public.
+ * @param method the mutator Method.
+ * @param beanKey the key associated with the MBean in the
+ * beansMap.
+ * @return true if the Method is declared in one of the
+ * configured interfaces, otherwise false.
+ */
+ protected boolean includeWriteAttribute(Method method, String beanKey) {
+ return isPublicInInterface(method, beanKey);
+ }
+
+ /**
+ * Check to see if the Method is declared in
+ * one of the configured interfaces and that it is public.
+ * @param method the operation Method.
+ * @param beanKey the key associated with the MBean in the
+ * beansMap.
+ * @return true if the Method is declared in one of the
+ * configured interfaces, otherwise false.
+ */
+ protected boolean includeOperation(Method method, String beanKey) {
+ return isPublicInInterface(method, beanKey);
+ }
+
+ /**
+ * Check to see if the Method is both public and declared in
+ * one of the configured interfaces.
+ * @param method the Method to check.
+ * @param beanKey the key associated with the MBean in the beans map
+ * @return true if the Method is declared in one of the
+ * configured interfaces and is public, otherwise false.
+ */
+ private boolean isPublicInInterface(Method method, String beanKey) {
+ return ((method.getModifiers() & Modifier.PUBLIC) > 0) && isDeclaredInInterface(method, beanKey);
+ }
+
+ /**
+ * Checks to see if the given method is declared in a managed
+ * interface for the given bean.
+ */
+ private boolean isDeclaredInInterface(Method method, String beanKey) {
+ Class[] ifaces = null;
+
+ if (this.resolvedInterfaceMappings != null) {
+ ifaces = (Class[]) this.resolvedInterfaceMappings.get(beanKey);
+ }
+
+ if (ifaces == null) {
+ ifaces = this.managedInterfaces;
+ if (ifaces == null) {
+ ifaces = ClassUtils.getAllInterfacesForClass(method.getDeclaringClass());
+ }
+ }
+
+ if (ifaces != null) {
+ for (int i = 0; i < ifaces.length; i++) {
+ Method[] methods = ifaces[i].getMethods();
+ for (int j = 0; j < methods.length; j++) {
+ Method ifaceMethod = methods[j];
+ if (ifaceMethod.getName().equals(method.getName()) &&
+ Arrays.equals(ifaceMethod.getParameterTypes(), method.getParameterTypes())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/MBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.assembler;
+
+import javax.management.JMException;
+import javax.management.modelmbean.ModelMBeanInfo;
+
+/**
+ * Interface to be implemented by all classes that can
+ * create management interface metadata for a managed resource.
+ *
+ *
Used by the MBeanExporter to generate the management
+ * interface for any bean that is not an MBean.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public interface MBeanInfoAssembler {
+
+ /**
+ * Create the ModelMBeanInfo for the given managed resource.
+ * @param managedBean the bean that will be exposed (might be an AOP proxy)
+ * @param beanKey the key associated with the managed bean
+ * @return the ModelMBeanInfo metadata object
+ * @throws JMException in case of errors
+ */
+ ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MetadataMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.assembler;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+import javax.management.Descriptor;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.export.metadata.InvalidMetadataException;
+import org.springframework.jmx.export.metadata.JmxAttributeSource;
+import org.springframework.jmx.export.metadata.JmxMetadataUtils;
+import org.springframework.jmx.export.metadata.ManagedAttribute;
+import org.springframework.jmx.export.metadata.ManagedNotification;
+import org.springframework.jmx.export.metadata.ManagedOperation;
+import org.springframework.jmx.export.metadata.ManagedOperationParameter;
+import org.springframework.jmx.export.metadata.ManagedResource;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * Implementation of the {@link org.springframework.jmx.export.assembler.MBeanInfoAssembler}
+ * interface that reads the management interface information from source level metadata.
+ *
+ *
Uses the {@link JmxAttributeSource} strategy interface, so that
+ * metadata can be read using any supported implementation. Out of the box,
+ * two strategies are included:
+ *
+ *
AttributesJmxAttributeSource, for Commons Attributes
+ *
AnnotationJmxAttributeSource, for JDK 1.5+ annotations
+ *
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setAttributeSource
+ * @see org.springframework.jmx.export.metadata.AttributesJmxAttributeSource
+ * @see org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource
+ */
+public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssembler
+ implements AutodetectCapableMBeanInfoAssembler, InitializingBean {
+
+ private JmxAttributeSource attributeSource;
+
+
+ /**
+ * Create a new MetadataMBeanInfoAssembler which needs to be
+ * configured through the {@link #setAttributeSource} method.
+ */
+ public MetadataMBeanInfoAssembler() {
+ }
+
+ /**
+ * Create a new MetadataMBeanInfoAssembler for the given
+ * JmxAttributeSource.
+ * @param attributeSource the JmxAttributeSource to use
+ */
+ public MetadataMBeanInfoAssembler(JmxAttributeSource attributeSource) {
+ Assert.notNull(attributeSource, "JmxAttributeSource must not be null");
+ this.attributeSource = attributeSource;
+ }
+
+
+ /**
+ * Set the JmxAttributeSource implementation to use for
+ * reading the metadata from the bean class.
+ * @see org.springframework.jmx.export.metadata.AttributesJmxAttributeSource
+ * @see org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource
+ */
+ public void setAttributeSource(JmxAttributeSource attributeSource) {
+ Assert.notNull(attributeSource, "JmxAttributeSource must not be null");
+ this.attributeSource = attributeSource;
+ }
+
+ public void afterPropertiesSet() {
+ if (this.attributeSource == null) {
+ throw new IllegalArgumentException("Property 'attributeSource' is required");
+ }
+ }
+
+
+ /**
+ * Throws an IllegalArgumentException if it encounters a JDK dynamic proxy.
+ * Metadata can only be read from target classes and CGLIB proxies!
+ */
+ protected void checkManagedBean(Object managedBean) throws IllegalArgumentException {
+ if (AopUtils.isJdkDynamicProxy(managedBean)) {
+ throw new IllegalArgumentException(
+ "MetadataMBeanInfoAssembler does not support JDK dynamic proxies - " +
+ "export the target beans directly or use CGLIB proxies instead");
+ }
+ }
+
+ /**
+ * Used for autodetection of beans. Checks to see if the bean's class has a
+ * ManagedResource attribute. If so it will add it list of included beans.
+ * @param beanClass the class of the bean
+ * @param beanName the name of the bean in the bean factory
+ */
+ public boolean includeBean(Class beanClass, String beanName) {
+ return (this.attributeSource.getManagedResource(getClassToExpose(beanClass)) != null);
+ }
+
+ /**
+ * Vote on the inclusion of an attribute accessor.
+ * @param method the accessor method
+ * @param beanKey the key associated with the MBean in the beans map
+ * @return whether the method has the appropriate metadata
+ */
+ protected boolean includeReadAttribute(Method method, String beanKey) {
+ return hasManagedAttribute(method);
+ }
+
+ /**
+ * Votes on the inclusion of an attribute mutator.
+ * @param method the mutator method
+ * @param beanKey the key associated with the MBean in the beans map
+ * @return whether the method has the appropriate metadata
+ */
+ protected boolean includeWriteAttribute(Method method, String beanKey) {
+ return hasManagedAttribute(method);
+ }
+
+ /**
+ * Votes on the inclusion of an operation.
+ * @param method the operation method
+ * @param beanKey the key associated with the MBean in the beans map
+ * @return whether the method has the appropriate metadata
+ */
+ protected boolean includeOperation(Method method, String beanKey) {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ return hasManagedAttribute(method);
+ }
+ else {
+ return hasManagedOperation(method);
+ }
+ }
+
+ /**
+ * Checks to see if the given Method has the ManagedAttribute attribute.
+ */
+ private boolean hasManagedAttribute(Method method) {
+ return (this.attributeSource.getManagedAttribute(method) != null);
+ }
+
+ /**
+ * Checks to see if the given Method has the ManagedOperation attribute.
+ * @param method the method to check
+ */
+ private boolean hasManagedOperation(Method method) {
+ return (this.attributeSource.getManagedOperation(method) != null);
+ }
+
+
+ /**
+ * Reads managed resource description from the source level metadata.
+ * Returns an empty String if no description can be found.
+ */
+ protected String getDescription(Object managedBean, String beanKey) {
+ ManagedResource mr = this.attributeSource.getManagedResource(getClassToExpose(managedBean));
+ return (mr != null ? mr.getDescription() : "");
+ }
+
+ /**
+ * Creates a description for the attribute corresponding to this property
+ * descriptor. Attempts to create the description using metadata from either
+ * the getter or setter attributes, otherwise uses the property name.
+ */
+ protected String getAttributeDescription(PropertyDescriptor propertyDescriptor, String beanKey) {
+ Method readMethod = propertyDescriptor.getReadMethod();
+ Method writeMethod = propertyDescriptor.getWriteMethod();
+
+ ManagedAttribute getter =
+ (readMethod != null) ? this.attributeSource.getManagedAttribute(readMethod) : null;
+ ManagedAttribute setter =
+ (writeMethod != null) ? this.attributeSource.getManagedAttribute(writeMethod) : null;
+
+ if (getter != null && StringUtils.hasText(getter.getDescription())) {
+ return getter.getDescription();
+ }
+ else if (setter != null && StringUtils.hasText(setter.getDescription())) {
+ return setter.getDescription();
+ }
+ return propertyDescriptor.getDisplayName();
+ }
+
+ /**
+ * Retrieves the description for the supplied Method from the
+ * metadata. Uses the method name is no description is present in the metadata.
+ */
+ protected String getOperationDescription(Method method, String beanKey) {
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ ManagedAttribute ma = this.attributeSource.getManagedAttribute(method);
+ if (ma != null && StringUtils.hasText(ma.getDescription())) {
+ return ma.getDescription();
+ }
+ return method.getName();
+ }
+ else {
+ ManagedOperation mo = this.attributeSource.getManagedOperation(method);
+ if (mo != null && StringUtils.hasText(mo.getDescription())) {
+ return mo.getDescription();
+ }
+ return method.getName();
+ }
+ }
+
+ /**
+ * Reads MBeanParameterInfo from the ManagedOperationParameter
+ * attributes attached to a method. Returns an empty array of MBeanParameterInfo
+ * if no attributes are found.
+ */
+ protected MBeanParameterInfo[] getOperationParameters(Method method, String beanKey) {
+ ManagedOperationParameter[] params = this.attributeSource.getManagedOperationParameters(method);
+ if (params == null || params.length == 0) {
+ return new MBeanParameterInfo[0];
+ }
+
+ MBeanParameterInfo[] parameterInfo = new MBeanParameterInfo[params.length];
+ Class[] methodParameters = method.getParameterTypes();
+
+ for (int i = 0; i < params.length; i++) {
+ ManagedOperationParameter param = params[i];
+ parameterInfo[i] =
+ new MBeanParameterInfo(param.getName(), methodParameters[i].getName(), param.getDescription());
+ }
+
+ return parameterInfo;
+ }
+
+ /**
+ * Reads the {@link ManagedNotification} metadata from the Class of the managed resource
+ * and generates and returns the corresponding {@link ModelMBeanNotificationInfo} metadata.
+ */
+ protected ModelMBeanNotificationInfo[] getNotificationInfo(Object managedBean, String beanKey) {
+ ManagedNotification[] notificationAttributes =
+ this.attributeSource.getManagedNotifications(getClassToExpose(managedBean));
+ ModelMBeanNotificationInfo[] notificationInfos =
+ new ModelMBeanNotificationInfo[notificationAttributes.length];
+
+ for (int i = 0; i < notificationAttributes.length; i++) {
+ ManagedNotification attribute = notificationAttributes[i];
+ notificationInfos[i] = JmxMetadataUtils.convertToModelMBeanNotificationInfo(attribute);
+ }
+
+ return notificationInfos;
+ }
+
+ /**
+ * Adds descriptor fields from the ManagedResource attribute
+ * to the MBean descriptor. Specifically, adds the currencyTimeLimit,
+ * persistPolicy, persistPeriod, persistLocation
+ * and persistName descriptor fields if they are present in the metadata.
+ */
+ protected void populateMBeanDescriptor(Descriptor desc, Object managedBean, String beanKey) {
+ ManagedResource mr = this.attributeSource.getManagedResource(getClassToExpose(managedBean));
+ if (mr == null) {
+ throw new InvalidMetadataException(
+ "No ManagedResource attribute found for class: " + getClassToExpose(managedBean));
+ }
+
+ applyCurrencyTimeLimit(desc, mr.getCurrencyTimeLimit());
+
+ if (mr.isLog()) {
+ desc.setField(FIELD_LOG, "true");
+ }
+ if (StringUtils.hasLength(mr.getLogFile())) {
+ desc.setField(FIELD_LOG_FILE, mr.getLogFile());
+ }
+
+ if (StringUtils.hasLength(mr.getPersistPolicy())) {
+ desc.setField(FIELD_PERSIST_POLICY, mr.getPersistPolicy());
+ }
+ if (mr.getPersistPeriod() >= 0) {
+ desc.setField(FIELD_PERSIST_PERIOD, Integer.toString(mr.getPersistPeriod()));
+ }
+ if (StringUtils.hasLength(mr.getPersistName())) {
+ desc.setField(FIELD_PERSIST_NAME, mr.getPersistName());
+ }
+ if (StringUtils.hasLength(mr.getPersistLocation())) {
+ desc.setField(FIELD_PERSIST_LOCATION, mr.getPersistLocation());
+ }
+ }
+
+ /**
+ * Adds descriptor fields from the ManagedAttribute attribute
+ * to the attribute descriptor. Specifically, adds the currencyTimeLimit,
+ * default, persistPolicy and persistPeriod
+ * descriptor fields if they are present in the metadata.
+ */
+ protected void populateAttributeDescriptor(Descriptor desc, Method getter, Method setter, String beanKey) {
+ ManagedAttribute gma =
+ (getter == null) ? ManagedAttribute.EMPTY : this.attributeSource.getManagedAttribute(getter);
+ ManagedAttribute sma =
+ (setter == null) ? ManagedAttribute.EMPTY : this.attributeSource.getManagedAttribute(setter);
+
+ applyCurrencyTimeLimit(desc, resolveIntDescriptor(gma.getCurrencyTimeLimit(), sma.getCurrencyTimeLimit()));
+
+ Object defaultValue = resolveObjectDescriptor(gma.getDefaultValue(), sma.getDefaultValue());
+ desc.setField(FIELD_DEFAULT, defaultValue);
+
+ String persistPolicy = resolveStringDescriptor(gma.getPersistPolicy(), sma.getPersistPolicy());
+ if (StringUtils.hasLength(persistPolicy)) {
+ desc.setField(FIELD_PERSIST_POLICY, persistPolicy);
+ }
+ int persistPeriod = resolveIntDescriptor(gma.getPersistPeriod(), sma.getPersistPeriod());
+ if (persistPeriod >= 0) {
+ desc.setField(FIELD_PERSIST_PERIOD, Integer.toString(persistPeriod));
+ }
+ }
+
+ /**
+ * Adds descriptor fields from the ManagedAttribute attribute
+ * to the attribute descriptor. Specifically, adds the currencyTimeLimit
+ * descriptor field if it is present in the metadata.
+ */
+ protected void populateOperationDescriptor(Descriptor desc, Method method, String beanKey) {
+ ManagedOperation mo = this.attributeSource.getManagedOperation(method);
+ if (mo != null) {
+ applyCurrencyTimeLimit(desc, mo.getCurrencyTimeLimit());
+ }
+ }
+
+ /**
+ * Determines which of two int values should be used as the value
+ * for an attribute descriptor. In general, only the getter or the setter will
+ * be have a non-negative value so we use that value. In the event that both values
+ * are non-negative, we use the greater of the two. This method can be used to
+ * resolve any int valued descriptor where there are two possible values.
+ * @param getter the int value associated with the getter for this attribute
+ * @param setter the int associated with the setter for this attribute
+ */
+ private int resolveIntDescriptor(int getter, int setter) {
+ return (getter >= setter ? getter : setter);
+ }
+
+ /**
+ * Locates the value of a descriptor based on values attached
+ * to both the getter and setter methods. If both have values
+ * supplied then the value attached to the getter is preferred.
+ * @param getter the Object value associated with the get method
+ * @param setter the Object value associated with the set method
+ * @return the appropriate Object to use as the value for the descriptor
+ */
+ private Object resolveObjectDescriptor(Object getter, Object setter) {
+ return (getter != null ? getter : setter);
+ }
+
+ /**
+ * Locates the value of a descriptor based on values attached
+ * to both the getter and setter methods. If both have values
+ * supplied then the value attached to the getter is preferred.
+ * The supplied default value is used to check to see if the value
+ * associated with the getter has changed from the default.
+ * @param getter the String value associated with the get method
+ * @param setter the String value associated with the set method
+ * @return the appropriate String to use as the value for the descriptor
+ */
+ private String resolveStringDescriptor(String getter, String setter) {
+ return (StringUtils.hasLength(getter) ? getter : setter);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodExclusionMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.assembler;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * AbstractReflectiveMBeanInfoAssembler subclass that allows
+ * method names to be explicitly excluded as MBean operations and attributes.
+ *
+ *
Any method not explicitly excluded from the management interface will be exposed to
+ * JMX. JavaBean getters and setters will automatically be exposed as JMX attributes.
+ *
+ *
You can supply an array of method names via the ignoredMethods
+ * property. If you have multiple beans and you wish each bean to use a different
+ * set of method names, then you can map bean keys (that is the name used to pass
+ * the bean to the MBeanExporter) to a list of method names using the
+ * ignoredMethodMappings property.
+ *
+ *
If you specify values for both ignoredMethodMappings and
+ * ignoredMethods, Spring will attempt to find method names in the
+ * mappings first. If no method names for the bean are found, it will use the
+ * method names defined by ignoredMethods.
+ *
+ * @author Rob Harrop
+ * @author Seth Ladd
+ * @since 1.2.5
+ * @see #setIgnoredMethods
+ * @see #setIgnoredMethodMappings
+ * @see InterfaceBasedMBeanInfoAssembler
+ * @see SimpleReflectiveMBeanInfoAssembler
+ * @see MethodNameBasedMBeanInfoAssembler
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class MethodExclusionMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler {
+
+ private Set ignoredMethods;
+
+ private Map ignoredMethodMappings;
+
+
+ /**
+ * Set the array of method names to be ignored when creating the management info.
+ *
These method names will be used for a bean if no entry corresponding to
+ * that bean is found in the ignoredMethodsMappings property.
+ * @see #setIgnoredMethodMappings(java.util.Properties)
+ */
+ public void setIgnoredMethods(String[] ignoredMethodNames) {
+ this.ignoredMethods = new HashSet(Arrays.asList(ignoredMethodNames));
+ }
+
+ /**
+ * Set the mappings of bean keys to a comma-separated list of method names.
+ *
These method names are ignored when creating the management interface.
+ *
The property key must match the bean key and the property value must match
+ * the list of method names. When searching for method names to ignore for a bean,
+ * Spring will check these mappings first.
+ */
+ public void setIgnoredMethodMappings(Properties mappings) {
+ this.ignoredMethodMappings = new HashMap();
+ for (Enumeration en = mappings.keys(); en.hasMoreElements();) {
+ String beanKey = (String) en.nextElement();
+ String[] methodNames = StringUtils.commaDelimitedListToStringArray(mappings.getProperty(beanKey));
+ this.ignoredMethodMappings.put(beanKey, new HashSet(Arrays.asList(methodNames)));
+ }
+ }
+
+
+ protected boolean includeReadAttribute(Method method, String beanKey) {
+ return isNotIgnored(method, beanKey);
+ }
+
+ protected boolean includeWriteAttribute(Method method, String beanKey) {
+ return isNotIgnored(method, beanKey);
+ }
+
+ protected boolean includeOperation(Method method, String beanKey) {
+ return isNotIgnored(method, beanKey);
+ }
+
+ /**
+ * Determine whether the given method is supposed to be included,
+ * that is, not configured as to be ignored.
+ * @param method the operation method
+ * @param beanKey the key associated with the MBean in the beans map
+ * of the MBeanExporter
+ */
+ protected boolean isNotIgnored(Method method, String beanKey) {
+ if (this.ignoredMethodMappings != null) {
+ Set methodNames = (Set) this.ignoredMethodMappings.get(beanKey);
+ if (methodNames != null) {
+ return !methodNames.contains(method.getName());
+ }
+ }
+ if (this.ignoredMethods != null) {
+ return !this.ignoredMethods.contains(method.getName());
+ }
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.assembler;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Subclass of AbstractReflectiveMBeanInfoAssembler that allows
+ * to specify method names to be exposed as MBean operations and attributes.
+ * JavaBean getters and setters will automatically be exposed as JMX attributes.
+ *
+ *
You can supply an array of method names via the managedMethods
+ * property. If you have multiple beans and you wish each bean to use a different
+ * set of method names, then you can map bean keys (that is the name used to pass
+ * the bean to the MBeanExporter) to a list of method names using the
+ * methodMappings property.
+ *
+ *
If you specify values for both methodMappings and
+ * managedMethods, Spring will attempt to find method names in the
+ * mappings first. If no method names for the bean are found, it will use the
+ * method names defined by managedMethods.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setManagedMethods
+ * @see #setMethodMappings
+ * @see InterfaceBasedMBeanInfoAssembler
+ * @see SimpleReflectiveMBeanInfoAssembler
+ * @see MethodExclusionMBeanInfoAssembler
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class MethodNameBasedMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler {
+
+ /**
+ * Stores the set of method names to use for creating the management interface.
+ */
+ private Set managedMethods;
+
+ /**
+ * Stores the mappings of bean keys to an array of method names.
+ */
+ private Map methodMappings;
+
+
+ /**
+ * Set the array of method names to use for creating the management info.
+ * These method names will be used for a bean if no entry corresponding to
+ * that bean is found in the methodMappings property.
+ * @param methodNames an array of method names indicating the methods to use
+ * @see #setMethodMappings
+ */
+ public void setManagedMethods(String[] methodNames) {
+ this.managedMethods = new HashSet(Arrays.asList(methodNames));
+ }
+
+ /**
+ * Set the mappings of bean keys to a comma-separated list of method names.
+ * The property key should match the bean key and the property value should match
+ * the list of method names. When searching for method names for a bean, Spring
+ * will check these mappings first.
+ * @param mappings the mappins of bean keys to method names
+ */
+ public void setMethodMappings(Properties mappings) {
+ this.methodMappings = new HashMap();
+ for (Enumeration en = mappings.keys(); en.hasMoreElements();) {
+ String beanKey = (String) en.nextElement();
+ String[] methodNames = StringUtils.commaDelimitedListToStringArray(mappings.getProperty(beanKey));
+ this.methodMappings.put(beanKey, new HashSet(Arrays.asList(methodNames)));
+ }
+ }
+
+
+ protected boolean includeReadAttribute(Method method, String beanKey) {
+ return isMatch(method, beanKey);
+ }
+
+ protected boolean includeWriteAttribute(Method method, String beanKey) {
+ return isMatch(method, beanKey);
+ }
+
+ protected boolean includeOperation(Method method, String beanKey) {
+ return isMatch(method, beanKey);
+ }
+
+ protected boolean isMatch(Method method, String beanKey) {
+ if (this.methodMappings != null) {
+ Set methodNames = (Set) this.methodMappings.get(beanKey);
+ if (methodNames != null) {
+ return methodNames.contains(method.getName());
+ }
+ }
+ return (this.managedMethods != null && this.managedMethods.contains(method.getName()));
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/SimpleReflectiveMBeanInfoAssembler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/SimpleReflectiveMBeanInfoAssembler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/SimpleReflectiveMBeanInfoAssembler.java 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.assembler;
+
+import java.lang.reflect.Method;
+
+/**
+ * Simple subclass of AbstractReflectiveMBeanInfoAssembler
+ * that always votes yes for method and property inclusion, effectively exposing
+ * all public methods and properties as operations and attributes.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ */
+public class SimpleReflectiveMBeanInfoAssembler extends AbstractConfigurableMBeanInfoAssembler {
+
+ /**
+ * Always returns true.
+ */
+ protected boolean includeReadAttribute(Method method, String beanKey) {
+ return true;
+ }
+
+ /**
+ * Always returns true.
+ */
+ protected boolean includeWriteAttribute(Method method, String beanKey) {
+ return true;
+ }
+
+ /**
+ * Always returns true.
+ */
+ protected boolean includeOperation(Method method, String beanKey) {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/assembler/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/assembler/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/assembler/package.html 17 Aug 2012 15:15:29 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides a strategy for MBeanInfo assembly. Used by MBeanExporter to
+determine the attributes and operations to expose for Spring-managed beans.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/AbstractJmxAttribute.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/AbstractJmxAttribute.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/AbstractJmxAttribute.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.metadata;
+
+/**
+ * Base class for all JMX metadata classes.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ */
+public class AbstractJmxAttribute {
+
+ private String description = "";
+
+ private int currencyTimeLimit = -1;
+
+
+ /**
+ * Set a description for this attribute.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Return a description for this attribute.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Set a currency time limit for this attribute.
+ */
+ public void setCurrencyTimeLimit(int currencyTimeLimit) {
+ this.currencyTimeLimit = currencyTimeLimit;
+ }
+
+ /**
+ * Return a currency time limit for this attribute.
+ */
+ public int getCurrencyTimeLimit() {
+ return this.currencyTimeLimit;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/AttributesJmxAttributeSource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/AttributesJmxAttributeSource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/AttributesJmxAttributeSource.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.metadata;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.metadata.Attributes;
+import org.springframework.util.Assert;
+
+/**
+ * Implementation of the JmxAttributeSource interface that
+ * reads metadata via Spring's Attributes abstraction.
+ *
+ *
Typically used for reading in source-level attributes via
+ * Commons Attributes.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.metadata.Attributes
+ * @see org.springframework.metadata.commons.CommonsAttributes
+ */
+public class AttributesJmxAttributeSource implements JmxAttributeSource, InitializingBean {
+
+ /**
+ * Underlying Attributes implementation that we're using.
+ */
+ private Attributes attributes;
+
+
+ /**
+ * Create a new AttributesJmxAttributeSource.
+ * @see #setAttributes
+ */
+ public AttributesJmxAttributeSource() {
+ }
+
+ /**
+ * Create a new AttributesJmxAttributeSource.
+ * @param attributes the Attributes implementation to use
+ * @see org.springframework.metadata.commons.CommonsAttributes
+ */
+ public AttributesJmxAttributeSource(Attributes attributes) {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Attributes is required");
+ }
+ this.attributes = attributes;
+ }
+
+ /**
+ * Set the Attributes implementation to use.
+ * @see org.springframework.metadata.commons.CommonsAttributes
+ */
+ public void setAttributes(Attributes attributes) {
+ this.attributes = attributes;
+ }
+
+ public void afterPropertiesSet() {
+ if (this.attributes == null) {
+ throw new IllegalArgumentException("'attributes' is required");
+ }
+ }
+
+
+ /**
+ * If the specified class has a ManagedResource attribute,
+ * then it is returned. Otherwise returns null.
+ * @param clazz the class to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException if more than one attribute exists
+ */
+ public ManagedResource getManagedResource(Class clazz) {
+ Assert.notNull(this.attributes, "'attributes' is required");
+ Collection attrs = this.attributes.getAttributes(clazz, ManagedResource.class);
+ if (attrs.isEmpty()) {
+ return null;
+ }
+ else if (attrs.size() == 1) {
+ return (ManagedResource) attrs.iterator().next();
+ }
+ else {
+ throw new InvalidMetadataException("A Class can have only one ManagedResource attribute");
+ }
+ }
+
+ /**
+ * If the specified method has a ManagedAttribute attribute,
+ * then it is returned. Otherwise returns null.
+ * @param method the method to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException if more than one attribute exists,
+ * or if the supplied method does not represent a JavaBean property
+ */
+ public ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
+ Assert.notNull(this.attributes, "'attributes' is required");
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd == null) {
+ throw new InvalidMetadataException(
+ "The ManagedAttribute attribute is only valid for JavaBean properties: " +
+ "use ManagedOperation for methods");
+ }
+ Collection attrs = this.attributes.getAttributes(method, ManagedAttribute.class);
+ if (attrs.isEmpty()) {
+ return null;
+ }
+ else if (attrs.size() == 1) {
+ return (ManagedAttribute) attrs.iterator().next();
+ }
+ else {
+ throw new InvalidMetadataException("A Method can have only one ManagedAttribute attribute");
+ }
+ }
+
+ /**
+ * If the specified method has a ManagedOperation attribute,
+ * then it is returned. Otherwise return null.
+ * @param method the method to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException if more than one attribute exists,
+ * or if the supplied method represents a JavaBean property
+ */
+ public ManagedOperation getManagedOperation(Method method) {
+ Assert.notNull(this.attributes, "'attributes' is required");
+ PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
+ if (pd != null) {
+ throw new InvalidMetadataException(
+ "The ManagedOperation attribute is not valid for JavaBean properties: " +
+ "use ManagedAttribute instead");
+ }
+ Collection attrs = this.attributes.getAttributes(method, ManagedOperation.class);
+ if (attrs.isEmpty()) {
+ return null;
+ }
+ else if (attrs.size() == 1) {
+ return (ManagedOperation) attrs.iterator().next();
+ }
+ else {
+ throw new InvalidMetadataException("A Method can have only one ManagedAttribute attribute");
+ }
+ }
+
+ /**
+ * If the specified method has ManagedOperationParameter attributes,
+ * then these are returned, otherwise a zero length array is returned.
+ * @param method the method to get the managed operation parameters for
+ * @return the array of ManagedOperationParameter objects
+ * @throws InvalidMetadataException if the number of ManagedOperationParameter
+ * attributes does not match the number of parameters in the method
+ */
+ public ManagedOperationParameter[] getManagedOperationParameters(Method method)
+ throws InvalidMetadataException {
+
+ Assert.notNull(this.attributes, "'attributes' is required");
+ Collection attrs = this.attributes.getAttributes(method, ManagedOperationParameter.class);
+ if (attrs.size() == 0) {
+ return new ManagedOperationParameter[0];
+ }
+ else if (attrs.size() != method.getParameterTypes().length) {
+ throw new InvalidMetadataException(
+ "Method [" + method + "] has an incorrect number of ManagedOperationParameters specified");
+ }
+ else {
+ ManagedOperationParameter[] params = new ManagedOperationParameter[attrs.size()];
+ for (Iterator it = attrs.iterator(); it.hasNext();) {
+ ManagedOperationParameter param = (ManagedOperationParameter) it.next();
+ if (param.getIndex() < 0 || param.getIndex() >= params.length) {
+ throw new InvalidMetadataException(
+ "ManagedOperationParameter index for [" + param.getName() + "] is out of bounds");
+ }
+ params[param.getIndex()] = param;
+ }
+ return params;
+ }
+ }
+
+ /**
+ * If the specified has {@link ManagedNotification} attributes these are returned, otherwise
+ * a zero-length array is returned.
+ */
+ public ManagedNotification[] getManagedNotifications(Class clazz) {
+ Assert.notNull(this.attributes, "'attributes' is required");
+ Collection attrs = this.attributes.getAttributes(clazz, ManagedNotification.class);
+ return attrs.isEmpty() ? new ManagedNotification[0] : (ManagedNotification[]) attrs.toArray(new ManagedNotification[attrs.size()]);
+ }
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/InvalidMetadataException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/InvalidMetadataException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/InvalidMetadataException.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.metadata;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Thrown by the JmxAttributeSource when it encounters
+ * incorrect metadata on a managed resource or one of its methods.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see JmxAttributeSource
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
+ */
+public class InvalidMetadataException extends JmxException {
+
+ /**
+ * Create a new InvalidMetadataException with the supplied
+ * error message.
+ * @param msg the detail message
+ */
+ public InvalidMetadataException(String msg) {
+ super(msg);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxAttributeSource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxAttributeSource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxAttributeSource.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.metadata;
+
+import java.lang.reflect.Method;
+
+/**
+ * Interface used by the MetadataMBeanInfoAssembler to
+ * read source-level metadata from a managed resource's class.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler#setAttributeSource
+ * @see org.springframework.jmx.export.MBeanExporter#setAssembler
+ */
+public interface JmxAttributeSource {
+
+ /**
+ * Implementations should return an instance of ManagedResource
+ * if the supplied Class has the appropriate metadata.
+ * Otherwise should return null.
+ * @param clazz the class to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException in case of invalid attributes
+ */
+ ManagedResource getManagedResource(Class clazz) throws InvalidMetadataException;
+
+ /**
+ * Implementations should return an instance of ManagedAttribute
+ * if the supplied Method has the corresponding metadata.
+ * Otherwise should return null.
+ * @param method the method to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException in case of invalid attributes
+ */
+ ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException;
+
+ /**
+ * Implementations should return an instance of ManagedOperation
+ * if the supplied Method has the corresponding metadata.
+ * Otherwise should return null.
+ * @param method the method to read the attribute data from
+ * @return the attribute, or null if not found
+ * @throws InvalidMetadataException in case of invalid attributes
+ */
+ ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException;
+
+ /**
+ * Implementations should return an array of ManagedOperationParameter
+ * if the supplied Method has the corresponding metadata. Otherwise
+ * should return an empty array if no metadata is found.
+ * @param method the Method to read the metadata from
+ * @return the parameter information.
+ * @throws InvalidMetadataException in the case of invalid attributes.
+ */
+ ManagedOperationParameter[] getManagedOperationParameters(Method method) throws InvalidMetadataException;
+
+ /**
+ * Implementations should return an array of {@link ManagedNotification ManagedNotifications}
+ * if the supplied the Class has the corresponding metadata. Otherwise
+ * should return an empty array.
+ * @param clazz the Class to read the metadata from
+ * @return the notification information
+ * @throws InvalidMetadataException in the case of invalid metadata
+ */
+ ManagedNotification[] getManagedNotifications(Class clazz) throws InvalidMetadataException;
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxMetadataUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxMetadataUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/JmxMetadataUtils.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.metadata;
+
+import javax.management.modelmbean.ModelMBeanNotificationInfo;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Utility methods for converting Spring JMX metadata into their plain JMX equivalents.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public abstract class JmxMetadataUtils {
+
+ /**
+ * Convert the supplied {@link ManagedNotification} into the corresponding
+ * {@link javax.management.modelmbean.ModelMBeanNotificationInfo}.
+ */
+ public static ModelMBeanNotificationInfo convertToModelMBeanNotificationInfo(ManagedNotification notificationInfo) {
+ String name = notificationInfo.getName();
+ if (!StringUtils.hasText(name)) {
+ throw new IllegalArgumentException("Must specify notification name");
+ }
+
+ String[] notifTypes = notificationInfo.getNotificationTypes();
+ if (notifTypes == null || notifTypes.length == 0) {
+ throw new IllegalArgumentException("Must specify at least one notification type");
+ }
+
+ String description = notificationInfo.getDescription();
+ return new ModelMBeanNotificationInfo(notifTypes, name, description);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedAttribute.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedAttribute.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedAttribute.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.metadata;
+
+/**
+ * Metadata that indicates to expose a given bean property as JMX attribute.
+ * Only valid when used on a JavaBean getter or setter.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class ManagedAttribute extends AbstractJmxAttribute {
+
+ public static final ManagedAttribute EMPTY = new ManagedAttribute();
+
+
+ private Object defaultValue;
+
+ private String persistPolicy;
+
+ private int persistPeriod = -1;
+
+
+ /**
+ * Set the default value of this attribute.
+ */
+ public void setDefaultValue(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Return the default value of this attribute.
+ */
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ public void setPersistPolicy(String persistPolicy) {
+ this.persistPolicy = persistPolicy;
+ }
+
+ public String getPersistPolicy() {
+ return this.persistPolicy;
+ }
+
+ public void setPersistPeriod(int persistPeriod) {
+ this.persistPeriod = persistPeriod;
+ }
+
+ public int getPersistPeriod() {
+ return this.persistPeriod;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedNotification.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedNotification.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedNotification.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.metadata;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Metadata that indicates a JMX notification emitted by a bean.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ */
+public class ManagedNotification {
+
+ private String[] notificationTypes;
+
+ private String name;
+
+ private String description;
+
+
+ /**
+ * Set a single notification type, or a list of notification types
+ * as comma-delimited String.
+ */
+ public void setNotificationType(String notificationType) {
+ this.notificationTypes = StringUtils.commaDelimitedListToStringArray(notificationType);
+ }
+
+ /**
+ * Set a list of notification types.
+ */
+ public void setNotificationTypes(String[] notificationTypes) {
+ this.notificationTypes = notificationTypes;
+ }
+
+ /**
+ * Return the list of notification types.
+ */
+ public String[] getNotificationTypes() {
+ return this.notificationTypes;
+ }
+
+ /**
+ * Set the name of this notification.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the name of this notification.
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Set a description for this notification.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Return a description for this notification.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperation.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperation.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperation.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.metadata;
+
+/**
+ * Metadata that indicates to expose a given method as JMX operation.
+ * Only valid when used on a method that is not a JavaBean getter or setter.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class ManagedOperation extends AbstractJmxAttribute {
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperationParameter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperationParameter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedOperationParameter.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.metadata;
+
+/**
+ * Metadata about JMX operation parameters.
+ * Used in conjunction with a {@link ManagedOperation} attribute.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ */
+public class ManagedOperationParameter {
+
+ private int index = 0;
+
+ private String name = "";
+
+ private String description = "";
+
+
+ /**
+ * Set the index of this parameter in the operation signature.
+ */
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ /**
+ * Return the index of this parameter in the operation signature.
+ */
+ public int getIndex() {
+ return this.index;
+ }
+
+ /**
+ * Set the name of this parameter in the operation signature.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return the name of this parameter in the operation signature.
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Set a description for this parameter.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Return a description for this parameter.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedResource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedResource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/ManagedResource.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.metadata;
+
+/**
+ * Metadata indicating that instances of an annotated class
+ * are to be registered with a JMX server.
+ * Only valid when used on a Class.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
+ * @see org.springframework.jmx.export.naming.MetadataNamingStrategy
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class ManagedResource extends AbstractJmxAttribute {
+
+ private String objectName;
+
+ private boolean log = false;
+
+ private String logFile;
+
+ private String persistPolicy;
+
+ private int persistPeriod = -1;
+
+ private String persistName;
+
+ private String persistLocation;
+
+
+ /**
+ * Set the JMX ObjectName of this managed resource.
+ */
+ public void setObjectName(String objectName) {
+ this.objectName = objectName;
+ }
+
+ /**
+ * Return the JMX ObjectName of this managed resource.
+ */
+ public String getObjectName() {
+ return this.objectName;
+ }
+
+ public void setLog(boolean log) {
+ this.log = log;
+ }
+
+ public boolean isLog() {
+ return this.log;
+ }
+
+ public void setLogFile(String logFile) {
+ this.logFile = logFile;
+ }
+
+ public String getLogFile() {
+ return this.logFile;
+ }
+
+ public void setPersistPolicy(String persistPolicy) {
+ this.persistPolicy = persistPolicy;
+ }
+
+ public String getPersistPolicy() {
+ return this.persistPolicy;
+ }
+
+ public void setPersistPeriod(int persistPeriod) {
+ this.persistPeriod = persistPeriod;
+ }
+
+ public int getPersistPeriod() {
+ return this.persistPeriod;
+ }
+
+ public void setPersistName(String persistName) {
+ this.persistName = persistName;
+ }
+
+ public String getPersistName() {
+ return this.persistName;
+ }
+
+ public void setPersistLocation(String persistLocation) {
+ this.persistLocation = persistLocation;
+ }
+
+ public String getPersistLocation() {
+ return this.persistLocation;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/metadata/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/metadata/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/metadata/package.html 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides generic JMX metadata classes and basic support for reading
+JMX metadata in a provider-agnostic manner.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/IdentityNamingStrategy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/IdentityNamingStrategy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/IdentityNamingStrategy.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.naming;
+
+import java.util.Hashtable;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.jmx.support.ObjectNameManager;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * An implementation of the ObjectNamingStrategy interface that
+ * creates a name based on the the identity of a given instance.
+ *
+ *
The resulting ObjectName will be in the form
+ * package:class=class name,hashCode=identity hash (in hex)
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ */
+public class IdentityNamingStrategy implements ObjectNamingStrategy {
+
+ public static final String TYPE_KEY = "type";
+
+ public static final String HASH_CODE_KEY = "hashCode";
+
+
+ /**
+ * Returns an instance of ObjectName based on the identity
+ * of the managed resource.
+ */
+ public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
+ String domain = ClassUtils.getPackageName(managedBean.getClass());
+ Hashtable keys = new Hashtable();
+ keys.put(TYPE_KEY, ClassUtils.getShortName(managedBean.getClass()));
+ keys.put(HASH_CODE_KEY, ObjectUtils.getIdentityHexString(managedBean));
+ return ObjectNameManager.getInstance(domain, keys);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/KeyNamingStrategy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/KeyNamingStrategy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/KeyNamingStrategy.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.naming;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+import org.springframework.jmx.support.ObjectNameManager;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * ObjectNamingStrategy implementation that builds
+ * ObjectName instances from the key used in the
+ * "beans" map passed to MBeanExporter.
+ *
+ *
Can also check object name mappings, given as Properties
+ * or as mappingLocations of properties files. The key used
+ * to look up is the key used in MBeanExporter's "beans" map.
+ * If no mapping is found for a given key, the key itself is used to
+ * build an ObjectName.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setMappings
+ * @see #setMappingLocation
+ * @see #setMappingLocations
+ * @see org.springframework.jmx.export.MBeanExporter#setBeans
+ */
+public class KeyNamingStrategy implements ObjectNamingStrategy, InitializingBean {
+
+ /**
+ * Log instance for this class.
+ */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ /**
+ * Stores the mappings of bean key to ObjectName.
+ */
+ private Properties mappings;
+
+ /**
+ * Stores the Resources containing properties that should be loaded
+ * into the final merged set of Properties used for ObjectName
+ * resolution.
+ */
+ private Resource[] mappingLocations;
+
+ /**
+ * Stores the result of merging the mappingsProperties
+ * with the the properties stored in the resources defined by mappingLocations.
+ */
+ private Properties mergedMappings;
+
+
+ /**
+ * Set local properties, containing object name mappings, e.g. via
+ * the "props" tag in XML bean definitions. These can be considered
+ * defaults, to be overridden by properties loaded from files.
+ */
+ public void setMappings(Properties mappings) {
+ this.mappings = mappings;
+ }
+
+ /**
+ * Set a location of a properties file to be loaded,
+ * containing object name mappings.
+ */
+ public void setMappingLocation(Resource location) {
+ this.mappingLocations = new Resource[]{location};
+ }
+
+ /**
+ * Set location of properties files to be loaded,
+ * containing object name mappings.
+ */
+ public void setMappingLocations(Resource[] mappingLocations) {
+ this.mappingLocations = mappingLocations;
+ }
+
+
+ /**
+ * Merges the Properties configured in the mappings and
+ * mappingLocations into the final Properties instance
+ * used for ObjectName resolution.
+ * @throws IOException
+ */
+ public void afterPropertiesSet() throws IOException {
+ this.mergedMappings = new Properties();
+
+ CollectionUtils.mergePropertiesIntoMap(this.mappings, this.mergedMappings);
+
+ if (this.mappingLocations != null) {
+ for (int i = 0; i < this.mappingLocations.length; i++) {
+ Resource location = this.mappingLocations[i];
+ if (logger.isInfoEnabled()) {
+ logger.info("Loading JMX object name mappings file from " + location);
+ }
+ PropertiesLoaderUtils.fillProperties(this.mergedMappings, location);
+ }
+ }
+ }
+
+
+ /**
+ * Attempts to retrieve the ObjectName via the given key, trying to
+ * find a mapped value in the mappings first.
+ */
+ public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
+ String objectName = null;
+ if (this.mergedMappings != null) {
+ objectName = this.mergedMappings.getProperty(beanKey);
+ }
+ if (objectName == null) {
+ objectName = beanKey;
+ }
+ return ObjectNameManager.getInstance(objectName);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/MetadataNamingStrategy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/MetadataNamingStrategy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/MetadataNamingStrategy.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.naming;
+
+import java.util.Hashtable;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.export.metadata.JmxAttributeSource;
+import org.springframework.jmx.export.metadata.ManagedResource;
+import org.springframework.jmx.support.ObjectNameManager;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * An implementation of the {@link ObjectNamingStrategy} interface
+ * that reads the ObjectName from the source-level metadata.
+ * Falls back to the bean key (bean name) if no ObjectName
+ * can be found in source-level metadata.
+ *
+ *
Uses the {@link JmxAttributeSource} strategy interface, so that
+ * metadata can be read using any supported implementation. Out of the box,
+ * two strategies are included:
+ *
+ *
AttributesJmxAttributeSource, for Commons Attributes
+ *
AnnotationJmxAttributeSource, for JDK 1.5+ annotations
+ *
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see ObjectNamingStrategy
+ */
+public class MetadataNamingStrategy implements ObjectNamingStrategy, InitializingBean {
+
+ /**
+ * The JmxAttributeSource implementation to use for reading metadata.
+ */
+ private JmxAttributeSource attributeSource;
+
+ private String defaultDomain;
+
+
+ /**
+ * Create a new MetadataNamingStrategy which needs to be
+ * configured through the {@link #setAttributeSource} method.
+ */
+ public MetadataNamingStrategy() {
+ }
+
+ /**
+ * Create a new MetadataNamingStrategy for the given
+ * JmxAttributeSource.
+ * @param attributeSource the JmxAttributeSource to use
+ */
+ public MetadataNamingStrategy(JmxAttributeSource attributeSource) {
+ Assert.notNull(attributeSource, "JmxAttributeSource must not be null");
+ this.attributeSource = attributeSource;
+ }
+
+
+ /**
+ * Set the implementation of the JmxAttributeSource interface to use
+ * when reading the source-level metadata.
+ */
+ public void setAttributeSource(JmxAttributeSource attributeSource) {
+ Assert.notNull(attributeSource, "JmxAttributeSource must not be null");
+ this.attributeSource = attributeSource;
+ }
+
+ /**
+ * Specify the default domain to be used for generating ObjectNames
+ * when no source-level metadata has been specified.
+ *
The default is to use the domain specified in the bean name
+ * (if the bean name follows the JMX ObjectName syntax); else,
+ * the package name of the managed bean class.
+ */
+ public void setDefaultDomain(String defaultDomain) {
+ this.defaultDomain = defaultDomain;
+ }
+
+ public void afterPropertiesSet() {
+ if (this.attributeSource == null) {
+ throw new IllegalArgumentException("Property 'attributeSource' is required");
+ }
+ }
+
+
+ /**
+ * Reads the ObjectName from the source-level metadata associated
+ * with the managed resource's Class.
+ */
+ public ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException {
+ Class managedClass = AopUtils.getTargetClass(managedBean);
+ ManagedResource mr = this.attributeSource.getManagedResource(managedClass);
+
+ // Check that an object name has been specified.
+ if (mr != null && StringUtils.hasText(mr.getObjectName())) {
+ return ObjectNameManager.getInstance(mr.getObjectName());
+ }
+ else {
+ try {
+ return ObjectNameManager.getInstance(beanKey);
+ }
+ catch (MalformedObjectNameException ex) {
+ String domain = this.defaultDomain;
+ if (domain == null) {
+ domain = ClassUtils.getPackageName(managedClass);
+ }
+ Hashtable properties = new Hashtable();
+ properties.put("type", ClassUtils.getShortName(managedClass));
+ properties.put("name", beanKey);
+ return ObjectNameManager.getInstance(domain, properties);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/ObjectNamingStrategy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/ObjectNamingStrategy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/ObjectNamingStrategy.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.naming;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+/**
+ * Strategy interface that encapsulates the creation of ObjectName instances.
+ *
+ *
Used by the MBeanExporter to obtain ObjectNames
+ * when registering beans.
+ *
+ * @author Rob Harrop
+ * @since 1.2
+ * @see org.springframework.jmx.export.MBeanExporter
+ * @see javax.management.ObjectName
+ */
+public interface ObjectNamingStrategy {
+
+ /**
+ * Obtain an ObjectName for the supplied bean.
+ * @param managedBean the bean that will be exposed under the
+ * returned ObjectName
+ * @param beanKey the key associated with this bean in the beans map
+ * passed to the MBeanExporter
+ * @return the ObjectName instance
+ * @throws MalformedObjectNameException if the resulting ObjectName is invalid
+ */
+ ObjectName getObjectName(Object managedBean, String beanKey) throws MalformedObjectNameException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/SelfNaming.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/SelfNaming.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/SelfNaming.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.naming;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+/**
+ * Interface that allows infrastructure components to provide their own
+ * ObjectNames to the MBeanExporter.
+ *
+ *
Note: This interface is mainly intended for internal usage.
+ *
+ * @author Rob Harrop
+ * @since 1.2.2
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public interface SelfNaming {
+
+ /**
+ * Return the ObjectName for the implementing object.
+ * @throws MalformedObjectNameException if thrown by the ObjectName constructor
+ * @see javax.management.ObjectName#ObjectName(String)
+ * @see javax.management.ObjectName#getInstance(String)
+ * @see org.springframework.jmx.support.ObjectNameManager#getInstance(String)
+ */
+ ObjectName getObjectName() throws MalformedObjectNameException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/naming/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/naming/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/naming/package.html 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides a strategy for ObjectName creation. Used by MBeanExporter
+to determine the JMX names to use for exported Spring-managed beans.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisher.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisher.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/notification/ModelMBeanNotificationPublisher.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.notification;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.MBeanException;
+import javax.management.Notification;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+import javax.management.modelmbean.ModelMBeanNotificationBroadcaster;
+
+import org.springframework.util.Assert;
+
+/**
+ * {@link NotificationPublisher} implementation that uses the infrastructure
+ * provided by the {@link ModelMBean} interface to track
+ * {@link javax.management.NotificationListener javax.management.NotificationListeners}
+ * and send {@link Notification Notifications} to those listeners.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @author Rick Evans
+ * @since 2.0
+ * @see javax.management.modelmbean.ModelMBeanNotificationBroadcaster
+ * @see NotificationPublisherAware
+ */
+public class ModelMBeanNotificationPublisher implements NotificationPublisher {
+
+ /**
+ * The {@link ModelMBean} instance wrapping the managed resource into which this
+ * NotificationPublisher will be injected.
+ */
+ private final ModelMBeanNotificationBroadcaster modelMBean;
+
+ /**
+ * The {@link ObjectName} associated with the {@link ModelMBean modelMBean}.
+ */
+ private final ObjectName objectName;
+
+ /**
+ * The managed resource associated with the {@link ModelMBean modelMBean}.
+ */
+ private final Object managedResource;
+
+
+ /**
+ * Create a new instance of the {@link ModelMBeanNotificationPublisher} class
+ * that will publish all {@link javax.management.Notification Notifications}
+ * to the supplied {@link ModelMBean}.
+ * @param modelMBean the target {@link ModelMBean}; must not be null
+ * @param objectName the {@link ObjectName} of the source {@link ModelMBean}
+ * @param managedResource the managed resource exposed by the supplied {@link ModelMBean}
+ * @throws IllegalArgumentException if any of the parameters is null
+ */
+ public ModelMBeanNotificationPublisher(
+ ModelMBeanNotificationBroadcaster modelMBean, ObjectName objectName, Object managedResource) {
+
+ Assert.notNull(modelMBean, "'modelMBean' must not be null");
+ Assert.notNull(objectName, "'objectName' must not be null");
+ Assert.notNull(managedResource, "'managedResource' must not be null");
+ this.modelMBean = modelMBean;
+ this.objectName = objectName;
+ this.managedResource = managedResource;
+ }
+
+
+ /**
+ * Send the supplied {@link Notification} using the wrapped
+ * {@link ModelMBean} instance.
+ * @param notification the {@link Notification} to be sent
+ * @throws IllegalArgumentException if the supplied notification is null
+ * @throws UnableToSendNotificationException if the supplied notification could not be sent
+ */
+ public void sendNotification(Notification notification) {
+ Assert.notNull(notification, "Notification must not be null");
+ replaceNotificationSourceIfNecessary(notification);
+ try {
+ if (notification instanceof AttributeChangeNotification) {
+ this.modelMBean.sendAttributeChangeNotification((AttributeChangeNotification) notification);
+ }
+ else {
+ this.modelMBean.sendNotification(notification);
+ }
+ }
+ catch (MBeanException ex) {
+ throw new UnableToSendNotificationException("Unable to send notification [" + notification + "]", ex);
+ }
+ }
+
+ /**
+ * From the {@link Notification javadoc}:
+ *
"It is strongly recommended that notification senders use the object name
+ * rather than a reference to the MBean object as the source."
+ * @param notification the {@link Notification} whose
+ * {@link javax.management.Notification#getSource()} might need massaging
+ */
+ private void replaceNotificationSourceIfNecessary(Notification notification) {
+ if (notification.getSource() == null || notification.getSource().equals(this.managedResource)) {
+ notification.setSource(this.objectName);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisher.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisher.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisher.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2005 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.jmx.export.notification;
+
+import javax.management.Notification;
+
+/**
+ * Simple interface allowing Spring-managed MBeans to publish JMX notifications
+ * without being aware of how those notifications are being transmitted to the
+ * {@link javax.management.MBeanServer}.
+ *
+ *
Managed resources can access a NotificationPublisher by
+ * implementing the {@link NotificationPublisherAware} interface. After a particular
+ * managed resource instance is registered with the {@link javax.management.MBeanServer},
+ * Spring will inject a NotificationPublisher instance into it if that
+ * resource implements the {@link NotificationPublisherAware} inteface.
+ *
+ *
Each managed resource instance will have a distinct instance of a
+ * NotificationPublisher implementation. This instance will keep
+ * track of all the {@link javax.management.NotificationListener NotificationListeners}
+ * registered for a particular mananaged resource.
+ *
+ *
Any existing, user-defined MBeans should use standard JMX APIs for notification
+ * publication; this interface is intended for use only by Spring-created MBeans.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see NotificationPublisherAware
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public interface NotificationPublisher {
+
+ /**
+ * Send the specified {@link javax.management.Notification} to all registered
+ * {@link javax.management.NotificationListener NotificationListeners}.
+ * Managed resources are not responsible for managing the list
+ * of registered {@link javax.management.NotificationListener NotificationListeners};
+ * that is performed automatically.
+ * @param notification the JMX Notification to send
+ * @throws UnableToSendNotificationException if sending failed
+ */
+ void sendNotification(Notification notification) throws UnableToSendNotificationException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisherAware.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisherAware.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/notification/NotificationPublisherAware.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2007 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.jmx.export.notification;
+
+/**
+ * Interface to be implemented by any Spring-managed resource that is to be
+ * registered with an {@link javax.management.MBeanServer} and wishes to send
+ * JMX {@link javax.management.Notification javax.management.Notifications}.
+ *
+ *
Provides Spring-created managed resources with a {@link NotificationPublisher}
+ * as soon as they are registered with the {@link javax.management.MBeanServer}.
+ *
+ *
NOTE: This interface only applies to simple Spring-managed
+ * beans which happen to get exported through Spring's
+ * {@link org.springframework.jmx.export.MBeanExporter}.
+ * It does not apply to any non-exported beans; neither does it apply
+ * to standard MBeans exported by Spring. For standard JMX MBeans,
+ * consider implementing the {@link javax.management.modelmbean.ModelMBeanNotificationBroadcaster}
+ * interface (or implementing a full {@link javax.management.modelmbean.ModelMBean}).
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see NotificationPublisher
+ */
+public interface NotificationPublisherAware {
+
+ /**
+ * Set the {@link NotificationPublisher} instance for the current managed resource instance.
+ */
+ void setNotificationPublisher(NotificationPublisher notificationPublisher);
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/notification/UnableToSendNotificationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/notification/UnableToSendNotificationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/notification/UnableToSendNotificationException.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002-2006 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.jmx.export.notification;
+
+import org.springframework.jmx.JmxException;
+
+/**
+ * Thrown when a JMX {@link javax.management.Notification} is unable to be sent.
+ *
+ *
The root cause of just why a particular notification could not be sent
+ * will typically be available via the {@link #getCause()} property.
+ *
+ * @author Rob Harrop
+ * @since 2.0
+ * @see NotificationPublisher
+ */
+public class UnableToSendNotificationException extends JmxException {
+
+ /**
+ * Create a new instance of the {@link UnableToSendNotificationException}
+ * class with the specified error message.
+ * @param msg the detail message
+ */
+ public UnableToSendNotificationException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new instance of the {@link UnableToSendNotificationException}
+ * with the specified error message and root cause.
+ * @param msg the detail message
+ * @param cause the root cause
+ */
+ public UnableToSendNotificationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/export/notification/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/export/notification/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/export/notification/package.html 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Provides supporting infrastructure to allow Spring-created MBeans
+to send JMX notifications.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jmx/support/ConnectorServerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/ConnectorServerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/ConnectorServerFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2002-2006 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.jmx.support;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.JmxException;
+
+/**
+ * FactoryBean that creates a JSR-160 JMXConnectorServer,
+ * optionally registers it with the MBeanServer and then starts it.
+ *
+ *
The JMXConnectorServer can be started in a separate thread by setting the
+ * threaded property to true. You can configure this thread to be a
+ * daemon thread by setting the daemon property to true.
+ *
+ *
The JMXConnectorServer is correctly shutdown when an instance of this
+ * class is destroyed on shutdown of the containing ApplicationContext.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see FactoryBean
+ * @see JMXConnectorServer
+ * @see MBeanServer
+ */
+public class ConnectorServerFactoryBean extends MBeanRegistrationSupport
+ implements FactoryBean, InitializingBean, DisposableBean {
+
+ /** The default service URL */
+ public static final String DEFAULT_SERVICE_URL = "service:jmx:jmxmp://localhost:9875";
+
+
+ private String serviceUrl = DEFAULT_SERVICE_URL;
+
+ private Map environment;
+
+ private ObjectName objectName;
+
+ private boolean threaded = false;
+
+ private boolean daemon = false;
+
+ private JMXConnectorServer connectorServer;
+
+
+ /**
+ * Set the service URL for the JMXConnectorServer.
+ */
+ public void setServiceUrl(String serviceUrl) {
+ this.serviceUrl = serviceUrl;
+ }
+
+ /**
+ * Set the environment properties used to construct the JMXConnectorServer
+ * as java.util.Properties (String key/value pairs).
+ */
+ public void setEnvironment(Properties environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Set the environment properties used to construct the JMXConnector
+ * as a Map of String keys and arbitrary Object values.
+ */
+ public void setEnvironmentMap(Map environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Set the ObjectName used to register the JMXConnectorServer
+ * itself with the MBeanServer, as ObjectName instance
+ * or as String.
+ * @throws MalformedObjectNameException if the ObjectName is malformed
+ */
+ public void setObjectName(Object objectName) throws MalformedObjectNameException {
+ this.objectName = ObjectNameManager.getInstance(objectName);
+ }
+
+ /**
+ * Set whether the JMXConnectorServer should be started in a separate thread.
+ */
+ public void setThreaded(boolean threaded) {
+ this.threaded = threaded;
+ }
+
+ /**
+ * Set whether any threads started for the JMXConnectorServer should be
+ * started as daemon threads.
+ */
+ public void setDaemon(boolean daemon) {
+ this.daemon = daemon;
+ }
+
+
+ /**
+ * Start the connector server. If the threaded flag is set to true,
+ * the JMXConnectorServer will be started in a separate thread.
+ * If the daemon flag is set to true, that thread will be
+ * started as a daemon thread.
+ * @throws JMException if a problem occured when registering the connector server
+ * with the MBeanServer
+ * @throws IOException if there is a problem starting the connector server
+ */
+ public void afterPropertiesSet() throws JMException, IOException {
+ if (this.server == null) {
+ this.server = JmxUtils.locateMBeanServer();
+ }
+
+ // Create the JMX service URL.
+ JMXServiceURL url = new JMXServiceURL(this.serviceUrl);
+
+ // Create the connector server now.
+ this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, this.environment, this.server);
+
+ // Do we want to register the connector with the MBean server?
+ if (this.objectName != null) {
+ doRegister(this.connectorServer, this.objectName);
+ }
+
+ try {
+ if (this.threaded) {
+ // Start the connector server asynchronously (in a separate thread).
+ Thread connectorThread = new Thread() {
+ public void run() {
+ try {
+ connectorServer.start();
+ }
+ catch (IOException ex) {
+ throw new JmxException("Could not start JMX connector server after delay", ex);
+ }
+ }
+ };
+
+ connectorThread.setName("JMX Connector Thread [" + this.serviceUrl + "]");
+ connectorThread.setDaemon(this.daemon);
+ connectorThread.start();
+ }
+ else {
+ // Start the connector server in the same thread.
+ this.connectorServer.start();
+ }
+
+ if (logger.isInfoEnabled()) {
+ logger.info("JMX connector server started: " + this.connectorServer);
+ }
+ }
+
+ catch (IOException ex) {
+ // Unregister the connector server if startup failed.
+ unregisterBeans();
+ throw ex;
+ }
+ }
+
+
+ public Object getObject() {
+ return this.connectorServer;
+ }
+
+ public Class getObjectType() {
+ return (this.connectorServer != null ? this.connectorServer.getClass() : JMXConnectorServer.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Stop the JMXConnectorServer managed by an instance of this class.
+ * Automatically called on ApplicationContext shutdown.
+ * @throws IOException if there is an error stopping the connector server
+ */
+ public void destroy() throws IOException {
+ if (logger.isInfoEnabled()) {
+ logger.info("Stopping JMX connector server: " + this.connectorServer);
+ }
+ try {
+ this.connectorServer.stop();
+ }
+ finally {
+ unregisterBeans();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/JmxUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/JmxUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/JmxUtils.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2002-2008 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.jmx.support;
+
+import java.beans.PropertyDescriptor;
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.management.DynamicMBean;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MXBean;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.JdkVersion;
+import org.springframework.jmx.MBeanServerNotFoundException;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * Collection of generic utility methods to support Spring JMX.
+ * Includes a convenient method to locate an MBeanServer.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #locateMBeanServer
+ */
+public abstract class JmxUtils {
+
+ /**
+ * The key used when extending an existing {@link ObjectName} with the
+ * identity hash code of its corresponding managed resource.
+ */
+ public static final String IDENTITY_OBJECT_NAME_KEY = "identity";
+
+ /**
+ * Suffix used to identify an MBean interface.
+ */
+ private static final String MBEAN_SUFFIX = "MBean";
+
+ /**
+ * Suffix used to identify a Java 6 MXBean interface.
+ */
+ private static final String MXBEAN_SUFFIX = "MXBean";
+
+ private static final String MXBEAN_ANNOTATION_CLASS_NAME = "javax.management.MXBean";
+
+
+ private static final boolean mxBeanAnnotationAvailable =
+ ClassUtils.isPresent(MXBEAN_ANNOTATION_CLASS_NAME, JmxUtils.class.getClassLoader());
+
+ private static final Log logger = LogFactory.getLog(JmxUtils.class);
+
+
+ /**
+ * Attempt to find a locally running MBeanServer. Fails if no
+ * MBeanServer can be found. Logs a warning if more than one
+ * MBeanServer found, returning the first one from the list.
+ * @return the MBeanServer if found
+ * @throws org.springframework.jmx.MBeanServerNotFoundException
+ * if no MBeanServer could be found
+ * @see javax.management.MBeanServerFactory#findMBeanServer
+ */
+ public static MBeanServer locateMBeanServer() throws MBeanServerNotFoundException {
+ return locateMBeanServer(null);
+ }
+
+ /**
+ * Attempt to find a locally running MBeanServer. Fails if no
+ * MBeanServer can be found. Logs a warning if more than one
+ * MBeanServer found, returning the first one from the list.
+ * @param agentId the agent identifier of the MBeanServer to retrieve.
+ * If this parameter is null, all registered MBeanServers are
+ * considered.
+ * @return the MBeanServer if found
+ * @throws org.springframework.jmx.MBeanServerNotFoundException
+ * if no MBeanServer could be found
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ public static MBeanServer locateMBeanServer(String agentId) throws MBeanServerNotFoundException {
+ List servers = MBeanServerFactory.findMBeanServer(agentId);
+
+ MBeanServer server = null;
+ if (servers != null && servers.size() > 0) {
+ // Check to see if an MBeanServer is registered.
+ if (servers.size() > 1 && logger.isWarnEnabled()) {
+ logger.warn("Found more than one MBeanServer instance" +
+ (agentId != null ? " with agent id [" + agentId + "]" : "") +
+ ". Returning first from list.");
+ }
+ server = (MBeanServer) servers.get(0);
+ }
+
+ if (server == null && agentId == null && JdkVersion.isAtLeastJava15()) {
+ // Attempt to load the PlatformMBeanServer.
+ try {
+ server = ManagementFactory.getPlatformMBeanServer();
+ }
+ catch (SecurityException ex) {
+ throw new MBeanServerNotFoundException("No specific MBeanServer found, " +
+ "and not allowed to obtain the Java platform MBeanServer", ex);
+ }
+ }
+
+ if (server == null) {
+ throw new MBeanServerNotFoundException(
+ "Unable to locate an MBeanServer instance" +
+ (agentId != null ? " with agent id [" + agentId + "]" : ""));
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found MBeanServer: " + server);
+ }
+ return server;
+ }
+
+ /**
+ * Convert an array of MBeanParameterInfo into an array of
+ * Class instances corresponding to the parameters.
+ * @param paramInfo the JMX parameter info
+ * @return the parameter types as classes
+ * @throws ClassNotFoundException if a parameter type could not be resolved
+ */
+ public static Class[] parameterInfoToTypes(MBeanParameterInfo[] paramInfo) throws ClassNotFoundException {
+ return parameterInfoToTypes(paramInfo, ClassUtils.getDefaultClassLoader());
+ }
+
+ /**
+ * Convert an array of MBeanParameterInfo into an array of
+ * Class instances corresponding to the parameters.
+ * @param paramInfo the JMX parameter info
+ * @param classLoader the ClassLoader to use for loading parameter types
+ * @return the parameter types as classes
+ * @throws ClassNotFoundException if a parameter type could not be resolved
+ */
+ public static Class[] parameterInfoToTypes(MBeanParameterInfo[] paramInfo, ClassLoader classLoader)
+ throws ClassNotFoundException {
+
+ Class[] types = null;
+ if (paramInfo != null && paramInfo.length > 0) {
+ types = new Class[paramInfo.length];
+ for (int x = 0; x < paramInfo.length; x++) {
+ types[x] = ClassUtils.forName(paramInfo[x].getType(), classLoader);
+ }
+ }
+ return types;
+ }
+
+ /**
+ * Create a String[] representing the argument signature of a
+ * method. Each element in the array is the fully qualified class name
+ * of the corresponding argument in the methods signature.
+ * @param method the method to build an argument signature for
+ * @return the signature as array of argument types
+ */
+ public static String[] getMethodSignature(Method method) {
+ Class[] types = method.getParameterTypes();
+ String[] signature = new String[types.length];
+ for (int x = 0; x < types.length; x++) {
+ signature[x] = types[x].getName();
+ }
+ return signature;
+ }
+
+ /**
+ * Return the JMX attribute name to use for the given JavaBeans property.
+ *
When using strict casing, a JavaBean property with a getter method
+ * such as getFoo() translates to an attribute called
+ * Foo. With strict casing disabled, getFoo()
+ * would translate to just foo.
+ * @param property the JavaBeans property descriptor
+ * @param useStrictCasing whether to use strict casing
+ * @return the JMX attribute name to use
+ */
+ public static String getAttributeName(PropertyDescriptor property, boolean useStrictCasing) {
+ if (useStrictCasing) {
+ return StringUtils.capitalize(property.getName());
+ }
+ else {
+ return property.getName();
+ }
+ }
+
+ /**
+ * Append an additional key/value pair to an existing {@link ObjectName} with the key being
+ * the static value identity and the value being the identity hash code of the
+ * managed resource being exposed on the supplied {@link ObjectName}. This can be used to
+ * provide a unique {@link ObjectName} for each distinct instance of a particular bean or
+ * class. Useful when generating {@link ObjectName ObjectNames} at runtime for a set of
+ * managed resources based on the template value supplied by a
+ * {@link org.springframework.jmx.export.naming.ObjectNamingStrategy}.
+ * @param objectName the original JMX ObjectName
+ * @param managedResource the MBean instance
+ * @return an ObjectName with the MBean identity added
+ * @throws MalformedObjectNameException in case of an invalid object name specification
+ * @see org.springframework.util.ObjectUtils#getIdentityHexString(Object)
+ */
+ public static ObjectName appendIdentityToObjectName(ObjectName objectName, Object managedResource)
+ throws MalformedObjectNameException {
+
+ Hashtable keyProperties = objectName.getKeyPropertyList();
+ keyProperties.put(IDENTITY_OBJECT_NAME_KEY, ObjectUtils.getIdentityHexString(managedResource));
+ return ObjectNameManager.getInstance(objectName.getDomain(), keyProperties);
+ }
+
+ /**
+ * Return the class or interface to expose for the given bean.
+ * This is the class that will be searched for attributes and operations
+ * (for example, checked for annotations).
+ *
This implementation returns the superclass for a CGLIB proxy and
+ * the class of the given bean else (for a JDK proxy or a plain bean class).
+ * @param managedBean the bean instance (might be an AOP proxy)
+ * @return the bean class to expose
+ * @see org.springframework.util.ClassUtils#getUserClass(Object)
+ */
+ public static Class getClassToExpose(Object managedBean) {
+ return ClassUtils.getUserClass(managedBean);
+ }
+
+ /**
+ * Return the class or interface to expose for the given bean class.
+ * This is the class that will be searched for attributes and operations
+ * (for example, checked for annotations).
+ *
This implementation returns the superclass for a CGLIB proxy and
+ * the class of the given bean else (for a JDK proxy or a plain bean class).
+ * @param beanClass the bean class (might be an AOP proxy class)
+ * @return the bean class to expose
+ * @see org.springframework.util.ClassUtils#getUserClass(Class)
+ */
+ public static Class getClassToExpose(Class beanClass) {
+ return ClassUtils.getUserClass(beanClass);
+ }
+
+ /**
+ * Determine whether the given bean class qualifies as an MBean as-is.
+ *
This implementation checks for {@link javax.management.DynamicMBean}
+ * classes as well as classes with corresponding "*MBean" interface
+ * (Standard MBeans) or corresponding "*MXBean" interface (Java 6 MXBeans).
+ * @param beanClass the bean class to analyze
+ * @return whether the class qualifies as an MBean
+ * @see org.springframework.jmx.export.MBeanExporter#isMBean(Class)
+ */
+ public static boolean isMBean(Class beanClass) {
+ return (beanClass != null &&
+ (DynamicMBean.class.isAssignableFrom(beanClass) ||
+ (getMBeanInterface(beanClass) != null || getMXBeanInterface(beanClass) != null)));
+ }
+
+ /**
+ * Return the Standard MBean interface for the given class, if any
+ * (that is, an interface whose name matches the class name of the
+ * given class but with suffix "MBean").
+ * @param clazz the class to check
+ * @return the Standard MBean interface for the given class
+ */
+ public static Class getMBeanInterface(Class clazz) {
+ if (clazz.getSuperclass() == null) {
+ return null;
+ }
+ String mbeanInterfaceName = clazz.getName() + MBEAN_SUFFIX;
+ Class[] implementedInterfaces = clazz.getInterfaces();
+ for (int x = 0; x < implementedInterfaces.length; x++) {
+ Class iface = implementedInterfaces[x];
+ if (iface.getName().equals(mbeanInterfaceName)) {
+ return iface;
+ }
+ }
+ return getMBeanInterface(clazz.getSuperclass());
+ }
+
+ /**
+ * Return the Java 6 MXBean interface exists for the given class, if any
+ * (that is, an interface whose name ends with "MXBean" and/or
+ * carries an appropriate MXBean annotation).
+ * @param clazz the class to check
+ * @return whether there is an MXBean interface for the given class
+ */
+ public static Class getMXBeanInterface(Class clazz) {
+ if (clazz.getSuperclass() == null) {
+ return null;
+ }
+ Class[] implementedInterfaces = clazz.getInterfaces();
+ for (int x = 0; x < implementedInterfaces.length; x++) {
+ Class iface = implementedInterfaces[x];
+ boolean isMxBean = iface.getName().endsWith(MXBEAN_SUFFIX);
+ if (mxBeanAnnotationAvailable) {
+ Boolean checkResult = MXBeanChecker.hasMXBeanAnnotation(iface);
+ if (checkResult != null) {
+ isMxBean = checkResult.booleanValue();
+ }
+ }
+ if (isMxBean) {
+ return iface;
+ }
+ }
+ return getMXBeanInterface(clazz.getSuperclass());
+ }
+
+
+ /**
+ * Inner class to avoid a Java 6 dependency.
+ */
+ private static class MXBeanChecker {
+
+ public static Boolean hasMXBeanAnnotation(Class iface) {
+ MXBean mxBean = (MXBean) iface.getAnnotation(MXBean.class);
+ if (mxBean != null) {
+ return Boolean.valueOf(mxBean.value());
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/MBeanRegistrationSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/MBeanRegistrationSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/MBeanRegistrationSupport.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2002-2008 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.jmx.support;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.Constants;
+
+/**
+ * Provides supporting infrastructure for registering MBeans with an
+ * {@link javax.management.MBeanServer}. The behavior when encountering
+ * an existing MBean at a given {@link ObjectName} is fully configurable
+ * allowing for flexible registration settings.
+ *
+ *
All registered MBeans are tracked and can be unregistered by calling
+ * the #{@link #unregisterBeans()} method.
+ *
+ *
Sub-classes can receive notifications when an MBean is registered or
+ * unregistered by overriding the {@link #onRegister(ObjectName)} and
+ * {@link #onUnregister(ObjectName)} methods respectively.
+ *
+ *
By default, the registration process will fail if attempting to
+ * register an MBean using a {@link javax.management.ObjectName} that is
+ * already used.
+ *
+ *
By setting the {@link #setRegistrationBehaviorName(String) registrationBehaviorName}
+ * property to REGISTRATION_IGNORE_EXISTING the registration process
+ * will simply ignore existing MBeans leaving them registered. This is useful in settings
+ * where multiple applications want to share a common MBean in a shared {@link MBeanServer}.
+ *
+ *
Setting {@link #setRegistrationBehaviorName(String) registrationBehaviorName} property
+ * to REGISTRATION_REPLACE_EXISTING will cause existing MBeans to be replaced
+ * during registration if necessary. This is useful in situations where you can't guarantee
+ * the state of your {@link MBeanServer}.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setServer
+ * @see #setRegistrationBehaviorName
+ * @see org.springframework.jmx.export.MBeanExporter
+ */
+public class MBeanRegistrationSupport {
+
+ /**
+ * Constant indicating that registration should fail when
+ * attempting to register an MBean under a name that already exists.
+ *
This is the default registration behavior.
+ */
+ public static final int REGISTRATION_FAIL_ON_EXISTING = 0;
+
+ /**
+ * Constant indicating that registration should ignore the affected MBean
+ * when attempting to register an MBean under a name that already exists.
+ */
+ public static final int REGISTRATION_IGNORE_EXISTING = 1;
+
+ /**
+ * Constant indicating that registration should replace the affected MBean
+ * when attempting to register an MBean under a name that already exists.
+ */
+ public static final int REGISTRATION_REPLACE_EXISTING = 2;
+
+
+ /**
+ * Constants for this class.
+ */
+ private static final Constants constants = new Constants(MBeanRegistrationSupport.class);
+
+ /**
+ * Log instance for this class.
+ */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ /**
+ * The MBeanServer instance being used to register beans.
+ */
+ protected MBeanServer server;
+
+ /**
+ * The beans that have been registered by this exporter.
+ */
+ protected final Set registeredBeans = new LinkedHashSet();
+
+ /**
+ * The action take when registering an MBean and finding that it already exists.
+ * By default an exception is raised.
+ */
+ private int registrationBehavior = REGISTRATION_FAIL_ON_EXISTING;
+
+
+ /**
+ * Specify the MBeanServer instance with which all beans should
+ * be registered. The MBeanExporter will attempt to locate an
+ * existing MBeanServer if none is supplied.
+ */
+ public void setServer(MBeanServer server) {
+ this.server = server;
+ }
+
+ /**
+ * Return the MBeanServer that the beans will be registered with.
+ */
+ public final MBeanServer getServer() {
+ return this.server;
+ }
+
+ /**
+ * Set the registration behavior by the name of the corresponding constant,
+ * e.g. "REGISTRATION_IGNORE_EXISTING".
+ * @see #setRegistrationBehavior
+ * @see #REGISTRATION_FAIL_ON_EXISTING
+ * @see #REGISTRATION_IGNORE_EXISTING
+ * @see #REGISTRATION_REPLACE_EXISTING
+ */
+ public void setRegistrationBehaviorName(String registrationBehavior) {
+ setRegistrationBehavior(constants.asNumber(registrationBehavior).intValue());
+ }
+
+ /**
+ * Specify what action should be taken when attempting to register an MBean
+ * under an {@link javax.management.ObjectName} that already exists.
+ *
Default is REGISTRATION_FAIL_ON_EXISTING.
+ * @see #setRegistrationBehaviorName(String)
+ * @see #REGISTRATION_FAIL_ON_EXISTING
+ * @see #REGISTRATION_IGNORE_EXISTING
+ * @see #REGISTRATION_REPLACE_EXISTING
+ */
+ public void setRegistrationBehavior(int registrationBehavior) {
+ this.registrationBehavior = registrationBehavior;
+ }
+
+
+ /**
+ * Actually register the MBean with the server. The behavior when encountering
+ * an existing MBean can be configured using the {@link #setRegistrationBehavior(int)}
+ * and {@link #setRegistrationBehaviorName(String)} methods.
+ * @param mbean the MBean instance
+ * @param objectName the suggested ObjectName for the MBean
+ * @throws JMException if the registration failed
+ */
+ protected void doRegister(Object mbean, ObjectName objectName) throws JMException {
+ ObjectInstance registeredBean = null;
+ try {
+ registeredBean = this.server.registerMBean(mbean, objectName);
+ }
+ catch (InstanceAlreadyExistsException ex) {
+ if (this.registrationBehavior == REGISTRATION_IGNORE_EXISTING) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Ignoring existing MBean at [" + objectName + "]");
+ }
+ }
+ else if (this.registrationBehavior == REGISTRATION_REPLACE_EXISTING) {
+ try {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Replacing existing MBean at [" + objectName + "]");
+ }
+ this.server.unregisterMBean(objectName);
+ registeredBean = this.server.registerMBean(mbean, objectName);
+ }
+ catch (InstanceNotFoundException ex2) {
+ logger.error("Unable to replace existing MBean at [" + objectName + "]", ex2);
+ throw ex;
+ }
+ }
+ else {
+ throw ex;
+ }
+ }
+
+ // Track registration and notify listeners.
+ ObjectName actualObjectName = (registeredBean != null ? registeredBean.getObjectName() : null);
+ if (actualObjectName == null) {
+ actualObjectName = objectName;
+ }
+ this.registeredBeans.add(actualObjectName);
+ onRegister(actualObjectName, mbean);
+ }
+
+ /**
+ * Unregisters all beans that have been registered by an instance of this class.
+ */
+ protected void unregisterBeans() {
+ for (Iterator it = this.registeredBeans.iterator(); it.hasNext();) {
+ doUnregister((ObjectName) it.next());
+ }
+ this.registeredBeans.clear();
+ }
+
+ /**
+ * Actually unregister the specified MBean from the server.
+ * @param objectName the suggested ObjectName for the MBean
+ */
+ protected void doUnregister(ObjectName objectName) {
+ try {
+ // MBean might already have been unregistered by an external process.
+ if (this.server.isRegistered(objectName)) {
+ this.server.unregisterMBean(objectName);
+ onUnregister(objectName);
+ }
+ else {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Could not unregister MBean [" + objectName + "] as said MBean " +
+ "is not registered (perhaps already unregistered by an external process)");
+ }
+ }
+ }
+ catch (JMException ex) {
+ if (logger.isErrorEnabled()) {
+ logger.error("Could not unregister MBean [" + objectName + "]", ex);
+ }
+ }
+ }
+
+ /**
+ * Return the {@link ObjectName ObjectNames} of all registered beans.
+ */
+ protected final ObjectName[] getRegisteredObjectNames() {
+ return (ObjectName[]) this.registeredBeans.toArray(new ObjectName[this.registeredBeans.size()]);
+ }
+
+
+ /**
+ * Called when an MBean is registered under the given {@link ObjectName}. Allows
+ * subclasses to perform additional processing when an MBean is registered.
+ *
The default implementation delegates to {@link #onRegister(ObjectName)}.
+ * @param objectName the actual {@link ObjectName} that the MBean was registered with
+ * @param mbean the registered MBean instance
+ */
+ protected void onRegister(ObjectName objectName, Object mbean) {
+ onRegister(objectName);
+ }
+
+ /**
+ * Called when an MBean is registered under the given {@link ObjectName}. Allows
+ * subclasses to perform additional processing when an MBean is registered.
+ *
The default implementation is empty. Can be overridden in subclasses.
+ * @param objectName the actual {@link ObjectName} that the MBean was registered with
+ */
+ protected void onRegister(ObjectName objectName) {
+ }
+
+ /**
+ * Called when an MBean is unregistered under the given {@link ObjectName}. Allows
+ * subclasses to perform additional processing when an MBean is unregistered.
+ *
The default implementation is empty. Can be overridden in subclasses.
+ * @param objectName the {@link ObjectName} that the MBean was registered with
+ */
+ protected void onUnregister(ObjectName objectName) {
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerConnectionFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2002-2008 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.jmx.support;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.springframework.aop.TargetSource;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.target.AbstractLazyCreationTargetSource;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.ClassUtils;
+
+/**
+ * FactoryBean that creates a JMX 1.2 MBeanServerConnection
+ * to a remote MBeanServer exposed via a JMXServerConnector.
+ * Exposes the MBeanServer for bean references.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see MBeanServerFactoryBean
+ * @see ConnectorServerFactoryBean
+ * @see org.springframework.jmx.access.MBeanClientInterceptor#setServer
+ * @see org.springframework.jmx.access.NotificationListenerRegistrar#setServer
+ */
+public class MBeanServerConnectionFactoryBean
+ implements FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean {
+
+ private JMXServiceURL serviceUrl;
+
+ private Map environment;
+
+ private boolean connectOnStartup = true;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private JMXConnector connector;
+
+ private MBeanServerConnection connection;
+
+ private JMXConnectorLazyInitTargetSource connectorTargetSource;
+
+
+ /**
+ * Set the service URL of the remote MBeanServer.
+ */
+ public void setServiceUrl(String url) throws MalformedURLException {
+ this.serviceUrl = new JMXServiceURL(url);
+ }
+
+ /**
+ * Set the environment properties used to construct the JMXConnector
+ * as java.util.Properties (String key/value pairs).
+ */
+ public void setEnvironment(Properties environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Set the environment properties used to construct the JMXConnector
+ * as a Map of String keys and arbitrary Object values.
+ */
+ public void setEnvironmentMap(Map environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Set whether to connect to the server on startup. Default is "true".
+ *
Can be turned off to allow for late start of the JMX server.
+ * In this case, the JMX connector will be fetched on first access.
+ */
+ public void setConnectOnStartup(boolean connectOnStartup) {
+ this.connectOnStartup = connectOnStartup;
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+
+ /**
+ * Creates a JMXConnector for the given settings
+ * and exposes the associated MBeanServerConnection.
+ */
+ public void afterPropertiesSet() throws IOException {
+ if (this.serviceUrl == null) {
+ throw new IllegalArgumentException("Property 'serviceUrl' is required");
+ }
+
+ if (this.connectOnStartup) {
+ connect();
+ }
+ else {
+ createLazyConnection();
+ }
+ }
+
+ /**
+ * Connects to the remote MBeanServer using the configured service URL and
+ * environment properties.
+ */
+ private void connect() throws IOException {
+ this.connector = JMXConnectorFactory.connect(this.serviceUrl, this.environment);
+ this.connection = this.connector.getMBeanServerConnection();
+ }
+
+ /**
+ * Creates lazy proxies for the JMXConnector and MBeanServerConnection
+ */
+ private void createLazyConnection() {
+ this.connectorTargetSource = new JMXConnectorLazyInitTargetSource();
+ TargetSource connectionTargetSource = new MBeanServerConnectionLazyInitTargetSource();
+
+ this.connector = (JMXConnector)
+ new ProxyFactory(JMXConnector.class, this.connectorTargetSource).getProxy(this.beanClassLoader);
+ this.connection = (MBeanServerConnection)
+ new ProxyFactory(MBeanServerConnection.class, connectionTargetSource).getProxy(this.beanClassLoader);
+ }
+
+
+ public Object getObject() {
+ return this.connection;
+ }
+
+ public Class getObjectType() {
+ return (this.connection != null ? this.connection.getClass() : MBeanServerConnection.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Closes the underlying JMXConnector.
+ */
+ public void destroy() throws IOException {
+ if (this.connectorTargetSource == null || this.connectorTargetSource.isInitialized()) {
+ this.connector.close();
+ }
+ }
+
+
+ /**
+ * Lazily creates a JMXConnector using the configured service URL
+ * and environment properties.
+ * @see MBeanServerConnectionFactoryBean#setServiceUrl(String)
+ * @see MBeanServerConnectionFactoryBean#setEnvironment(java.util.Properties)
+ */
+ private class JMXConnectorLazyInitTargetSource extends AbstractLazyCreationTargetSource {
+
+ protected Object createObject() throws Exception {
+ return JMXConnectorFactory.connect(serviceUrl, environment);
+ }
+
+ public Class getTargetClass() {
+ return JMXConnector.class;
+ }
+ }
+
+
+ /**
+ * Lazily creates an MBeanServerConnection.
+ */
+ private class MBeanServerConnectionLazyInitTargetSource extends AbstractLazyCreationTargetSource {
+
+ protected Object createObject() throws Exception {
+ return connector.getMBeanServerConnection();
+ }
+
+ public Class getTargetClass() {
+ return MBeanServerConnection.class;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/MBeanServerFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2002-2007 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.jmx.support;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.MBeanServerNotFoundException;
+
+/**
+ * FactoryBean that obtains an {@link javax.management.MBeanServer} reference
+ * through the standard JMX 1.2 {@link javax.management.MBeanServerFactory}
+ * API (which is available on JDK 1.5 or as part of a JMX 1.2 provider).
+ * Exposes the MBeanServer for bean references.
+ *
+ *
By default, MBeanServerFactoryBean will always create
+ * a new MBeanServer even if one is already running. To have
+ * the MBeanServerFactoryBean attempt to locate a running
+ * MBeanServer first, set the value of the
+ * "locateExistingServerIfPossible" property to "true".
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setLocateExistingServerIfPossible
+ * @see #locateMBeanServer
+ * @see javax.management.MBeanServer
+ * @see javax.management.MBeanServerFactory#findMBeanServer
+ * @see javax.management.MBeanServerFactory#createMBeanServer
+ * @see javax.management.MBeanServerFactory#newMBeanServer
+ * @see MBeanServerConnectionFactoryBean
+ * @see ConnectorServerFactoryBean
+ */
+public class MBeanServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private boolean locateExistingServerIfPossible = false;
+
+ private String agentId;
+
+ private String defaultDomain;
+
+ private boolean registerWithFactory = true;
+
+ private MBeanServer server;
+
+ private boolean newlyRegistered = false;
+
+
+ /**
+ * Set whether or not the MBeanServerFactoryBean should attempt
+ * to locate a running MBeanServer before creating one.
+ *
Default is false.
+ */
+ public void setLocateExistingServerIfPossible(boolean locateExistingServerIfPossible) {
+ this.locateExistingServerIfPossible = locateExistingServerIfPossible;
+ }
+
+ /**
+ * Set the agent id of the MBeanServer to locate.
+ *
Default is none. If specified, this will result in an
+ * automatic attempt being made to locate the attendant MBeanServer,
+ * and (importantly) if said MBeanServer cannot be located no
+ * attempt will be made to create a new MBeanServer (and an
+ * MBeanServerNotFoundException will be thrown at resolution time).
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ public void setAgentId(String agentId) {
+ this.agentId = agentId;
+ }
+
+ /**
+ * Set the default domain to be used by the MBeanServer,
+ * to be passed to MBeanServerFactory.createMBeanServer()
+ * or MBeanServerFactory.findMBeanServer().
+ *
Default is none.
+ * @see javax.management.MBeanServerFactory#createMBeanServer(String)
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ public void setDefaultDomain(String defaultDomain) {
+ this.defaultDomain = defaultDomain;
+ }
+
+ /**
+ * Set whether to register the MBeanServer with the
+ * MBeanServerFactory, making it available through
+ * MBeanServerFactory.findMBeanServer().
+ * @see javax.management.MBeanServerFactory#createMBeanServer
+ * @see javax.management.MBeanServerFactory#findMBeanServer
+ */
+ public void setRegisterWithFactory(boolean registerWithFactory) {
+ this.registerWithFactory = registerWithFactory;
+ }
+
+
+ /**
+ * Creates the MBeanServer instance.
+ */
+ public void afterPropertiesSet() throws MBeanServerNotFoundException {
+ // Try to locate existing MBeanServer, if desired.
+ if (this.locateExistingServerIfPossible || this.agentId != null) {
+ try {
+ this.server = locateMBeanServer(this.agentId);
+ }
+ catch (MBeanServerNotFoundException ex) {
+ // If agentId was specified, we were only supposed to locate that
+ // specific MBeanServer; so let's bail if we can't find it.
+ if (this.agentId != null) {
+ throw ex;
+ }
+ logger.info("No existing MBeanServer found - creating new one");
+ }
+ }
+
+ // Create a new MBeanServer and register it, if desired.
+ if (this.server == null) {
+ this.server = createMBeanServer(this.defaultDomain, this.registerWithFactory);
+ this.newlyRegistered = this.registerWithFactory;
+ }
+ }
+
+ /**
+ * Attempt to locate an existing MBeanServer.
+ * Called if locateExistingServerIfPossible is set to true.
+ *
The default implementation attempts to find an MBeanServer using
+ * a standard lookup. Subclasses may override to add additional location logic.
+ * @param agentId the agent identifier of the MBeanServer to retrieve.
+ * If this parameter is null, all registered MBeanServers are
+ * considered.
+ * @return the MBeanServer if found
+ * @throws org.springframework.jmx.MBeanServerNotFoundException
+ * if no MBeanServer could be found
+ * @see #setLocateExistingServerIfPossible
+ * @see JmxUtils#locateMBeanServer(String)
+ * @see javax.management.MBeanServerFactory#findMBeanServer(String)
+ */
+ protected MBeanServer locateMBeanServer(String agentId) throws MBeanServerNotFoundException {
+ return JmxUtils.locateMBeanServer(agentId);
+ }
+
+ /**
+ * Create a new MBeanServer instance and register it with the
+ * MBeanServerFactory, if desired.
+ * @param defaultDomain the default domain, or null if none
+ * @param registerWithFactory whether to register the MBeanServer
+ * with the MBeanServerFactory
+ * @see javax.management.MBeanServerFactory#createMBeanServer
+ * @see javax.management.MBeanServerFactory#newMBeanServer
+ */
+ protected MBeanServer createMBeanServer(String defaultDomain, boolean registerWithFactory) {
+ if (registerWithFactory) {
+ return MBeanServerFactory.createMBeanServer(defaultDomain);
+ }
+ else {
+ return MBeanServerFactory.newMBeanServer(defaultDomain);
+ }
+ }
+
+
+ public Object getObject() {
+ return this.server;
+ }
+
+ public Class getObjectType() {
+ return (this.server != null ? this.server.getClass() : MBeanServer.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Unregisters the MBeanServer instance, if necessary.
+ */
+ public void destroy() {
+ if (this.newlyRegistered) {
+ MBeanServerFactory.releaseMBeanServer(this.server);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/NotificationListenerHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/NotificationListenerHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/NotificationListenerHolder.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2002-2008 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.jmx.support;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Helper class that aggregates a {@link javax.management.NotificationListener},
+ * a {@link javax.management.NotificationFilter}, and an arbitrary handback
+ * object, as well as the names of MBeans from which the listener wishes
+ * to receive {@link javax.management.Notification Notifications}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.2
+ * @see org.springframework.jmx.export.NotificationListenerBean
+ * @see org.springframework.jmx.access.NotificationListenerRegistrar
+ */
+public class NotificationListenerHolder {
+
+ private NotificationListener notificationListener;
+
+ private NotificationFilter notificationFilter;
+
+ private Object handback;
+
+ protected Set mappedObjectNames;
+
+
+ /**
+ * Set the {@link javax.management.NotificationListener}.
+ */
+ public void setNotificationListener(NotificationListener notificationListener) {
+ this.notificationListener = notificationListener;
+ }
+
+ /**
+ * Get the {@link javax.management.NotificationListener}.
+ */
+ public NotificationListener getNotificationListener() {
+ return this.notificationListener;
+ }
+
+ /**
+ * Set the {@link javax.management.NotificationFilter} associated
+ * with the encapsulated {@link #getNotificationFilter() NotificationFilter}.
+ *
May be null.
+ */
+ public void setNotificationFilter(NotificationFilter notificationFilter) {
+ this.notificationFilter = notificationFilter;
+ }
+
+ /**
+ * Return the {@link javax.management.NotificationFilter} associated
+ * with the encapsulated {@link #getNotificationFilter() NotificationFilter}.
+ *
May be null.
+ */
+ public NotificationFilter getNotificationFilter() {
+ return this.notificationFilter;
+ }
+
+ /**
+ * Set the (arbitrary) object that will be 'handed back' as-is by an
+ * {@link javax.management.NotificationBroadcaster} when notifying
+ * any {@link javax.management.NotificationListener}.
+ * @param handback the handback object (can be null)
+ * @see javax.management.NotificationListener#handleNotification(javax.management.Notification, Object)
+ */
+ public void setHandback(Object handback) {
+ this.handback = handback;
+ }
+
+ /**
+ * Return the (arbitrary) object that will be 'handed back' as-is by an
+ * {@link javax.management.NotificationBroadcaster} when notifying
+ * any {@link javax.management.NotificationListener}.
+ * @return the handback object (may be null)
+ * @see javax.management.NotificationListener#handleNotification(javax.management.Notification, Object)
+ */
+ public Object getHandback() {
+ return this.handback;
+ }
+
+ /**
+ * Set the {@link javax.management.ObjectName}-style name of the single MBean
+ * that the encapsulated {@link #getNotificationFilter() NotificationFilter}
+ * will be registered with to listen for {@link javax.management.Notification Notifications}.
+ * Can be specified as ObjectName instance or as String.
+ * @see #setMappedObjectNames
+ */
+ public void setMappedObjectName(Object mappedObjectName) {
+ setMappedObjectNames(mappedObjectName != null ? new Object[] {mappedObjectName} : null);
+ }
+
+ /**
+ * Set an array of {@link javax.management.ObjectName}-style names of the MBeans
+ * that the encapsulated {@link #getNotificationFilter() NotificationFilter}
+ * will be registered with to listen for {@link javax.management.Notification Notifications}.
+ * Can be specified as ObjectName instances or as Strings.
+ * @see #setMappedObjectName
+ */
+ public void setMappedObjectNames(Object[] mappedObjectNames) {
+ if (mappedObjectNames != null) {
+ this.mappedObjectNames = new LinkedHashSet(mappedObjectNames.length);
+ for (int i = 0; i < mappedObjectNames.length; i++) {
+ this.mappedObjectNames.add(mappedObjectNames[i]);
+ }
+ }
+ else {
+ this.mappedObjectNames = null;
+ }
+ }
+
+ /**
+ * Return the list of {@link javax.management.ObjectName} String representations for
+ * which the encapsulated {@link #getNotificationFilter() NotificationFilter} will
+ * be registered as a listener for {@link javax.management.Notification Notifications}.
+ * @throws MalformedObjectNameException if an ObjectName is malformed
+ */
+ public ObjectName[] getResolvedObjectNames() throws MalformedObjectNameException {
+ if (this.mappedObjectNames == null) {
+ return null;
+ }
+ ObjectName[] resolved = new ObjectName[this.mappedObjectNames.size()];
+ int i = 0;
+ for (Iterator it = this.mappedObjectNames.iterator(); it.hasNext();) {
+ resolved[i] = ObjectNameManager.getInstance(it.next());
+ i++;
+ }
+ return resolved;
+ }
+
+
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof NotificationListenerHolder)) {
+ return false;
+ }
+ NotificationListenerHolder otherNlh = (NotificationListenerHolder) other;
+ return (ObjectUtils.nullSafeEquals(this.notificationListener, otherNlh.notificationListener) &&
+ ObjectUtils.nullSafeEquals(this.notificationFilter, otherNlh.notificationFilter) &&
+ ObjectUtils.nullSafeEquals(this.handback, otherNlh.handback) &&
+ ObjectUtils.nullSafeEquals(this.mappedObjectNames, otherNlh.mappedObjectNames));
+ }
+
+ public int hashCode() {
+ int hashCode = ObjectUtils.nullSafeHashCode(this.notificationListener);
+ hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.notificationFilter);
+ hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.handback);
+ hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.mappedObjectNames);
+ return hashCode;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/ObjectNameManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/ObjectNameManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/ObjectNameManager.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2002-2007 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.jmx.support;
+
+import java.util.Hashtable;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.util.ClassUtils;
+
+/**
+ * Helper class for the creation of {@link javax.management.ObjectName} instances.
+ *
+ *
ObjectName instances will be cached on JMX 1.2,
+ * whereas they will be recreated for each request on JMX 1.0.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see javax.management.ObjectName#getInstance(String)
+ */
+public class ObjectNameManager {
+
+ // Determine whether the JMX 1.2 ObjectName.getInstance method is available.
+ private static final boolean getInstanceAvailable =
+ ClassUtils.hasMethod(ObjectName.class, "getInstance", new Class[] {String.class});
+
+
+ /**
+ * Retrieve the ObjectName instance corresponding to the supplied name.
+ * @param objectName the ObjectName in ObjectName or
+ * String format
+ * @return the ObjectName instance
+ * @throws MalformedObjectNameException in case of an invalid object name specification
+ * @see ObjectName#ObjectName(String)
+ * @see ObjectName#getInstance(String)
+ */
+ public static ObjectName getInstance(Object objectName) throws MalformedObjectNameException {
+ if (objectName instanceof ObjectName) {
+ return (ObjectName) objectName;
+ }
+ if (!(objectName instanceof String)) {
+ throw new MalformedObjectNameException("Invalid ObjectName value type [" +
+ objectName.getClass().getName() + "]: only ObjectName and String supported.");
+ }
+ return getInstance((String) objectName);
+ }
+
+ /**
+ * Retrieve the ObjectName instance corresponding to the supplied name.
+ * @param objectName the ObjectName in String format
+ * @return the ObjectName instance
+ * @throws MalformedObjectNameException in case of an invalid object name specification
+ * @see ObjectName#ObjectName(String)
+ * @see ObjectName#getInstance(String)
+ */
+ public static ObjectName getInstance(String objectName) throws MalformedObjectNameException {
+ if (getInstanceAvailable) {
+ return ObjectName.getInstance(objectName);
+ }
+ else {
+ return new ObjectName(objectName);
+ }
+ }
+
+ /**
+ * Retrieve an ObjectName instance for the specified domain and a
+ * single property with the supplied key and value.
+ * @param domainName the domain name for the ObjectName
+ * @param key the key for the single property in the ObjectName
+ * @param value the value for the single property in the ObjectName
+ * @return the ObjectName instance
+ * @throws MalformedObjectNameException in case of an invalid object name specification
+ * @see ObjectName#ObjectName(String, String, String)
+ * @see ObjectName#getInstance(String, String, String)
+ */
+ public static ObjectName getInstance(String domainName, String key, String value)
+ throws MalformedObjectNameException {
+
+ if (getInstanceAvailable) {
+ return ObjectName.getInstance(domainName, key, value);
+ }
+ else {
+ return new ObjectName(domainName, key, value);
+ }
+ }
+
+ /**
+ * Retrieve an ObjectName instance with the specified domain name
+ * and the supplied key/name properties.
+ * @param domainName the domain name for the ObjectName
+ * @param properties the properties for the ObjectName
+ * @return the ObjectName instance
+ * @throws MalformedObjectNameException in case of an invalid object name specification
+ * @see ObjectName#ObjectName(String, java.util.Hashtable)
+ * @see ObjectName#getInstance(String, java.util.Hashtable)
+ */
+ public static ObjectName getInstance(String domainName, Hashtable properties)
+ throws MalformedObjectNameException {
+
+ if (getInstanceAvailable) {
+ return ObjectName.getInstance(domainName, properties);
+ }
+ else {
+ return new ObjectName(domainName, properties);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/WebLogicJndiMBeanServerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/WebLogicJndiMBeanServerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/WebLogicJndiMBeanServerFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2002-2007 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.jmx.support;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.management.MBeanServer;
+import javax.naming.NamingException;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.MBeanServerNotFoundException;
+import org.springframework.jndi.JndiLocatorSupport;
+
+/**
+ * FactoryBean that obtains a specified WebLogic {@link javax.management.MBeanServer}
+ * reference through a WebLogic MBeanHome obtained via a JNDI lookup.
+ * By default, the server's local MBeanHome will be obtained.
+ *
+ *
Exposes the MBeanServer for bean references.
+ * This FactoryBean is a direct alternative to {@link MBeanServerFactoryBean},
+ * which uses standard JMX 1.2 API to access the platform's MBeanServer.
+ *
+ *
Note: There is also a more general {@link WebLogicMBeanServerFactoryBean}
+ * for accessing any specified WebLogic MBeanServer,
+ * potentially a remote one.
+ *
+ *
NOTE: This class is only intended for use with WebLogic 8.1.
+ * On WebLogic 9.x, simply obtain the MBeanServer directly from the JNDI location
+ * "java:comp/env/jmx/runtime", for example through the following configuration:
+ *
+ *
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2.6
+ * @see weblogic.management.MBeanHome#LOCAL_JNDI_NAME
+ * @see weblogic.management.MBeanHome#getMBeanServer()
+ * @see javax.management.MBeanServer
+ * @see MBeanServerFactoryBean
+ * @see WebLogicMBeanServerFactoryBean
+ */
+public class WebLogicJndiMBeanServerFactoryBean extends JndiLocatorSupport
+ implements FactoryBean, InitializingBean {
+
+ private static final String WEBLOGIC_MBEAN_HOME_CLASS = "weblogic.management.MBeanHome";
+
+ private static final String LOCAL_JNDI_NAME_FIELD = "LOCAL_JNDI_NAME";
+
+ private static final String GET_MBEAN_SERVER_METHOD = "getMBeanServer";
+
+
+ private String mbeanHomeName;
+
+ private MBeanServer mbeanServer;
+
+
+ /**
+ * Specify the JNDI name of the WebLogic MBeanHome object to use
+ * for creating the JMX MBeanServer reference.
+ *
Default is MBeanHome.LOCAL_JNDI_NAME
+ * @see weblogic.management.MBeanHome#LOCAL_JNDI_NAME
+ */
+ public void setMbeanHomeName(String mbeanHomeName) {
+ this.mbeanHomeName = mbeanHomeName;
+ }
+
+
+ public void afterPropertiesSet() throws MBeanServerNotFoundException {
+ try {
+ String jndiName = this.mbeanHomeName;
+ if (jndiName == null) {
+ /*
+ * jndiName = MBeanHome.LOCAL_JNDI_NAME;
+ */
+ Class mbeanHomeClass = getClass().getClassLoader().loadClass(WEBLOGIC_MBEAN_HOME_CLASS);
+ jndiName = (String) mbeanHomeClass.getField(LOCAL_JNDI_NAME_FIELD).get(null);
+ }
+ Object mbeanHome = lookup(jndiName);
+
+ /*
+ * this.mbeanServer = mbeanHome.getMBeanServer();
+ */
+ this.mbeanServer = (MBeanServer)
+ mbeanHome.getClass().getMethod(GET_MBEAN_SERVER_METHOD, null).invoke(mbeanHome, null);
+ }
+ catch (NamingException ex) {
+ throw new MBeanServerNotFoundException("Could not find WebLogic's MBeanHome object in JNDI", ex);
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MBeanServerNotFoundException("Could not find WebLogic's MBeanHome class", ex);
+ }
+ catch (InvocationTargetException ex) {
+ throw new MBeanServerNotFoundException(
+ "WebLogic's MBeanHome.getMBeanServer method failed", ex.getTargetException());
+ }
+ catch (Exception ex) {
+ throw new MBeanServerNotFoundException(
+ "Could not access WebLogic's MBeanHome/getMBeanServer method", ex);
+ }
+ }
+
+
+ public Object getObject() {
+ return this.mbeanServer;
+ }
+
+ public Class getObjectType() {
+ return (this.mbeanServer != null ? this.mbeanServer.getClass() : MBeanServer.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/WebLogicMBeanServerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/WebLogicMBeanServerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/WebLogicMBeanServerFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2002-2007 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.jmx.support;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.management.MBeanServer;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.MBeanServerNotFoundException;
+
+/**
+ * FactoryBean that obtains a specified WebLogic {@link javax.management.MBeanServer}
+ * reference through WebLogic's proprietary Helper /
+ * MBeanHome API, which is available on WebLogic 6.1 and higher.
+ *
+ *
Exposes the MBeanServer for bean references.
+ * This FactoryBean is a direct alternative to {@link MBeanServerFactoryBean},
+ * which uses standard JMX 1.2 API to access the platform's MBeanServer.
+ *
+ *
Note: There is also a {@link WebLogicJndiMBeanServerFactoryBean} for
+ * accessing the WebLogic MBeanServer instance through a WebLogic
+ * MBeanHome obtained via a JNDI lookup, typical a local one.
+ *
+ *
NOTE: This class is only intended for use with WebLogic up to 8.1.
+ * On WebLogic 9.x, simply obtain the MBeanServer directly from the JNDI location
+ * "java:comp/env/jmx/runtime", for example through the following configuration:
+ *
+ *
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see weblogic.management.Helper#getMBeanHome(String, String, String, String)
+ * @see weblogic.management.MBeanHome#getMBeanServer()
+ * @see javax.management.MBeanServer
+ * @see MBeanServerFactoryBean
+ * @see WebLogicJndiMBeanServerFactoryBean
+ */
+public class WebLogicMBeanServerFactoryBean implements FactoryBean, InitializingBean {
+
+ private static final String WEBLOGIC_JMX_HELPER_CLASS = "weblogic.management.Helper";
+
+ private static final String GET_MBEAN_HOME_METHOD = "getMBeanHome";
+
+ private static final String GET_MBEAN_SERVER_METHOD = "getMBeanServer";
+
+
+ private String username = "weblogic";
+
+ private String password = "weblogic";
+
+ private String serverUrl = "t3://localhost:7001";
+
+ private String serverName = "server";
+
+ private MBeanServer mbeanServer;
+
+
+ /**
+ * Set the username to use for retrieving the WebLogic MBeanServer.
+ * Default is "weblogic".
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Set the password to use for retrieving the WebLogic MBeanServer.
+ * Default is "weblogic".
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Set the server URL to use for retrieving the WebLogic MBeanServer.
+ * Default is "t3://localhost:7001".
+ */
+ public void setServerUrl(String serverUrl) {
+ this.serverUrl = serverUrl;
+ }
+
+ /**
+ * Set the server name to use for retrieving the WebLogic MBeanServer.
+ * Default is "server".
+ */
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+
+ public void afterPropertiesSet() throws MBeanServerNotFoundException {
+ try {
+ /*
+ * MBeanHome mbeanHome = Helper.getMBeanHome(this.username, this.password, this.serverUrl, this.serverName);
+ */
+ Class helperClass = getClass().getClassLoader().loadClass(WEBLOGIC_JMX_HELPER_CLASS);
+ Class[] argTypes = new Class[] {String.class, String.class, String.class, String.class};
+ Object[] args = new Object[] {this.username, this.password, this.serverUrl, this.serverName};
+ Object mbeanHome = helperClass.getMethod(GET_MBEAN_HOME_METHOD, argTypes).invoke(null, args);
+
+ /*
+ * this.mbeanServer = mbeanHome.getMBeanServer();
+ */
+ this.mbeanServer = (MBeanServer)
+ mbeanHome.getClass().getMethod(GET_MBEAN_SERVER_METHOD, null).invoke(mbeanHome, null);
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MBeanServerNotFoundException("Could not find WebLogic's JMX Helper class", ex);
+ }
+ catch (InvocationTargetException ex) {
+ throw new MBeanServerNotFoundException(
+ "WebLogic's JMX Helper.getMBeanHome/getMBeanServer method failed", ex.getTargetException());
+ }
+ catch (Exception ex) {
+ throw new MBeanServerNotFoundException(
+ "Could not access WebLogic's JMX Helper.getMBeanHome/getMBeanServer method", ex);
+ }
+ }
+
+
+ public Object getObject() {
+ return this.mbeanServer;
+ }
+
+ public Class getObjectType() {
+ return (this.mbeanServer != null ? this.mbeanServer.getClass() : MBeanServer.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/WebSphereMBeanServerFactoryBean.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2002-2007 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.jmx.support;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.management.MBeanServer;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jmx.MBeanServerNotFoundException;
+
+/**
+ * FactoryBean that obtains a WebSphere {@link javax.management.MBeanServer}
+ * reference through WebSphere's proprietary AdminServiceFactory API,
+ * available on WebSphere 5.1 and higher.
+ *
+ *
Exposes the MBeanServer for bean references.
+ * This FactoryBean is a direct alternative to {@link MBeanServerFactoryBean},
+ * which uses standard JMX 1.2 API to access the platform's MBeanServer.
+ *
+ * @author Juergen Hoeller
+ * @author Rob Harrop
+ * @since 2.0.3
+ * @see com.ibm.websphere.management.AdminServiceFactory#getMBeanFactory()
+ * @see com.ibm.websphere.management.MBeanFactory#getMBeanServer()
+ * @see javax.management.MBeanServer
+ * @see MBeanServerFactoryBean
+ */
+public class WebSphereMBeanServerFactoryBean implements FactoryBean, InitializingBean {
+
+ private static final String ADMIN_SERVICE_FACTORY_CLASS = "com.ibm.websphere.management.AdminServiceFactory";
+
+ private static final String GET_MBEAN_FACTORY_METHOD = "getMBeanFactory";
+
+ private static final String GET_MBEAN_SERVER_METHOD = "getMBeanServer";
+
+
+ private MBeanServer mbeanServer;
+
+
+ public void afterPropertiesSet() throws MBeanServerNotFoundException {
+ try {
+ /*
+ * this.mbeanServer = AdminServiceFactory.getMBeanFactory().getMBeanServer();
+ */
+ Class adminServiceClass = getClass().getClassLoader().loadClass(ADMIN_SERVICE_FACTORY_CLASS);
+ Method getMBeanFactoryMethod = adminServiceClass.getMethod(GET_MBEAN_FACTORY_METHOD, new Class[0]);
+ Object mbeanFactory = getMBeanFactoryMethod.invoke(null, new Object[0]);
+ Method getMBeanServerMethod = mbeanFactory.getClass().getMethod(GET_MBEAN_SERVER_METHOD, new Class[0]);
+ this.mbeanServer = (MBeanServer) getMBeanServerMethod.invoke(mbeanFactory, new Object[0]);
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MBeanServerNotFoundException("Could not find WebSphere's AdminServiceFactory class", ex);
+ }
+ catch (InvocationTargetException ex) {
+ throw new MBeanServerNotFoundException(
+ "WebSphere's AdminServiceFactory.getMBeanFactory/getMBeanServer method failed", ex.getTargetException());
+ }
+ catch (Exception ex) {
+ throw new MBeanServerNotFoundException(
+ "Could not access WebSphere's AdminServiceFactory.getMBeanFactory/getMBeanServer method", ex);
+ }
+ }
+
+
+ public Object getObject() {
+ return this.mbeanServer;
+ }
+
+ public Class getObjectType() {
+ return (this.mbeanServer != null ? this.mbeanServer.getClass() : MBeanServer.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jmx/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jmx/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jmx/support/package.html 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Contains support classes for connecting to local and remote MBeanServers
+and for exposing an MBeanServer to remote clients.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiAccessor.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002-2007 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.jndi;
+
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Convenient superclass for JNDI accessors, providing "jndiTemplate"
+ * and "jndiEnvironment" bean properties.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setJndiTemplate
+ * @see #setJndiEnvironment
+ */
+public class JndiAccessor {
+
+ /**
+ * Logger, available to subclasses.
+ */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private JndiTemplate jndiTemplate = new JndiTemplate();
+
+
+ /**
+ * Set the JNDI template to use for JNDI lookups.
+ *
You can also specify JNDI environment settings via "jndiEnvironment".
+ * @see #setJndiEnvironment
+ */
+ public void setJndiTemplate(JndiTemplate jndiTemplate) {
+ this.jndiTemplate = (jndiTemplate != null ? jndiTemplate : new JndiTemplate());
+ }
+
+ /**
+ * Return the JNDI template to use for JNDI lookups.
+ */
+ public JndiTemplate getJndiTemplate() {
+ return this.jndiTemplate;
+ }
+
+ /**
+ * Set the JNDI environment to use for JNDI lookups.
+ *
Creates a JndiTemplate with the given environment settings.
+ * @see #setJndiTemplate
+ */
+ public void setJndiEnvironment(Properties jndiEnvironment) {
+ this.jndiTemplate = new JndiTemplate(jndiEnvironment);
+ }
+
+ /**
+ * Return the JNDI environment to use for JNDI lookups.
+ */
+ public Properties getJndiEnvironment() {
+ return this.jndiTemplate.getEnvironment();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiCallback.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2002-2005 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.jndi;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+/**
+ * Callback interface to be implemented by classes that need to perform an
+ * operation (such as a lookup) in a JNDI context. This callback approach
+ * is valuable in simplifying error handling, which is performed by the
+ * JndiTemplate class. This is a similar to JdbcTemplate's approach.
+ *
+ *
Note that there is hardly any need to implement this callback
+ * interface, as JndiTemplate provides all usual JNDI operations via
+ * convenience methods.
+ *
+ * @see JndiTemplate
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ * @author Rod Johnson
+ */
+public interface JndiCallback {
+
+ /**
+ * Do something with the given JNDI context.
+ * Implementations don't need to worry about error handling
+ * or cleanup, as the JndiTemplate class will handle this.
+ * @param ctx the current JNDI context
+ * @throws NamingException if thrown by JNDI methods
+ * @return a result object, or null
+ */
+ Object doInContext(Context ctx) throws NamingException;
+
+}
+
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiLocatorSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiLocatorSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiLocatorSupport.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2002-2008 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.jndi;
+
+import javax.naming.NamingException;
+
+import org.springframework.util.Assert;
+
+/**
+ * Convenient superclass for classes that can locate any number of JNDI objects.
+ * Derives from JndiAccessor to inherit the "jndiTemplate" and "jndiEnvironment"
+ * bean properties.
+ *
+ *
JNDI names may or may not include the "java:comp/env/" prefix expected
+ * by J2EE applications when accessing a locally mapped (ENC - Environmental
+ * Naming Context) resource. If it doesn't, the "java:comp/env/" prefix will
+ * be prepended if the "resourceRef" property is true (the default is
+ * false) and no other scheme (e.g. "java:") is given.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setJndiTemplate
+ * @see #setJndiEnvironment
+ * @see #setResourceRef
+ */
+public abstract class JndiLocatorSupport extends JndiAccessor {
+
+ /** JNDI prefix used in a J2EE container */
+ public static final String CONTAINER_PREFIX = "java:comp/env/";
+
+
+ private boolean resourceRef = false;
+
+
+ /**
+ * Set whether the lookup occurs in a J2EE container, i.e. if the prefix
+ * "java:comp/env/" needs to be added if the JNDI name doesn't already
+ * contain it. Default is "false".
+ *
Note: Will only get applied if no other scheme (e.g. "java:") is given.
+ */
+ public void setResourceRef(boolean resourceRef) {
+ this.resourceRef = resourceRef;
+ }
+
+ /**
+ * Return whether the lookup occurs in a J2EE container.
+ */
+ public boolean isResourceRef() {
+ return this.resourceRef;
+ }
+
+
+ /**
+ * Perform an actual JNDI lookup for the given name via the JndiTemplate.
+ *
If the name doesn't begin with "java:comp/env/", this prefix is added
+ * if "resourceRef" is set to "true".
+ * @param jndiName the JNDI name to look up
+ * @return the obtained object
+ * @throws NamingException if the JNDI lookup failed
+ * @see #setResourceRef
+ */
+ protected Object lookup(String jndiName) throws NamingException {
+ return lookup(jndiName, null);
+ }
+
+ /**
+ * Perform an actual JNDI lookup for the given name via the JndiTemplate.
+ *
If the name doesn't begin with "java:comp/env/", this prefix is added
+ * if "resourceRef" is set to "true".
+ * @param jndiName the JNDI name to look up
+ * @param requiredType the required type of the object
+ * @return the obtained object
+ * @throws NamingException if the JNDI lookup failed
+ * @see #setResourceRef
+ */
+ protected Object lookup(String jndiName, Class requiredType) throws NamingException {
+ Assert.notNull(jndiName, "'jndiName' must not be null");
+ String convertedName = convertJndiName(jndiName);
+ Object jndiObject = null;
+ try {
+ jndiObject = getJndiTemplate().lookup(convertedName, requiredType);
+ }
+ catch (NamingException ex) {
+ if (!convertedName.equals(jndiName)) {
+ // Try fallback to originally specified name...
+ if (logger.isDebugEnabled()) {
+ logger.debug("Converted JNDI name [" + convertedName +
+ "] not found - trying original name [" + jndiName + "]. " + ex);
+ }
+ jndiObject = getJndiTemplate().lookup(jndiName, requiredType);
+ }
+ else {
+ throw ex;
+ }
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Located object with JNDI name [" + convertedName + "]");
+ }
+ return jndiObject;
+ }
+
+ /**
+ * Convert the given JNDI name into the actual JNDI name to use.
+ *
The default implementation applies the "java:comp/env/" prefix if
+ * "resourceRef" is "true" and no other scheme (e.g. "java:") is given.
+ * @param jndiName the original JNDI name
+ * @return the JNDI name to use
+ * @see #CONTAINER_PREFIX
+ * @see #setResourceRef
+ */
+ protected String convertJndiName(String jndiName) {
+ // Prepend container prefix if not already specified and no other scheme given.
+ if (isResourceRef() && !jndiName.startsWith(CONTAINER_PREFIX) && jndiName.indexOf(':') == -1) {
+ jndiName = CONTAINER_PREFIX + jndiName;
+ }
+ return jndiName;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiLookupFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiLookupFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiLookupFailureException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2002-2007 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.jndi;
+
+import javax.naming.NamingException;
+
+import org.springframework.core.NestedRuntimeException;
+
+/**
+ * RuntimeException to be thrown in case of JNDI lookup failures,
+ * in particular from code that does not declare JNDI's checked
+ * {@link javax.naming.NamingException}: for example, from Spring's
+ * {@link JndiObjectTargetSource}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.3
+ */
+public class JndiLookupFailureException extends NestedRuntimeException {
+
+ /**
+ * Construct a new JndiLookupFailureException,
+ * wrapping the given JNDI NamingException.
+ * @param msg the detail message
+ * @param cause the NamingException root cause
+ */
+ public JndiLookupFailureException(String msg, NamingException cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiObjectFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiObjectFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiObjectFactoryBean.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2002-2008 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.jndi;
+
+import java.lang.reflect.Method;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that looks up a
+ * JNDI object. Exposes the object found in JNDI for bean references,
+ * e.g. for data access object's "dataSource" property in case of a
+ * {@link javax.sql.DataSource}.
+ *
+ *
The typical usage will be to register this as singleton factory
+ * (e.g. for a certain JNDI-bound DataSource) in an application context,
+ * and give bean references to application services that need it.
+ *
+ *
The default behavior is to look up the JNDI object on startup and cache it.
+ * This can be customized through the "lookupOnStartup" and "cache" properties,
+ * using a {@link JndiObjectTargetSource} underneath. Note that you need to specify
+ * a "proxyInterface" in such a scenario, since the actual JNDI object type is not
+ * known in advance.
+ *
+ *
Of course, bean classes in a Spring environment may lookup e.g. a DataSource
+ * from JNDI themselves. This class simply enables central configuration of the
+ * JNDI name, and easy switching to non-JNDI alternatives. The latter is
+ * particularly convenient for test setups, reuse in standalone clients, etc.
+ *
+ *
Note that switching to e.g. DriverManagerDataSource is just a matter of
+ * configuration: Simply replace the definition of this FactoryBean with a
+ * {@link org.springframework.jdbc.datasource.DriverManagerDataSource} definition!
+ *
+ * @author Juergen Hoeller
+ * @since 22.05.2003
+ * @see #setProxyInterface
+ * @see #setLookupOnStartup
+ * @see #setCache
+ * @see JndiObjectTargetSource
+ */
+public class JndiObjectFactoryBean extends JndiObjectLocator implements FactoryBean, BeanClassLoaderAware {
+
+ private Class[] proxyInterfaces;
+
+ private boolean lookupOnStartup = true;
+
+ private boolean cache = true;
+
+ private boolean exposeAccessContext = false;
+
+ private Object defaultObject;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private Object jndiObject;
+
+
+ /**
+ * Specify the proxy interface to use for the JNDI object.
+ *
Typically used in conjunction with "lookupOnStartup"=false and/or "cache"=false.
+ * Needs to be specified because the actual JNDI object type is not known
+ * in advance in case of a lazy lookup.
+ * @see #setProxyInterfaces
+ * @see #setLookupOnStartup
+ * @see #setCache
+ */
+ public void setProxyInterface(Class proxyInterface) {
+ this.proxyInterfaces = new Class[] {proxyInterface};
+ }
+
+ /**
+ * Specify multiple proxy interfaces to use for the JNDI object.
+ *
Typically used in conjunction with "lookupOnStartup"=false and/or "cache"=false.
+ * Note that proxy interfaces will be autodetected from a specified "expectedType",
+ * if necessary.
+ * @see #setExpectedType
+ * @see #setLookupOnStartup
+ * @see #setCache
+ */
+ public void setProxyInterfaces(Class[] proxyInterfaces) {
+ this.proxyInterfaces = proxyInterfaces;
+ }
+
+ /**
+ * Set whether to look up the JNDI object on startup. Default is "true".
+ *
Can be turned off to allow for late availability of the JNDI object.
+ * In this case, the JNDI object will be fetched on first access.
+ *
For a lazy lookup, a proxy interface needs to be specified.
+ * @see #setProxyInterface
+ * @see #setCache
+ */
+ public void setLookupOnStartup(boolean lookupOnStartup) {
+ this.lookupOnStartup = lookupOnStartup;
+ }
+
+ /**
+ * Set whether to cache the JNDI object once it has been located.
+ * Default is "true".
+ *
Can be turned off to allow for hot redeployment of JNDI objects.
+ * In this case, the JNDI object will be fetched for each invocation.
+ *
For hot redeployment, a proxy interface needs to be specified.
+ * @see #setProxyInterface
+ * @see #setLookupOnStartup
+ */
+ public void setCache(boolean cache) {
+ this.cache = cache;
+ }
+
+ /**
+ * Set whether to expose the JNDI environment context for all access to the target
+ * object, i.e. for all method invocations on the exposed object reference.
+ *
Default is "false", i.e. to only expose the JNDI context for object lookup.
+ * Switch this flag to "true" in order to expose the JNDI environment (including
+ * the authorization context) for each method invocation, as needed by WebLogic
+ * for JNDI-obtained factories (e.g. JDBC DataSource, JMS ConnectionFactory)
+ * with authorization requirements.
+ */
+ public void setExposeAccessContext(boolean exposeAccessContext) {
+ this.exposeAccessContext = exposeAccessContext;
+ }
+
+ /**
+ * Specify a default object to fall back to if the JNDI lookup fails.
+ * Default is none.
+ *
This can be an arbitrary bean reference or literal value.
+ * It is typically used for literal values in scenarios where the JNDI environment
+ * might define specific config settings but those are not required to be present.
+ *
Note: This is only supported for lookup on startup.
+ * @see #setLookupOnStartup
+ */
+ public void setDefaultObject(Object defaultObject) {
+ this.defaultObject = defaultObject;
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+
+ /**
+ * Look up the JNDI object and store it.
+ */
+ public void afterPropertiesSet() throws IllegalArgumentException, NamingException {
+ super.afterPropertiesSet();
+
+ if (this.proxyInterfaces != null || !this.lookupOnStartup || !this.cache || this.exposeAccessContext) {
+ // We need to create a proxy for this...
+ if (this.defaultObject != null) {
+ throw new IllegalArgumentException(
+ "'defaultObject' is not supported in combination with 'proxyInterface'");
+ }
+ // We need a proxy and a JndiObjectTargetSource.
+ this.jndiObject = JndiObjectProxyFactory.createJndiObjectProxy(this);
+ }
+ else {
+ if (this.defaultObject != null && getExpectedType() != null &&
+ !getExpectedType().isInstance(this.defaultObject)) {
+ throw new IllegalArgumentException("Default object [" + this.defaultObject +
+ "] of type [" + this.defaultObject.getClass().getName() +
+ "] is not of expected type [" + getExpectedType().getName() + "]");
+ }
+ // Locate specified JNDI object.
+ this.jndiObject = lookupWithFallback();
+ }
+ }
+
+ /**
+ * Lookup variant that that returns the specified "defaultObject"
+ * (if any) in case of lookup failure.
+ * @return the located object, or the "defaultObject" as fallback
+ * @throws NamingException in case of lookup failure without fallback
+ * @see #setDefaultObject
+ */
+ protected Object lookupWithFallback() throws NamingException {
+ ClassLoader originalClassLoader = ClassUtils.overrideThreadContextClassLoader(this.beanClassLoader);
+ try {
+ return lookup();
+ }
+ catch (TypeMismatchNamingException ex) {
+ // Always let TypeMismatchNamingException through -
+ // we don't want to fall back to the defaultObject in this case.
+ throw ex;
+ }
+ catch (NamingException ex) {
+ if (this.defaultObject != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("JNDI lookup failed - returning specified default object instead", ex);
+ }
+ else if (logger.isInfoEnabled()) {
+ logger.info("JNDI lookup failed - returning specified default object instead: " + ex);
+ }
+ return this.defaultObject;
+ }
+ throw ex;
+ }
+ finally {
+ if (originalClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(originalClassLoader);
+ }
+ }
+ }
+
+
+ /**
+ * Return the singleton JNDI object.
+ */
+ public Object getObject() {
+ return this.jndiObject;
+ }
+
+ public Class getObjectType() {
+ if (this.proxyInterfaces != null) {
+ if (this.proxyInterfaces.length == 1) {
+ return this.proxyInterfaces[0];
+ }
+ else if (this.proxyInterfaces.length > 1) {
+ return createCompositeInterface(this.proxyInterfaces);
+ }
+ }
+ if (this.jndiObject != null) {
+ return this.jndiObject.getClass();
+ }
+ else {
+ return getExpectedType();
+ }
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Create a composite interface Class for the given interfaces,
+ * implementing the given interfaces in one single Class.
+ *
The default implementation builds a JDK proxy class for the
+ * given interfaces.
+ * @param interfaces the interfaces to merge
+ * @return the merged interface as Class
+ * @see java.lang.reflect.Proxy#getProxyClass
+ */
+ protected Class createCompositeInterface(Class[] interfaces) {
+ return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
+ }
+
+
+ /**
+ * Inner class to just introduce an AOP dependency when actually creating a proxy.
+ */
+ private static class JndiObjectProxyFactory {
+
+ private static Object createJndiObjectProxy(JndiObjectFactoryBean jof) throws NamingException {
+ // Create a JndiObjectTargetSource that mirrors the JndiObjectFactoryBean's configuration.
+ JndiObjectTargetSource targetSource = new JndiObjectTargetSource();
+ targetSource.setJndiTemplate(jof.getJndiTemplate());
+ targetSource.setJndiName(jof.getJndiName());
+ targetSource.setExpectedType(jof.getExpectedType());
+ targetSource.setResourceRef(jof.isResourceRef());
+ targetSource.setLookupOnStartup(jof.lookupOnStartup);
+ targetSource.setCache(jof.cache);
+ targetSource.afterPropertiesSet();
+
+ // Create a proxy with JndiObjectFactoryBean's proxy interface and the JndiObjectTargetSource.
+ ProxyFactory proxyFactory = new ProxyFactory();
+ if (jof.proxyInterfaces != null) {
+ proxyFactory.setInterfaces(jof.proxyInterfaces);
+ }
+ else {
+ Class targetClass = targetSource.getTargetClass();
+ if (targetClass == null) {
+ throw new IllegalStateException(
+ "Cannot deactivate 'lookupOnStartup' without specifying a 'proxyInterface' or 'expectedType'");
+ }
+ proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, jof.beanClassLoader));
+ }
+ if (jof.exposeAccessContext) {
+ proxyFactory.addAdvice(new JndiContextExposingInterceptor(jof.getJndiTemplate()));
+ }
+ proxyFactory.setTargetSource(targetSource);
+ return proxyFactory.getProxy(jof.beanClassLoader);
+ }
+ }
+
+
+ /**
+ * Interceptor that exposes the JNDI context for all method invocations,
+ * according to JndiObjectFactoryBean's "exposeAccessContext" flag.
+ */
+ private static class JndiContextExposingInterceptor implements MethodInterceptor {
+
+ private final JndiTemplate jndiTemplate;
+
+ public JndiContextExposingInterceptor(JndiTemplate jndiTemplate) {
+ this.jndiTemplate = jndiTemplate;
+ }
+
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ Context ctx = (isEligible(invocation.getMethod()) ? this.jndiTemplate.getContext() : null);
+ try {
+ return invocation.proceed();
+ }
+ finally {
+ this.jndiTemplate.releaseContext(ctx);
+ }
+ }
+
+ protected boolean isEligible(Method method) {
+ return !Object.class.equals(method.getDeclaringClass());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiObjectLocator.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiObjectLocator.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiObjectLocator.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002-2008 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.jndi;
+
+import javax.naming.NamingException;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.StringUtils;
+
+/**
+ * Convenient superclass for JNDI-based service locators,
+ * providing configurable lookup of a specific JNDI resource.
+ *
+ *
Exposes a {@link #setJndiName "jndiName"} property. This may or may not
+ * include the "java:comp/env/" prefix expected by J2EE applications when
+ * accessing a locally mapped (Environmental Naming Context) resource. If it
+ * doesn't, the "java:comp/env/" prefix will be prepended if the "resourceRef"
+ * property is true (the default is false) and no other scheme
+ * (e.g. "java:") is given.
+ *
+ *
Subclasses may invoke the {@link #lookup()} method whenever it is appropriate.
+ * Some classes might do this on initialization, while others might do it
+ * on demand. The latter strategy is more flexible in that it allows for
+ * initialization of the locator before the JNDI object is available.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setJndiName
+ * @see #setJndiTemplate
+ * @see #setJndiEnvironment
+ * @see #setResourceRef
+ * @see #lookup()
+ */
+public abstract class JndiObjectLocator extends JndiLocatorSupport implements InitializingBean {
+
+ private String jndiName;
+
+ private Class expectedType;
+
+
+ /**
+ * Specify the JNDI name to look up. If it doesn't begin with "java:comp/env/"
+ * this prefix is added automatically if "resourceRef" is set to "true".
+ * @param jndiName the JNDI name to look up
+ * @see #setResourceRef
+ */
+ public void setJndiName(String jndiName) {
+ this.jndiName = jndiName;
+ }
+
+ /**
+ * Return the JNDI name to look up.
+ */
+ public String getJndiName() {
+ return this.jndiName;
+ }
+
+ /**
+ * Specify the type that the located JNDI object is supposed
+ * to be assignable to, if any.
+ */
+ public void setExpectedType(Class expectedType) {
+ this.expectedType = expectedType;
+ }
+
+ /**
+ * Return the type that the located JNDI object is supposed
+ * to be assignable to, if any.
+ */
+ public Class getExpectedType() {
+ return this.expectedType;
+ }
+
+ public void afterPropertiesSet() throws IllegalArgumentException, NamingException {
+ if (!StringUtils.hasLength(getJndiName())) {
+ throw new IllegalArgumentException("Property 'jndiName' is required");
+ }
+ }
+
+
+ /**
+ * Perform the actual JNDI lookup for this locator's target resource.
+ * @return the located target object
+ * @throws NamingException if the JNDI lookup failed or if the
+ * located JNDI object is not assigable to the expected type
+ * @see #setJndiName
+ * @see #setExpectedType
+ * @see #lookup(String, Class)
+ */
+ protected Object lookup() throws NamingException {
+ return lookup(getJndiName(), getExpectedType());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiObjectTargetSource.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiObjectTargetSource.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiObjectTargetSource.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2002-2007 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.jndi;
+
+import javax.naming.NamingException;
+
+import org.springframework.aop.TargetSource;
+
+/**
+ * AOP {@link org.springframework.aop.TargetSource} that provides
+ * configurable JNDI lookups for getTarget() calls.
+ *
+ *
Can be used as alternative to {@link JndiObjectFactoryBean}, to allow for
+ * relocating a JNDI object lazily or for each operation (see "lookupOnStartup"
+ * and "cache" properties). This is particularly useful during development, as it
+ * allows for hot restarting of the JNDI server (for example, a remote JMS server).
+ *
+ *
+ *
+ * A createQueueConnection call on the "queueConnectionFactory" proxy will
+ * cause a lazy JNDI lookup for "JmsQueueConnectionFactory" and a subsequent delegating
+ * call to the retrieved QueueConnectionFactory's createQueueConnection.
+ *
+ *
Alternatively, use a {@link JndiObjectFactoryBean} with a "proxyInterface".
+ * "lookupOnStartup" and "cache" can then be specified on the JndiObjectFactoryBean,
+ * creating a JndiObjectTargetSource underneath (instead of defining separate
+ * ProxyFactoryBean and JndiObjectTargetSource beans).
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setLookupOnStartup
+ * @see #setCache
+ * @see org.springframework.aop.framework.ProxyFactoryBean#setTargetSource
+ * @see JndiObjectFactoryBean#setProxyInterface
+ */
+public class JndiObjectTargetSource extends JndiObjectLocator implements TargetSource {
+
+ private boolean lookupOnStartup = true;
+
+ private boolean cache = true;
+
+ private Object cachedObject;
+
+ private Class targetClass;
+
+
+ /**
+ * Set whether to look up the JNDI object on startup. Default is "true".
+ *
Can be turned off to allow for late availability of the JNDI object.
+ * In this case, the JNDI object will be fetched on first access.
+ * @see #setCache
+ */
+ public void setLookupOnStartup(boolean lookupOnStartup) {
+ this.lookupOnStartup = lookupOnStartup;
+ }
+
+ /**
+ * Set whether to cache the JNDI object once it has been located.
+ * Default is "true".
+ *
Can be turned off to allow for hot redeployment of JNDI objects.
+ * In this case, the JNDI object will be fetched for each invocation.
+ * @see #setLookupOnStartup
+ */
+ public void setCache(boolean cache) {
+ this.cache = cache;
+ }
+
+ public void afterPropertiesSet() throws NamingException {
+ super.afterPropertiesSet();
+ if (this.lookupOnStartup) {
+ Object object = lookup();
+ if (this.cache) {
+ this.cachedObject = object;
+ }
+ else {
+ this.targetClass = object.getClass();
+ }
+ }
+ }
+
+
+ public Class getTargetClass() {
+ if (this.cachedObject != null) {
+ return this.cachedObject.getClass();
+ }
+ else if (this.targetClass != null) {
+ return this.targetClass;
+ }
+ else {
+ return getExpectedType();
+ }
+ }
+
+ public boolean isStatic() {
+ return (this.cachedObject != null);
+ }
+
+ public Object getTarget() {
+ try {
+ if (this.lookupOnStartup || !this.cache) {
+ return (this.cachedObject != null ? this.cachedObject : lookup());
+ }
+ else {
+ synchronized (this) {
+ if (this.cachedObject == null) {
+ this.cachedObject = lookup();
+ }
+ return this.cachedObject;
+ }
+ }
+ }
+ catch (NamingException ex) {
+ throw new JndiLookupFailureException("JndiObjectTargetSource failed to obtain new target object", ex);
+ }
+ }
+
+ public void releaseTarget(Object target) {
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiTemplate.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2002-2008 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.jndi;
+
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Helper class that simplifies JNDI operations. It provides methods to lookup and
+ * bind objects, and allows implementations of the {@link JndiCallback} interface
+ * to perform any operation they like with a JNDI naming context provided.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @see JndiCallback
+ * @see #execute
+ */
+public class JndiTemplate {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private Properties environment;
+
+
+ /**
+ * Create a new JndiTemplate instance.
+ */
+ public JndiTemplate() {
+ }
+
+ /**
+ * Create a new JndiTemplate instance, using the given environment.
+ */
+ public JndiTemplate(Properties environment) {
+ this.environment = environment;
+ }
+
+
+ /**
+ * Set the environment for the JNDI InitialContext.
+ */
+ public void setEnvironment(Properties environment) {
+ this.environment = environment;
+ }
+
+ /**
+ * Return the environment for the JNDI InitialContext, if any.
+ */
+ public Properties getEnvironment() {
+ return this.environment;
+ }
+
+
+ /**
+ * Execute the given JNDI context callback implementation.
+ * @param contextCallback JndiCallback implementation
+ * @return a result object returned by the callback, or null
+ * @throws NamingException thrown by the callback implementation
+ * @see #createInitialContext
+ */
+ public Object execute(JndiCallback contextCallback) throws NamingException {
+ Context ctx = getContext();
+ try {
+ return contextCallback.doInContext(ctx);
+ }
+ finally {
+ releaseContext(ctx);
+ }
+ }
+
+ /**
+ * Obtain a JNDI context corresponding to this template's configuration.
+ * Called by {@link #execute}; may also be called directly.
+ *
The default implementation delegates to {@link #createInitialContext()}.
+ * @return the JNDI context (never null)
+ * @throws NamingException if context retrieval failed
+ * @see #releaseContext
+ */
+ public Context getContext() throws NamingException {
+ return createInitialContext();
+ }
+
+ /**
+ * Release a JNDI context as obtained from {@link #getContext()}.
+ * @param ctx the JNDI context to release (may be null)
+ * @see #getContext
+ */
+ public void releaseContext(Context ctx) {
+ if (ctx != null) {
+ try {
+ ctx.close();
+ }
+ catch (NamingException ex) {
+ logger.debug("Could not close JNDI InitialContext", ex);
+ }
+ }
+ }
+
+ /**
+ * Create a new JNDI initial context. Invoked by {@link #getContext}.
+ *
The default implementation use this template's environment settings.
+ * Can be subclassed for custom contexts, e.g. for testing.
+ * @return the initial Context instance
+ * @throws NamingException in case of initialization errors
+ */
+ protected Context createInitialContext() throws NamingException {
+ Hashtable icEnv = null;
+ Properties env = getEnvironment();
+ if (env != null) {
+ icEnv = new Hashtable(env.size());
+ CollectionUtils.mergePropertiesIntoMap(env, icEnv);
+ }
+ return new InitialContext(icEnv);
+ }
+
+
+ /**
+ * Look up the object with the given name in the current JNDI context.
+ * @param name the JNDI name of the object
+ * @return object found (cannot be null; if a not so well-behaved
+ * JNDI implementations returns null, a NamingException gets thrown)
+ * @throws NamingException if there is no object with the given
+ * name bound to JNDI
+ */
+ public Object lookup(final String name) throws NamingException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Looking up JNDI object with name [" + name + "]");
+ }
+ return execute(new JndiCallback() {
+ public Object doInContext(Context ctx) throws NamingException {
+ Object located = ctx.lookup(name);
+ if (located == null) {
+ throw new NameNotFoundException(
+ "JNDI object with [" + name + "] not found: JNDI implementation returned null");
+ }
+ return located;
+ }
+ });
+ }
+
+ /**
+ * Look up the object with the given name in the current JNDI context.
+ * @param name the JNDI name of the object
+ * @param requiredType type the JNDI object must match. Can be an interface or
+ * superclass of the actual class, or null for any match. For example,
+ * if the value is Object.class, this method will succeed whatever
+ * the class of the returned instance.
+ * @return object found (cannot be null; if a not so well-behaved
+ * JNDI implementations returns null, a NamingException gets thrown)
+ * @throws NamingException if there is no object with the given
+ * name bound to JNDI
+ */
+ public Object lookup(String name, Class requiredType) throws NamingException {
+ Object jndiObject = lookup(name);
+ if (requiredType != null && !requiredType.isInstance(jndiObject)) {
+ throw new TypeMismatchNamingException(
+ name, requiredType, (jndiObject != null ? jndiObject.getClass() : null));
+ }
+ return jndiObject;
+ }
+
+ /**
+ * Bind the given object to the current JNDI context, using the given name.
+ * @param name the JNDI name of the object
+ * @param object the object to bind
+ * @throws NamingException thrown by JNDI, mostly name already bound
+ */
+ public void bind(final String name, final Object object) throws NamingException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Binding JNDI object with name [" + name + "]");
+ }
+ execute(new JndiCallback() {
+ public Object doInContext(Context ctx) throws NamingException {
+ ctx.bind(name, object);
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Rebind the given object to the current JNDI context, using the given name.
+ * Overwrites any existing binding.
+ * @param name the JNDI name of the object
+ * @param object the object to rebind
+ * @throws NamingException thrown by JNDI
+ */
+ public void rebind(final String name, final Object object) throws NamingException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Rebinding JNDI object with name [" + name + "]");
+ }
+ execute(new JndiCallback() {
+ public Object doInContext(Context ctx) throws NamingException {
+ ctx.rebind(name, object);
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Remove the binding for the given name from the current JNDI context.
+ * @param name the JNDI name of the object
+ * @throws NamingException thrown by JNDI, mostly name not found
+ */
+ public void unbind(final String name) throws NamingException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Unbinding JNDI object with name [" + name + "]");
+ }
+ execute(new JndiCallback() {
+ public Object doInContext(Context ctx) throws NamingException {
+ ctx.unbind(name);
+ return null;
+ }
+ });
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/JndiTemplateEditor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/JndiTemplateEditor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/JndiTemplateEditor.java 17 Aug 2012 15:15:27 -0000 1.1
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2005 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.jndi;
+
+import java.beans.PropertyEditorSupport;
+import java.util.Properties;
+
+import org.springframework.beans.propertyeditors.PropertiesEditor;
+
+/**
+ * Properties editor for JndiTemplate objects. Allows properties of type
+ * JndiTemplate to be populated with a properties-format string.
+ *
+ * @author Rod Johnson
+ * @since 09.05.2003
+ */
+public class JndiTemplateEditor extends PropertyEditorSupport {
+
+ private final PropertiesEditor propertiesEditor = new PropertiesEditor();
+
+ public void setAsText(String text) throws IllegalArgumentException {
+ if (text == null) {
+ throw new IllegalArgumentException("JndiTemplate cannot be created from null string");
+ }
+ if ("".equals(text)) {
+ // empty environment
+ setValue(new JndiTemplate());
+ }
+ else {
+ // we have a non-empty properties string
+ this.propertiesEditor.setAsText(text);
+ Properties props = (Properties) this.propertiesEditor.getValue();
+ setValue(new JndiTemplate(props));
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/TypeMismatchNamingException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/TypeMismatchNamingException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/TypeMismatchNamingException.java 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2007 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.jndi;
+
+import javax.naming.NamingException;
+
+/**
+ * Exception thrown if a type mismatch is encountered for an object
+ * located in a JNDI environment. Thrown by JndiTemplate.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2.8
+ * @see JndiTemplate#lookup(String, Class)
+ */
+public class TypeMismatchNamingException extends NamingException {
+
+ private Class requiredType;
+
+ private Class actualType;
+
+
+ /**
+ * Construct a new TypeMismatchNamingException,
+ * building an explanation text from the given arguments.
+ * @param jndiName the JNDI name
+ * @param requiredType the required type for the lookup
+ * @param actualType the actual type that the lookup returned
+ */
+ public TypeMismatchNamingException(String jndiName, Class requiredType, Class actualType) {
+ super("Object of type [" + actualType + "] available at JNDI location [" +
+ jndiName + "] is not assignable to [" + requiredType.getName() + "]");
+ this.requiredType = requiredType;
+ this.actualType = actualType;
+ }
+
+ /**
+ * Construct a new TypeMismatchNamingException.
+ * @param explanation the explanation text
+ */
+ public TypeMismatchNamingException(String explanation) {
+ super(explanation);
+ }
+
+
+ /**
+ * Return the required type for the lookup, if available.
+ */
+ public final Class getRequiredType() {
+ return this.requiredType;
+ }
+
+ /**
+ * Return the actual type that the lookup returned, if available.
+ */
+ public final Class getActualType() {
+ return this.actualType;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/package.html 17 Aug 2012 15:15:28 -0000 1.1
@@ -0,0 +1,13 @@
+
+
+
+The classes in this package make JNDI easier to use,
+facilitating the accessing of configuration stored in JNDI,
+and provide useful superclasses for JNDI access classes.
+
+
The classes in this package are discussed in Chapter 11 of
+Expert One-On-One J2EE Design and Development
+by Rod Johnson (Wrox, 2002).
+
+
+
Index: 3rdParty_sources/spring/org/springframework/jndi/support/SimpleJndiBeanFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/support/SimpleJndiBeanFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/support/SimpleJndiBeanFactory.java 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2002-2007 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.jndi.support;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.jndi.JndiLocatorSupport;
+import org.springframework.jndi.TypeMismatchNamingException;
+
+/**
+ * Simple JNDI-based implementation of Spring's
+ * {@link org.springframework.beans.factory.BeanFactory} interface.
+ * Does not support enumerating bean definitions, hence doesn't implement
+ * the {@link org.springframework.beans.factory.ListableBeanFactory} interface.
+ *
+ *
This factory resolves given bean names as JNDI names within the
+ * J2EE application's "java:comp/env/" namespace. It caches the resolved
+ * types for all obtained objects, and optionally also caches shareable
+ * objects (if they are explicitly marked as
+ * {@link #addShareableResource shareable resource}.
+ *
+ *
The main intent of this factory is usage in combination with Spring's
+ * {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor},
+ * configured as "resourceFactory" for resolving @Resource
+ * annotations as JNDI objects without intermediate bean definitions.
+ * It may be used for similar lookup scenarios as well, of course,
+ * in particular if BeanFactory-style type checking is required.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ * @see org.springframework.beans.factory.support.DefaultListableBeanFactory
+ * @see org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
+ */
+public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFactory {
+
+ /** JNDI names of resources that are known to be shareable, i.e. can be cached */
+ private final Set shareableResources = new HashSet();
+
+ /** Cache of shareable singleton objects: bean name --> bean instance */
+ private final Map singletonObjects = new HashMap();
+
+ /** Cache of the types of nonshareable resources: bean name --> bean type */
+ private final Map resourceTypes = new HashMap();
+
+
+ public SimpleJndiBeanFactory() {
+ setResourceRef(true);
+ }
+
+
+ /**
+ * Set a list of names of shareable JNDI resources,
+ * which this factory is allowed to cache once obtained.
+ * @param shareableResources the JNDI names
+ * (typically within the "java:comp/env/" namespace)
+ */
+ public void setShareableResources(String[] shareableResources) {
+ this.shareableResources.addAll(Arrays.asList(shareableResources));
+ }
+
+ /**
+ * Add the name of a shareable JNDI resource,
+ * which this factory is allowed to cache once obtained.
+ * @param shareableResource the JNDI name
+ * (typically within the "java:comp/env/" namespace)
+ */
+ public void addShareableResource(String shareableResource) {
+ this.shareableResources.add(shareableResource);
+ }
+
+
+ public Object getBean(String name) throws BeansException {
+ return getBean(name, (Class) null);
+ }
+
+ public Object getBean(String name, Class requiredType) throws BeansException {
+ try {
+ if (isSingleton(name)) {
+ return doGetSingleton(name, requiredType);
+ }
+ else {
+ return lookup(name, requiredType);
+ }
+ }
+ catch (NameNotFoundException ex) {
+ throw new NoSuchBeanDefinitionException(name, "not found in JNDI environment");
+ }
+ catch (TypeMismatchNamingException ex) {
+ throw new BeanNotOfRequiredTypeException(name, ex.getRequiredType(), ex.getActualType());
+ }
+ catch (NamingException ex) {
+ throw new BeanDefinitionStoreException("JNDI environment", name, "JNDI lookup failed", ex);
+ }
+ }
+
+ public Object getBean(String name, Object[] args) throws BeansException {
+ if (args != null) {
+ throw new UnsupportedOperationException(
+ "SimpleJndiBeanFactory does not support explicit bean creation arguments)");
+ }
+ return getBean(name);
+ }
+
+ public boolean containsBean(String name) {
+ if (this.singletonObjects.containsKey(name) || this.resourceTypes.containsKey(name)) {
+ return true;
+ }
+ try {
+ doGetType(name);
+ return true;
+ }
+ catch (NamingException ex) {
+ return false;
+ }
+ }
+
+ public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+ return this.shareableResources.contains(name);
+ }
+
+ public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
+ return !this.shareableResources.contains(name);
+ }
+
+ public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
+ Class type = getType(name);
+ return (targetType == null || (type != null && targetType.isAssignableFrom(type)));
+ }
+
+ public Class getType(String name) throws NoSuchBeanDefinitionException {
+ try {
+ return doGetType(name);
+ }
+ catch (NameNotFoundException ex) {
+ throw new NoSuchBeanDefinitionException(name, "not found in JNDI environment");
+ }
+ catch (NamingException ex) {
+ return null;
+ }
+ }
+
+ public String[] getAliases(String name) {
+ return new String[0];
+ }
+
+
+ private Object doGetSingleton(String name, Class requiredType) throws NamingException {
+ synchronized (this.singletonObjects) {
+ if (this.singletonObjects.containsKey(name)) {
+ Object jndiObject = this.singletonObjects.get(name);
+ if (requiredType != null && !requiredType.isInstance(jndiObject)) {
+ throw new TypeMismatchNamingException(
+ convertJndiName(name), requiredType, (jndiObject != null ? jndiObject.getClass() : null));
+ }
+ return jndiObject;
+ }
+ Object jndiObject = lookup(name, requiredType);
+ this.singletonObjects.put(name, jndiObject);
+ return jndiObject;
+ }
+ }
+
+ private Class doGetType(String name) throws NamingException {
+ if (isSingleton(name)) {
+ Object jndiObject = doGetSingleton(name, null);
+ return (jndiObject != null ? jndiObject.getClass() : null);
+ }
+ else {
+ synchronized (this.resourceTypes) {
+ if (this.resourceTypes.containsKey(name)) {
+ return (Class) this.resourceTypes.get(name);
+ }
+ else {
+ Object jndiObject = lookup(name, null);
+ Class type = (jndiObject != null ? jndiObject.getClass() : null);
+ this.resourceTypes.put(name, type);
+ return type;
+ }
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/jndi/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/jndi/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/jndi/support/package.html 17 Aug 2012 15:15:30 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Support classes for JNDI usage,
+including a JNDI-based BeanFactory implementation.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/mail/MailAuthenticationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailAuthenticationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailAuthenticationException.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002-2006 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.mail;
+
+/**
+ * Exception thrown on failed authentication.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ */
+public class MailAuthenticationException extends MailException {
+
+ /**
+ * Constructor for MailAuthenticationException.
+ * @param msg message
+ */
+ public MailAuthenticationException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for MailAuthenticationException.
+ * @param msg the detail message
+ * @param cause the root cause from the mail API in use
+ */
+ public MailAuthenticationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructor for MailAuthenticationException.
+ * @param cause the root cause from the mail API in use
+ */
+ public MailAuthenticationException(Throwable cause) {
+ super("Authentication failed", cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailException.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-2006 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.mail;
+
+import org.springframework.core.NestedRuntimeException;
+
+/**
+ * Base class for all mail exceptions.
+ *
+ * @author Dmitriy Kopylenko
+ */
+public abstract class MailException extends NestedRuntimeException {
+
+ /**
+ * Constructor for MailException.
+ * @param msg the detail message
+ */
+ public MailException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for MailException.
+ * @param msg the detail message
+ * @param cause the root cause from the mail API in use
+ */
+ public MailException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailMessage.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailMessage.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailMessage.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2002-2005 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.mail;
+
+import java.util.Date;
+
+/**
+ * This is a common interface for mail messages, allowing a user to set key
+ * values required in assembling a mail message, without needing to know if
+ * the underlying message is a simple text message or a more sophisticated
+ * MIME message.
+ *
+ *
Implemented by both SimpleMailMessage and MimeMessageHelper,
+ * to let message population code interact with a simple message or a
+ * MIME message through a common interface.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see SimpleMailMessage
+ * @see org.springframework.mail.javamail.MimeMessageHelper
+ */
+public interface MailMessage {
+
+ public void setFrom(String from) throws MailParseException;
+
+ public void setReplyTo(String replyTo) throws MailParseException;
+
+ public void setTo(String to) throws MailParseException;
+
+ public void setTo(String[] to) throws MailParseException;
+
+ public void setCc(String cc) throws MailParseException;
+
+ public void setCc(String[] cc) throws MailParseException;
+
+ public void setBcc(String bcc) throws MailParseException;
+
+ public void setBcc(String[] bcc) throws MailParseException;
+
+ public void setSentDate(Date sentDate) throws MailParseException;
+
+ public void setSubject(String subject) throws MailParseException;
+
+ public void setText(String text) throws MailParseException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailParseException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailParseException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailParseException.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2002-2006 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.mail;
+
+/**
+ * Exception thrown if illegal message properties are encountered.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ */
+public class MailParseException extends MailException {
+
+ /**
+ * Constructor for MailParseException.
+ * @param msg the detail message
+ */
+ public MailParseException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for MailParseException.
+ * @param msg the detail message
+ * @param cause the root cause from the mail API in use
+ */
+ public MailParseException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructor for MailParseException.
+ * @param cause the root cause from the mail API in use
+ */
+ public MailParseException(Throwable cause) {
+ super("Could not parse mail", cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailPreparationException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailPreparationException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailPreparationException.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2006 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.mail;
+
+/**
+ * Exception to be thrown by user code if a mail cannot be prepared properly,
+ * for example when a Velocity template cannot be rendered for the mail text.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see org.springframework.ui.velocity.VelocityEngineUtils#mergeTemplateIntoString
+ * @see org.springframework.ui.freemarker.FreeMarkerTemplateUtils#processTemplateIntoString
+ */
+public class MailPreparationException extends MailException {
+
+ /**
+ * Constructor for MailPreparationException.
+ * @param msg the detail message
+ */
+ public MailPreparationException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for MailPreparationException.
+ * @param msg the detail message
+ * @param cause the root cause from the mail API in use
+ */
+ public MailPreparationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public MailPreparationException(Throwable cause) {
+ super("Could not prepare mail", cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailSendException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailSendException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailSendException.java 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2002-2007 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.mail;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Exception thrown when a mail sending error is encountered.
+ * Can register failed messages with their exceptions.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ */
+public class MailSendException extends MailException {
+
+ private transient Map failedMessages;
+
+ private Exception[] messageExceptions;
+
+
+ /**
+ * Constructor for MailSendException.
+ * @param msg the detail message
+ */
+ public MailSendException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructor for MailSendException.
+ * @param msg the detail message
+ * @param cause the root cause from the mail API in use
+ */
+ public MailSendException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Constructor for registration of failed messages, with the
+ * messages that failed as keys, and the thrown exceptions as values.
+ *
The messages should be the same that were originally passed
+ * to the invoked send method.
+ * @param failedMessages Map of failed messages as keys and thrown
+ * exceptions as values
+ */
+ public MailSendException(Map failedMessages) {
+ super(null);
+ this.failedMessages = new LinkedHashMap(failedMessages);
+ this.messageExceptions = (Exception[]) failedMessages.values().toArray(new Exception[failedMessages.size()]);
+ }
+
+
+ /**
+ * Return a Map with the failed messages as keys, and the thrown exceptions
+ * as values.
+ *
Note that a general mail server connection failure will not result
+ * in failed messages being returned here: A message will only be
+ * contained here if actually sending it was attempted but failed.
+ *
The messages will be the same that were originally passed to the
+ * invoked send method, that is, SimpleMailMessages in case of using
+ * the generic MailSender interface.
+ *
In case of sending MimeMessage instances via JavaMailSender,
+ * the messages will be of type MimeMessage.
+ *
NOTE: This Map will not be available after serialization.
+ * Use {@link #getMessageExceptions()} in such a scenario, which will
+ * be available after serialization as well.
+ * @return the Map of failed messages as keys and thrown exceptions as
+ * values, or an empty Map if no failed messages
+ * @see SimpleMailMessage
+ * @see javax.mail.internet.MimeMessage
+ */
+ public final Map getFailedMessages() {
+ return (this.failedMessages != null ? this.failedMessages : Collections.EMPTY_MAP);
+ }
+
+ /**
+ * Return an array with thrown message exceptions.
+ *
Note that a general mail server connection failure will not result
+ * in failed messages being returned here: A message will only be
+ * contained here if actually sending it was attempted but failed.
+ * @return the array of thrown message exceptions,
+ * or an empty array if no failed messages
+ */
+ public final Exception[] getMessageExceptions() {
+ return (this.messageExceptions != null ? this.messageExceptions : new Exception[0]);
+ }
+
+
+ public String getMessage() {
+ if (ObjectUtils.isEmpty(this.messageExceptions)) {
+ return super.getMessage();
+ }
+ else {
+ StringBuffer sb = new StringBuffer("Failed messages: ");
+ for (int i = 0; i < this.messageExceptions.length; i++) {
+ Exception subEx = this.messageExceptions[i];
+ sb.append(subEx.toString());
+ if (i < this.messageExceptions.length - 1) {
+ sb.append("; ");
+ }
+ }
+ return sb.toString();
+ }
+ }
+
+ public String toString() {
+ if (ObjectUtils.isEmpty(this.messageExceptions)) {
+ return super.toString();
+ }
+ else {
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("; nested exceptions (").append(this.messageExceptions.length).append(") are:");
+ for (int i = 0; i < this.messageExceptions.length; i++) {
+ Exception subEx = this.messageExceptions[i];
+ sb.append('\n').append("Failed message ").append(i + 1).append(": ");
+ sb.append(subEx);
+ }
+ return sb.toString();
+ }
+ }
+
+ public void printStackTrace(PrintStream ps) {
+ if (ObjectUtils.isEmpty(this.messageExceptions)) {
+ super.printStackTrace(ps);
+ }
+ else {
+ ps.println(getClass().getName() + "; nested exception details (" +
+ this.messageExceptions.length + ") are:");
+ for (int i = 0; i < this.messageExceptions.length; i++) {
+ Exception subEx = this.messageExceptions[i];
+ ps.println("Failed message " + (i + 1) + ":");
+ subEx.printStackTrace(ps);
+ }
+ }
+ }
+
+ public void printStackTrace(PrintWriter pw) {
+ if (ObjectUtils.isEmpty(this.messageExceptions)) {
+ super.printStackTrace(pw);
+ }
+ else {
+ pw.println(getClass().getName() + "; nested exception details (" +
+ this.messageExceptions.length + ") are:");
+ for (int i = 0; i < this.messageExceptions.length; i++) {
+ Exception subEx = this.messageExceptions[i];
+ pw.println("Failed message " + (i + 1) + ":");
+ subEx.printStackTrace(pw);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/MailSender.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/MailSender.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/MailSender.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2005 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.mail;
+
+/**
+ * This interface defines a strategy for sending simple mails. Can be
+ * implemented for a variety of mailing systems due to the simple requirements.
+ * For richer functionality like MIME messages, consider JavaMailSender.
+ *
+ *
Allows for easy testing of clients, as it does not depend on JavaMail's
+ * infrastructure classes: no mocking of JavaMail Session or Transport necessary.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ * @since 10.09.2003
+ * @see org.springframework.mail.javamail.JavaMailSender
+ */
+public interface MailSender {
+
+ /**
+ * Send the given simple mail message.
+ * @param simpleMessage the message to send
+ * @throws org.springframework.mail.MailParseException
+ * in case of failure when parsing the message
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending the message
+ */
+ void send(SimpleMailMessage simpleMessage) throws MailException;
+
+ /**
+ * Send the given array of simple mail messages in batch.
+ * @param simpleMessages the messages to send
+ * @throws org.springframework.mail.MailParseException
+ * in case of failure when parsing a message
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending a message
+ */
+ void send(SimpleMailMessage[] simpleMessages) throws MailException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/SimpleMailMessage.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/SimpleMailMessage.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/SimpleMailMessage.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2002-2006 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.mail;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.util.Assert;
+
+/**
+ * Models a simple mail message, including data such as the from, to, cc, subject, and text fields.
+ *
+ *
Consider JavaMailSender and JavaMail MimeMessages for creating
+ * more sophisticated messages, for example messages with attachments, special
+ * character encodings, or personal names that accompany mail addresses.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ * @since 10.09.2003
+ * @see MailSender
+ * @see org.springframework.mail.javamail.JavaMailSender
+ * @see org.springframework.mail.javamail.MimeMessagePreparator
+ * @see org.springframework.mail.javamail.MimeMessageHelper
+ * @see org.springframework.mail.javamail.MimeMailMessage
+ */
+public class SimpleMailMessage implements MailMessage, Serializable {
+
+ private String from;
+
+ private String replyTo;
+
+ private String[] to;
+
+ private String[] cc;
+
+ private String[] bcc;
+
+ private Date sentDate;
+
+ private String subject;
+
+ private String text;
+
+
+ /**
+ * Create a new SimpleMailMessage.
+ */
+ public SimpleMailMessage() {
+ }
+
+ /**
+ * Copy constructor for creating a new SimpleMailMessage from the state
+ * of an existing SimpleMailMessage instance.
+ * @throws IllegalArgumentException if the supplied message is null
+ */
+ public SimpleMailMessage(SimpleMailMessage original) {
+ Assert.notNull(original, "The 'original' message argument cannot be null");
+ this.from = original.getFrom();
+ this.replyTo = original.getReplyTo();
+ if (original.getTo() != null) {
+ this.to = copy(original.getTo());
+ }
+ if (original.getCc() != null) {
+ this.cc = copy(original.getCc());
+ }
+ if (original.getBcc() != null) {
+ this.bcc = copy(original.getBcc());
+ }
+ this.sentDate = original.getSentDate();
+ this.subject = original.getSubject();
+ this.text = original.getText();
+ }
+
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getFrom() {
+ return this.from;
+ }
+
+ public void setReplyTo(String replyTo) {
+ this.replyTo = replyTo;
+ }
+
+ public String getReplyTo() {
+ return replyTo;
+ }
+
+ public void setTo(String to) {
+ this.to = new String[] {to};
+ }
+
+ public void setTo(String[] to) {
+ this.to = to;
+ }
+
+ public String[] getTo() {
+ return this.to;
+ }
+
+ public void setCc(String cc) {
+ this.cc = new String[] {cc};
+ }
+
+ public void setCc(String[] cc) {
+ this.cc = cc;
+ }
+
+ public String[] getCc() {
+ return cc;
+ }
+
+ public void setBcc(String bcc) {
+ this.bcc = new String[] {bcc};
+ }
+
+ public void setBcc(String[] bcc) {
+ this.bcc = bcc;
+ }
+
+ public String[] getBcc() {
+ return bcc;
+ }
+
+ public void setSentDate(Date sentDate) {
+ this.sentDate = sentDate;
+ }
+
+ public Date getSentDate() {
+ return sentDate;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public String getSubject() {
+ return this.subject;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return this.text;
+ }
+
+
+ /**
+ * Copy the contents of this message to the given target message.
+ * @param target the MailMessage to copy to
+ * @throws IllegalArgumentException if the supplied target is null
+ */
+ public void copyTo(MailMessage target) {
+ Assert.notNull(target, "The 'target' message argument cannot be null");
+ if (getFrom() != null) {
+ target.setFrom(getFrom());
+ }
+ if (getReplyTo() != null) {
+ target.setReplyTo(getReplyTo());
+ }
+ if (getTo() != null) {
+ target.setTo(getTo());
+ }
+ if (getCc() != null) {
+ target.setCc(getCc());
+ }
+ if (getBcc() != null) {
+ target.setBcc(getBcc());
+ }
+ if (getSentDate() != null) {
+ target.setSentDate(getSentDate());
+ }
+ if (getSubject() != null) {
+ target.setSubject(getSubject());
+ }
+ if (getText() != null) {
+ target.setText(getText());
+ }
+ }
+
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("SimpleMailMessage: ");
+ sb.append("from=").append(this.from).append("; ");
+ sb.append("replyTo=").append(this.replyTo).append("; ");
+ sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");
+ sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");
+ sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");
+ sb.append("sentDate=").append(this.sentDate).append("; ");
+ sb.append("subject=").append(this.subject).append("; ");
+ sb.append("text=").append(this.text);
+ return sb.toString();
+ }
+
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof SimpleMailMessage)) {
+ return false;
+ }
+ SimpleMailMessage otherMessage = (SimpleMailMessage) other;
+ return (ObjectUtils.nullSafeEquals(this.from, otherMessage.from) &&
+ ObjectUtils.nullSafeEquals(this.replyTo, otherMessage.replyTo) &&
+ java.util.Arrays.equals(this.to, otherMessage.to) &&
+ java.util.Arrays.equals(this.cc, otherMessage.cc) &&
+ java.util.Arrays.equals(this.bcc, otherMessage.bcc) &&
+ ObjectUtils.nullSafeEquals(this.sentDate, otherMessage.sentDate) &&
+ ObjectUtils.nullSafeEquals(this.subject, otherMessage.subject) &&
+ ObjectUtils.nullSafeEquals(this.text, otherMessage.text));
+ }
+
+ public int hashCode() {
+ int hashCode = (this.from == null ? 0 : this.from.hashCode());
+ hashCode = 29 * hashCode + (this.replyTo == null ? 0 : this.replyTo.hashCode());
+ for (int i = 0; this.to != null && i < this.to.length; i++) {
+ hashCode = 29 * hashCode + (this.to == null ? 0 : this.to[i].hashCode());
+ }
+ for (int i = 0; this.cc != null && i < this.cc.length; i++) {
+ hashCode = 29 * hashCode + (this.cc == null ? 0 : this.cc[i].hashCode());
+ }
+ for (int i = 0; this.bcc != null && i < this.bcc.length; i++) {
+ hashCode = 29 * hashCode + (this.bcc == null ? 0 : this.bcc[i].hashCode());
+ }
+ hashCode = 29 * hashCode + (this.sentDate == null ? 0 : this.sentDate.hashCode());
+ hashCode = 29 * hashCode + (this.subject == null ? 0 : this.subject.hashCode());
+ hashCode = 29 * hashCode + (this.text == null ? 0 : this.text.hashCode());
+ return hashCode;
+ }
+
+
+ private static String[] copy(String[] state) {
+ String[] copy = new String[state.length];
+ System.arraycopy(state, 0, copy, 0, state.length);
+ return copy;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/package.html 17 Aug 2012 15:15:24 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Spring's generic mail infrastructure.
+Concrete implementations are provided in the subpackages.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/ConfigurableMimeFileTypeMap.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2002-2008 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.mail.javamail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.activation.FileTypeMap;
+import javax.activation.MimetypesFileTypeMap;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+/**
+ * Spring-configurable FileTypeMap implementation that will read
+ * MIME type to file extension mappings from a standard JavaMail MIME type
+ * mapping file, using a standard MimetypesFileTypeMap underneath.
+ *
+ *
The mapping file should be in the following format, as specified by the
+ * Java Activation Framework:
+ *
+ *
+ * # map text/html to .htm and .html files
+ * text/html html htm HTML HTM
+ *
+ * Lines starting with # are treated as comments and are ignored. All
+ * other lines are treated as mappings. Each mapping line should contain the MIME
+ * type as the first entry and then each file extension to map to that MIME type
+ * as subsequent entries. Each entry is separated by spaces or tabs.
+ *
+ *
By default, the mappings in the mime.types file located in the
+ * same package as this class are used, which cover many common file extensions
+ * (in contrast to the out-of-the-box mappings in activation.jar).
+ * This can be overridden using the mappingLocation property.
+ *
+ *
Additional mappings can be added via the mappings bean property,
+ * as lines that follow the mime.types file format.
+ *
+ * @author Rob Harrop
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setMappingLocation
+ * @see #setMappings
+ * @see javax.activation.MimetypesFileTypeMap
+ */
+public class ConfigurableMimeFileTypeMap extends FileTypeMap implements InitializingBean {
+
+ /**
+ * The Resource to load the mapping file from.
+ */
+ private Resource mappingLocation = new ClassPathResource("mime.types", getClass());
+
+ /**
+ * Used to configure additional mappings.
+ */
+ private String[] mappings;
+
+ /**
+ * The delegate FileTypeMap, compiled from the mappings in the mapping file
+ * and the entries in the mappings property.
+ */
+ private FileTypeMap fileTypeMap;
+
+
+ /**
+ * Specify the Resource from which mappings are loaded.
+ *
Needs to follow the mime.types file format, as specified
+ * by the Java Activation Framework, containing lines such as:
+ * text/html html htm HTML HTM
+ */
+ public void setMappingLocation(Resource mappingLocation) {
+ this.mappingLocation = mappingLocation;
+ }
+
+ /**
+ * Specify additional MIME type mappings as lines that follow the
+ * mime.types file format, as specified by the
+ * Java Activation Framework, for example:
+ * text/html html htm HTML HTM
+ */
+ public void setMappings(String[] mappings) {
+ this.mappings = mappings;
+ }
+
+
+ /**
+ * Creates the final merged mapping set.
+ */
+ public void afterPropertiesSet() {
+ getFileTypeMap();
+ }
+
+ /**
+ * Return the delegate FileTypeMap, compiled from the mappings in the mapping file
+ * and the entries in the mappings property.
+ * @see #setMappingLocation
+ * @see #setMappings
+ * @see #createFileTypeMap
+ */
+ protected final FileTypeMap getFileTypeMap() {
+ if (this.fileTypeMap == null) {
+ try {
+ this.fileTypeMap = createFileTypeMap(this.mappingLocation, this.mappings);
+ }
+ catch (IOException ex) {
+ IllegalStateException ise = new IllegalStateException(
+ "Could not load specified MIME type mapping file: " + this.mappingLocation);
+ ise.initCause(ex);
+ throw ise;
+ }
+ }
+ return this.fileTypeMap;
+ }
+
+ /**
+ * Compile a {@link FileTypeMap} from the mappings in the given mapping file
+ * and the given mapping entries.
+ *
The default implementation creates an Activation Framework {@link MimetypesFileTypeMap},
+ * passing in an InputStream from the mapping resource (if any) and registering
+ * the mapping lines programmatically.
+ * @param mappingLocation a mime.types mapping resource (can be null)
+ * @param mappings MIME type mapping lines (can be null)
+ * @return the compiled FileTypeMap
+ * @throws IOException if resource access failed
+ * @see javax.activation.MimetypesFileTypeMap#MimetypesFileTypeMap(java.io.InputStream)
+ * @see javax.activation.MimetypesFileTypeMap#addMimeTypes(String)
+ */
+ protected FileTypeMap createFileTypeMap(Resource mappingLocation, String[] mappings) throws IOException {
+ MimetypesFileTypeMap fileTypeMap = null;
+ if (mappingLocation != null) {
+ InputStream is = mappingLocation.getInputStream();
+ try {
+ fileTypeMap = new MimetypesFileTypeMap(is);
+ }
+ finally {
+ is.close();
+ }
+ }
+ else {
+ fileTypeMap = new MimetypesFileTypeMap();
+ }
+ if (mappings != null) {
+ for (int i = 0; i < mappings.length; i++) {
+ fileTypeMap.addMimeTypes(mappings[i]);
+ }
+ }
+ return fileTypeMap;
+ }
+
+
+ /**
+ * Delegates to the underlying FileTypeMap.
+ * @see #getFileTypeMap()
+ */
+ public String getContentType(File file) {
+ return getFileTypeMap().getContentType(file);
+ }
+
+ /**
+ * Delegates to the underlying FileTypeMap.
+ * @see #getFileTypeMap()
+ */
+ public String getContentType(String fileName) {
+ return getFileTypeMap().getContentType(fileName);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/InternetAddressEditor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/InternetAddressEditor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/InternetAddressEditor.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2005 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.mail.javamail;
+
+import java.beans.PropertyEditorSupport;
+
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Editor for java.mail.internet.InternetAddress,
+ * to directly populate an InternetAddress property.
+ *
+ *
Expects the same syntax as InternetAddress's constructor with
+ * a String argument. Converts empty Strings into null values.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2.3
+ * @see javax.mail.internet.InternetAddress
+ */
+public class InternetAddressEditor extends PropertyEditorSupport {
+
+ public void setAsText(String text) throws IllegalArgumentException {
+ if (StringUtils.hasText(text)) {
+ try {
+ setValue(new InternetAddress(text));
+ }
+ catch (AddressException ex) {
+ throw new IllegalArgumentException("Could not parse mail address: " + ex.getMessage());
+ }
+ }
+ else {
+ setValue(null);
+ }
+ }
+
+ public String getAsText() {
+ InternetAddress value = (InternetAddress) getValue();
+ return (value != null ? value.toUnicodeString() : "");
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSender.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSender.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSender.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2002-2006 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.mail.javamail;
+
+import java.io.InputStream;
+
+import javax.mail.internet.MimeMessage;
+
+import org.springframework.mail.MailException;
+import org.springframework.mail.MailSender;
+
+/**
+ * Extended {@link org.springframework.mail.MailSender} interface for JavaMail,
+ * supporting MIME messages both as direct arguments and through preparation
+ * callbacks. Typically used in conjunction with the {@link MimeMessageHelper}
+ * class for convenient creation of JavaMail {@link MimeMessage MimeMessages},
+ * including attachments etc.
+ *
+ *
Clients should talk to the mail sender through this interface if they need
+ * mail functionality beyond {@link org.springframework.mail.SimpleMailMessage}.
+ * The production implementation is {@link JavaMailSenderImpl}; for testing,
+ * mocks can be created based on this interface. Clients will typically receive
+ * the JavaMailSender reference through dependency injection.
+ *
+ *
The recommended way of using this interface is the {@link MimeMessagePreparator}
+ * mechanism, possibly using a {@link MimeMessageHelper} for populating the message.
+ * See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
+ *
+ *
The entire JavaMail {@link javax.mail.Session} management is abstracted
+ * by the JavaMailSender. Client code should not deal with a Session in any way,
+ * rather leave the entire JavaMail configuration and resource handling to the
+ * JavaMailSender implementation. This also increases testability.
+ *
+ *
A JavaMailSender client is not as easy to test as a plain
+ * {@link org.springframework.mail.MailSender} client, but still straightforward
+ * compared to traditional JavaMail code: Just let {@link #createMimeMessage()}
+ * return a plain {@link MimeMessage} created with a
+ * Session.getInstance(new Properties()) call, and check the passed-in
+ * messages in your mock implementations of the various send methods.
+ *
+ * @author Juergen Hoeller
+ * @since 07.10.2003
+ * @see javax.mail.internet.MimeMessage
+ * @see javax.mail.Session
+ * @see JavaMailSenderImpl
+ * @see MimeMessagePreparator
+ * @see MimeMessageHelper
+ */
+public interface JavaMailSender extends MailSender {
+
+ /**
+ * Create a new JavaMail MimeMessage for the underlying JavaMail Session
+ * of this sender. Needs to be called to create MimeMessage instances
+ * that can be prepared by the client and passed to send(MimeMessage).
+ * @return the new MimeMessage instance
+ * @see #send(MimeMessage)
+ * @see #send(MimeMessage[])
+ */
+ MimeMessage createMimeMessage();
+
+ /**
+ * Create a new JavaMail MimeMessage for the underlying JavaMail Session
+ * of this sender, using the given input stream as the message source.
+ * @param contentStream the raw MIME input stream for the message
+ * @return the new MimeMessage instance
+ * @throws org.springframework.mail.MailParseException
+ * in case of message creation failure
+ */
+ MimeMessage createMimeMessage(InputStream contentStream) throws MailException;
+
+ /**
+ * Send the given JavaMail MIME message.
+ * The message needs to have been created with {@link #createMimeMessage()}.
+ * @param mimeMessage message to send
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending the message
+ * @see #createMimeMessage
+ */
+ void send(MimeMessage mimeMessage) throws MailException;
+
+ /**
+ * Send the given array of JavaMail MIME messages in batch.
+ * The messages need to have been created with {@link #createMimeMessage()}.
+ * @param mimeMessages messages to send
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending a message
+ * @see #createMimeMessage
+ */
+ void send(MimeMessage[] mimeMessages) throws MailException;
+
+ /**
+ * Send the JavaMail MIME message prepared by the given MimeMessagePreparator.
+ *
Alternative way to prepare MimeMessage instances, instead of
+ * {@link #createMimeMessage()} and {@link #send(MimeMessage)} calls.
+ * Takes care of proper exception conversion.
+ * @param mimeMessagePreparator the preparator to use
+ * @throws org.springframework.mail.MailPreparationException
+ * in case of failure when preparing the message
+ * @throws org.springframework.mail.MailParseException
+ * in case of failure when parsing the message
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending the message
+ */
+ void send(MimeMessagePreparator mimeMessagePreparator) throws MailException;
+
+ /**
+ * Send the JavaMail MIME messages prepared by the given MimeMessagePreparators.
+ *
Alternative way to prepare MimeMessage instances, instead of
+ * {@link #createMimeMessage()} and {@link #send(MimeMessage[])} calls.
+ * Takes care of proper exception conversion.
+ * @param mimeMessagePreparators the preparator to use
+ * @throws org.springframework.mail.MailPreparationException
+ * in case of failure when preparing a message
+ * @throws org.springframework.mail.MailParseException
+ * in case of failure when parsing a message
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending a message
+ */
+ void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSenderImpl.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSenderImpl.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/JavaMailSenderImpl.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2002-2007 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.mail.javamail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.activation.FileTypeMap;
+import javax.mail.AuthenticationFailedException;
+import javax.mail.MessagingException;
+import javax.mail.NoSuchProviderException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.MimeMessage;
+
+import org.springframework.mail.MailAuthenticationException;
+import org.springframework.mail.MailException;
+import org.springframework.mail.MailParseException;
+import org.springframework.mail.MailPreparationException;
+import org.springframework.mail.MailSendException;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.util.Assert;
+
+/**
+ * Production implementation of the {@link JavaMailSender} interface,
+ * supporting both JavaMail {@link MimeMessage MimeMessages} and Spring
+ * {@link SimpleMailMessage SimpleMailMessages}. Can also be used as a
+ * plain {@link org.springframework.mail.MailSender} implementation.
+ *
+ *
Allows for defining all settings locally as bean properties.
+ * Alternatively, a pre-configured JavaMail {@link javax.mail.Session} can be
+ * specified, possibly pulled from an application server's JNDI environment.
+ *
+ *
Non-default properties in this object will always override the settings
+ * in the JavaMail Session. Note that if overriding all values locally,
+ * there is no added value in setting a pre-configured Session.
+ *
+ * @author Dmitriy Kopylenko
+ * @author Juergen Hoeller
+ * @since 10.09.2003
+ * @see javax.mail.internet.MimeMessage
+ * @see javax.mail.Session
+ * @see #setSession
+ * @see #setJavaMailProperties
+ * @see #setHost
+ * @see #setPort
+ * @see #setUsername
+ * @see #setPassword
+ */
+public class JavaMailSenderImpl implements JavaMailSender {
+
+ /** The default protocol: 'smtp' */
+ public static final String DEFAULT_PROTOCOL = "smtp";
+
+ /** The default port: -1 */
+ public static final int DEFAULT_PORT = -1;
+
+ private static final String HEADER_MESSAGE_ID = "Message-ID";
+
+
+ private Properties javaMailProperties = new Properties();
+
+ private Session session;
+
+ private String protocol = DEFAULT_PROTOCOL;
+
+ private String host;
+
+ private int port = DEFAULT_PORT;
+
+ private String username;
+
+ private String password;
+
+ private String defaultEncoding;
+
+ private FileTypeMap defaultFileTypeMap;
+
+
+ /**
+ * Create a new instance of the JavaMailSenderImpl class.
+ *
Initializes the {@link #setDefaultFileTypeMap "defaultFileTypeMap"}
+ * property with a default {@link ConfigurableMimeFileTypeMap}.
+ */
+ public JavaMailSenderImpl() {
+ ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
+ fileTypeMap.afterPropertiesSet();
+ this.defaultFileTypeMap = fileTypeMap;
+ }
+
+
+ /**
+ * Set JavaMail properties for the Session.
+ *
A new Session will be created with those properties.
+ * Use either this method or {@link #setSession}, but not both.
+ *
Non-default properties in this instance will override given
+ * JavaMail properties.
+ */
+ public void setJavaMailProperties(Properties javaMailProperties) {
+ this.javaMailProperties = javaMailProperties;
+ synchronized (this) {
+ this.session = null;
+ }
+ }
+
+ /**
+ * Allow Map access to the JavaMail properties of this sender,
+ * with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via
+ * "javaMailProperties[mail.smtp.auth]".
+ */
+ public Properties getJavaMailProperties() {
+ return this.javaMailProperties;
+ }
+
+ /**
+ * Set the JavaMail Session, possibly pulled from JNDI.
+ *
Default is a new Session without defaults, that is
+ * completely configured via this instance's properties.
+ *
If using a pre-configured Session, non-default properties
+ * in this instance will override the settings in the Session.
+ * @see #setJavaMailProperties
+ */
+ public synchronized void setSession(Session session) {
+ Assert.notNull(session, "Session must not be null");
+ this.session = session;
+ }
+
+ /**
+ * Return the JavaMail Session,
+ * lazily initializing it if hasn't been specified explicitly.
+ */
+ public synchronized Session getSession() {
+ if (this.session == null) {
+ this.session = Session.getInstance(this.javaMailProperties);
+ }
+ return this.session;
+ }
+
+ /**
+ * Set the mail protocol. Default is "smtp".
+ */
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ /**
+ * Return the mail protocol.
+ */
+ public String getProtocol() {
+ return this.protocol;
+ }
+
+ /**
+ * Set the mail server host, typically an SMTP host.
+ *
Default is the default host of the underlying JavaMail Session.
+ */
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ /**
+ * Return the mail server host.
+ */
+ public String getHost() {
+ return this.host;
+ }
+
+ /**
+ * Set the mail server port.
+ *
Default is {@link #DEFAULT_PORT}, letting JavaMail use the default
+ * SMTP port (25).
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * Return the mail server port.
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * Set the username for the account at the mail host, if any.
+ *
Note that the underlying JavaMail Session has to be
+ * configured with the property "mail.smtp.auth" set to
+ * true, else the specified username will not be sent to the
+ * mail server by the JavaMail runtime. If you are not explicitly passing
+ * in a Session to use, simply specify this setting via
+ * {@link #setJavaMailProperties}.
+ * @see #setSession
+ * @see #setPassword
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Return the username for the account at the mail host.
+ */
+ public String getUsername() {
+ return this.username;
+ }
+
+ /**
+ * Set the password for the account at the mail host, if any.
+ *
Note that the underlying JavaMail Session has to be
+ * configured with the property "mail.smtp.auth" set to
+ * true, else the specified password will not be sent to the
+ * mail server by the JavaMail runtime. If you are not explicitly passing
+ * in a Session to use, simply specify this setting via
+ * {@link #setJavaMailProperties}.
+ * @see #setSession
+ * @see #setUsername
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Return the password for the account at the mail host.
+ */
+ public String getPassword() {
+ return this.password;
+ }
+
+ /**
+ * Set the default encoding to use for {@link MimeMessage MimeMessages}
+ * created by this instance.
+ *
Such an encoding will be auto-detected by {@link MimeMessageHelper}.
+ */
+ public void setDefaultEncoding(String defaultEncoding) {
+ this.defaultEncoding = defaultEncoding;
+ }
+
+ /**
+ * Return the default encoding for {@link MimeMessage MimeMessages},
+ * or null if none.
+ */
+ public String getDefaultEncoding() {
+ return this.defaultEncoding;
+ }
+
+ /**
+ * Set the default Java Activation {@link FileTypeMap} to use for
+ * {@link MimeMessage MimeMessages} created by this instance.
+ *
A FileTypeMap specified here will be autodetected by
+ * {@link MimeMessageHelper}, avoiding the need to specify the
+ * FileTypeMap for each MimeMessageHelper instance.
+ *
For example, you can specify a custom instance of Spring's
+ * {@link ConfigurableMimeFileTypeMap} here. If not explicitly specified,
+ * a default ConfigurableMimeFileTypeMap will be used, containing
+ * an extended set of MIME type mappings (as defined by the
+ * mime.types file contained in the Spring jar).
+ * @see MimeMessageHelper#setFileTypeMap
+ */
+ public void setDefaultFileTypeMap(FileTypeMap defaultFileTypeMap) {
+ this.defaultFileTypeMap = defaultFileTypeMap;
+ }
+
+ /**
+ * Return the default Java Activation {@link FileTypeMap} for
+ * {@link MimeMessage MimeMessages}, or null if none.
+ */
+ public FileTypeMap getDefaultFileTypeMap() {
+ return this.defaultFileTypeMap;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of MailSender
+ //---------------------------------------------------------------------
+
+ public void send(SimpleMailMessage simpleMessage) throws MailException {
+ send(new SimpleMailMessage[] { simpleMessage });
+ }
+
+ public void send(SimpleMailMessage[] simpleMessages) throws MailException {
+ List mimeMessages = new ArrayList(simpleMessages.length);
+ for (int i = 0; i < simpleMessages.length; i++) {
+ SimpleMailMessage simpleMessage = simpleMessages[i];
+ MimeMailMessage message = new MimeMailMessage(createMimeMessage());
+ simpleMessage.copyTo(message);
+ mimeMessages.add(message.getMimeMessage());
+ }
+ doSend((MimeMessage[]) mimeMessages.toArray(new MimeMessage[mimeMessages.size()]), simpleMessages);
+ }
+
+
+ //---------------------------------------------------------------------
+ // Implementation of JavaMailSender
+ //---------------------------------------------------------------------
+
+ /**
+ * This implementation creates a SmartMimeMessage, holding the specified
+ * default encoding and default FileTypeMap. This special defaults-carrying
+ * message will be autodetected by {@link MimeMessageHelper}, which will use
+ * the carried encoding and FileTypeMap unless explicitly overridden.
+ * @see #setDefaultEncoding
+ * @see #setDefaultFileTypeMap
+ */
+ public MimeMessage createMimeMessage() {
+ return new SmartMimeMessage(getSession(), getDefaultEncoding(), getDefaultFileTypeMap());
+ }
+
+ public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
+ try {
+ return new MimeMessage(getSession(), contentStream);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException("Could not parse raw MIME content", ex);
+ }
+ }
+
+ public void send(MimeMessage mimeMessage) throws MailException {
+ send(new MimeMessage[] { mimeMessage });
+ }
+
+ public void send(MimeMessage[] mimeMessages) throws MailException {
+ doSend(mimeMessages, null);
+ }
+
+ public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
+ send(new MimeMessagePreparator[] { mimeMessagePreparator });
+ }
+
+ public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {
+ try {
+ List mimeMessages = new ArrayList(mimeMessagePreparators.length);
+ for (int i = 0; i < mimeMessagePreparators.length; i++) {
+ MimeMessage mimeMessage = createMimeMessage();
+ mimeMessagePreparators[i].prepare(mimeMessage);
+ mimeMessages.add(mimeMessage);
+ }
+ send((MimeMessage[]) mimeMessages.toArray(new MimeMessage[mimeMessages.size()]));
+ }
+ catch (MailException ex) {
+ throw ex;
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ catch (IOException ex) {
+ throw new MailPreparationException(ex);
+ }
+ catch (Exception ex) {
+ throw new MailPreparationException(ex);
+ }
+ }
+
+
+ /**
+ * Actually send the given array of MimeMessages via JavaMail.
+ * @param mimeMessages MimeMessage objects to send
+ * @param originalMessages corresponding original message objects
+ * that the MimeMessages have been created from (with same array
+ * length and indices as the "mimeMessages" array), if any
+ * @throws org.springframework.mail.MailAuthenticationException
+ * in case of authentication failure
+ * @throws org.springframework.mail.MailSendException
+ * in case of failure when sending a message
+ */
+ protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
+ Map failedMessages = new LinkedHashMap();
+ try {
+ Transport transport = getTransport(getSession());
+ transport.connect(getHost(), getPort(), getUsername(), getPassword());
+ try {
+ for (int i = 0; i < mimeMessages.length; i++) {
+ MimeMessage mimeMessage = mimeMessages[i];
+ try {
+ if (mimeMessage.getSentDate() == null) {
+ mimeMessage.setSentDate(new Date());
+ }
+ String messageId = mimeMessage.getMessageID();
+ mimeMessage.saveChanges();
+ if (messageId != null) {
+ // Preserve explicitly specified message id...
+ mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
+ }
+ transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
+ }
+ catch (MessagingException ex) {
+ Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
+ failedMessages.put(original, ex);
+ }
+ }
+ }
+ finally {
+ transport.close();
+ }
+ }
+ catch (AuthenticationFailedException ex) {
+ throw new MailAuthenticationException(ex);
+ }
+ catch (MessagingException ex) {
+ throw new MailSendException("Mail server connection failed", ex);
+ }
+ if (!failedMessages.isEmpty()) {
+ throw new MailSendException(failedMessages);
+ }
+ }
+
+ /**
+ * Obtain a Transport object from the given JavaMail Session,
+ * using the configured protocol.
+ *
Can be overridden in subclasses, e.g. to return a mock Transport object.
+ * @see javax.mail.Session#getTransport(String)
+ * @see #getProtocol()
+ */
+ protected Transport getTransport(Session session) throws NoSuchProviderException {
+ return session.getTransport(getProtocol());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMailMessage.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/MimeMailMessage.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMailMessage.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2002-2005 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.mail.javamail;
+
+import java.util.Date;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.springframework.mail.MailMessage;
+import org.springframework.mail.MailParseException;
+
+/**
+ * Implementation of the MailMessage interface for a JavaMail MIME message,
+ * to let message population code interact with a simple message or a MIME
+ * message through a common interface.
+ *
+ *
Uses a MimeMessageHelper underneath. Can either be created with a
+ * MimeMessageHelper instance or with a JavaMail MimeMessage instance.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see MimeMessageHelper
+ * @see javax.mail.internet.MimeMessage
+ */
+public class MimeMailMessage implements MailMessage {
+
+ private final MimeMessageHelper helper;
+
+
+ /**
+ * Create a new MimeMailMessage based on the given MimeMessageHelper.
+ * @param mimeMessageHelper the MimeMessageHelper
+ */
+ public MimeMailMessage(MimeMessageHelper mimeMessageHelper) {
+ this.helper = mimeMessageHelper;
+ }
+
+ /**
+ * Create a new MimeMailMessage based on the given JavaMail MimeMessage.
+ * @param mimeMessage the JavaMail MimeMessage
+ */
+ public MimeMailMessage(MimeMessage mimeMessage) {
+ this.helper = new MimeMessageHelper(mimeMessage);
+ }
+
+ /**
+ * Return the MimeMessageHelper that this MimeMailMessage is based on.
+ */
+ public final MimeMessageHelper getMimeMessageHelper() {
+ return this.helper;
+ }
+
+ /**
+ * Return the JavaMail MimeMessage that this MimeMailMessage is based on.
+ */
+ public final MimeMessage getMimeMessage() {
+ return this.helper.getMimeMessage();
+ }
+
+
+ public void setFrom(String from) throws MailParseException {
+ try {
+ this.helper.setFrom(from);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setReplyTo(String replyTo) throws MailParseException {
+ try {
+ this.helper.setReplyTo(replyTo);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setTo(String to) throws MailParseException {
+ try {
+ this.helper.setTo(to);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setTo(String[] to) throws MailParseException {
+ try {
+ this.helper.setTo(to);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setCc(String cc) throws MailParseException {
+ try {
+ this.helper.setCc(cc);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setCc(String[] cc) throws MailParseException {
+ try {
+ this.helper.setCc(cc);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setBcc(String bcc) throws MailParseException {
+ try {
+ this.helper.setBcc(bcc);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setBcc(String[] bcc) throws MailParseException {
+ try {
+ this.helper.setBcc(bcc);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setSentDate(Date sentDate) throws MailParseException {
+ try {
+ this.helper.setSentDate(sentDate);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setSubject(String subject) throws MailParseException {
+ try {
+ this.helper.setSubject(subject);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+ public void setText(String text) throws MailParseException {
+ try {
+ this.helper.setText(text);
+ }
+ catch (MessagingException ex) {
+ throw new MailParseException(ex);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessageHelper.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessageHelper.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessageHelper.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,1086 @@
+/*
+ * Copyright 2002-2007 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.mail.javamail;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.activation.FileDataSource;
+import javax.activation.FileTypeMap;
+import javax.mail.BodyPart;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimePart;
+
+import org.springframework.core.io.InputStreamSource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class for populating a {@link javax.mail.internet.MimeMessage}.
+ *
+ *
Mirrors the simple setters of {@link org.springframework.mail.SimpleMailMessage},
+ * directly applying the values to the underlying MimeMessage. Allows for defining
+ * a character encoding for the entire message, automatically applied by all methods
+ * of this helper class.
+ *
+ *
Offers support for HTML text content, inline elements such as images, and typical
+ * mail attachments. Also supports personal names that accompany mail addresses. Note that
+ * advanced settings can still be applied directly to the underlying MimeMessage object!
+ *
+ *
Typically used in {@link MimeMessagePreparator} implementations or
+ * {@link JavaMailSender} client code: simply instantiating it as a MimeMessage wrapper,
+ * invoking setters on the wrapper, using the underlying MimeMessage for mail sending.
+ * Also used internally by {@link JavaMailSenderImpl}.
+ *
+ *
Sample code for an HTML mail with an inline image and a PDF attachment:
+ *
+ *
+ *
+ * Consider using {@link MimeMailMessage} (which implements the common
+ * {@link org.springframework.mail.MailMessage} interface, just like
+ * {@link org.springframework.mail.SimpleMailMessage}) on top of this helper,
+ * in order to let message population code interact with a simple message
+ * or a MIME message through a common interface.
+ *
+ *
Warning regarding multipart mails: Simple MIME messages that
+ * just contain HTML text but no inline elements or attachments will work on
+ * more or less any email client that is capable of HTML rendering. However,
+ * inline elements and attachments are still a major compatibility issue
+ * between email clients: It's virtually impossible to get inline elements
+ * and attachments working across Microsoft Outlook, Lotus Notes and Mac Mail.
+ * Consider choosing a specific multipart mode for your needs: The javadoc
+ * on the MULTIPART_MODE constants contains more detailed information.
+ *
+ * @author Juergen Hoeller
+ * @since 19.01.2004
+ * @see #setText(String, boolean)
+ * @see #setText(String, String)
+ * @see #addInline(String, org.springframework.core.io.Resource)
+ * @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
+ * @see #MULTIPART_MODE_MIXED_RELATED
+ * @see #MULTIPART_MODE_RELATED
+ * @see #getMimeMessage()
+ * @see JavaMailSender
+ */
+public class MimeMessageHelper {
+
+ /**
+ * Constant indicating a non-multipart message.
+ */
+ public static final int MULTIPART_MODE_NO = 0;
+
+ /**
+ * Constant indicating a multipart message with a single root multipart
+ * element of type "mixed". Texts, inline elements and attachements
+ * will all get added to that root element.
+ *
This was Spring 1.0's default behavior. It is known to work properly
+ * on Outlook. However, other mail clients tend to misinterpret inline
+ * elements as attachments and/or show attachments inline as well.
+ */
+ public static final int MULTIPART_MODE_MIXED = 1;
+
+ /**
+ * Constant indicating a multipart message with a single root multipart
+ * element of type "related". Texts, inline elements and attachements
+ * will all get added to that root element.
+ *
This was the default behavior from Spring 1.1 up to 1.2 final.
+ * This is the "Microsoft multipart mode", as natively sent by Outlook.
+ * It is known to work properly on Outlook, Outlook Express, Yahoo Mail, and
+ * to a large degree also on Mac Mail (with an additional attachment listed
+ * for an inline element, despite the inline element also shown inline).
+ * Does not work properly on Lotus Notes (attachments won't be shown there).
+ */
+ public static final int MULTIPART_MODE_RELATED = 2;
+
+ /**
+ * Constant indicating a multipart message with a root multipart element
+ * "mixed" plus a nested multipart element of type "related". Texts and
+ * inline elements will get added to the nested "related" element,
+ * while attachments will get added to the "mixed" root element.
+ *
This is the default since Spring 1.2.1. This is arguably the most correct
+ * MIME structure, according to the MIME spec: It is known to work properly
+ * on Outlook, Outlook Express, Yahoo Mail, and Lotus Notes. Does not work
+ * properly on Mac Mail. If you target Mac Mail or experience issues with
+ * specific mails on Outlook, consider using MULTIPART_MODE_RELATED instead.
+ */
+ public static final int MULTIPART_MODE_MIXED_RELATED = 3;
+
+
+ private static final String MULTIPART_SUBTYPE_MIXED = "mixed";
+
+ private static final String MULTIPART_SUBTYPE_RELATED = "related";
+
+ private static final String MULTIPART_SUBTYPE_ALTERNATIVE = "alternative";
+
+ private static final String CONTENT_TYPE_ALTERNATIVE = "text/alternative";
+
+ private static final String CONTENT_TYPE_HTML = "text/html";
+
+ private static final String CONTENT_TYPE_CHARSET_SUFFIX = ";charset=";
+
+ private static final String HEADER_PRIORITY = "X-Priority";
+
+ private static final String HEADER_CONTENT_ID = "Content-ID";
+
+
+ private final MimeMessage mimeMessage;
+
+ private MimeMultipart rootMimeMultipart;
+
+ private MimeMultipart mimeMultipart;
+
+ private final String encoding;
+
+ private FileTypeMap fileTypeMap;
+
+ private boolean validateAddresses = false;
+
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * assuming a simple text message (no multipart content,
+ * i.e. no alternative texts and no inline elements or attachments).
+ *
The character encoding for the message will be taken from
+ * the passed-in MimeMessage object, if carried there. Else,
+ * JavaMail's default encoding will be used.
+ * @param mimeMessage MimeMessage to work on
+ * @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
+ * @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
+ * @see JavaMailSenderImpl#setDefaultEncoding
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage) {
+ this(mimeMessage, null);
+ }
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * assuming a simple text message (no multipart content,
+ * i.e. no alternative texts and no inline elements or attachments).
+ * @param mimeMessage MimeMessage to work on
+ * @param encoding the character encoding to use for the message
+ * @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage, String encoding) {
+ this.mimeMessage = mimeMessage;
+ this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
+ this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
+ }
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * in multipart mode (supporting alternative texts, inline
+ * elements and attachments) if requested.
+ *
Consider using the MimeMessageHelper constructor that
+ * takes a multipartMode argument to choose a specific multipart
+ * mode other than MULTIPART_MODE_MIXED_RELATED.
+ *
The character encoding for the message will be taken from
+ * the passed-in MimeMessage object, if carried there. Else,
+ * JavaMail's default encoding will be used.
+ * @param mimeMessage MimeMessage to work on
+ * @param multipart whether to create a multipart message that
+ * supports alternative texts, inline elements and attachments
+ * (corresponds to MULTIPART_MODE_MIXED_RELATED)
+ * @throws MessagingException if multipart creation failed
+ * @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int)
+ * @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
+ * @see JavaMailSenderImpl#setDefaultEncoding
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart) throws MessagingException {
+ this(mimeMessage, multipart, null);
+ }
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * in multipart mode (supporting alternative texts, inline
+ * elements and attachments) if requested.
+ *
Consider using the MimeMessageHelper constructor that
+ * takes a multipartMode argument to choose a specific multipart
+ * mode other than MULTIPART_MODE_MIXED_RELATED.
+ * @param mimeMessage MimeMessage to work on
+ * @param multipart whether to create a multipart message that
+ * supports alternative texts, inline elements and attachments
+ * (corresponds to MULTIPART_MODE_MIXED_RELATED)
+ * @param encoding the character encoding to use for the message
+ * @throws MessagingException if multipart creation failed
+ * @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int, String)
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, String encoding)
+ throws MessagingException {
+
+ this(mimeMessage, (multipart ? MULTIPART_MODE_MIXED_RELATED : MULTIPART_MODE_NO), encoding);
+ }
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * in multipart mode (supporting alternative texts, inline
+ * elements and attachments) if requested.
+ *
The character encoding for the message will be taken from
+ * the passed-in MimeMessage object, if carried there. Else,
+ * JavaMail's default encoding will be used.
+ * @param mimeMessage MimeMessage to work on
+ * @param multipartMode which kind of multipart message to create
+ * (MIXED, RELATED, MIXED_RELATED, or NO)
+ * @throws MessagingException if multipart creation failed
+ * @see #MULTIPART_MODE_NO
+ * @see #MULTIPART_MODE_MIXED
+ * @see #MULTIPART_MODE_RELATED
+ * @see #MULTIPART_MODE_MIXED_RELATED
+ * @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
+ * @see JavaMailSenderImpl#setDefaultEncoding
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
+ this(mimeMessage, multipartMode, null);
+ }
+
+ /**
+ * Create a new MimeMessageHelper for the given MimeMessage,
+ * in multipart mode (supporting alternative texts, inline
+ * elements and attachments) if requested.
+ * @param mimeMessage MimeMessage to work on
+ * @param multipartMode which kind of multipart message to create
+ * (MIXED, RELATED, MIXED_RELATED, or NO)
+ * @param encoding the character encoding to use for the message
+ * @throws MessagingException if multipart creation failed
+ * @see #MULTIPART_MODE_NO
+ * @see #MULTIPART_MODE_MIXED
+ * @see #MULTIPART_MODE_RELATED
+ * @see #MULTIPART_MODE_MIXED_RELATED
+ */
+ public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode, String encoding)
+ throws MessagingException {
+
+ this.mimeMessage = mimeMessage;
+ createMimeMultiparts(mimeMessage, multipartMode);
+ this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
+ this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
+ }
+
+
+ /**
+ * Return the underlying MimeMessage object.
+ */
+ public final MimeMessage getMimeMessage() {
+ return this.mimeMessage;
+ }
+
+
+ /**
+ * Determine the MimeMultipart objects to use, which will be used
+ * to store attachments on the one hand and text(s) and inline elements
+ * on the other hand.
+ *
Texts and inline elements can either be stored in the root element
+ * itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED) or in a nested element
+ * rather than the root element directly (MULTIPART_MODE_MIXED_RELATED).
+ *
By default, the root MimeMultipart element will be of type "mixed"
+ * (MULTIPART_MODE_MIXED) or "related" (MULTIPART_MODE_RELATED).
+ * The main multipart element will either be added as nested element of
+ * type "related" (MULTIPART_MODE_MIXED_RELATED) or be identical to the root
+ * element itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED).
+ * @param mimeMessage the MimeMessage object to add the root MimeMultipart
+ * object to
+ * @param multipartMode the multipart mode, as passed into the constructor
+ * (MIXED, RELATED, MIXED_RELATED, or NO)
+ * @throws MessagingException if multipart creation failed
+ * @see #setMimeMultiparts
+ * @see #MULTIPART_MODE_NO
+ * @see #MULTIPART_MODE_MIXED
+ * @see #MULTIPART_MODE_RELATED
+ * @see #MULTIPART_MODE_MIXED_RELATED
+ */
+ protected void createMimeMultiparts(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
+ switch (multipartMode) {
+ case MULTIPART_MODE_NO:
+ setMimeMultiparts(null, null);
+ break;
+ case MULTIPART_MODE_MIXED:
+ MimeMultipart mixedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_MIXED);
+ mimeMessage.setContent(mixedMultipart);
+ setMimeMultiparts(mixedMultipart, mixedMultipart);
+ break;
+ case MULTIPART_MODE_RELATED:
+ MimeMultipart relatedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_RELATED);
+ mimeMessage.setContent(relatedMultipart);
+ setMimeMultiparts(relatedMultipart, relatedMultipart);
+ break;
+ case MULTIPART_MODE_MIXED_RELATED:
+ MimeMultipart rootMixedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_MIXED);
+ mimeMessage.setContent(rootMixedMultipart);
+ MimeMultipart nestedRelatedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_RELATED);
+ MimeBodyPart relatedBodyPart = new MimeBodyPart();
+ relatedBodyPart.setContent(nestedRelatedMultipart);
+ rootMixedMultipart.addBodyPart(relatedBodyPart);
+ setMimeMultiparts(rootMixedMultipart, nestedRelatedMultipart);
+ break;
+ default:
+ throw new IllegalArgumentException("Only multipart modes MIXED_RELATED, RELATED and NO supported");
+ }
+ }
+
+ /**
+ * Set the given MimeMultipart objects for use by this MimeMessageHelper.
+ * @param root the root MimeMultipart object, which attachments will be added to;
+ * or null to indicate no multipart at all
+ * @param main the main MimeMultipart object, which text(s) and inline elements
+ * will be added to (can be the same as the root multipart object, or an element
+ * nested underneath the root multipart element)
+ */
+ protected final void setMimeMultiparts(MimeMultipart root, MimeMultipart main) {
+ this.rootMimeMultipart = root;
+ this.mimeMultipart = main;
+ }
+
+ /**
+ * Return whether this helper is in multipart mode,
+ * i.e. whether it holds a multipart message.
+ * @see #MimeMessageHelper(MimeMessage, boolean)
+ */
+ public final boolean isMultipart() {
+ return (this.rootMimeMultipart != null);
+ }
+
+ /**
+ * Throw an IllegalStateException if this helper is not in multipart mode.
+ */
+ private void checkMultipart() throws IllegalStateException {
+ if (!isMultipart()) {
+ throw new IllegalStateException("Not in multipart mode - " +
+ "create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " +
+ "if you need to set alternative texts or add inline elements or attachments.");
+ }
+ }
+
+ /**
+ * Return the root MIME "multipart/mixed" object, if any.
+ * Can be used to manually add attachments.
+ *
This will be the direct content of the MimeMessage,
+ * in case of a multipart mail.
+ * @throws IllegalStateException if this helper is not in multipart mode
+ * @see #isMultipart
+ * @see #getMimeMessage
+ * @see javax.mail.internet.MimeMultipart#addBodyPart
+ */
+ public final MimeMultipart getRootMimeMultipart() throws IllegalStateException {
+ checkMultipart();
+ return this.rootMimeMultipart;
+ }
+
+ /**
+ * Return the underlying MIME "multipart/related" object, if any.
+ * Can be used to manually add body parts, inline elements, etc.
+ *
This will be nested within the root MimeMultipart,
+ * in case of a multipart mail.
+ * @throws IllegalStateException if this helper is not in multipart mode
+ * @see #isMultipart
+ * @see #getRootMimeMultipart
+ * @see javax.mail.internet.MimeMultipart#addBodyPart
+ */
+ public final MimeMultipart getMimeMultipart() throws IllegalStateException {
+ checkMultipart();
+ return this.mimeMultipart;
+ }
+
+
+ /**
+ * Determine the default encoding for the given MimeMessage.
+ * @param mimeMessage the passed-in MimeMessage
+ * @return the default encoding associated with the MimeMessage,
+ * or null if none found
+ */
+ protected String getDefaultEncoding(MimeMessage mimeMessage) {
+ if (mimeMessage instanceof SmartMimeMessage) {
+ return ((SmartMimeMessage) mimeMessage).getDefaultEncoding();
+ }
+ return null;
+ }
+
+ /**
+ * Return the specific character encoding used for this message, if any.
+ */
+ public String getEncoding() {
+ return this.encoding;
+ }
+
+ /**
+ * Determine the default Java Activation FileTypeMap for the given MimeMessage.
+ * @param mimeMessage the passed-in MimeMessage
+ * @return the default FileTypeMap associated with the MimeMessage,
+ * or a default ConfigurableMimeFileTypeMap if none found for the message
+ * @see ConfigurableMimeFileTypeMap
+ */
+ protected FileTypeMap getDefaultFileTypeMap(MimeMessage mimeMessage) {
+ if (mimeMessage instanceof SmartMimeMessage) {
+ FileTypeMap fileTypeMap = ((SmartMimeMessage) mimeMessage).getDefaultFileTypeMap();
+ if (fileTypeMap != null) {
+ return fileTypeMap;
+ }
+ }
+ ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
+ fileTypeMap.afterPropertiesSet();
+ return fileTypeMap;
+ }
+
+ /**
+ * Set the Java Activation Framework FileTypeMap to use
+ * for determining the content type of inline content and attachments
+ * that get added to the message.
+ *
Default is the FileTypeMap that the underlying
+ * MimeMessage carries, if any, or the Activation Framework's default
+ * FileTypeMap instance else.
+ * @see #addInline
+ * @see #addAttachment
+ * @see #getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
+ * @see JavaMailSenderImpl#setDefaultFileTypeMap
+ * @see javax.activation.FileTypeMap#getDefaultFileTypeMap
+ * @see ConfigurableMimeFileTypeMap
+ */
+ public void setFileTypeMap(FileTypeMap fileTypeMap) {
+ this.fileTypeMap = (fileTypeMap != null ? fileTypeMap : getDefaultFileTypeMap(getMimeMessage()));
+ }
+
+ /**
+ * Return the FileTypeMap used by this MimeMessageHelper.
+ */
+ public FileTypeMap getFileTypeMap() {
+ return this.fileTypeMap;
+ }
+
+
+ /**
+ * Set whether to validate all addresses which get passed to this helper.
+ * Default is "false".
+ *
Note that this is by default just available for JavaMail >= 1.3.
+ * You can override the default validateAddress method for
+ * validation on older JavaMail versions (or for custom validation).
+ * @see #validateAddress
+ */
+ public void setValidateAddresses(boolean validateAddresses) {
+ this.validateAddresses = validateAddresses;
+ }
+
+ /**
+ * Return whether this helper will validate all addresses passed to it.
+ */
+ public boolean isValidateAddresses() {
+ return this.validateAddresses;
+ }
+
+ /**
+ * Validate the given mail address.
+ * Called by all of MimeMessageHelper's address setters and adders.
+ *
Default implementation invokes InternetAddress.validate(),
+ * provided that address validation is activated for the helper instance.
+ *
Note that this method will just work on JavaMail >= 1.3. You can override
+ * it for validation on older JavaMail versions or for custom validation.
+ * @param address the address to validate
+ * @throws AddressException if validation failed
+ * @see #isValidateAddresses()
+ * @see javax.mail.internet.InternetAddress#validate()
+ */
+ protected void validateAddress(InternetAddress address) throws AddressException {
+ if (isValidateAddresses()) {
+ address.validate();
+ }
+ }
+
+ /**
+ * Validate all given mail addresses.
+ * Default implementation simply delegates to validateAddress for each address.
+ * @param addresses the addresses to validate
+ * @throws AddressException if validation failed
+ * @see #validateAddress(InternetAddress)
+ */
+ protected void validateAddresses(InternetAddress[] addresses) throws AddressException {
+ for (int i = 0; i < addresses.length; i++) {
+ validateAddress(addresses[i]);
+ }
+ }
+
+
+ public void setFrom(InternetAddress from) throws MessagingException {
+ Assert.notNull(from, "From address must not be null");
+ validateAddress(from);
+ this.mimeMessage.setFrom(from);
+ }
+
+ public void setFrom(String from) throws MessagingException {
+ Assert.notNull(from, "From address must not be null");
+ setFrom(new InternetAddress(from));
+ }
+
+ public void setFrom(String from, String personal) throws MessagingException, UnsupportedEncodingException {
+ Assert.notNull(from, "From address must not be null");
+ setFrom(getEncoding() != null ?
+ new InternetAddress(from, personal, getEncoding()) : new InternetAddress(from, personal));
+ }
+
+ public void setReplyTo(InternetAddress replyTo) throws MessagingException {
+ Assert.notNull(replyTo, "Reply-to address must not be null");
+ validateAddress(replyTo);
+ this.mimeMessage.setReplyTo(new InternetAddress[] {replyTo});
+ }
+
+ public void setReplyTo(String replyTo) throws MessagingException {
+ Assert.notNull(replyTo, "Reply-to address must not be null");
+ setReplyTo(new InternetAddress(replyTo));
+ }
+
+ public void setReplyTo(String replyTo, String personal) throws MessagingException, UnsupportedEncodingException {
+ Assert.notNull(replyTo, "Reply-to address must not be null");
+ InternetAddress replyToAddress = (getEncoding() != null) ?
+ new InternetAddress(replyTo, personal, getEncoding()) : new InternetAddress(replyTo, personal);
+ setReplyTo(replyToAddress);
+ }
+
+
+ public void setTo(InternetAddress to) throws MessagingException {
+ Assert.notNull(to, "To address must not be null");
+ validateAddress(to);
+ this.mimeMessage.setRecipient(Message.RecipientType.TO, to);
+ }
+
+ public void setTo(InternetAddress[] to) throws MessagingException {
+ Assert.notNull(to, "To address array must not be null");
+ validateAddresses(to);
+ this.mimeMessage.setRecipients(Message.RecipientType.TO, to);
+ }
+
+ public void setTo(String to) throws MessagingException {
+ Assert.notNull(to, "To address must not be null");
+ setTo(new InternetAddress(to));
+ }
+
+ public void setTo(String[] to) throws MessagingException {
+ Assert.notNull(to, "To address array must not be null");
+ InternetAddress[] addresses = new InternetAddress[to.length];
+ for (int i = 0; i < to.length; i++) {
+ addresses[i] = new InternetAddress(to[i]);
+ }
+ setTo(addresses);
+ }
+
+ public void addTo(InternetAddress to) throws MessagingException {
+ Assert.notNull(to, "To address must not be null");
+ validateAddress(to);
+ this.mimeMessage.addRecipient(Message.RecipientType.TO, to);
+ }
+
+ public void addTo(String to) throws MessagingException {
+ Assert.notNull(to, "To address must not be null");
+ addTo(new InternetAddress(to));
+ }
+
+ public void addTo(String to, String personal) throws MessagingException, UnsupportedEncodingException {
+ Assert.notNull(to, "To address must not be null");
+ addTo(getEncoding() != null ?
+ new InternetAddress(to, personal, getEncoding()) :
+ new InternetAddress(to, personal));
+ }
+
+
+ public void setCc(InternetAddress cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address must not be null");
+ validateAddress(cc);
+ this.mimeMessage.setRecipient(Message.RecipientType.CC, cc);
+ }
+
+ public void setCc(InternetAddress[] cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address array must not be null");
+ validateAddresses(cc);
+ this.mimeMessage.setRecipients(Message.RecipientType.CC, cc);
+ }
+
+ public void setCc(String cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address must not be null");
+ setCc(new InternetAddress(cc));
+ }
+
+ public void setCc(String[] cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address array must not be null");
+ InternetAddress[] addresses = new InternetAddress[cc.length];
+ for (int i = 0; i < cc.length; i++) {
+ addresses[i] = new InternetAddress(cc[i]);
+ }
+ setCc(addresses);
+ }
+
+ public void addCc(InternetAddress cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address must not be null");
+ validateAddress(cc);
+ this.mimeMessage.addRecipient(Message.RecipientType.CC, cc);
+ }
+
+ public void addCc(String cc) throws MessagingException {
+ Assert.notNull(cc, "Cc address must not be null");
+ addCc(new InternetAddress(cc));
+ }
+
+ public void addCc(String cc, String personal) throws MessagingException, UnsupportedEncodingException {
+ Assert.notNull(cc, "Cc address must not be null");
+ addCc(getEncoding() != null ?
+ new InternetAddress(cc, personal, getEncoding()) :
+ new InternetAddress(cc, personal));
+ }
+
+
+ public void setBcc(InternetAddress bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address must not be null");
+ validateAddress(bcc);
+ this.mimeMessage.setRecipient(Message.RecipientType.BCC, bcc);
+ }
+
+ public void setBcc(InternetAddress[] bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address array must not be null");
+ validateAddresses(bcc);
+ this.mimeMessage.setRecipients(Message.RecipientType.BCC, bcc);
+ }
+
+ public void setBcc(String bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address must not be null");
+ setBcc(new InternetAddress(bcc));
+ }
+
+ public void setBcc(String[] bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address array must not be null");
+ InternetAddress[] addresses = new InternetAddress[bcc.length];
+ for (int i = 0; i < bcc.length; i++) {
+ addresses[i] = new InternetAddress(bcc[i]);
+ }
+ setBcc(addresses);
+ }
+
+ public void addBcc(InternetAddress bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address must not be null");
+ validateAddress(bcc);
+ this.mimeMessage.addRecipient(Message.RecipientType.BCC, bcc);
+ }
+
+ public void addBcc(String bcc) throws MessagingException {
+ Assert.notNull(bcc, "Bcc address must not be null");
+ addBcc(new InternetAddress(bcc));
+ }
+
+ public void addBcc(String bcc, String personal) throws MessagingException, UnsupportedEncodingException {
+ Assert.notNull(bcc, "Bcc address must not be null");
+ addBcc(getEncoding() != null ?
+ new InternetAddress(bcc, personal, getEncoding()) :
+ new InternetAddress(bcc, personal));
+ }
+
+
+ /**
+ * Set the priority ("X-Priority" header) of the message.
+ * @param priority the priority value;
+ * typically between 1 (highest) and 5 (lowest)
+ * @throws MessagingException in case of errors
+ */
+ public void setPriority(int priority) throws MessagingException {
+ this.mimeMessage.setHeader(HEADER_PRIORITY, Integer.toString(priority));
+ }
+
+ /**
+ * Set the sent-date of the message.
+ * @param sentDate the date to set (never null)
+ * @throws MessagingException in case of errors
+ */
+ public void setSentDate(Date sentDate) throws MessagingException {
+ Assert.notNull(sentDate, "Sent date must not be null");
+ this.mimeMessage.setSentDate(sentDate);
+ }
+
+ /**
+ * Set the subject of the message, using the correct encoding.
+ * @param subject the subject text
+ * @throws MessagingException in case of errors
+ */
+ public void setSubject(String subject) throws MessagingException {
+ Assert.notNull(subject, "Subject must not be null");
+ if (getEncoding() != null) {
+ this.mimeMessage.setSubject(subject, getEncoding());
+ }
+ else {
+ this.mimeMessage.setSubject(subject);
+ }
+ }
+
+
+ /**
+ * Set the given text directly as content in non-multipart mode
+ * or as default body part in multipart mode.
+ * Always applies the default content type "text/plain".
+ *
NOTE: Invoke {@link #addInline} aftersetText;
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param text the text for the message
+ * @throws MessagingException in case of errors
+ */
+ public void setText(String text) throws MessagingException {
+ setText(text, false);
+ }
+
+ /**
+ * Set the given text directly as content in non-multipart mode
+ * or as default body part in multipart mode.
+ * The "html" flag determines the content type to apply.
+ *
NOTE: Invoke {@link #addInline} aftersetText;
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param text the text for the message
+ * @param html whether to apply content type "text/html" for an
+ * HTML mail, using default content type ("text/plain") else
+ * @throws MessagingException in case of errors
+ */
+ public void setText(String text, boolean html) throws MessagingException {
+ Assert.notNull(text, "Text must not be null");
+ MimePart partToUse = null;
+ if (isMultipart()) {
+ partToUse = getMainPart();
+ }
+ else {
+ partToUse = this.mimeMessage;
+ }
+ if (html) {
+ setHtmlTextToMimePart(partToUse, text);
+ }
+ else {
+ setPlainTextToMimePart(partToUse, text);
+ }
+ }
+
+ /**
+ * Set the given plain text and HTML text as alternatives, offering
+ * both options to the email client. Requires multipart mode.
+ *
NOTE: Invoke {@link #addInline} aftersetText;
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param plainText the plain text for the message
+ * @param htmlText the HTML text for the message
+ * @throws MessagingException in case of errors
+ */
+ public void setText(String plainText, String htmlText) throws MessagingException {
+ Assert.notNull(plainText, "Plain text must not be null");
+ Assert.notNull(htmlText, "HTML text must not be null");
+
+ MimeMultipart messageBody = new MimeMultipart(MULTIPART_SUBTYPE_ALTERNATIVE);
+ getMainPart().setContent(messageBody, CONTENT_TYPE_ALTERNATIVE);
+
+ // Create the plain text part of the message.
+ MimeBodyPart plainTextPart = new MimeBodyPart();
+ setPlainTextToMimePart(plainTextPart, plainText);
+ messageBody.addBodyPart(plainTextPart);
+
+ // Create the HTML text part of the message.
+ MimeBodyPart htmlTextPart = new MimeBodyPart();
+ setHtmlTextToMimePart(htmlTextPart, htmlText);
+ messageBody.addBodyPart(htmlTextPart);
+ }
+
+ private MimeBodyPart getMainPart() throws MessagingException {
+ MimeMultipart mimeMultipart = getMimeMultipart();
+ MimeBodyPart bodyPart = null;
+ for (int i = 0; i < mimeMultipart.getCount(); i++) {
+ BodyPart bp = mimeMultipart.getBodyPart(i);
+ if (bp.getFileName() == null) {
+ bodyPart = (MimeBodyPart) bp;
+ }
+ }
+ if (bodyPart == null) {
+ MimeBodyPart mimeBodyPart = new MimeBodyPart();
+ mimeMultipart.addBodyPart(mimeBodyPart);
+ bodyPart = mimeBodyPart;
+ }
+ return bodyPart;
+ }
+
+ private void setPlainTextToMimePart(MimePart mimePart, String text) throws MessagingException {
+ if (getEncoding() != null) {
+ mimePart.setText(text, getEncoding());
+ }
+ else {
+ mimePart.setText(text);
+ }
+ }
+
+ private void setHtmlTextToMimePart(MimePart mimePart, String text) throws MessagingException {
+ if (getEncoding() != null) {
+ mimePart.setContent(text, CONTENT_TYPE_HTML + CONTENT_TYPE_CHARSET_SUFFIX + getEncoding());
+ }
+ else {
+ mimePart.setContent(text, CONTENT_TYPE_HTML);
+ }
+ }
+
+
+ /**
+ * Add an inline element to the MimeMessage, taking the content from a
+ * javax.activation.DataSource.
+ *
Note that the InputStream returned by the DataSource implementation
+ * needs to be a fresh one on each call, as JavaMail will invoke
+ * getInputStream() multiple times.
+ *
NOTE: Invoke addInlineafter {@link #setText};
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param contentId the content ID to use. Will end up as "Content-ID" header
+ * in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
+ * Can be referenced in HTML source via src="cid:myId" expressions.
+ * @param dataSource the javax.activation.DataSource to take
+ * the content from, determining the InputStream and the content type
+ * @throws MessagingException in case of errors
+ * @see #addInline(String, java.io.File)
+ * @see #addInline(String, org.springframework.core.io.Resource)
+ */
+ public void addInline(String contentId, DataSource dataSource) throws MessagingException {
+ Assert.notNull(contentId, "Content ID must not be null");
+ Assert.notNull(dataSource, "DataSource must not be null");
+ MimeBodyPart mimeBodyPart = new MimeBodyPart();
+ mimeBodyPart.setDisposition(MimeBodyPart.INLINE);
+ // We're using setHeader here to remain compatible with JavaMail 1.2,
+ // rather than JavaMail 1.3's setContentID.
+ mimeBodyPart.setHeader(HEADER_CONTENT_ID, "<" + contentId + ">");
+ mimeBodyPart.setDataHandler(new DataHandler(dataSource));
+ getMimeMultipart().addBodyPart(mimeBodyPart);
+ }
+
+ /**
+ * Add an inline element to the MimeMessage, taking the content from a
+ * java.io.File.
+ *
The content type will be determined by the name of the given
+ * content file. Do not use this for temporary files with arbitrary
+ * filenames (possibly ending in ".tmp" or the like)!
+ *
NOTE: Invoke addInlineafter {@link #setText};
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param contentId the content ID to use. Will end up as "Content-ID" header
+ * in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
+ * Can be referenced in HTML source via src="cid:myId" expressions.
+ * @param file the File resource to take the content from
+ * @throws MessagingException in case of errors
+ * @see #setText
+ * @see #addInline(String, org.springframework.core.io.Resource)
+ * @see #addInline(String, javax.activation.DataSource)
+ */
+ public void addInline(String contentId, File file) throws MessagingException {
+ Assert.notNull(file, "File must not be null");
+ FileDataSource dataSource = new FileDataSource(file);
+ dataSource.setFileTypeMap(getFileTypeMap());
+ addInline(contentId, dataSource);
+ }
+
+ /**
+ * Add an inline element to the MimeMessage, taking the content from a
+ * org.springframework.core.io.Resource.
+ *
The content type will be determined by the name of the given
+ * content file. Do not use this for temporary files with arbitrary
+ * filenames (possibly ending in ".tmp" or the like)!
+ *
Note that the InputStream returned by the Resource implementation
+ * needs to be a fresh one on each call, as JavaMail will invoke
+ * getInputStream() multiple times.
+ *
NOTE: Invoke addInlineafter {@link #setText};
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param contentId the content ID to use. Will end up as "Content-ID" header
+ * in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
+ * Can be referenced in HTML source via src="cid:myId" expressions.
+ * @param resource the resource to take the content from
+ * @throws MessagingException in case of errors
+ * @see #setText
+ * @see #addInline(String, java.io.File)
+ * @see #addInline(String, javax.activation.DataSource)
+ */
+ public void addInline(String contentId, Resource resource) throws MessagingException {
+ Assert.notNull(resource, "Resource must not be null");
+ String contentType = getFileTypeMap().getContentType(resource.getFilename());
+ addInline(contentId, resource, contentType);
+ }
+
+ /**
+ * Add an inline element to the MimeMessage, taking the content from an
+ * org.springframework.core.InputStreamResource, and
+ * specifying the content type explicitly.
+ *
You can determine the content type for any given filename via a Java
+ * Activation Framework's FileTypeMap, for example the one held by this helper.
+ *
Note that the InputStream returned by the InputStreamSource implementation
+ * needs to be a fresh one on each call, as JavaMail will invoke
+ * getInputStream() multiple times.
+ *
NOTE: Invoke addInlineaftersetText;
+ * else, mail readers might not be able to resolve inline references correctly.
+ * @param contentId the content ID to use. Will end up as "Content-ID" header
+ * in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
+ * Can be referenced in HTML source via src="cid:myId" expressions.
+ * @param inputStreamSource the resource to take the content from
+ * @param contentType the content type to use for the element
+ * @throws MessagingException in case of errors
+ * @see #setText
+ * @see #getFileTypeMap
+ * @see #addInline(String, org.springframework.core.io.Resource)
+ * @see #addInline(String, javax.activation.DataSource)
+ */
+ public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
+ throws MessagingException {
+
+ Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
+ if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
+ throw new IllegalArgumentException(
+ "Passed-in Resource contains an open stream: invalid argument. " +
+ "JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
+ }
+ DataSource dataSource = createDataSource(inputStreamSource, contentType, "inline");
+ addInline(contentId, dataSource);
+ }
+
+ /**
+ * Add an attachment to the MimeMessage, taking the content from a
+ * javax.activation.DataSource.
+ *
Note that the InputStream returned by the DataSource implementation
+ * needs to be a fresh one on each call, as JavaMail will invoke
+ * getInputStream() multiple times.
+ * @param attachmentFilename the name of the attachment as it will
+ * appear in the mail (the content type will be determined by this)
+ * @param dataSource the javax.activation.DataSource to take
+ * the content from, determining the InputStream and the content type
+ * @throws MessagingException in case of errors
+ * @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
+ * @see #addAttachment(String, java.io.File)
+ */
+ public void addAttachment(String attachmentFilename, DataSource dataSource) throws MessagingException {
+ Assert.notNull(attachmentFilename, "Attachment filename must not be null");
+ Assert.notNull(dataSource, "DataSource must not be null");
+ MimeBodyPart mimeBodyPart = new MimeBodyPart();
+ mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
+ mimeBodyPart.setFileName(attachmentFilename);
+ mimeBodyPart.setDataHandler(new DataHandler(dataSource));
+ getRootMimeMultipart().addBodyPart(mimeBodyPart);
+ }
+
+ /**
+ * Add an attachment to the MimeMessage, taking the content from a
+ * java.io.File.
+ *
The content type will be determined by the name of the given
+ * content file. Do not use this for temporary files with arbitrary
+ * filenames (possibly ending in ".tmp" or the like)!
+ * @param attachmentFilename the name of the attachment as it will
+ * appear in the mail
+ * @param file the File resource to take the content from
+ * @throws MessagingException in case of errors
+ * @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
+ * @see #addAttachment(String, javax.activation.DataSource)
+ */
+ public void addAttachment(String attachmentFilename, File file) throws MessagingException {
+ Assert.notNull(file, "File must not be null");
+ FileDataSource dataSource = new FileDataSource(file);
+ dataSource.setFileTypeMap(getFileTypeMap());
+ addAttachment(attachmentFilename, dataSource);
+ }
+
+ /**
+ * Add an attachment to the MimeMessage, taking the content from an
+ * org.springframework.core.io.InputStreamResource.
+ *
The content type will be determined by the given filename for
+ * the attachment. Thus, any content source will be fine, including
+ * temporary files with arbitrary filenames.
+ *
Note that the InputStream returned by the InputStreamSource
+ * implementation needs to be a fresh one on each call, as
+ * JavaMail will invoke getInputStream() multiple times.
+ * @param attachmentFilename the name of the attachment as it will
+ * appear in the mail
+ * @param inputStreamSource the resource to take the content from
+ * (all of Spring's Resource implementations can be passed in here)
+ * @throws MessagingException in case of errors
+ * @see #addAttachment(String, java.io.File)
+ * @see #addAttachment(String, javax.activation.DataSource)
+ * @see org.springframework.core.io.Resource
+ */
+ public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
+ throws MessagingException {
+
+ String contentType = getFileTypeMap().getContentType(attachmentFilename);
+ addAttachment(attachmentFilename, inputStreamSource, contentType);
+ }
+
+ /**
+ * Add an attachment to the MimeMessage, taking the content from an
+ * org.springframework.core.io.InputStreamResource.
+ *
Note that the InputStream returned by the InputStreamSource
+ * implementation needs to be a fresh one on each call, as
+ * JavaMail will invoke getInputStream() multiple times.
+ * @param attachmentFilename the name of the attachment as it will
+ * appear in the mail
+ * @param inputStreamSource the resource to take the content from
+ * (all of Spring's Resource implementations can be passed in here)
+ * @param contentType the content type to use for the element
+ * @throws MessagingException in case of errors
+ * @see #addAttachment(String, java.io.File)
+ * @see #addAttachment(String, javax.activation.DataSource)
+ * @see org.springframework.core.io.Resource
+ */
+ public void addAttachment(
+ String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
+ throws MessagingException {
+
+ Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
+ if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
+ throw new IllegalArgumentException(
+ "Passed-in Resource contains an open stream: invalid argument. " +
+ "JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
+ }
+ DataSource dataSource = createDataSource(inputStreamSource, contentType, attachmentFilename);
+ addAttachment(attachmentFilename, dataSource);
+ }
+
+ /**
+ * Create an Activation Framework DataSource for the given InputStreamSource.
+ * @param inputStreamSource the InputStreamSource (typically a Spring Resource)
+ * @param contentType the content type
+ * @param name the name of the DataSource
+ * @return the Activation Framework DataSource
+ */
+ protected DataSource createDataSource(
+ final InputStreamSource inputStreamSource, final String contentType, final String name) {
+
+ return new DataSource() {
+ public InputStream getInputStream() throws IOException {
+ return inputStreamSource.getInputStream();
+ }
+ public OutputStream getOutputStream() {
+ throw new UnsupportedOperationException("Read-only javax.activation.DataSource");
+ }
+ public String getContentType() {
+ return contentType;
+ }
+ public String getName() {
+ return name;
+ }
+ };
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessagePreparator.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessagePreparator.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/MimeMessagePreparator.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2002-2006 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.mail.javamail;
+
+import javax.mail.internet.MimeMessage;
+
+/**
+ * Callback interface for the preparation of JavaMail MIME messages.
+ *
+ *
The corresponding send methods of {@link JavaMailSender}
+ * will take care of the actual creation of a {@link MimeMessage} instance,
+ * and of proper exception conversion.
+ *
+ *
It is often convenient to use a {@link MimeMessageHelper} for populating
+ * the passed-in MimeMessage, in particular when working with attachments or
+ * special character encodings.
+ * See {@link MimeMessageHelper MimeMessageHelper's javadoc} for an example.
+ *
+ * @author Juergen Hoeller
+ * @since 07.10.2003
+ * @see JavaMailSender#send(MimeMessagePreparator)
+ * @see JavaMailSender#send(MimeMessagePreparator[])
+ * @see MimeMessageHelper
+ */
+public interface MimeMessagePreparator {
+
+ /**
+ * Prepare the given new MimeMessage instance.
+ * @param mimeMessage the message to prepare
+ * @throws javax.mail.MessagingException passing any exceptions thrown by MimeMessage
+ * methods through for automatic conversion to the MailException hierarchy
+ * @throws java.io.IOException passing any exceptions thrown by MimeMessage methods
+ * through for automatic conversion to the MailException hierarchy
+ * @throws Exception if mail preparation failed, for example when a
+ * Velocity template cannot be rendered for the mail text
+ */
+ void prepare(MimeMessage mimeMessage) throws Exception;
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/SmartMimeMessage.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/SmartMimeMessage.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/SmartMimeMessage.java 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2002-2008 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.mail.javamail;
+
+import javax.activation.FileTypeMap;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+/**
+ * Special subclass of the standard JavaMail {@link MimeMessage}, carrying a
+ * default encoding to be used when populating the message and a default Java
+ * Activation {@link FileTypeMap} to be used for resolving attachment types.
+ *
+ *
Created by {@link JavaMailSenderImpl} in case of a specified default encoding
+ * and/or default FileTypeMap. Autodetected by {@link MimeMessageHelper}, which
+ * will use the carried encoding and FileTypeMap unless explicitly overridden.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see JavaMailSenderImpl#createMimeMessage()
+ * @see MimeMessageHelper#getDefaultEncoding(javax.mail.internet.MimeMessage)
+ * @see MimeMessageHelper#getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
+ */
+class SmartMimeMessage extends MimeMessage {
+
+ private final String defaultEncoding;
+
+ private final FileTypeMap defaultFileTypeMap;
+
+
+ /**
+ * Create a new SmartMimeMessage.
+ * @param session the JavaMail Session to create the message for
+ * @param defaultEncoding the default encoding, or null if none
+ * @param defaultFileTypeMap the default FileTypeMap, or null if none
+ */
+ public SmartMimeMessage(Session session, String defaultEncoding, FileTypeMap defaultFileTypeMap) {
+ super(session);
+ this.defaultEncoding = defaultEncoding;
+ this.defaultFileTypeMap = defaultFileTypeMap;
+ }
+
+
+ /**
+ * Return the default encoding of this message, or null if none.
+ */
+ public final String getDefaultEncoding() {
+ return this.defaultEncoding;
+ }
+
+ /**
+ * Return the default FileTypeMap of this message, or null if none.
+ */
+ public final FileTypeMap getDefaultFileTypeMap() {
+ return this.defaultFileTypeMap;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/mime.types
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/mime.types,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/mime.types 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,306 @@
+################################################################################
+#
+# Defaults for the Java Activation Framework
+# Additional extensions registered in this file:
+# text/plain java c c++ pl cc h
+#
+################################################################################
+
+text/html html htm HTML HTM
+text/plain txt text TXT TEXT java c c++ pl cc h
+image/gif gif GIF
+image/ief ief
+image/jpeg jpeg jpg jpe JPG
+image/tiff tiff tif
+image/x-xwindowdump xwd
+application/postscript ai eps ps
+application/rtf rtf
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-troff t tr roff
+audio/basic au
+audio/midi midi mid
+audio/x-aifc aifc
+audio/x-aiff aif aiff
+audio/x-mpeg mpeg mpg
+audio/x-wav wav
+video/mpeg mpeg mpg mpe
+video/quicktime qt mov
+video/x-msvideo avi
+
+################################################################################
+#
+# Additional file types adapted from
+# http://www.utoronto.ca/webdocs/HTMLdocs/Book/Book-3ed/appb/mimetype.html
+#
+################################################################################
+
+# TEXT TYPES
+
+text/x-speech talk
+text/css css
+text/csv csv
+
+# IMAGE TYPES
+
+# X-Windows bitmap (b/w)
+image/x-xbitmap xbm
+# X-Windows pixelmap (8-bit color)
+image/x-xpixmap xpm
+# Portable Network Graphics
+image/x-png png
+# Image Exchange Format (RFC 1314)
+image/ief ief
+# JPEG
+image/jpeg jpeg jpg jpe
+# RGB
+image/rgb rgb
+# Group III Fax (RFC 1494)
+image/g3fax g3f
+# X Windowdump format
+image/x-xwindowdump xwd
+# Macintosh PICT format
+image/x-pict pict
+# PPM (UNIX PPM package)
+image/x-portable-pixmap ppm
+# PGM (UNIX PPM package)
+image/x-portable-graymap pgm
+# PBM (UNIX PPM package)
+image/x-portable-bitmap pbm
+# PNM (UNIX PPM package)
+image/x-portable-anymap pnm
+# Microsoft Windows bitmap
+image/x-ms-bmp bmp
+# CMU raster
+image/x-cmu-raster ras
+# Kodak Photo-CD
+image/x-photo-cd pcd
+# Computer Graphics Metafile
+image/cgm cgm
+# CALS Type 1 or 2
+image/x-cals mil cal
+# Fractal Image Format (Iterated Systems)
+image/fif fif
+# QuickSilver active image (Micrografx)
+image/x-mgx-dsf dsf
+# CMX vector image (Corel)
+image/x-cmx cmx
+# Wavelet-compressed (Summus)
+image/wavelet wi
+# AutoCad Drawing (SoftSource)
+image/vnd.dwg dwg
+# AutoCad DXF file (SoftSource)
+image/vnd.dxf dxf
+# Simple Vector Format (SoftSource)
+image/vnd.svf svf
+
+# AUDIO/VOICE/MUSIC RELATED TYPES
+
+# """basic""audio - 8-bit u-law PCM"
+audio/basic au snd
+# Macintosh audio format (AIpple)
+audio/x-aiff aif aiff aifc
+# Microsoft audio
+audio/x-wav wav
+# MPEG audio
+audio/x-mpeg mpa abs mpega
+# MPEG-2 audio
+audio/x-mpeg-2 mp2a mpa2
+# compressed speech (Echo Speech Corp.)
+audio/echospeech es
+# Toolvox speech audio (Voxware)
+audio/voxware vox
+# RapidTransit compressed audio (Fast Man)
+application/fastman lcc
+# Realaudio (Progressive Networks)
+application/x-pn-realaudio ra ram
+# MIDI music data
+x-music/x-midi mmid
+# Koan music data (SSeyo)
+application/vnd.koan skp
+# Speech synthesis data (MVP Solutions)
+text/x-speech talk
+
+# VIDEO TYPES
+
+# MPEG video
+video/mpeg mpeg mpg mpe
+# MPEG-2 video
+video/mpeg-2 mpv2 mp2v
+# Macintosh Quicktime
+video/quicktime qt mov
+# Microsoft video
+video/x-msvideo avi
+# SGI Movie format
+video/x-sgi-movie movie
+# VDOlive streaming video (VDOnet)
+video/vdo vdo
+# Vivo streaming video (Vivo software)
+video/vnd.vivo viv
+
+# SPECIAL HTTP/WEB APPLICATION TYPES
+
+# Proxy autoconfiguration (Netscape browsers)
+application/x-ns-proxy-autoconfig pac
+# Netscape Cooltalk chat data (Netscape)
+x-conference/x-cooltalk ice
+
+# TEXT-RELATED
+
+# PostScript
+application/postscript ai eps ps
+# Microsoft Rich Text Format
+application/rtf rtf
+# Adobe Acrobat PDF
+application/pdf pdf
+# Maker Interchange Format (FrameMaker)
+application/vnd.mif mif
+# Troff document
+application/x-troff t tr roff
+# Troff document with MAN macros
+application/x-troff-man man
+# Troff document with ME macros
+application/x-troff-me me
+# Troff document with MS macros
+application/x-troff-ms ms
+# LaTeX document
+application/x-latex latex
+# Tex/LateX document
+application/x-tex tex
+# GNU TexInfo document
+application/x-texinfo texinfo texi
+# TeX dvi format
+application/x-dvi dvi
+# MS word document
+application/msword doc DOC
+# Office Document Architecture
+application/oda oda
+# Envoy Document
+application/envoy evy
+
+# ARCHIVE/COMPRESSED ARCHIVES
+
+# Gnu tar format
+application/x-gtar gtar
+# 4.3BSD tar format
+application/x-tar tar
+# POSIX tar format
+application/x-ustar ustar
+# Old CPIO format
+application/x-bcpio bcpio
+# POSIX CPIO format
+application/x-cpio cpio
+# UNIX sh shell archive
+application/x-shar shar
+# DOS/PC - Pkzipped archive
+application/zip zip
+# Macintosh Binhexed archive
+application/mac-binhex40 hqx
+# Macintosh Stuffit Archive
+application/x-stuffit sit sea
+# Fractal Image Format
+application/fractals fif
+# "Binary UUencoded"
+application/octet-stream bin uu
+# PC executable
+application/octet-stream exe
+# "WAIS ""sources"""
+application/x-wais-source src wsrc
+# NCSA HDF data format
+application/hdf hdf
+
+# DOWNLOADABLE PROGRAM/SCRIPTS
+
+# Javascript program
+text/javascript js ls mocha
+# UNIX bourne shell program
+application/x-sh sh
+# UNIX c-shell program
+application/x-csh csh
+# Perl program
+application/x-perl pl
+# Tcl (Tool Control Language) program
+application/x-tcl tcl
+
+# ANIMATION/MULTIMEDIA
+
+# FutureSplash vector animation (FutureWave)
+application/futuresplash spl
+# mBED multimedia data (mBED)
+application/mbedlet mbd
+# PowerMedia multimedia (RadMedia)
+application/x-rad-powermedia rad
+
+# PRESENTATION
+
+# PowerPoint presentation (Microsoft)
+application/mspowerpoint ppz
+# ASAP WordPower (Software Publishing Corp.)
+application/x-asap asp
+# Astound Web Player multimedia data (GoldDisk)
+application/astound asn
+
+# SPECIAL EMBEDDED OBJECT
+
+# OLE script e.g. Visual Basic (Ncompass)
+application/x-olescript axs
+# OLE Object (Microsoft/NCompass)
+application/x-oleobject ods
+# OpenScape OLE/OCX objects (Business@Web)
+x-form/x-openscape opp
+# Visual Basic objects (Amara)
+application/x-webbasic wba
+# Specialized data entry forms (Alpha Software)
+application/x-alpha-form frm
+# client-server objects (Wayfarer Communications)
+x-script/x-wfxclient wfx
+
+# GENERAL APPLICATIONS
+
+# Undefined binary data (often executable progs)
+application/octet-stream exe com
+# Pointcast news data (Pointcast)
+application/x-pcn pcn
+# Excel spreadsheet (Microsoft)
+application/vnd.ms-excel xls
+# PowerPoint (Microsoft)
+application/vnd.ms-powerpoint ppt
+# Microsoft Project (Microsoft)
+application/vnd.ms-project mpp
+# SourceView document (Dataware Electronics)
+application/vnd.svd svd
+# Net Install - software install (20/20 Software)
+application/x-net-install ins
+# Carbon Copy - remote control/access (Microcom)
+application/ccv ccv
+# Spreadsheets (Visual Components)
+workbook/formulaone vts
+
+# 2D/3D DATA/VIRTUAL REALITY TYPES
+
+# VRML data file
+x-world/x-vrml wrl vrml
+# WIRL - VRML data (VREAM)
+x-world/x-vream vrw
+# Play3D 3d scene data (Play3D)
+application/x-p3d p3d
+# Viscape Interactive 3d world data (Superscape)
+x-world/x-svr svr
+# WebActive 3d data (Plastic Thought)
+x-world/x-wvr wvr
+# QuickDraw3D scene data (Apple)
+x-world/x-3dmf 3dmf
+
+# SCIENTIFIC/MATH/CAD TYPES
+
+# Mathematica notebook
+application/mathematica ma
+# Computational meshes for numerical simulations
+x-model/x-mesh msh
+# Vis5D 5-dimensional data
+application/vis5d v5d
+# IGES models -- CAD/CAM (CGM) data
+application/iges igs
+# Autocad WHIP vector drawings
+drawing/x-dwf dwf
+
Index: 3rdParty_sources/spring/org/springframework/mail/javamail/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/mail/javamail/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/mail/javamail/package.html 17 Aug 2012 15:15:23 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
+JavaMail support for Spring's mail infrastructure.
+Provides an extended JavaMailSender interface and a MimeMessageHelper
+class for convenient population of a JavaMail MimeMessage.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/metadata/Attributes.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/metadata/Attributes.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/metadata/Attributes.java 17 Aug 2012 15:16:16 -0000 1.1
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2002-2005 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.metadata;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+/**
+ * Interface for accessing attributes at runtime. This is a facade,
+ * which can accommodate any attributes API such as Jakarta Commons Attributes,
+ * or (possibly in future) a Spring attributes implementation.
+ *
+ *
The purpose of using this interface is to decouple Spring code from any
+ * specific attributes implementation. Even once JSR-175 is available, there
+ * is still value in such a facade interface, as it allows for hierarchical
+ * attribute sources: for example, an XML file or properties file might override
+ * some attributes defined in source-level metadata with JSR-175 or another framework.
+ *
+ * @author Mark Pollack
+ * @author Rod Johnson
+ * @since 30.09.2003
+ * @see org.springframework.metadata.commons.CommonsAttributes
+ */
+public interface Attributes {
+
+ /**
+ * Return the class attributes of the target class.
+ * @param targetClass the class that contains attribute information
+ * @return a collection of attributes, possibly an empty collection, never null
+ */
+ Collection getAttributes(Class targetClass);
+
+ /**
+ * Return the class attributes of the target class of a given type.
+ *
The class attributes are filtered by providing a Class
+ * reference to indicate the type to filter on. This is useful if you know
+ * the type of the attribute you are looking for and don't want to sort
+ * through the unfiltered Collection yourself.
+ * @param targetClass the class that contains attribute information
+ * @param filter specify that only this type of class should be returned
+ * @return return only the Collection of attributes that are of the filter type
+ */
+ Collection getAttributes(Class targetClass, Class filter);
+
+ /**
+ * Return the method attributes of the target method.
+ * @param targetMethod the method that contains attribute information
+ * @return a Collection of attributes, possibly an empty Collection, never null
+ */
+ Collection getAttributes(Method targetMethod);
+
+ /**
+ * Return the method attributes of the target method of a given type.
+ *
The method attributes are filtered by providing a Class
+ * reference to indicate the type to filter on. This is useful if you know
+ * the type of the attribute you are looking for and don't want to sort
+ * through the unfiltered Collection yourself.
+ * @param targetMethod the method that contains attribute information
+ * @param filter specify that only this type of class should be returned
+ * @return a Collection of attributes, possibly an empty Collection, never null
+ */
+ Collection getAttributes(Method targetMethod, Class filter);
+
+ /**
+ * Return the field attributes of the target field.
+ * @param targetField the field that contains attribute information
+ * @return a Collection of attribute, possibly an empty Collection, never null
+ */
+ Collection getAttributes(Field targetField);
+
+ /**
+ * Return the field attributes of the target method of a given type.
+ *
The field attributes are filtered by providing a Class
+ * reference to indicate the type to filter on. This is useful if you know
+ * the type of the attribute you are looking for and don't want to sort
+ * through the unfiltered Collection yourself.
+ * @param targetField the field that contains attribute information
+ * @param filter specify that only this type of class should be returned
+ * @return a Collection of attributes, possibly an empty Collection, never null
+ */
+ Collection getAttributes(Field targetField, Class filter);
+
+}
Index: 3rdParty_sources/spring/org/springframework/metadata/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/metadata/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/metadata/package.html 17 Aug 2012 15:16:16 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Package defining a facade for accessing source-level
+metadata attributes at runtime.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/metadata/commons/CommonsAttributes.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/metadata/commons/CommonsAttributes.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/metadata/commons/CommonsAttributes.java 17 Aug 2012 15:16:18 -0000 1.1
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2005 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.metadata.commons;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+import org.springframework.metadata.Attributes;
+
+/**
+ * Implementation of the Spring Attributes facade for Commons Attributes.
+ *
+ *
As of December 2003, follow the Javadocs to the AttributeCompiler class
+ * to see how the Ant task works. Note that you need to put the following jars
+ * in your $ANT_HOME/lib directory for the Common Attributes compiler to work:
+ *
+ *
Commons Attributes compiler jar
+ *
the xjavadoc Jar (from XDoclet)
+ *
commons-collection.jar (from Jakarta Commons)
+ *
+ *
+ *
You need to perform the attribute compilation step before compiling your source.
+ *
+ *
See build.xml in the tests for package org.springframework.aop.autoproxy.metadata
+ * for an example of the required Ant scripting. The header of this build script
+ * includes some quick, and hopefully useful, hints on using Commons Attributes.
+ * The source files in the same package (TxClass and TxClassWithClassAttribute)
+ * illustrate attribute usage in source files.
+ *
+ *
The Spring Framework project does not provide support usage of specific
+ * attributes implementations. Please refer to the appropriate site and mailing
+ * list of the attributes implementation.
+ *
+ * @author Rod Johnson
+ */
+public class CommonsAttributes implements Attributes {
+
+ /*
+ * Commons Attributes caches attributes, so we don't need to cache here
+ * as well.
+ */
+
+ public Collection getAttributes(Class targetClass) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetClass);
+ }
+
+ public Collection getAttributes(Class targetClass, Class filter) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetClass, filter);
+ }
+
+ public Collection getAttributes(Method targetMethod) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetMethod);
+ }
+
+ public Collection getAttributes(Method targetMethod, Class filter) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetMethod, filter);
+ }
+
+ public Collection getAttributes(Field targetField) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetField);
+ }
+
+ public Collection getAttributes(Field targetField, Class filter) {
+ return org.apache.commons.attributes.Attributes.getAttributes(targetField, filter);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/metadata/commons/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/metadata/commons/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/metadata/commons/package.html 17 Aug 2012 15:16:18 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Attributes wrapper for
+Commons Attributes.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/ObjectOptimisticLockingFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ObjectOptimisticLockingFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ObjectOptimisticLockingFailureException.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2002-2006 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.orm;
+
+import org.springframework.dao.OptimisticLockingFailureException;
+
+/**
+ * Exception thrown on an optimistic locking violation for a mapped object.
+ * Provides information about the persistent class and the identifier.
+ *
+ * @author Juergen Hoeller
+ * @since 13.10.2003
+ */
+public class ObjectOptimisticLockingFailureException extends OptimisticLockingFailureException {
+
+ private Object persistentClass;
+
+ private Object identifier;
+
+
+ /**
+ * Create a general ObjectOptimisticLockingFailureException with the given message,
+ * without any information on the affected object.
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectOptimisticLockingFailureException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the default "optimistic locking failed" message.
+ * @param persistentClass the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ */
+ public ObjectOptimisticLockingFailureException(Class persistentClass, Object identifier) {
+ this(persistentClass, identifier, null);
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the default "optimistic locking failed" message.
+ * @param persistentClass the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ * @param cause the source exception
+ */
+ public ObjectOptimisticLockingFailureException(
+ Class persistentClass, Object identifier, Throwable cause) {
+
+ this(persistentClass, identifier,
+ "Object of class [" + persistentClass.getName() + "] with identifier [" + identifier +
+ "]: optimistic locking failed", cause);
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the given explicit message.
+ * @param persistentClass the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectOptimisticLockingFailureException(
+ Class persistentClass, Object identifier, String msg, Throwable cause) {
+
+ super(msg, cause);
+ this.persistentClass = persistentClass;
+ this.identifier = identifier;
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the default "optimistic locking failed" message.
+ * @param persistentClassName the name of the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ */
+ public ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier) {
+ this(persistentClassName, identifier, null);
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the default "optimistic locking failed" message.
+ * @param persistentClassName the name of the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ * @param cause the source exception
+ */
+ public ObjectOptimisticLockingFailureException(
+ String persistentClassName, Object identifier, Throwable cause) {
+
+ this(persistentClassName, identifier,
+ "Object of class [" + persistentClassName + "] with identifier [" + identifier +
+ "]: optimistic locking failed", cause);
+ }
+
+ /**
+ * Create a new ObjectOptimisticLockingFailureException for the given object,
+ * with the given explicit message.
+ * @param persistentClassName the name of the persistent class
+ * @param identifier the ID of the object for which the locking failed
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectOptimisticLockingFailureException(
+ String persistentClassName, Object identifier, String msg, Throwable cause) {
+
+ super(msg, cause);
+ this.persistentClass = persistentClassName;
+ this.identifier = identifier;
+ }
+
+
+ /**
+ * Return the persistent class of the object for which the locking failed.
+ * If no Class was specified, this method returns null.
+ */
+ public Class getPersistentClass() {
+ return (this.persistentClass instanceof Class ? (Class) this.persistentClass : null);
+ }
+
+ /**
+ * Return the name of the persistent class of the object for which the locking failed.
+ * Will work for both Class objects and String names.
+ */
+ public String getPersistentClassName() {
+ if (this.persistentClass instanceof Class) {
+ return ((Class) this.persistentClass).getName();
+ }
+ return (this.persistentClass != null ? this.persistentClass.toString() : null);
+ }
+
+ /**
+ * Return the identifier of the object for which the locking failed.
+ */
+ public Object getIdentifier() {
+ return identifier;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ObjectRetrievalFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ObjectRetrievalFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ObjectRetrievalFailureException.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002-2006 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.orm;
+
+import org.springframework.dao.DataRetrievalFailureException;
+
+/**
+ * Exception thrown if a mapped object could not be retrieved via its identifier.
+ * Provides information about the persistent class and the identifier.
+ *
+ * @author Juergen Hoeller
+ * @since 13.10.2003
+ */
+public class ObjectRetrievalFailureException extends DataRetrievalFailureException {
+
+ private Object persistentClass;
+
+ private Object identifier;
+
+
+ /**
+ * Create a general ObjectRetrievalFailureException with the given message,
+ * without any information on the affected object.
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectRetrievalFailureException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Create a new ObjectRetrievalFailureException for the given object,
+ * with the default "not found" message.
+ * @param persistentClass the persistent class
+ * @param identifier the ID of the object that should have been retrieved
+ */
+ public ObjectRetrievalFailureException(Class persistentClass, Object identifier) {
+ this(persistentClass, identifier,
+ "Object of class [" + persistentClass.getName() + "] with identifier [" + identifier + "]: not found",
+ null);
+ }
+
+ /**
+ * Create a new ObjectRetrievalFailureException for the given object,
+ * with the given explicit message and exception.
+ * @param persistentClass the persistent class
+ * @param identifier the ID of the object that should have been retrieved
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectRetrievalFailureException(
+ Class persistentClass, Object identifier, String msg, Throwable cause) {
+
+ super(msg, cause);
+ this.persistentClass = persistentClass;
+ this.identifier = identifier;
+ }
+
+ /**
+ * Create a new ObjectRetrievalFailureException for the given object,
+ * with the default "not found" message.
+ * @param persistentClassName the name of the persistent class
+ * @param identifier the ID of the object that should have been retrieved
+ */
+ public ObjectRetrievalFailureException(String persistentClassName, Object identifier) {
+ this(persistentClassName, identifier,
+ "Object of class [" + persistentClassName + "] with identifier [" + identifier + "]: not found",
+ null);
+ }
+
+ /**
+ * Create a new ObjectRetrievalFailureException for the given object,
+ * with the given explicit message and exception.
+ * @param persistentClassName the name of the persistent class
+ * @param identifier the ID of the object that should have been retrieved
+ * @param msg the detail message
+ * @param cause the source exception
+ */
+ public ObjectRetrievalFailureException(
+ String persistentClassName, Object identifier, String msg, Throwable cause) {
+
+ super(msg, cause);
+ this.persistentClass = persistentClassName;
+ this.identifier = identifier;
+ }
+
+
+ /**
+ * Return the persistent class of the object that was not found.
+ * If no Class was specified, this method returns null.
+ */
+ public Class getPersistentClass() {
+ return (this.persistentClass instanceof Class ? (Class) this.persistentClass : null);
+ }
+
+ /**
+ * Return the name of the persistent class of the object that was not found.
+ * Will work for both Class objects and String names.
+ */
+ public String getPersistentClassName() {
+ if (this.persistentClass instanceof Class) {
+ return ((Class) this.persistentClass).getName();
+ }
+ return (this.persistentClass != null ? this.persistentClass.toString() : null);
+ }
+
+ /**
+ * Return the identifier of the object that was not found.
+ */
+ public Object getIdentifier() {
+ return identifier;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/package.html 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Root package for Spring's O/R Mapping integration classes.
+Contains generic DataAccessExceptions related to O/R Mapping.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.SessionFactory;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+
+/**
+ * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
+ * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
+ * context, providing general infrastructure not related to Hibernate's
+ * specific configuration API.
+ *
+ *
This class implements the
+ * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
+ * interface, as autodetected by Spring's
+ * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
+ * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
+ * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
+ * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
+ *
+ *
This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
+ * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setExposeTransactionAwareSessionFactory
+ * @see org.hibernate.SessionFactory#getCurrentSession()
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ */
+public abstract class AbstractSessionFactoryBean
+ implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private DataSource dataSource;
+
+ private boolean useTransactionAwareDataSource = false;
+
+ private boolean exposeTransactionAwareSessionFactory = true;
+
+ private SQLExceptionTranslator jdbcExceptionTranslator;
+
+ private SessionFactory sessionFactory;
+
+
+ /**
+ * Set the DataSource to be used by the SessionFactory.
+ * If set, this will override corresponding settings in Hibernate properties.
+ *
If this is set, the Hibernate settings should not define
+ * a connection provider to avoid meaningless double configuration.
+ *
If using HibernateTransactionManager as transaction strategy, consider
+ * proxying your target DataSource with a LazyConnectionDataSourceProxy.
+ * This defers fetching of an actual JDBC Connection until the first JDBC
+ * Statement gets executed, even within JDBC transactions (as performed by
+ * HibernateTransactionManager). Such lazy fetching is particularly beneficial
+ * for read-only operations, in particular if the chances of resolving the
+ * result in the second-level cache are high.
+ *
As JTA and transactional JNDI DataSources already provide lazy enlistment
+ * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
+ * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
+ * @see #setUseTransactionAwareDataSource
+ * @see HibernateTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
+ */
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ /**
+ * Return the DataSource to be used by the SessionFactory.
+ */
+ public DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * Set whether to use a transaction-aware DataSource for the SessionFactory,
+ * i.e. whether to automatically wrap the passed-in DataSource with Spring's
+ * TransactionAwareDataSourceProxy.
+ *
Default is "false": LocalSessionFactoryBean is usually used with Spring's
+ * HibernateTransactionManager or JtaTransactionManager, both of which work nicely
+ * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
+ * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
+ *
If you switch this flag to "true", Spring's Hibernate access will be able to
+ * participate in JDBC-based transactions managed outside of Hibernate
+ * (for example, by Spring's DataSourceTransactionManager). This can be convenient
+ * if you need a different local transaction strategy for another O/R mapping tool,
+ * for example, but still want Hibernate access to join into those transactions.
+ *
A further benefit of this option is that plain Sessions opened directly
+ * via the SessionFactory, outside of Spring's Hibernate support, will still
+ * participate in active Spring-managed transactions. However, consider using
+ * Hibernate's getCurrentSession() method instead (see javadoc of
+ * "exposeTransactionAwareSessionFactory" property).
+ *
WARNING: When using a transaction-aware JDBC DataSource in combination
+ * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
+ * external JDBC-based transactions, it is strongly recommended to set Hibernate's
+ * Connection release mode to "after_transaction" or "after_statement", which
+ * guarantees proper Connection handling in such a scenario. In contrast to that,
+ * HibernateTransactionManager generally requires release mode "on_close".
+ *
Note: If you want to use Hibernate's Connection release mode "after_statement"
+ * with a DataSource specified on this LocalSessionFactoryBean (for example, a
+ * JTA-aware DataSource fetched from JNDI), switch this setting to "true".
+ * Otherwise, the ConnectionProvider used underneath will vote against aggressive
+ * release and thus silently switch to release mode "after_transaction".
+ * @see #setDataSource
+ * @see #setExposeTransactionAwareSessionFactory
+ * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
+ * @see HibernateTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+ public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
+ this.useTransactionAwareDataSource = useTransactionAwareDataSource;
+ }
+
+ /**
+ * Return whether to use a transaction-aware DataSource for the SessionFactory.
+ */
+ protected boolean isUseTransactionAwareDataSource() {
+ return this.useTransactionAwareDataSource;
+ }
+
+ /**
+ * Set whether to expose a transaction-aware current Session from the
+ * SessionFactory's getCurrentSession() method, returning the
+ * Session that's associated with the current Spring-managed transaction, if any.
+ *
Default is "true", letting data access code work with the plain
+ * Hibernate SessionFactory and its getCurrentSession() method,
+ * while still being able to participate in current Spring-managed transactions:
+ * with any transaction management strategy, either local or JTA / EJB CMT,
+ * and any transaction synchronization mechanism, either Spring or JTA.
+ * Furthermore, getCurrentSession() will also seamlessly work with
+ * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
+ *
Turn this flag off to expose the plain Hibernate SessionFactory with
+ * Hibernate's default getCurrentSession() behavior, supporting
+ * plain JTA synchronization only. Alternatively, simply override the
+ * corresponding Hibernate property "hibernate.current_session_context_class".
+ * @see SpringSessionContext
+ * @see org.hibernate.SessionFactory#getCurrentSession()
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see HibernateTransactionManager
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
+ */
+ public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
+ this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
+ }
+
+ /**
+ * Return whether to expose a transaction-aware proxy for the SessionFactory.
+ */
+ protected boolean isExposeTransactionAwareSessionFactory() {
+ return this.exposeTransactionAwareSessionFactory;
+ }
+
+ /**
+ * Set the JDBC exception translator for the SessionFactory,
+ * exposed via the PersistenceExceptionTranslator interface.
+ *
Applied to any SQLException root cause of a Hibernate JDBCException,
+ * overriding Hibernate's default SQLException translation (which is
+ * based on Hibernate's Dialect for a specific target database).
+ * @param jdbcExceptionTranslator the exception translator
+ * @see java.sql.SQLException
+ * @see org.hibernate.JDBCException
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ * @see org.springframework.dao.support.PersistenceExceptionTranslator
+ */
+ public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
+ this.jdbcExceptionTranslator = jdbcExceptionTranslator;
+ }
+
+
+ /**
+ * Build and expose the SessionFactory.
+ * @see #buildSessionFactory()
+ * @see #wrapSessionFactoryIfNecessary
+ */
+ public void afterPropertiesSet() throws Exception {
+ SessionFactory rawSf = buildSessionFactory();
+ this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
+ afterSessionFactoryCreation();
+ }
+
+ /**
+ * Wrap the given SessionFactory with a proxy, if demanded.
+ *
The default implementation simply returns the given SessionFactory as-is.
+ * Subclasses may override this to implement transaction awareness through
+ * a SessionFactory proxy, for example.
+ * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
+ * @return the SessionFactory reference to expose
+ * @see #buildSessionFactory()
+ */
+ protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
+ return rawSf;
+ }
+
+ /**
+ * Return the exposed SessionFactory.
+ * Will throw an exception if not initialized yet.
+ * @return the SessionFactory (never null)
+ * @throws IllegalStateException if the SessionFactory has not been initialized yet
+ */
+ protected final SessionFactory getSessionFactory() {
+ if (this.sessionFactory == null) {
+ throw new IllegalStateException("SessionFactory not initialized yet");
+ }
+ return this.sessionFactory;
+ }
+
+ /**
+ * Close the SessionFactory on bean factory shutdown.
+ */
+ public void destroy() throws HibernateException {
+ logger.info("Closing Hibernate SessionFactory");
+ try {
+ beforeSessionFactoryDestruction();
+ }
+ finally {
+ this.sessionFactory.close();
+ }
+ }
+
+
+ /**
+ * Return the singleton SessionFactory.
+ */
+ public Object getObject() {
+ return this.sessionFactory;
+ }
+
+ public Class getObjectType() {
+ return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Implementation of the PersistenceExceptionTranslator interface,
+ * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
+ *
Converts the exception if it is a HibernateException;
+ * else returns null to indicate an unknown exception.
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ * @see #convertHibernateAccessException
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ if (ex instanceof HibernateException) {
+ return convertHibernateAccessException((HibernateException) ex);
+ }
+ return null;
+ }
+
+ /**
+ * Convert the given HibernateException to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ *
Will automatically apply a specified SQLExceptionTranslator to a
+ * Hibernate JDBCException, else rely on Hibernate's default translation.
+ * @param ex HibernateException that occured
+ * @return a corresponding DataAccessException
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ * @see #setJdbcExceptionTranslator
+ */
+ protected DataAccessException convertHibernateAccessException(HibernateException ex) {
+ if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
+ JDBCException jdbcEx = (JDBCException) ex;
+ return this.jdbcExceptionTranslator.translate(
+ "Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
+ }
+ return SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+
+
+ /**
+ * Build the underlying Hibernate SessionFactory.
+ * @return the raw SessionFactory (potentially to be wrapped with a
+ * transaction-aware proxy before it is exposed to the application)
+ * @throws Exception in case of initialization failure
+ */
+ protected abstract SessionFactory buildSessionFactory() throws Exception;
+
+ /**
+ * Hook that allows post-processing after the SessionFactory has been
+ * successfully created. The SessionFactory is already available through
+ * getSessionFactory() at this point.
+ *
This implementation is empty.
+ * @throws Exception in case of initialization failure
+ * @see #getSessionFactory()
+ */
+ protected void afterSessionFactoryCreation() throws Exception {
+ }
+
+ /**
+ * Hook that allows shutdown processing before the SessionFactory
+ * will be closed. The SessionFactory is still available through
+ * getSessionFactory() at this point.
+ *
This implementation is empty.
+ * @see #getSessionFactory()
+ */
+ protected void beforeSessionFactoryDestruction() {
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.type.TypeFactory;
+
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Convenient FactoryBean for defining Hibernate FilterDefinitions.
+ * Exposes a corresponding Hibernate FilterDefinition object.
+ *
+ *
Typically defined as an inner bean within a LocalSessionFactoryBean
+ * definition, as the list element for the "filterDefinitions" bean property.
+ * For example:
+ *
+ *
+ *
+ * Alternatively, specify a bean id (or name) attribute for the inner bean,
+ * instead of the "filterName" property.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.hibernate.engine.FilterDefinition
+ * @see LocalSessionFactoryBean#setFilterDefinitions
+ */
+public class FilterDefinitionFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {
+
+ private String filterName;
+
+ private Map parameterTypeMap = new HashMap();
+
+ private String defaultFilterCondition;
+
+ private FilterDefinition filterDefinition;
+
+
+ /**
+ * Set the name of the filter.
+ */
+ public void setFilterName(String filterName) {
+ this.filterName = filterName;
+ }
+
+ /**
+ * Set the parameter types for the filter,
+ * with parameter names as keys and type names as values.
+ * @see org.hibernate.type.TypeFactory#heuristicType(String)
+ */
+ public void setParameterTypes(Properties parameterTypes) {
+ if (parameterTypes != null) {
+ this.parameterTypeMap = new HashMap(parameterTypes.size());
+ for (Enumeration names = parameterTypes.propertyNames(); names.hasMoreElements();) {
+ String paramName = (String) names.nextElement();
+ String typeName = parameterTypes.getProperty(paramName);
+ this.parameterTypeMap.put(paramName, TypeFactory.heuristicType(typeName));
+ }
+ }
+ else {
+ this.parameterTypeMap = new HashMap();
+ }
+ }
+
+ /**
+ * Specify a default filter condition for the filter, if any.
+ */
+ public void setDefaultFilterCondition(String defaultFilterCondition) {
+ this.defaultFilterCondition = defaultFilterCondition;
+ }
+
+ /**
+ * If no explicit filter name has been specified, the bean name of
+ * the FilterDefinitionFactoryBean will be used.
+ * @see #setFilterName
+ */
+ public void setBeanName(String name) {
+ if (this.filterName == null) {
+ this.filterName = name;
+ }
+ }
+
+ public void afterPropertiesSet() {
+ this.filterDefinition =
+ new FilterDefinition(this.filterName, this.defaultFilterCondition, this.parameterTypeMap);
+ }
+
+
+ public Object getObject() {
+ return this.filterDefinition;
+ }
+
+ public Class getObjectType() {
+ return FilterDefinition.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateAccessor.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.exception.GenericJDBCException;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.Constants;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+
+/**
+ * Base class for {@link HibernateTemplate} and {@link HibernateInterceptor},
+ * defining common properties such as SessionFactory and flushing behavior.
+ *
+ *
Not intended to be used directly.
+ * See {@link HibernateTemplate} and {@link HibernateInterceptor}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see HibernateTemplate
+ * @see HibernateInterceptor
+ * @see #setFlushMode
+ */
+public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
+
+ /**
+ * Never flush is a good strategy for read-only units of work.
+ * Hibernate will not track and look for changes in this case,
+ * avoiding any overhead of modification detection.
+ *
In case of an existing Session, FLUSH_NEVER will turn the flush mode
+ * to NEVER for the scope of the current operation, resetting the previous
+ * flush mode afterwards.
+ * @see #setFlushMode
+ */
+ public static final int FLUSH_NEVER = 0;
+
+ /**
+ * Automatic flushing is the default mode for a Hibernate Session.
+ * A session will get flushed on transaction commit, and on certain find
+ * operations that might involve already modified instances, but not
+ * after each unit of work like with eager flushing.
+ *
In case of an existing Session, FLUSH_AUTO will participate in the
+ * existing flush mode, not modifying it for the current operation.
+ * This in particular means that this setting will not modify an existing
+ * flush mode NEVER, in contrast to FLUSH_EAGER.
+ * @see #setFlushMode
+ */
+ public static final int FLUSH_AUTO = 1;
+
+ /**
+ * Eager flushing leads to immediate synchronization with the database,
+ * even if in a transaction. This causes inconsistencies to show up and throw
+ * a respective exception immediately, and JDBC access code that participates
+ * in the same transaction will see the changes as the database is already
+ * aware of them then. But the drawbacks are:
+ *
+ *
additional communication roundtrips with the database, instead of a
+ * single batch at transaction commit;
+ *
the fact that an actual database rollback is needed if the Hibernate
+ * transaction rolls back (due to already submitted SQL statements).
+ *
+ *
In case of an existing Session, FLUSH_EAGER will turn the flush mode
+ * to AUTO for the scope of the current operation and issue a flush at the
+ * end, resetting the previous flush mode afterwards.
+ * @see #setFlushMode
+ */
+ public static final int FLUSH_EAGER = 2;
+
+ /**
+ * Flushing at commit only is intended for units of work where no
+ * intermediate flushing is desired, not even for find operations
+ * that might involve already modified instances.
+ *
In case of an existing Session, FLUSH_COMMIT will turn the flush mode
+ * to COMMIT for the scope of the current operation, resetting the previous
+ * flush mode afterwards. The only exception is an existing flush mode
+ * NEVER, which will not be modified through this setting.
+ * @see #setFlushMode
+ */
+ public static final int FLUSH_COMMIT = 3;
+
+ /**
+ * Flushing before every query statement is rarely necessary.
+ * It is only available for special needs.
+ *
In case of an existing Session, FLUSH_ALWAYS will turn the flush mode
+ * to ALWAYS for the scope of the current operation, resetting the previous
+ * flush mode afterwards.
+ * @see #setFlushMode
+ */
+ public static final int FLUSH_ALWAYS = 4;
+
+
+ /** Constants instance for HibernateAccessor */
+ private static final Constants constants = new Constants(HibernateAccessor.class);
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private SessionFactory sessionFactory;
+
+ private Object entityInterceptor;
+
+ private SQLExceptionTranslator jdbcExceptionTranslator;
+
+ private SQLExceptionTranslator defaultJdbcExceptionTranslator;
+
+ private int flushMode = FLUSH_AUTO;
+
+ private String[] filterNames;
+
+ /**
+ * Just needed for entityInterceptorBeanName.
+ * @see #setEntityInterceptorBeanName
+ */
+ private BeanFactory beanFactory;
+
+
+ /**
+ * Set the Hibernate SessionFactory that should be used to create
+ * Hibernate Sessions.
+ */
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ /**
+ * Return the Hibernate SessionFactory that should be used to create
+ * Hibernate Sessions.
+ */
+ public SessionFactory getSessionFactory() {
+ return this.sessionFactory;
+ }
+
+ /**
+ * Set the bean name of a Hibernate entity interceptor that allows to inspect
+ * and change property values before writing to and reading from the database.
+ * Will get applied to any new Session created by this transaction manager.
+ *
Requires the bean factory to be known, to be able to resolve the bean
+ * name to an interceptor instance on session creation. Typically used for
+ * prototype interceptors, i.e. a new interceptor instance per session.
+ *
Can also be used for shared interceptor instances, but it is recommended
+ * to set the interceptor reference directly in such a scenario.
+ * @param entityInterceptorBeanName the name of the entity interceptor in
+ * the bean factory
+ * @see #setBeanFactory
+ * @see #setEntityInterceptor
+ */
+ public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
+ this.entityInterceptor = entityInterceptorBeanName;
+ }
+
+ /**
+ * Set a Hibernate entity interceptor that allows to inspect and change
+ * property values before writing to and reading from the database.
+ * Will get applied to any new Session created by this object.
+ *
Such an interceptor can either be set at the SessionFactory level,
+ * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
+ * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
+ * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
+ * to avoid repeated configuration and guarantee consistent behavior in transactions.
+ * @see #setEntityInterceptorBeanName
+ * @see LocalSessionFactoryBean#setEntityInterceptor
+ * @see HibernateTransactionManager#setEntityInterceptor
+ */
+ public void setEntityInterceptor(Interceptor entityInterceptor) {
+ this.entityInterceptor = entityInterceptor;
+ }
+
+ /**
+ * Return the current Hibernate entity interceptor, or null if none.
+ * Resolves an entity interceptor bean name via the bean factory,
+ * if necessary.
+ * @throws IllegalStateException if bean name specified but no bean factory set
+ * @throws org.springframework.beans.BeansException if bean name resolution via the bean factory failed
+ * @see #setEntityInterceptor
+ * @see #setEntityInterceptorBeanName
+ * @see #setBeanFactory
+ */
+ public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
+ if (this.entityInterceptor instanceof String) {
+ if (this.beanFactory == null) {
+ throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
+ }
+ return (Interceptor) this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
+ }
+ return (Interceptor) this.entityInterceptor;
+ }
+
+ /**
+ * Set the JDBC exception translator for this instance.
+ *
Applied to any SQLException root cause of a Hibernate JDBCException,
+ * overriding Hibernate's default SQLException translation (which is
+ * based on Hibernate's Dialect for a specific target database).
+ * @param jdbcExceptionTranslator the exception translator
+ * @see java.sql.SQLException
+ * @see org.hibernate.JDBCException
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ */
+ public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
+ this.jdbcExceptionTranslator = jdbcExceptionTranslator;
+ }
+
+ /**
+ * Return the JDBC exception translator for this instance, if any.
+ */
+ public SQLExceptionTranslator getJdbcExceptionTranslator() {
+ return this.jdbcExceptionTranslator;
+ }
+
+ /**
+ * Set the flush behavior by the name of the respective constant
+ * in this class, e.g. "FLUSH_AUTO". Default is "FLUSH_AUTO".
+ * @param constantName name of the constant
+ * @see #setFlushMode
+ * @see #FLUSH_AUTO
+ */
+ public void setFlushModeName(String constantName) {
+ setFlushMode(constants.asNumber(constantName).intValue());
+ }
+
+ /**
+ * Set the flush behavior to one of the constants in this class.
+ * Default is FLUSH_AUTO.
+ * @see #setFlushModeName
+ * @see #FLUSH_AUTO
+ */
+ public void setFlushMode(int flushMode) {
+ this.flushMode = flushMode;
+ }
+
+ /**
+ * Return if a flush should be forced after executing the callback code.
+ */
+ public int getFlushMode() {
+ return this.flushMode;
+ }
+
+ /**
+ * Set the name of a Hibernate filter to be activated for all
+ * Sessions that this accessor works with.
+ *
This filter will be enabled at the beginning of each operation
+ * and correspondingly disabled at the end of the operation.
+ * This will work for newly opened Sessions as well as for existing
+ * Sessions (for example, within a transaction).
+ * @see #enableFilters(org.hibernate.Session)
+ * @see org.hibernate.Session#enableFilter(String)
+ * @see LocalSessionFactoryBean#setFilterDefinitions
+ */
+ public void setFilterName(String filter) {
+ this.filterNames = new String[] {filter};
+ }
+
+ /**
+ * Set one or more names of Hibernate filters to be activated for all
+ * Sessions that this accessor works with.
+ *
Each of those filters will be enabled at the beginning of each
+ * operation and correspondingly disabled at the end of the operation.
+ * This will work for newly opened Sessions as well as for existing
+ * Sessions (for example, within a transaction).
+ * @see #enableFilters(org.hibernate.Session)
+ * @see org.hibernate.Session#enableFilter(String)
+ * @see LocalSessionFactoryBean#setFilterDefinitions
+ */
+ public void setFilterNames(String[] filterNames) {
+ this.filterNames = filterNames;
+ }
+
+ /**
+ * Return the names of Hibernate filters to be activated, if any.
+ */
+ public String[] getFilterNames() {
+ return this.filterNames;
+ }
+
+ /**
+ * The bean factory just needs to be known for resolving entity interceptor
+ * bean names. It does not need to be set for any other mode of operation.
+ * @see #setEntityInterceptorBeanName
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ public void afterPropertiesSet() {
+ if (getSessionFactory() == null) {
+ throw new IllegalArgumentException("Property 'sessionFactory' is required");
+ }
+ }
+
+
+ /**
+ * Apply the flush mode that's been specified for this accessor
+ * to the given Session.
+ * @param session the current Hibernate Session
+ * @param existingTransaction if executing within an existing transaction
+ * @return the previous flush mode to restore after the operation,
+ * or null if none
+ * @see #setFlushMode
+ * @see org.hibernate.Session#setFlushMode
+ */
+ protected FlushMode applyFlushMode(Session session, boolean existingTransaction) {
+ if (getFlushMode() == FLUSH_NEVER) {
+ if (existingTransaction) {
+ FlushMode previousFlushMode = session.getFlushMode();
+ if (!previousFlushMode.lessThan(FlushMode.COMMIT)) {
+ session.setFlushMode(FlushMode.NEVER);
+ return previousFlushMode;
+ }
+ }
+ else {
+ session.setFlushMode(FlushMode.NEVER);
+ }
+ }
+ else if (getFlushMode() == FLUSH_EAGER) {
+ if (existingTransaction) {
+ FlushMode previousFlushMode = session.getFlushMode();
+ if (!previousFlushMode.equals(FlushMode.AUTO)) {
+ session.setFlushMode(FlushMode.AUTO);
+ return previousFlushMode;
+ }
+ }
+ else {
+ // rely on default FlushMode.AUTO
+ }
+ }
+ else if (getFlushMode() == FLUSH_COMMIT) {
+ if (existingTransaction) {
+ FlushMode previousFlushMode = session.getFlushMode();
+ if (previousFlushMode.equals(FlushMode.AUTO) || previousFlushMode.equals(FlushMode.ALWAYS)) {
+ session.setFlushMode(FlushMode.COMMIT);
+ return previousFlushMode;
+ }
+ }
+ else {
+ session.setFlushMode(FlushMode.COMMIT);
+ }
+ }
+ else if (getFlushMode() == FLUSH_ALWAYS) {
+ if (existingTransaction) {
+ FlushMode previousFlushMode = session.getFlushMode();
+ if (!previousFlushMode.equals(FlushMode.ALWAYS)) {
+ session.setFlushMode(FlushMode.ALWAYS);
+ return previousFlushMode;
+ }
+ }
+ else {
+ session.setFlushMode(FlushMode.ALWAYS);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Flush the given Hibernate Session if necessary.
+ * @param session the current Hibernate Session
+ * @param existingTransaction if executing within an existing transaction
+ * @throws HibernateException in case of Hibernate flushing errors
+ */
+ protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
+ if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
+ logger.debug("Eagerly flushing Hibernate session");
+ session.flush();
+ }
+ }
+
+
+ /**
+ * Convert the given HibernateException to an appropriate exception
+ * from the org.springframework.dao hierarchy.
+ *
Will automatically apply a specified SQLExceptionTranslator to a
+ * Hibernate JDBCException, else rely on Hibernate's default translation.
+ * @param ex HibernateException that occured
+ * @return a corresponding DataAccessException
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ * @see #setJdbcExceptionTranslator
+ */
+ public DataAccessException convertHibernateAccessException(HibernateException ex) {
+ if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
+ return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
+ }
+ else if (GenericJDBCException.class.equals(ex.getClass())) {
+ return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
+ }
+ return SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+
+ /**
+ * Convert the given Hibernate JDBCException to an appropriate exception
+ * from the org.springframework.dao hierarchy, using the
+ * given SQLExceptionTranslator.
+ * @param ex Hibernate JDBCException that occured
+ * @param translator the SQLExceptionTranslator to use
+ * @return a corresponding DataAccessException
+ */
+ protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
+ return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
+ }
+
+ /**
+ * Convert the given SQLException to an appropriate exception from the
+ * org.springframework.dao hierarchy. Can be overridden in subclasses.
+ *
Note that a direct SQLException can just occur when callback code
+ * performs direct JDBC access via Session.connection().
+ * @param ex the SQLException
+ * @return the corresponding DataAccessException instance
+ * @see #setJdbcExceptionTranslator
+ * @see org.hibernate.Session#connection()
+ */
+ protected DataAccessException convertJdbcAccessException(SQLException ex) {
+ SQLExceptionTranslator translator = getJdbcExceptionTranslator();
+ if (translator == null) {
+ translator = getDefaultJdbcExceptionTranslator();
+ }
+ return translator.translate("Hibernate-related JDBC operation", null, ex);
+ }
+
+ /**
+ * Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
+ *
Creates a default
+ * {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
+ * for the SessionFactory's underlying DataSource.
+ */
+ protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
+ if (this.defaultJdbcExceptionTranslator == null) {
+ this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
+ }
+ return this.defaultJdbcExceptionTranslator;
+ }
+
+
+ /**
+ * Enable the specified filters on the given Session.
+ * @param session the current Hibernate Session
+ * @see #setFilterNames
+ * @see org.hibernate.Session#enableFilter(String)
+ */
+ protected void enableFilters(Session session) {
+ String[] filterNames = getFilterNames();
+ if (filterNames != null) {
+ for (int i = 0; i < filterNames.length; i++) {
+ session.enableFilter(filterNames[i]);
+ }
+ }
+ }
+
+ /**
+ * Disable the specified filters on the given Session.
+ * @param session the current Hibernate Session
+ * @see #setFilterNames
+ * @see org.hibernate.Session#disableFilter(String)
+ */
+ protected void disableFilters(Session session) {
+ String[] filterNames = getFilterNames();
+ if (filterNames != null) {
+ for (int i = 0; i < filterNames.length; i++) {
+ session.disableFilter(filterNames[i]);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateCallback.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002-2006 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.orm.hibernate3;
+
+import java.sql.SQLException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+
+/**
+ * Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
+ * execution methods, often as anonymous classes within a method implementation.
+ * A typical implementation will call Session.load/find/update to perform
+ * some operations on persistent objects. It can also perform direct JDBC operations
+ * via Hibernate's Session.connection(), operating on a JDBC Connection.
+ *
+ *
Note that Hibernate works on unmodified plain Java objects, performing dirty
+ * detection via copies made at load time. Returned objects can thus be used outside
+ * of an active Hibernate Session without any hassle, e.g. for display in a web GUI.
+ * Reassociating such instances with a new Session, e.g. for updates when coming
+ * back from the GUI, is straightforward, as the instance has kept its identity.
+ * You should care to reassociate them as early as possible though, to avoid having
+ * already loaded a version from the database in the same Session.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see HibernateTemplate
+ * @see HibernateTransactionManager
+ */
+public interface HibernateCallback {
+
+ /**
+ * Gets called by HibernateTemplate.execute with an active
+ * Hibernate Session. Does not need to care about activating
+ * or closing the Session, or handling transactions.
+ *
+ *
If called without a thread-bound Hibernate transaction (initiated
+ * by HibernateTransactionManager), the code will simply get executed on the
+ * underlying JDBC connection with its transactional semantics. If Hibernate
+ * is configured to use a JTA-aware DataSource, the JDBC connection and thus
+ * the callback code will be transactional if a JTA transaction is active.
+ *
+ *
Allows for returning a result object created within the callback,
+ * i.e. a domain object or a collection of domain objects.
+ * A thrown custom RuntimeException is treated as an application exception:
+ * It gets propagated to the caller of the template.
+ *
+ * @param session active Hibernate session
+ * @return a result object, or null if none
+ * @throws HibernateException if thrown by the Hibernate API
+ * @throws SQLException if thrown by Hibernate-exposed JDBC API
+ * @see HibernateTemplate#execute
+ * @see HibernateTemplate#executeFind
+ */
+ Object doInHibernate(Session session) throws HibernateException, SQLException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateInterceptor.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * This interceptor binds a new Hibernate Session to the thread before a method
+ * call, closing and removing it afterwards in case of any method outcome.
+ * If there already is a pre-bound Session (e.g. from HibernateTransactionManager,
+ * or from a surrounding Hibernate-intercepted method), the interceptor simply
+ * participates in it.
+ *
+ *
Application code must retrieve a Hibernate Session via the
+ * SessionFactoryUtils.getSession method or - preferably -
+ * Hibernate's own SessionFactory.getCurrentSession() method, to be
+ * able to detect a thread-bound Session. Typically, the code will look like as follows:
+ *
+ *
+ * public void doSomeDataAccessAction() {
+ * Session session = this.sessionFactory.getCurrentSession();
+ * ...
+ * // No need to close the Session or translate exceptions!
+ * }
+ *
+ * Note that this interceptor automatically translates HibernateExceptions,
+ * via delegating to the SessionFactoryUtils.convertHibernateAccessException
+ * method that converts them to exceptions that are compatible with the
+ * org.springframework.dao exception hierarchy (like HibernateTemplate does).
+ * This can be turned off if the raw exceptions are preferred.
+ *
+ *
This class can be considered a declarative alternative to HibernateTemplate's
+ * callback approach. The advantages are:
+ *
+ *
no anonymous classes necessary for callback implementations;
+ *
the possibility to throw any application exceptions from within data access code.
+ *
+ *
+ *
The drawback is the dependency on interceptor configuration. However, note
+ * that this interceptor is usually not necessary in scenarios where the
+ * data access code always executes within transactions. A transaction will always
+ * have a thread-bound Session in the first place, so adding this interceptor to the
+ * configuration just adds value when fine-tuning Session settings like the flush mode
+ * - or when relying on exception translation.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.hibernate.SessionFactory#getCurrentSession()
+ * @see HibernateTransactionManager
+ * @see HibernateTemplate
+ */
+public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor {
+
+ private boolean exceptionConversionEnabled = true;
+
+
+ /**
+ * Set whether to convert any HibernateException raised to a Spring DataAccessException,
+ * compatible with the org.springframework.dao exception hierarchy.
+ *
Default is "true". Turn this flag off to let the caller receive raw exceptions
+ * as-is, without any wrapping.
+ * @see org.springframework.dao.DataAccessException
+ */
+ public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
+ this.exceptionConversionEnabled = exceptionConversionEnabled;
+ }
+
+
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+ Session session = getSession();
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
+
+ boolean existingTransaction = (sessionHolder != null && sessionHolder.containsSession(session));
+ if (existingTransaction) {
+ logger.debug("Found thread-bound Session for HibernateInterceptor");
+ }
+ else {
+ if (sessionHolder != null) {
+ sessionHolder.addSession(session);
+ }
+ else {
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
+ }
+ }
+
+ FlushMode previousFlushMode = null;
+ try {
+ previousFlushMode = applyFlushMode(session, existingTransaction);
+ enableFilters(session);
+ Object retVal = methodInvocation.proceed();
+ flushIfNecessary(session, existingTransaction);
+ return retVal;
+ }
+ catch (HibernateException ex) {
+ if (this.exceptionConversionEnabled) {
+ throw convertHibernateAccessException(ex);
+ }
+ else {
+ throw ex;
+ }
+ }
+ finally {
+ if (existingTransaction) {
+ logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor");
+ disableFilters(session);
+ if (previousFlushMode != null) {
+ session.setFlushMode(previousFlushMode);
+ }
+ }
+ else {
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
+ if (sessionHolder == null || sessionHolder.doesNotHoldNonDefaultSession()) {
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+ }
+ }
+ }
+
+ /**
+ * Return a Session for use by this interceptor.
+ * @see SessionFactoryUtils#getSession
+ */
+ protected Session getSession() {
+ return SessionFactoryUtils.getSession(
+ getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateJdbcException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateJdbcException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateJdbcException.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import java.sql.SQLException;
+
+import org.hibernate.JDBCException;
+
+import org.springframework.dao.UncategorizedDataAccessException;
+
+/**
+ * Hibernate-specific subclass of UncategorizedDataAccessException,
+ * for JDBC exceptions that Hibernate wrapped.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ */
+public class HibernateJdbcException extends UncategorizedDataAccessException {
+
+ public HibernateJdbcException(JDBCException ex) {
+ super("JDBC exception on Hibernate data access: SQLException for SQL [" + ex.getSQL() + "]; SQL state [" +
+ ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
+ }
+
+ /**
+ * Return the underlying SQLException.
+ */
+ public SQLException getSQLException() {
+ return ((JDBCException) getCause()).getSQLException();
+ }
+
+ /**
+ * Return the SQL that led to the problem.
+ */
+ public String getSql() {
+ return ((JDBCException) getCause()).getSQL();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateObjectRetrievalFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateObjectRetrievalFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateObjectRetrievalFailureException.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006 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.orm.hibernate3;
+
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.WrongClassException;
+
+import org.springframework.orm.ObjectRetrievalFailureException;
+
+/**
+ * Hibernate-specific subclass of ObjectRetrievalFailureException.
+ * Converts Hibernate's UnresolvableObjectException and WrongClassException.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ */
+public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
+
+ public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
+ super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
+ }
+
+ public HibernateObjectRetrievalFailureException(WrongClassException ex) {
+ super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOperations.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,937 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.Filter;
+import org.hibernate.LockMode;
+import org.hibernate.ReplicationMode;
+import org.hibernate.criterion.DetachedCriteria;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Interface that specifies a basic set of Hibernate operations,
+ * implemented by {@link HibernateTemplate}. Not often used, but a useful
+ * option to enhance testability, as it can easily be mocked or stubbed.
+ *
+ *
Defines HibernateTemplate's data access methods that
+ * mirror various {@link org.hibernate.Session} methods. Users are
+ * strongly encouraged to read the Hibernate Session javadocs
+ * for details on the semantics of those methods.
+ *
+ *
Note that operations that return an {@link java.util.Iterator} (i.e.
+ * iterate(..)) are supposed to be used within Spring-driven
+ * or JTA-driven transactions (with {@link HibernateTransactionManager},
+ * {@link org.springframework.transaction.jta.JtaTransactionManager},
+ * or EJB CMT). Else, the Iterator won't be able to read
+ * results from its {@link java.sql.ResultSet} anymore, as the underlying
+ * Hibernate Session will already have been closed.
+ *
+ *
Note that lazy loading will just work with an open Hibernate
+ * Session, either within a transaction or within
+ * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}/
+ * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
+ * Furthermore, some operations just make sense within transactions,
+ * for example: contains, evict, lock,
+ * flush, clear.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see HibernateTemplate
+ * @see org.hibernate.Session
+ * @see HibernateTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
+ */
+public interface HibernateOperations {
+
+ /**
+ * Execute the action specified by the given action object within a
+ * {@link org.hibernate.Session}.
+ *
Application exceptions thrown by the action object get propagated
+ * to the caller (can only be unchecked). Hibernate exceptions are
+ * transformed into appropriate DAO ones. Allows for returning a result
+ * object, that is a domain object or a collection of domain objects.
+ *
Note: Callback code is not supposed to handle transactions itself!
+ * Use an appropriate transaction manager like
+ * {@link HibernateTransactionManager}. Generally, callback code must not
+ * touch any Session lifecycle methods, like close,
+ * disconnect, or reconnect, to let the template do its work.
+ * @param action callback object that specifies the Hibernate action
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see HibernateTransactionManager
+ * @see org.springframework.dao
+ * @see org.springframework.transaction
+ * @see org.hibernate.Session
+ */
+ Object execute(HibernateCallback action) throws DataAccessException;
+
+ /**
+ * Execute the specified action assuming that the result object is a
+ * {@link List}.
+ *
This is a convenience method for executing Hibernate find calls or
+ * queries within an action.
+ * @param action calback object that specifies the Hibernate action
+ * @return a List result returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ */
+ List executeFind(HibernateCallback action) throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for loading individual objects
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, or null if not found.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityClass a persistent class
+ * @param id the identifier of the persistent instance
+ * @return the persistent instance, or null if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#get(Class, java.io.Serializable)
+ */
+ Object get(Class entityClass, Serializable id) throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, or null if not found.
+ *
Obtains the specified lock mode if the instance exists.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityClass a persistent class
+ * @param id the identifier of the persistent instance
+ * @param lockMode the lock mode to obtain
+ * @return the persistent instance, or null if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
+ */
+ Object get(Class entityClass, Serializable id, LockMode lockMode)
+ throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, or null if not found.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityName the name of the persistent entity
+ * @param id the identifier of the persistent instance
+ * @return the persistent instance, or null if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#get(Class, java.io.Serializable)
+ */
+ Object get(String entityName, Serializable id) throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, or null if not found.
+ * Obtains the specified lock mode if the instance exists.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityName the name of the persistent entity
+ * @param id the identifier of the persistent instance
+ * @param lockMode the lock mode to obtain
+ * @return the persistent instance, or null if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode)
+ */
+ Object get(String entityName, Serializable id, LockMode lockMode)
+ throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, throwing an exception if not found.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityClass a persistent class
+ * @param id the identifier of the persistent instance
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#load(Class, java.io.Serializable)
+ */
+ Object load(Class entityClass, Serializable id) throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, throwing an exception if not found.
+ * Obtains the specified lock mode if the instance exists.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityClass a persistent class
+ * @param id the identifier of the persistent instance
+ * @param lockMode the lock mode to obtain
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#load(Class, java.io.Serializable)
+ */
+ Object load(Class entityClass, Serializable id, LockMode lockMode)
+ throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, throwing an exception if not found.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityName the name of the persistent entity
+ * @param id the identifier of the persistent instance
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#load(Class, java.io.Serializable)
+ */
+ Object load(String entityName, Serializable id) throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given identifier, throwing an exception if not found.
+ *
Obtains the specified lock mode if the instance exists.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entityName the name of the persistent entity
+ * @param id the identifier of the persistent instance
+ * @param lockMode the lock mode to obtain
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#load(Class, java.io.Serializable)
+ */
+ Object load(String entityName, Serializable id, LockMode lockMode)
+ throws DataAccessException;
+
+ /**
+ * Return all persistent instances of the given entity class.
+ * Note: Use queries or criteria for retrieving a specific subset.
+ * @param entityClass a persistent class
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException if there is a Hibernate error
+ * @see org.hibernate.Session#createCriteria
+ */
+ List loadAll(Class entityClass) throws DataAccessException;
+
+ /**
+ * Load the persistent instance with the given identifier
+ * into the given object, throwing an exception if not found.
+ *
This method is a thin wrapper around
+ * {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience.
+ * For an explanation of the exact semantics of this method, please do refer to
+ * the Hibernate API documentation in the first instance.
+ * @param entity the object (of the target class) to load into
+ * @param id the identifier of the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#load(Object, java.io.Serializable)
+ */
+ void load(Object entity, Serializable id) throws DataAccessException;
+
+ /**
+ * Re-read the state of the given persistent instance.
+ * @param entity the persistent instance to re-read
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#refresh(Object)
+ */
+ void refresh(Object entity) throws DataAccessException;
+
+ /**
+ * Re-read the state of the given persistent instance.
+ * Obtains the specified lock mode for the instance.
+ * @param entity the persistent instance to re-read
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode)
+ */
+ void refresh(Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Check whether the given object is in the Session cache.
+ * @param entity the persistence instance to check
+ * @return whether the given object is in the Session cache
+ * @throws org.springframework.dao.DataAccessException if there is a Hibernate error
+ * @see org.hibernate.Session#contains
+ */
+ boolean contains(Object entity) throws DataAccessException;
+
+ /**
+ * Remove the given object from the {@link org.hibernate.Session} cache.
+ * @param entity the persistent instance to evict
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#evict
+ */
+ void evict(Object entity) throws DataAccessException;
+
+ /**
+ * Force initialization of a Hibernate proxy or persistent collection.
+ * @param proxy a proxy for a persistent object or a persistent collection
+ * @throws DataAccessException if we can't initialize the proxy, for example
+ * because it is not associated with an active Session
+ * @see org.hibernate.Hibernate#initialize
+ */
+ void initialize(Object proxy) throws DataAccessException;
+
+ /**
+ * Return an enabled Hibernate {@link Filter} for the given filter name.
+ * The returned Filter instance can be used to set filter parameters.
+ * @param filterName the name of the filter
+ * @return the enabled Hibernate Filter (either already
+ * enabled or enabled on the fly by this operation)
+ * @throws IllegalStateException if we are not running within a
+ * transactional Session (in which case this operation does not make sense)
+ */
+ Filter enableFilter(String filterName) throws IllegalStateException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for storing individual objects
+ //-------------------------------------------------------------------------
+
+ /**
+ * Obtain the specified lock level upon the given object, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entity the persistent instance to lock
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#lock(Object, org.hibernate.LockMode)
+ */
+ void lock(Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Obtain the specified lock level upon the given object, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to lock
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode)
+ */
+ void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Persist the given transient instance.
+ * @param entity the transient instance to persist
+ * @return the generated identifier
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#save(Object)
+ */
+ Serializable save(Object entity) throws DataAccessException;
+
+ /**
+ * Persist the given transient instance.
+ * @param entityName the name of the persistent entity
+ * @param entity the transient instance to persist
+ * @return the generated identifier
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#save(String, Object)
+ */
+ Serializable save(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Update the given persistent instance,
+ * associating it with the current Hibernate {@link org.hibernate.Session}.
+ * @param entity the persistent instance to update
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#update(Object)
+ */
+ void update(Object entity) throws DataAccessException;
+
+ /**
+ * Update the given persistent instance,
+ * associating it with the current Hibernate {@link org.hibernate.Session}.
+ *
Obtains the specified lock mode if the instance exists, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entity the persistent instance to update
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#update(Object)
+ */
+ void update(Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Update the given persistent instance,
+ * associating it with the current Hibernate {@link org.hibernate.Session}.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to update
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#update(String, Object)
+ */
+ void update(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Update the given persistent instance,
+ * associating it with the current Hibernate {@link org.hibernate.Session}.
+ *
Obtains the specified lock mode if the instance exists, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to update
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#update(String, Object)
+ */
+ void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Save or update the given persistent instance,
+ * according to its id (matching the configured "unsaved-value"?).
+ * Associates the instance with the current Hibernate {@link org.hibernate.Session}.
+ * @param entity the persistent instance to save or update
+ * (to be associated with the Hibernate Session)
+ * @throws DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#saveOrUpdate(Object)
+ */
+ void saveOrUpdate(Object entity) throws DataAccessException;
+
+ /**
+ * Save or update the given persistent instance,
+ * according to its id (matching the configured "unsaved-value"?).
+ * Associates the instance with the current Hibernate Session.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to save or update
+ * (to be associated with the Hibernate Session)
+ * @throws DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#saveOrUpdate(String, Object)
+ */
+ void saveOrUpdate(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Save or update all given persistent instances,
+ * according to its id (matching the configured "unsaved-value"?).
+ * Associates the instances with the current Hibernate Session.
+ * @param entities the persistent instances to save or update
+ * (to be associated with the Hibernate Session)
+ * @throws DataAccessException in case of Hibernate errors
+ * @deprecated as of Spring 2.5, in favor of individual
+ * saveOrUpdate or merge usage
+ */
+ void saveOrUpdateAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Persist the state of the given detached instance according to the
+ * given replication mode, reusing the current identifier value.
+ * @param entity the persistent object to replicate
+ * @param replicationMode the Hibernate ReplicationMode
+ * @throws DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
+ */
+ void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException;
+
+ /**
+ * Persist the state of the given detached instance according to the
+ * given replication mode, reusing the current identifier value.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent object to replicate
+ * @param replicationMode the Hibernate ReplicationMode
+ * @throws DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode)
+ */
+ void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException;
+
+ /**
+ * Persist the given transient instance. Follows JSR-220 semantics.
+ *
Similar to save, associating the given object
+ * with the current Hibernate {@link org.hibernate.Session}.
+ * @param entity the persistent instance to persist
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#persist(Object)
+ * @see #save
+ */
+ void persist(Object entity) throws DataAccessException;
+
+ /**
+ * Persist the given transient instance. Follows JSR-220 semantics.
+ *
Similar to save, associating the given object
+ * with the current Hibernate {@link org.hibernate.Session}.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to persist
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#persist(String, Object)
+ * @see #save
+ */
+ void persist(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Copy the state of the given object onto the persistent object
+ * with the same identifier. Follows JSR-220 semantics.
+ *
Similar to saveOrUpdate, but never associates the given
+ * object with the current Hibernate Session. In case of a new entity,
+ * the state will be copied over as well.
+ *
Note that merge will not update the identifiers
+ * in the passed-in object graph (in contrast to TopLink)! Consider
+ * registering Spring's IdTransferringMergeEventListener if
+ * you would like to have newly assigned ids transferred to the original
+ * object graph too.
+ * @param entity the object to merge with the corresponding persistence instance
+ * @return the updated, registered persistent instance
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#merge(Object)
+ * @see #saveOrUpdate
+ * @see org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener
+ */
+ Object merge(Object entity) throws DataAccessException;
+
+ /**
+ * Copy the state of the given object onto the persistent object
+ * with the same identifier. Follows JSR-220 semantics.
+ *
Similar to saveOrUpdate, but never associates the given
+ * object with the current Hibernate {@link org.hibernate.Session}. In
+ * the case of a new entity, the state will be copied over as well.
+ *
Note that merge will not update the identifiers
+ * in the passed-in object graph (in contrast to TopLink)! Consider
+ * registering Spring's IdTransferringMergeEventListener
+ * if you would like to have newly assigned ids transferred to the
+ * original object graph too.
+ * @param entityName the name of the persistent entity
+ * @param entity the object to merge with the corresponding persistence instance
+ * @return the updated, registered persistent instance
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#merge(String, Object)
+ * @see #saveOrUpdate
+ */
+ Object merge(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Delete the given persistent instance.
+ * @param entity the persistent instance to delete
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#delete(Object)
+ */
+ void delete(Object entity) throws DataAccessException;
+
+ /**
+ * Delete the given persistent instance.
+ *
Obtains the specified lock mode if the instance exists, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entity the persistent instance to delete
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#delete(Object)
+ */
+ void delete(Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Delete the given persistent instance.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to delete
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#delete(Object)
+ */
+ void delete(String entityName, Object entity) throws DataAccessException;
+
+ /**
+ * Delete the given persistent instance.
+ *
Obtains the specified lock mode if the instance exists, implicitly
+ * checking whether the corresponding database entry still exists.
+ * @param entityName the name of the persistent entity
+ * @param entity the persistent instance to delete
+ * @param lockMode the lock mode to obtain
+ * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#delete(Object)
+ */
+ void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException;
+
+ /**
+ * Delete all given persistent instances.
+ *
This can be combined with any of the find methods to delete by query
+ * in two lines of code.
+ * @param entities the persistent instances to delete
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#delete(Object)
+ */
+ void deleteAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Flush all pending saves, updates and deletes to the database.
+ *
Only invoke this for selective eager flushing, for example when
+ * JDBC code needs to see certain changes within the same transaction.
+ * Else, it is preferable to rely on auto-flushing at transaction
+ * completion.
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#flush
+ */
+ void flush() throws DataAccessException;
+
+ /**
+ * Remove all objects from the {@link org.hibernate.Session} cache, and
+ * cancel all pending saves, updates and deletes.
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#clear
+ */
+ void clear() throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for HQL strings
+ //-------------------------------------------------------------------------
+
+ /**
+ * Execute an HQL query.
+ * @param queryString a query expressed in Hibernate's query language
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ */
+ List find(String queryString) throws DataAccessException;
+
+ /**
+ * Execute an HQL query, binding one value to a "?" parameter in the
+ * query string.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param value the value of the parameter
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ */
+ List find(String queryString, Object value) throws DataAccessException;
+
+ /**
+ * Execute an HQL query, binding a number of values to "?" parameters
+ * in the query string.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param values the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ */
+ List find(String queryString, Object[] values) throws DataAccessException;
+
+ /**
+ * Execute an HQL query, binding one value to a ":" named parameter
+ * in the query string.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param paramName the name of the parameter
+ * @param value the value of the parameter
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedParam(String queryString, String paramName, Object value)
+ throws DataAccessException;
+
+ /**
+ * Execute an HQL query, binding a number of values to ":" named
+ * parameters in the query string.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param paramNames the names of the parameters
+ * @param values the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedParam(String queryString, String[] paramNames, Object[] values)
+ throws DataAccessException;
+
+ /**
+ * Execute an HQL query, binding the properties of the given bean to
+ * named parameters in the query string.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param valueBean the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Query#setProperties
+ * @see org.hibernate.Session#createQuery
+ */
+ List findByValueBean(String queryString, Object valueBean) throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for named queries
+ //-------------------------------------------------------------------------
+
+ /**
+ * Execute a named query.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQuery(String queryName) throws DataAccessException;
+
+ /**
+ * Execute a named query, binding one value to a "?" parameter in
+ * the query string.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @param value the value of the parameter
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQuery(String queryName, Object value) throws DataAccessException;
+
+ /**
+ * Execute a named query binding a number of values to "?" parameters
+ * in the query string.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @param values the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQuery(String queryName, Object[] values) throws DataAccessException;
+
+ /**
+ * Execute a named query, binding one value to a ":" named parameter
+ * in the query string.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @param paramName the name of parameter
+ * @param value the value of the parameter
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
+ throws DataAccessException;
+
+ /**
+ * Execute a named query, binding a number of values to ":" named
+ * parameters in the query string.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @param paramNames the names of the parameters
+ * @param values the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values)
+ throws DataAccessException;
+
+ /**
+ * Execute a named query, binding the properties of the given bean to
+ * ":" named parameters in the query string.
+ *
A named query is defined in a Hibernate mapping file.
+ * @param queryName the name of a Hibernate query in a mapping file
+ * @param valueBean the values of the parameters
+ * @return a {@link List} containing the results of the query execution
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Query#setProperties
+ * @see org.hibernate.Session#getNamedQuery(String)
+ */
+ List findByNamedQueryAndValueBean(String queryName, Object valueBean)
+ throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for detached criteria
+ //-------------------------------------------------------------------------
+
+ /**
+ * Execute a query based on a given Hibernate criteria object.
+ * @param criteria the detached Hibernate criteria object.
+ * Note: Do not reuse criteria objects! They need to recreated per execution,
+ * due to the suboptimal design of Hibernate's criteria facility.
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
+ */
+ List findByCriteria(DetachedCriteria criteria) throws DataAccessException;
+
+ /**
+ * Execute a query based on the given Hibernate criteria object.
+ * @param criteria the detached Hibernate criteria object.
+ * Note: Do not reuse criteria objects! They need to recreated per execution,
+ * due to the suboptimal design of Hibernate's criteria facility.
+ * @param firstResult the index of the first result object to be retrieved
+ * (numbered from 0)
+ * @param maxResults the maximum number of result objects to retrieve
+ * (or <=0 for no limit)
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session)
+ * @see org.hibernate.Criteria#setFirstResult(int)
+ * @see org.hibernate.Criteria#setMaxResults(int)
+ */
+ List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) throws DataAccessException;
+
+ /**
+ * Execute a query based on the given example entity object.
+ * @param exampleEntity an instance of the desired entity,
+ * serving as example for "query-by-example"
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.Example#create(Object)
+ */
+ List findByExample(Object exampleEntity) throws DataAccessException;
+
+ /**
+ * Execute a query based on the given example entity object.
+ * @param entityName the name of the persistent entity
+ * @param exampleEntity an instance of the desired entity,
+ * serving as example for "query-by-example"
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.Example#create(Object)
+ */
+ List findByExample(String entityName, Object exampleEntity) throws DataAccessException;
+
+ /**
+ * Execute a query based on a given example entity object.
+ * @param exampleEntity an instance of the desired entity,
+ * serving as example for "query-by-example"
+ * @param firstResult the index of the first result object to be retrieved
+ * (numbered from 0)
+ * @param maxResults the maximum number of result objects to retrieve
+ * (or <=0 for no limit)
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.Example#create(Object)
+ * @see org.hibernate.Criteria#setFirstResult(int)
+ * @see org.hibernate.Criteria#setMaxResults(int)
+ */
+ List findByExample(Object exampleEntity, int firstResult, int maxResults) throws DataAccessException;
+
+ /**
+ * Execute a query based on a given example entity object.
+ * @param entityName the name of the persistent entity
+ * @param exampleEntity an instance of the desired entity,
+ * serving as example for "query-by-example"
+ * @param firstResult the index of the first result object to be retrieved
+ * (numbered from 0)
+ * @param maxResults the maximum number of result objects to retrieve
+ * (or <=0 for no limit)
+ * @return a {@link List} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.criterion.Example#create(Object)
+ * @see org.hibernate.Criteria#setFirstResult(int)
+ * @see org.hibernate.Criteria#setMaxResults(int)
+ */
+ List findByExample(String entityName, Object exampleEntity, int firstResult, int maxResults)
+ throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience query methods for iteration and bulk updates/deletes
+ //-------------------------------------------------------------------------
+
+ /**
+ * Execute a query for persistent instances.
+ *
Returns the results as an {@link Iterator}. Entities returned are
+ * initialized on demand. See the Hibernate API documentation for details.
+ * @param queryString a query expressed in Hibernate's query language
+ * @return an {@link Iterator} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#iterate
+ */
+ Iterator iterate(String queryString) throws DataAccessException;
+
+ /**
+ * Execute a query for persistent instances, binding one value
+ * to a "?" parameter in the query string.
+ *
Returns the results as an {@link Iterator}. Entities returned are
+ * initialized on demand. See the Hibernate API documentation for details.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param value the value of the parameter
+ * @return an {@link Iterator} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#iterate
+ */
+ Iterator iterate(String queryString, Object value) throws DataAccessException;
+
+ /**
+ * Execute a query for persistent instances, binding a number of
+ * values to "?" parameters in the query string.
+ *
Returns the results as an {@link Iterator}. Entities returned are
+ * initialized on demand. See the Hibernate API documentation for details.
+ * @param queryString a query expressed in Hibernate's query language
+ * @param values the values of the parameters
+ * @return an {@link Iterator} containing 0 or more persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#iterate
+ */
+ Iterator iterate(String queryString, Object[] values) throws DataAccessException;
+
+ /**
+ * Immediately close an {@link Iterator} created by any of the various
+ * iterate(..) operations, instead of waiting until the
+ * session is closed or disconnected.
+ * @param it the Iterator to close
+ * @throws DataAccessException if the Iterator could not be closed
+ * @see org.hibernate.Hibernate#close
+ */
+ void closeIterator(Iterator it) throws DataAccessException;
+
+ /**
+ * Update/delete all objects according to the given query.
+ * @param queryString an update/delete query expressed in Hibernate's query language
+ * @return the number of instances updated/deleted
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#executeUpdate
+ */
+ int bulkUpdate(String queryString) throws DataAccessException;
+
+ /**
+ * Update/delete all objects according to the given query, binding one value
+ * to a "?" parameter in the query string.
+ * @param queryString an update/delete query expressed in Hibernate's query language
+ * @param value the value of the parameter
+ * @return the number of instances updated/deleted
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#executeUpdate
+ */
+ int bulkUpdate(String queryString, Object value) throws DataAccessException;
+
+ /**
+ * Update/delete all objects according to the given query, binding a number of
+ * values to "?" parameters in the query string.
+ * @param queryString an update/delete query expressed in Hibernate's query language
+ * @param values the values of the parameters
+ * @return the number of instances updated/deleted
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @see org.hibernate.Session#createQuery
+ * @see org.hibernate.Query#executeUpdate
+ */
+ int bulkUpdate(String queryString, Object[] values) throws DataAccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOptimisticLockingFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOptimisticLockingFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateOptimisticLockingFailureException.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006 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.orm.hibernate3;
+
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+
+import org.springframework.orm.ObjectOptimisticLockingFailureException;
+
+/**
+ * Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
+ * Converts Hibernate's StaleObjectStateException and StaleStateException.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ */
+public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
+
+ public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
+ super(ex.getEntityName(), ex.getIdentifier(), ex);
+ }
+
+ public HibernateOptimisticLockingFailureException(StaleStateException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateQueryException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateQueryException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateQueryException.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3;
+
+import org.hibernate.QueryException;
+
+import org.springframework.dao.InvalidDataAccessResourceUsageException;
+
+/**
+ * Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
+ * thrown on invalid HQL query syntax.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ */
+public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
+
+ public HibernateQueryException(QueryException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+ /**
+ * Return the HQL query string that was invalid.
+ */
+ public String getQueryString() {
+ return ((QueryException) getCause()).getQueryString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateSystemException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateSystemException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateSystemException.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3;
+
+import org.hibernate.HibernateException;
+
+import org.springframework.dao.UncategorizedDataAccessException;
+
+/**
+ * Hibernate-specific subclass of UncategorizedDataAccessException,
+ * for Hibernate system errors that do not match any concrete
+ * org.springframework.dao exceptions.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ */
+public class HibernateSystemException extends UncategorizedDataAccessException {
+
+ /**
+ * Create a new HibernateSystemException,
+ * wrapping an arbitrary HibernateException.
+ * @param cause the HibernateException thrown
+ */
+ public HibernateSystemException(HibernateException cause) {
+ super(cause != null ? cause.getMessage() : null, cause);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTemplate.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,1312 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ReplicationMode;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.criterion.DetachedCriteria;
+import org.hibernate.criterion.Example;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class that simplifies Hibernate data access code. Automatically
+ * converts HibernateExceptions into DataAccessExceptions, following the
+ * org.springframework.dao exception hierarchy.
+ *
+ *
The central method is execute, supporting Hibernate access code
+ * implementing the {@link HibernateCallback} interface. It provides Hibernate Session
+ * handling such that neither the HibernateCallback implementation nor the calling
+ * code needs to explicitly care about retrieving/closing Hibernate Sessions,
+ * or handling Session lifecycle exceptions. For typical single step actions,
+ * there are various convenience methods (find, load, saveOrUpdate, delete).
+ *
+ *
Can be used within a service implementation via direct instantiation
+ * with a SessionFactory reference, or get prepared in an application context
+ * and given to services as bean reference. Note: The SessionFactory should
+ * always be configured as bean in the application context, in the first case
+ * given to the service directly, in the second case to the prepared template.
+ *
+ *
NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
+ * also be coded in plain Hibernate style. Hence, for newly started projects,
+ * consider adopting the standard Hibernate3 style of coding data access objects
+ * instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}.
+ *
+ *
This class can be considered as direct alternative to working with the raw
+ * Hibernate3 Session API (through SessionFactory.getCurrentSession()).
+ * The major advantage is its automatic conversion to DataAccessExceptions as well
+ * as its capability to fall back to 'auto-commit' style behavior when used outside
+ * of transactions. Note that HibernateTemplate will perform its own Session
+ * management, not participating in a custom Hibernate CurrentSessionContext
+ * unless you explicitly switch {@link #setAllowCreate "allowCreate"} to "false".
+ *
+ *
{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
+ * to a specific Hibernate SessionFactory, at least in a non-EJB environment.
+ * The Spring application context will manage its lifecycle, initializing and
+ * shutting down the factory as part of the application.
+ *
+ *
Note that operations that return an Iterator (i.e. iterate)
+ * are supposed to be used within Spring-driven or JTA-driven transactions
+ * (with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
+ * Else, the Iterator won't be able to read results from its ResultSet anymore,
+ * as the underlying Hibernate Session will already have been closed.
+ *
+ *
Lazy loading will also just work with an open Hibernate Session,
+ * either within a transaction or within OpenSessionInViewFilter/Interceptor.
+ * Furthermore, some operations just make sense within transactions,
+ * for example: contains, evict, lock,
+ * flush, clear.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setSessionFactory
+ * @see HibernateCallback
+ * @see org.hibernate.Session
+ * @see LocalSessionFactoryBean
+ * @see HibernateTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
+ */
+public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
+
+ private boolean allowCreate = true;
+
+ private boolean alwaysUseNewSession = false;
+
+ private boolean exposeNativeSession = false;
+
+ private boolean checkWriteOperations = true;
+
+ private boolean cacheQueries = false;
+
+ private String queryCacheRegion;
+
+ private int fetchSize = 0;
+
+ private int maxResults = 0;
+
+
+ /**
+ * Create a new HibernateTemplate instance.
+ */
+ public HibernateTemplate() {
+ }
+
+ /**
+ * Create a new HibernateTemplate instance.
+ * @param sessionFactory SessionFactory to create Sessions
+ */
+ public HibernateTemplate(SessionFactory sessionFactory) {
+ setSessionFactory(sessionFactory);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Create a new HibernateTemplate instance.
+ * @param sessionFactory SessionFactory to create Sessions
+ * @param allowCreate if a non-transactional Session should be created when no
+ * transactional Session can be found for the current thread
+ */
+ public HibernateTemplate(SessionFactory sessionFactory, boolean allowCreate) {
+ setSessionFactory(sessionFactory);
+ setAllowCreate(allowCreate);
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set if a new {@link Session} should be created when no transactional
+ * Session can be found for the current thread.
+ * The default value is true.
+ *
HibernateTemplate is aware of a corresponding
+ * Session bound to the current thread, for example when using
+ * {@link HibernateTransactionManager}. If allowCreate is
+ * true, a new non-transactional Session will be
+ * created if none is found, which needs to be closed at the end of the operation.
+ * If false, an {@link IllegalStateException} will get thrown in
+ * this case.
+ *
NOTE: As of Spring 2.5, switching allowCreate
+ * to false will delegate to Hibernate's
+ * {@link org.hibernate.SessionFactory#getCurrentSession()} method,
+ * which - with Spring-based setup - will by default delegate to Spring's
+ * SessionFactoryUtils.getSession(sessionFactory, false).
+ * This mode also allows for custom Hibernate CurrentSessionContext strategies
+ * to be plugged in, whereas allowCreate set to true
+ * will always use a Spring-managed Hibernate Session.
+ * @see SessionFactoryUtils#getSession(SessionFactory, boolean)
+ */
+ public void setAllowCreate(boolean allowCreate) {
+ this.allowCreate = allowCreate;
+ }
+
+ /**
+ * Return if a new Session should be created if no thread-bound found.
+ */
+ public boolean isAllowCreate() {
+ return this.allowCreate;
+ }
+
+ /**
+ * Set whether to always use a new Hibernate Session for this template.
+ * Default is "false"; if activated, all operations on this template will
+ * work on a new Hibernate Session even in case of a pre-bound Session
+ * (for example, within a transaction or OpenSessionInViewFilter).
+ *
Within a transaction, a new Hibernate Session used by this template
+ * will participate in the transaction through using the same JDBC
+ * Connection. In such a scenario, multiple Sessions will participate
+ * in the same database transaction.
+ *
Turn this on for operations that are supposed to always execute
+ * independently, without side effects caused by a shared Hibernate Session.
+ */
+ public void setAlwaysUseNewSession(boolean alwaysUseNewSession) {
+ this.alwaysUseNewSession = alwaysUseNewSession;
+ }
+
+ /**
+ * Return whether to always use a new Hibernate Session for this template.
+ */
+ public boolean isAlwaysUseNewSession() {
+ return this.alwaysUseNewSession;
+ }
+
+ /**
+ * Set whether to expose the native Hibernate Session to
+ * HibernateCallback code.
+ *
Default is "false": a Session proxy will be returned, suppressing
+ * close calls and automatically applying query cache
+ * settings and transaction timeouts.
+ * @see HibernateCallback
+ * @see org.hibernate.Session
+ * @see #setCacheQueries
+ * @see #setQueryCacheRegion
+ * @see #prepareQuery
+ * @see #prepareCriteria
+ */
+ public void setExposeNativeSession(boolean exposeNativeSession) {
+ this.exposeNativeSession = exposeNativeSession;
+ }
+
+ /**
+ * Return whether to expose the native Hibernate Session to
+ * HibernateCallback code, or rather a Session proxy.
+ */
+ public boolean isExposeNativeSession() {
+ return this.exposeNativeSession;
+ }
+
+ /**
+ * Set whether to check that the Hibernate Session is not in read-only mode
+ * in case of write operations (save/update/delete).
+ *
Default is "true", for fail-fast behavior when attempting write operations
+ * within a read-only transaction. Turn this off to allow save/update/delete
+ * on a Session with flush mode NEVER.
+ * @see #setFlushMode
+ * @see #checkWriteOperationAllowed
+ * @see org.springframework.transaction.TransactionDefinition#isReadOnly
+ */
+ public void setCheckWriteOperations(boolean checkWriteOperations) {
+ this.checkWriteOperations = checkWriteOperations;
+ }
+
+ /**
+ * Return whether to check that the Hibernate Session is not in read-only
+ * mode in case of write operations (save/update/delete).
+ */
+ public boolean isCheckWriteOperations() {
+ return this.checkWriteOperations;
+ }
+
+ /**
+ * Set whether to cache all queries executed by this template.
+ *
If this is "true", all Query and Criteria objects created by
+ * this template will be marked as cacheable (including all
+ * queries through find methods).
+ *
To specify the query region to be used for queries cached
+ * by this template, set the "queryCacheRegion" property.
+ * @see #setQueryCacheRegion
+ * @see org.hibernate.Query#setCacheable
+ * @see org.hibernate.Criteria#setCacheable
+ */
+ public void setCacheQueries(boolean cacheQueries) {
+ this.cacheQueries = cacheQueries;
+ }
+
+ /**
+ * Return whether to cache all queries executed by this template.
+ */
+ public boolean isCacheQueries() {
+ return this.cacheQueries;
+ }
+
+ /**
+ * Set the name of the cache region for queries executed by this template.
+ *
If this is specified, it will be applied to all Query and Criteria objects
+ * created by this template (including all queries through find methods).
+ *
The cache region will not take effect unless queries created by this
+ * template are configured to be cached via the "cacheQueries" property.
+ * @see #setCacheQueries
+ * @see org.hibernate.Query#setCacheRegion
+ * @see org.hibernate.Criteria#setCacheRegion
+ */
+ public void setQueryCacheRegion(String queryCacheRegion) {
+ this.queryCacheRegion = queryCacheRegion;
+ }
+
+ /**
+ * Return the name of the cache region for queries executed by this template.
+ */
+ public String getQueryCacheRegion() {
+ return this.queryCacheRegion;
+ }
+
+ /**
+ * Set the fetch size for this HibernateTemplate. This is important for processing
+ * large result sets: Setting this higher than the default value will increase
+ * processing speed at the cost of memory consumption; setting this lower can
+ * avoid transferring row data that will never be read by the application.
+ *
Default is 0, indicating to use the JDBC driver's default.
+ */
+ public void setFetchSize(int fetchSize) {
+ this.fetchSize = fetchSize;
+ }
+
+ /**
+ * Return the fetch size specified for this HibernateTemplate.
+ */
+ public int getFetchSize() {
+ return this.fetchSize;
+ }
+
+ /**
+ * Set the maximum number of rows for this HibernateTemplate. This is important
+ * for processing subsets of large result sets, avoiding to read and hold
+ * the entire result set in the database or in the JDBC driver if we're
+ * never interested in the entire result in the first place (for example,
+ * when performing searches that might return a large number of matches).
+ *
Default is 0, indicating to use the JDBC driver's default.
+ */
+ public void setMaxResults(int maxResults) {
+ this.maxResults = maxResults;
+ }
+
+ /**
+ * Return the maximum number of rows specified for this HibernateTemplate.
+ */
+ public int getMaxResults() {
+ return this.maxResults;
+ }
+
+
+ public Object execute(HibernateCallback action) throws DataAccessException {
+ return doExecute(action, false, false);
+ }
+
+ public List executeFind(HibernateCallback action) throws DataAccessException {
+ Object result = doExecute(action, false, false);
+ if (result != null && !(result instanceof List)) {
+ throw new InvalidDataAccessApiUsageException(
+ "Result object returned from HibernateCallback isn't a List: [" + result + "]");
+ }
+ return (List) result;
+ }
+
+ /**
+ * Execute the action specified by the given action object within a
+ * new {@link org.hibernate.Session}.
+ *
This execute variant overrides the template-wide
+ * {@link #isAlwaysUseNewSession() "alwaysUseNewSession"} setting.
+ * @param action callback object that specifies the Hibernate action
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ */
+ public Object executeWithNewSession(HibernateCallback action) {
+ return doExecute(action, true, false);
+ }
+
+ /**
+ * Execute the action specified by the given action object within a
+ * native {@link org.hibernate.Session}.
+ *
This execute variant overrides the template-wide
+ * {@link #isExposeNativeSession() "exposeNativeSession"} setting.
+ * @param action callback object that specifies the Hibernate action
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ */
+ public Object executeWithNativeSession(HibernateCallback action) {
+ return doExecute(action, false, true);
+ }
+
+ /**
+ * Execute the action specified by the given action object within a Session.
+ * @param action callback object that specifies the Hibernate action
+ * @param enforceNativeSession whether to enforce exposure of the native
+ * Hibernate Session to callback code
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ * @deprecated as of Spring 2.5, in favor of {@link #executeWithNativeSession}
+ */
+ public Object execute(HibernateCallback action, boolean enforceNativeSession) throws DataAccessException {
+ return doExecute(action, false, enforceNativeSession);
+ }
+
+ /**
+ * Execute the action specified by the given action object within a Session.
+ * @param action callback object that specifies the Hibernate action
+ * @param enforceNewSession whether to enforce a new Session for this template
+ * even if there is a pre-bound transactional Session
+ * @param enforceNativeSession whether to enforce exposure of the native
+ * Hibernate Session to callback code
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
+ */
+ protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
+ throws DataAccessException {
+
+ Assert.notNull(action, "Callback object must not be null");
+
+ Session session = (enforceNewSession ?
+ SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
+ boolean existingTransaction = (!enforceNewSession &&
+ (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
+ if (existingTransaction) {
+ logger.debug("Found thread-bound Session for HibernateTemplate");
+ }
+
+ FlushMode previousFlushMode = null;
+ try {
+ previousFlushMode = applyFlushMode(session, existingTransaction);
+ enableFilters(session);
+ Session sessionToExpose =
+ (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
+ Object result = action.doInHibernate(sessionToExpose);
+ flushIfNecessary(session, existingTransaction);
+ return result;
+ }
+ catch (HibernateException ex) {
+ throw convertHibernateAccessException(ex);
+ }
+ catch (SQLException ex) {
+ throw convertJdbcAccessException(ex);
+ }
+ catch (RuntimeException ex) {
+ // Callback code threw application exception...
+ throw ex;
+ }
+ finally {
+ if (existingTransaction) {
+ logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
+ disableFilters(session);
+ if (previousFlushMode != null) {
+ session.setFlushMode(previousFlushMode);
+ }
+ }
+ else {
+ // Never use deferred close for an explicitly new Session.
+ if (isAlwaysUseNewSession()) {
+ SessionFactoryUtils.closeSession(session);
+ }
+ else {
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
+ }
+ }
+ }
+ }
+
+ /**
+ * Return a Session for use by this template.
+ *
Returns a new Session in case of "alwaysUseNewSession" (using the same
+ * JDBC Connection as a transactional Session, if applicable), a pre-bound
+ * Session in case of "allowCreate" turned off, and a pre-bound or new Session
+ * otherwise (new only if no transactional or otherwise pre-bound Session exists).
+ * @return the Session to use (never null)
+ * @see SessionFactoryUtils#getSession
+ * @see SessionFactoryUtils#getNewSession
+ * @see #setAlwaysUseNewSession
+ * @see #setAllowCreate
+ */
+ protected Session getSession() {
+ if (isAlwaysUseNewSession()) {
+ return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
+ }
+ else if (isAllowCreate()) {
+ return SessionFactoryUtils.getSession(
+ getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
+ }
+ else if (SessionFactoryUtils.hasTransactionalSession(getSessionFactory())) {
+ return SessionFactoryUtils.getSession(getSessionFactory(), false);
+ }
+ else {
+ try {
+ return getSessionFactory().getCurrentSession();
+ }
+ catch (HibernateException ex) {
+ throw new DataAccessResourceFailureException("Could not obtain current Hibernate Session", ex);
+ }
+ }
+ }
+
+ /**
+ * Create a close-suppressing proxy for the given Hibernate Session.
+ * The proxy also prepares returned Query and Criteria objects.
+ * @param session the Hibernate Session to create a proxy for
+ * @return the Session proxy
+ * @see org.hibernate.Session#close()
+ * @see #prepareQuery
+ * @see #prepareCriteria
+ */
+ protected Session createSessionProxy(Session session) {
+ Class[] sessionIfcs = null;
+ Class mainIfc = (session instanceof org.hibernate.classic.Session ?
+ org.hibernate.classic.Session.class : Session.class);
+ if (session instanceof EventSource) {
+ sessionIfcs = new Class[] {mainIfc, EventSource.class};
+ }
+ else if (session instanceof SessionImplementor) {
+ sessionIfcs = new Class[] {mainIfc, SessionImplementor.class};
+ }
+ else {
+ sessionIfcs = new Class[] {mainIfc};
+ }
+ return (Session) Proxy.newProxyInstance(
+ session.getClass().getClassLoader(), sessionIfcs,
+ new CloseSuppressingInvocationHandler(session));
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for loading individual objects
+ //-------------------------------------------------------------------------
+
+ public Object get(Class entityClass, Serializable id) throws DataAccessException {
+ return get(entityClass, id, null);
+ }
+
+ public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
+ throws DataAccessException {
+
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ if (lockMode != null) {
+ return session.get(entityClass, id, lockMode);
+ }
+ else {
+ return session.get(entityClass, id);
+ }
+ }
+ });
+ }
+
+ public Object get(String entityName, Serializable id) throws DataAccessException {
+ return get(entityName, id, null);
+ }
+
+ public Object get(final String entityName, final Serializable id, final LockMode lockMode)
+ throws DataAccessException {
+
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ if (lockMode != null) {
+ return session.get(entityName, id, lockMode);
+ }
+ else {
+ return session.get(entityName, id);
+ }
+ }
+ });
+ }
+
+ public Object load(Class entityClass, Serializable id) throws DataAccessException {
+ return load(entityClass, id, null);
+ }
+
+ public Object load(final Class entityClass, final Serializable id, final LockMode lockMode)
+ throws DataAccessException {
+
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ if (lockMode != null) {
+ return session.load(entityClass, id, lockMode);
+ }
+ else {
+ return session.load(entityClass, id);
+ }
+ }
+ });
+ }
+
+ public Object load(String entityName, Serializable id) throws DataAccessException {
+ return load(entityName, id, null);
+ }
+
+ public Object load(final String entityName, final Serializable id, final LockMode lockMode)
+ throws DataAccessException {
+
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ if (lockMode != null) {
+ return session.load(entityName, id, lockMode);
+ }
+ else {
+ return session.load(entityName, id);
+ }
+ }
+ });
+ }
+
+ public List loadAll(final Class entityClass) throws DataAccessException {
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Criteria criteria = session.createCriteria(entityClass);
+ criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
+ prepareCriteria(criteria);
+ return criteria.list();
+ }
+ });
+ }
+
+ public void load(final Object entity, final Serializable id) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ session.load(entity, id);
+ return null;
+ }
+ });
+ }
+
+ public void refresh(final Object entity) throws DataAccessException {
+ refresh(entity, null);
+ }
+
+ public void refresh(final Object entity, final LockMode lockMode) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ if (lockMode != null) {
+ session.refresh(entity, lockMode);
+ }
+ else {
+ session.refresh(entity);
+ }
+ return null;
+ }
+ });
+ }
+
+ public boolean contains(final Object entity) throws DataAccessException {
+ Boolean result = (Boolean) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) {
+ return (session.contains(entity) ? Boolean.TRUE : Boolean.FALSE);
+ }
+ });
+ return result.booleanValue();
+ }
+
+ public void evict(final Object entity) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ session.evict(entity);
+ return null;
+ }
+ });
+ }
+
+ public void initialize(Object proxy) throws DataAccessException {
+ try {
+ Hibernate.initialize(proxy);
+ }
+ catch (HibernateException ex) {
+ throw SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+ }
+
+ public Filter enableFilter(String filterName) throws IllegalStateException {
+ Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
+ Filter filter = session.getEnabledFilter(filterName);
+ if (filter == null) {
+ filter = session.enableFilter(filterName);
+ }
+ return filter;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for storing individual objects
+ //-------------------------------------------------------------------------
+
+ public void lock(final Object entity, final LockMode lockMode) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ session.lock(entity, lockMode);
+ return null;
+ }
+ });
+ }
+
+ public void lock(final String entityName, final Object entity, final LockMode lockMode)
+ throws DataAccessException {
+
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ session.lock(entityName, entity, lockMode);
+ return null;
+ }
+ });
+ }
+
+ public Serializable save(final Object entity) throws DataAccessException {
+ return (Serializable) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ return session.save(entity);
+ }
+ });
+ }
+
+ public Serializable save(final String entityName, final Object entity) throws DataAccessException {
+ return (Serializable) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ return session.save(entityName, entity);
+ }
+ });
+ }
+
+ public void update(Object entity) throws DataAccessException {
+ update(entity, null);
+ }
+
+ public void update(final Object entity, final LockMode lockMode) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.update(entity);
+ if (lockMode != null) {
+ session.lock(entity, lockMode);
+ }
+ return null;
+ }
+ });
+ }
+
+ public void update(String entityName, Object entity) throws DataAccessException {
+ update(entityName, entity, null);
+ }
+
+ public void update(final String entityName, final Object entity, final LockMode lockMode)
+ throws DataAccessException {
+
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.update(entityName, entity);
+ if (lockMode != null) {
+ session.lock(entity, lockMode);
+ }
+ return null;
+ }
+ });
+ }
+
+ public void saveOrUpdate(final Object entity) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.saveOrUpdate(entity);
+ return null;
+ }
+ });
+ }
+
+ public void saveOrUpdate(final String entityName, final Object entity) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.saveOrUpdate(entityName, entity);
+ return null;
+ }
+ });
+ }
+
+ public void saveOrUpdateAll(final Collection entities) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ for (Iterator it = entities.iterator(); it.hasNext();) {
+ session.saveOrUpdate(it.next());
+ }
+ return null;
+ }
+ });
+ }
+
+ public void replicate(final Object entity, final ReplicationMode replicationMode)
+ throws DataAccessException {
+
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.replicate(entity, replicationMode);
+ return null;
+ }
+ });
+ }
+
+ public void replicate(final String entityName, final Object entity, final ReplicationMode replicationMode)
+ throws DataAccessException {
+
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.replicate(entityName, entity, replicationMode);
+ return null;
+ }
+ });
+ }
+
+ public void persist(final Object entity) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.persist(entity);
+ return null;
+ }
+ });
+ }
+
+ public void persist(final String entityName, final Object entity) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ session.persist(entityName, entity);
+ return null;
+ }
+ });
+ }
+
+ public Object merge(final Object entity) throws DataAccessException {
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ return session.merge(entity);
+ }
+ });
+ }
+
+ public Object merge(final String entityName, final Object entity) throws DataAccessException {
+ return executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ return session.merge(entityName, entity);
+ }
+ });
+ }
+
+ public void delete(Object entity) throws DataAccessException {
+ delete(entity, null);
+ }
+
+ public void delete(final Object entity, final LockMode lockMode) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ if (lockMode != null) {
+ session.lock(entity, lockMode);
+ }
+ session.delete(entity);
+ return null;
+ }
+ });
+ }
+
+ public void delete(String entityName, Object entity) throws DataAccessException {
+ delete(entityName, entity, null);
+ }
+
+ public void delete(final String entityName, final Object entity, final LockMode lockMode)
+ throws DataAccessException {
+
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ if (lockMode != null) {
+ session.lock(entityName, entity, lockMode);
+ }
+ session.delete(entityName, entity);
+ return null;
+ }
+ });
+ }
+
+ public void deleteAll(final Collection entities) throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ checkWriteOperationAllowed(session);
+ for (Iterator it = entities.iterator(); it.hasNext();) {
+ session.delete(it.next());
+ }
+ return null;
+ }
+ });
+ }
+
+ public void flush() throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ session.flush();
+ return null;
+ }
+ });
+ }
+
+ public void clear() throws DataAccessException {
+ executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) {
+ session.clear();
+ return null;
+ }
+ });
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for HQL strings
+ //-------------------------------------------------------------------------
+
+ public List find(String queryString) throws DataAccessException {
+ return find(queryString, (Object[]) null);
+ }
+
+ public List find(String queryString, Object value) throws DataAccessException {
+ return find(queryString, new Object[] {value});
+ }
+
+ public List find(final String queryString, final Object[] values) throws DataAccessException {
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.createQuery(queryString);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i, values[i]);
+ }
+ }
+ return queryObject.list();
+ }
+ });
+ }
+
+ public List findByNamedParam(String queryString, String paramName, Object value)
+ throws DataAccessException {
+
+ return findByNamedParam(queryString, new String[] {paramName}, new Object[] {value});
+ }
+
+ public List findByNamedParam(final String queryString, final String[] paramNames, final Object[] values)
+ throws DataAccessException {
+
+ if (paramNames.length != values.length) {
+ throw new IllegalArgumentException("Length of paramNames array must match length of values array");
+ }
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.createQuery(queryString);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
+ }
+ }
+ return queryObject.list();
+ }
+ });
+ }
+
+ public List findByValueBean(final String queryString, final Object valueBean)
+ throws DataAccessException {
+
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.createQuery(queryString);
+ prepareQuery(queryObject);
+ queryObject.setProperties(valueBean);
+ return queryObject.list();
+ }
+ });
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for named queries
+ //-------------------------------------------------------------------------
+
+ public List findByNamedQuery(String queryName) throws DataAccessException {
+ return findByNamedQuery(queryName, (Object[]) null);
+ }
+
+ public List findByNamedQuery(String queryName, Object value) throws DataAccessException {
+ return findByNamedQuery(queryName, new Object[] {value});
+ }
+
+ public List findByNamedQuery(final String queryName, final Object[] values) throws DataAccessException {
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.getNamedQuery(queryName);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i, values[i]);
+ }
+ }
+ return queryObject.list();
+ }
+ });
+ }
+
+ public List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value)
+ throws DataAccessException {
+
+ return findByNamedQueryAndNamedParam(queryName, new String[] {paramName}, new Object[] {value});
+ }
+
+ public List findByNamedQueryAndNamedParam(
+ final String queryName, final String[] paramNames, final Object[] values)
+ throws DataAccessException {
+
+ if (paramNames != null && values != null && paramNames.length != values.length) {
+ throw new IllegalArgumentException("Length of paramNames array must match length of values array");
+ }
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.getNamedQuery(queryName);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
+ }
+ }
+ return queryObject.list();
+ }
+ });
+ }
+
+ public List findByNamedQueryAndValueBean(final String queryName, final Object valueBean)
+ throws DataAccessException {
+
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.getNamedQuery(queryName);
+ prepareQuery(queryObject);
+ queryObject.setProperties(valueBean);
+ return queryObject.list();
+ }
+ });
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods for detached criteria
+ //-------------------------------------------------------------------------
+
+ public List findByCriteria(DetachedCriteria criteria) throws DataAccessException {
+ return findByCriteria(criteria, -1, -1);
+ }
+
+ public List findByCriteria(final DetachedCriteria criteria, final int firstResult, final int maxResults)
+ throws DataAccessException {
+
+ Assert.notNull(criteria, "DetachedCriteria must not be null");
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Criteria executableCriteria = criteria.getExecutableCriteria(session);
+ prepareCriteria(executableCriteria);
+ if (firstResult >= 0) {
+ executableCriteria.setFirstResult(firstResult);
+ }
+ if (maxResults > 0) {
+ executableCriteria.setMaxResults(maxResults);
+ }
+ return executableCriteria.list();
+ }
+ });
+ }
+
+ public List findByExample(Object exampleEntity) throws DataAccessException {
+ return findByExample(null, exampleEntity, -1, -1);
+ }
+
+ public List findByExample(String entityName, Object exampleEntity) throws DataAccessException {
+ return findByExample(entityName, exampleEntity, -1, -1);
+ }
+
+ public List findByExample(Object exampleEntity, int firstResult, int maxResults) throws DataAccessException {
+ return findByExample(null, exampleEntity, firstResult, maxResults);
+ }
+
+ public List findByExample(
+ final String entityName, final Object exampleEntity, final int firstResult, final int maxResults)
+ throws DataAccessException {
+
+ Assert.notNull(exampleEntity, "Example entity must not be null");
+ return (List) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Criteria executableCriteria = (entityName != null ?
+ session.createCriteria(entityName) : session.createCriteria(exampleEntity.getClass()));
+ executableCriteria.add(Example.create(exampleEntity));
+ prepareCriteria(executableCriteria);
+ if (firstResult >= 0) {
+ executableCriteria.setFirstResult(firstResult);
+ }
+ if (maxResults > 0) {
+ executableCriteria.setMaxResults(maxResults);
+ }
+ return executableCriteria.list();
+ }
+ });
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience query methods for iteration and bulk updates/deletes
+ //-------------------------------------------------------------------------
+
+ public Iterator iterate(String queryString) throws DataAccessException {
+ return iterate(queryString, (Object[]) null);
+ }
+
+ public Iterator iterate(String queryString, Object value) throws DataAccessException {
+ return iterate(queryString, new Object[] {value});
+ }
+
+ public Iterator iterate(final String queryString, final Object[] values) throws DataAccessException {
+ return (Iterator) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.createQuery(queryString);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i, values[i]);
+ }
+ }
+ return queryObject.iterate();
+ }
+ });
+ }
+
+ public void closeIterator(Iterator it) throws DataAccessException {
+ try {
+ Hibernate.close(it);
+ }
+ catch (HibernateException ex) {
+ throw SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+ }
+
+ public int bulkUpdate(String queryString) throws DataAccessException {
+ return bulkUpdate(queryString, (Object[]) null);
+ }
+
+ public int bulkUpdate(String queryString, Object value) throws DataAccessException {
+ return bulkUpdate(queryString, new Object[] {value});
+ }
+
+ public int bulkUpdate(final String queryString, final Object[] values) throws DataAccessException {
+ Integer updateCount = (Integer) executeWithNativeSession(new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException {
+ Query queryObject = session.createQuery(queryString);
+ prepareQuery(queryObject);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i, values[i]);
+ }
+ }
+ return new Integer(queryObject.executeUpdate());
+ }
+ });
+ return updateCount.intValue();
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Helper methods used by the operations above
+ //-------------------------------------------------------------------------
+
+ /**
+ * Check whether write operations are allowed on the given Session.
+ *
Default implementation throws an InvalidDataAccessApiUsageException in
+ * case of FlushMode.NEVER/MANUAL. Can be overridden in subclasses.
+ * @param session current Hibernate Session
+ * @throws InvalidDataAccessApiUsageException if write operations are not allowed
+ * @see #setCheckWriteOperations
+ * @see #getFlushMode()
+ * @see #FLUSH_EAGER
+ * @see org.hibernate.Session#getFlushMode()
+ * @see org.hibernate.FlushMode#NEVER
+ * @see org.hibernate.FlushMode#MANUAL
+ */
+ protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
+ if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
+ session.getFlushMode().lessThan(FlushMode.COMMIT)) {
+ throw new InvalidDataAccessApiUsageException(
+ "Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): "+
+ "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
+ }
+ }
+
+ /**
+ * Prepare the given Query object, applying cache settings and/or
+ * a transaction timeout.
+ * @param queryObject the Query object to prepare
+ * @see #setCacheQueries
+ * @see #setQueryCacheRegion
+ * @see SessionFactoryUtils#applyTransactionTimeout
+ */
+ protected void prepareQuery(Query queryObject) {
+ if (isCacheQueries()) {
+ queryObject.setCacheable(true);
+ if (getQueryCacheRegion() != null) {
+ queryObject.setCacheRegion(getQueryCacheRegion());
+ }
+ }
+ if (getFetchSize() > 0) {
+ queryObject.setFetchSize(getFetchSize());
+ }
+ if (getMaxResults() > 0) {
+ queryObject.setMaxResults(getMaxResults());
+ }
+ SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
+ }
+
+ /**
+ * Prepare the given Criteria object, applying cache settings and/or
+ * a transaction timeout.
+ * @param criteria the Criteria object to prepare
+ * @see #setCacheQueries
+ * @see #setQueryCacheRegion
+ * @see SessionFactoryUtils#applyTransactionTimeout
+ */
+ protected void prepareCriteria(Criteria criteria) {
+ if (isCacheQueries()) {
+ criteria.setCacheable(true);
+ if (getQueryCacheRegion() != null) {
+ criteria.setCacheRegion(getQueryCacheRegion());
+ }
+ }
+ if (getFetchSize() > 0) {
+ criteria.setFetchSize(getFetchSize());
+ }
+ if (getMaxResults() > 0) {
+ criteria.setMaxResults(getMaxResults());
+ }
+ SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
+ }
+
+ /**
+ * Apply the given name parameter to the given Query object.
+ * @param queryObject the Query object
+ * @param paramName the name of the parameter
+ * @param value the value of the parameter
+ * @throws HibernateException if thrown by the Query object
+ */
+ protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value)
+ throws HibernateException {
+
+ if (value instanceof Collection) {
+ queryObject.setParameterList(paramName, (Collection) value);
+ }
+ else if (value instanceof Object[]) {
+ queryObject.setParameterList(paramName, (Object[]) value);
+ }
+ else {
+ queryObject.setParameter(paramName, value);
+ }
+ }
+
+
+ /**
+ * Invocation handler that suppresses close calls on Hibernate Sessions.
+ * Also prepares returned Query and Criteria objects.
+ * @see org.hibernate.Session#close
+ */
+ private class CloseSuppressingInvocationHandler implements InvocationHandler {
+
+ private final Session target;
+
+ public CloseSuppressingInvocationHandler(Session target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on Session interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of Session proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: suppress, not valid.
+ return null;
+ }
+
+ // Invoke method on target Session.
+ try {
+ Object retVal = method.invoke(this.target, args);
+
+ // If return value is a Query or Criteria, apply transaction timeout.
+ // Applies to createQuery, getNamedQuery, createCriteria.
+ if (retVal instanceof Query) {
+ prepareQuery(((Query) retVal));
+ }
+ if (retVal instanceof Criteria) {
+ prepareCriteria(((Criteria) retVal));
+ }
+
+ return retVal;
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTransactionManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTransactionManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/HibernateTransactionManager.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.sql.Connection;
+
+import javax.sql.DataSource;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.exception.GenericJDBCException;
+import org.hibernate.impl.SessionImpl;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.jdbc.datasource.ConnectionHolder;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+import org.springframework.transaction.CannotCreateTransactionException;
+import org.springframework.transaction.IllegalTransactionStateException;
+import org.springframework.transaction.InvalidIsolationLevelException;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionSystemException;
+import org.springframework.transaction.support.AbstractPlatformTransactionManager;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+import org.springframework.transaction.support.ResourceTransactionManager;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * {@link org.springframework.transaction.PlatformTransactionManager}
+ * implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
+ * Binds a Hibernate Session from the specified factory to the thread, potentially
+ * allowing for one thread-bound Session per factory. {@link SessionFactoryUtils}
+ * and {@link HibernateTemplate} are aware of thread-bound Sessions and participate
+ * in such transactions automatically. Using either of those or going through
+ * SessionFactory.getCurrentSession() is required for Hibernate
+ * access code that needs to support this transaction handling mechanism.
+ *
+ *
Supports custom isolation levels, and timeouts that get applied as
+ * Hibernate transaction timeouts.
+ *
+ *
This transaction manager is appropriate for applications that use a single
+ * Hibernate SessionFactory for transactional data access, but it also supports
+ * direct DataSource access within a transaction (i.e. plain JDBC code working
+ * with the same DataSource). This allows for mixing services which access Hibernate
+ * and services which use plain JDBC (without being aware of Hibernate)!
+ * Application code needs to stick to the same simple Connection lookup pattern as
+ * with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
+ * (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
+ * or going through a
+ * {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
+ *
+ *
Note: To be able to register a DataSource's Connection for plain JDBC code,
+ * this instance needs to be aware of the DataSource ({@link #setDataSource}).
+ * The given DataSource should obviously match the one used by the given
+ * SessionFactory. To achieve this, configure both to the same JNDI DataSource,
+ * or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and
+ * a local DataSource (which will be autodetected by this transaction manager).
+ *
+ *
JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
+ * is necessary for accessing multiple transactional resources within the same
+ * transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
+ * such a scenario (see container setup). Normally, JTA setup for Hibernate is
+ * somewhat container-specific due to the JTA TransactionManager lookup, required
+ * for proper transactional handling of the SessionFactory-level read-write cache.
+ *
+ *
Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils}
+ * (and thus {@link HibernateTemplate}) registers synchronizations with Spring's
+ * {@link org.springframework.transaction.support.TransactionSynchronizationManager}
+ * (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}),
+ * for proper after-completion callbacks. Therefore, as long as Spring's
+ * JtaTransactionManager drives the JTA transactions, Hibernate does not require
+ * any special configuration for proper JTA participation. Note that there are
+ * special restrictions with EJB CMT and restrictive JTA subsystems: See
+ * {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details.
+ *
+ *
On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
+ * Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"}
+ * flag defaults to "false", though, as nested transactions will just apply to the
+ * JDBC Connection, not to the Hibernate Session and its cached objects. You can
+ * manually set the flag to "true" if you want to use nested transactions for
+ * JDBC access code which participates in Hibernate transactions (provided that
+ * your JDBC driver supports Savepoints). Note that Hibernate itself does not
+ * support nested transactions! Hence, do not expect Hibernate access code to
+ * semantically participate in a nested transaction.
+ *
+ *
Requires Hibernate 3.1 or later, as of Spring 2.5.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setSessionFactory
+ * @see #setDataSource
+ * @see LocalSessionFactoryBean
+ * @see SessionFactoryUtils#getSession
+ * @see SessionFactoryUtils#applyTransactionTimeout
+ * @see SessionFactoryUtils#releaseSession
+ * @see HibernateTemplate
+ * @see org.hibernate.SessionFactory#getCurrentSession()
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+public class HibernateTransactionManager extends AbstractPlatformTransactionManager
+ implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
+
+ private SessionFactory sessionFactory;
+
+ private DataSource dataSource;
+
+ private boolean autodetectDataSource = true;
+
+ private boolean prepareConnection = true;
+
+ private boolean hibernateManagedSession = false;
+
+ private boolean earlyFlushBeforeCommit = false;
+
+ private Object entityInterceptor;
+
+ private SQLExceptionTranslator jdbcExceptionTranslator;
+
+ private SQLExceptionTranslator defaultJdbcExceptionTranslator;
+
+ /**
+ * Just needed for entityInterceptorBeanName.
+ * @see #setEntityInterceptorBeanName
+ */
+ private BeanFactory beanFactory;
+
+
+ /**
+ * Create a new HibernateTransactionManager instance.
+ * A SessionFactory has to be set to be able to use it.
+ * @see #setSessionFactory
+ */
+ public HibernateTransactionManager() {
+ }
+
+ /**
+ * Create a new HibernateTransactionManager instance.
+ * @param sessionFactory SessionFactory to manage transactions for
+ */
+ public HibernateTransactionManager(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set the SessionFactory that this instance should manage transactions for.
+ */
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ /**
+ * Return the SessionFactory that this instance should manage transactions for.
+ */
+ public SessionFactory getSessionFactory() {
+ return this.sessionFactory;
+ }
+
+ /**
+ * Set the JDBC DataSource that this instance should manage transactions for.
+ * The DataSource should match the one used by the Hibernate SessionFactory:
+ * for example, you could specify the same JNDI DataSource for both.
+ *
If the SessionFactory was configured with LocalDataSourceConnectionProvider,
+ * i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource",
+ * the DataSource will be auto-detected: You can still explictly specify the
+ * DataSource, but you don't need to in this case.
+ *
A transactional JDBC Connection for this DataSource will be provided to
+ * application code accessing this DataSource directly via DataSourceUtils
+ * or JdbcTemplate. The Connection will be taken from the Hibernate Session.
+ *
The DataSource specified here should be the target DataSource to manage
+ * transactions for, not a TransactionAwareDataSourceProxy. Only data access
+ * code may work with TransactionAwareDataSourceProxy, while the transaction
+ * manager needs to work on the underlying target DataSource. If there's
+ * nevertheless a TransactionAwareDataSourceProxy passed in, it will be
+ * unwrapped to extract its target DataSource.
+ * @see #setAutodetectDataSource
+ * @see LocalDataSourceConnectionProvider
+ * @see LocalSessionFactoryBean#setDataSource
+ * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
+ * @see org.springframework.jdbc.datasource.DataSourceUtils
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ */
+ public void setDataSource(DataSource dataSource) {
+ if (dataSource instanceof TransactionAwareDataSourceProxy) {
+ // If we got a TransactionAwareDataSourceProxy, we need to perform transactions
+ // for its underlying target DataSource, else data access code won't see
+ // properly exposed transactions (i.e. transactions for the target DataSource).
+ this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
+ }
+ else {
+ this.dataSource = dataSource;
+ }
+ }
+
+ /**
+ * Return the JDBC DataSource that this instance manages transactions for.
+ */
+ public DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
+ * if set via LocalSessionFactoryBean's setDataSource. Default is "true".
+ *
Can be turned off to deliberately ignore an available DataSource, in order
+ * to not expose Hibernate transactions as JDBC transactions for that DataSource.
+ * @see #setDataSource
+ * @see LocalSessionFactoryBean#setDataSource
+ */
+ public void setAutodetectDataSource(boolean autodetectDataSource) {
+ this.autodetectDataSource = autodetectDataSource;
+ }
+
+ /**
+ * Set whether to prepare the underlying JDBC Connection of a transactional
+ * Hibernate Session, that is, whether to apply a transaction-specific
+ * isolation level and/or the transaction's read-only flag to the underlying
+ * JDBC Connection.
+ *
Default is "true". If you turn this flag off, the transaction manager
+ * will not support per-transaction isolation levels anymore. It will not
+ * call Connection.setReadOnly(true) for read-only transactions
+ * anymore either. If this flag is turned off, no cleanup of a JDBC Connection
+ * is required after a transaction, since no Connection settings will get modified.
+ *
It is recommended to turn this flag off if running against Hibernate 3.1
+ * and a connection pool that does not reset connection settings (for example,
+ * Jakarta Commons DBCP). To keep this flag turned on, you can set the
+ * "hibernate.connection.release_mode" property to "on_close" instead,
+ * or consider using a smarter connection pool (for example, C3P0).
+ * @see java.sql.Connection#setTransactionIsolation
+ * @see java.sql.Connection#setReadOnly
+ */
+ public void setPrepareConnection(boolean prepareConnection) {
+ this.prepareConnection = prepareConnection;
+ }
+
+ /**
+ * Set whether to operate on a Hibernate-managed Session instead of a
+ * Spring-managed Session, that is, whether to obtain the Session through
+ * Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
+ * instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
+ * {@link org.springframework.transaction.support.TransactionSynchronizationManager}
+ * check preceding it).
+ *
Default is "false", i.e. using a Spring-managed Session: taking the current
+ * thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
+ * creating a new Session for the current transaction otherwise.
+ *
Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
+ * Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
+ * to always return a proper Session when called for a Spring-managed transaction;
+ * transaction begin will fail if the getCurrentSession() call fails.
+ *
This mode will typically be used in combination with a custom Hibernate
+ * {@link org.hibernate.context.CurrentSessionContext} implementation that stores
+ * Sessions in a place other than Spring's TransactionSynchronizationManager.
+ * It may also be used in combination with Spring's Open-Session-in-View support
+ * (using Spring's default {@link SpringSessionContext}), in which case it subtly
+ * differs from the Spring-managed Session mode: The pre-bound Session will not
+ * receive a clear() call (on rollback) or a disconnect()
+ * call (on transaction completion) in such a scenario; this is rather left up
+ * to a custom CurrentSessionContext implementation (if desired).
+ */
+ public void setHibernateManagedSession(boolean hibernateManagedSession) {
+ this.hibernateManagedSession = hibernateManagedSession;
+ }
+
+ /**
+ * Set whether to perform an early flush before proceeding with a commit.
+ *
Default is "false", performing an implicit flush as part of the actual
+ * commit step. Switch this to "true" in order to enforce an explicit early
+ * flush right before the actual commit step.
+ *
An early flush happens before the before-commit synchronization phase,
+ * making flushed state visible to beforeCommit callbacks of registered
+ * {@link org.springframework.transaction.support.TransactionSynchronization}
+ * objects. Such explicit flush behavior is consistent with Spring-driven
+ * flushing in a JTA transaction environment, so may also get enforced for
+ * consistency with JTA transaction behavior.
+ * @see #prepareForCommit
+ */
+ public void setEarlyFlushBeforeCommit(boolean earlyFlushBeforeCommit) {
+ this.earlyFlushBeforeCommit = earlyFlushBeforeCommit;
+ }
+
+ /**
+ * Set the bean name of a Hibernate entity interceptor that allows to inspect
+ * and change property values before writing to and reading from the database.
+ * Will get applied to any new Session created by this transaction manager.
+ *
Requires the bean factory to be known, to be able to resolve the bean
+ * name to an interceptor instance on session creation. Typically used for
+ * prototype interceptors, i.e. a new interceptor instance per session.
+ *
Can also be used for shared interceptor instances, but it is recommended
+ * to set the interceptor reference directly in such a scenario.
+ * @param entityInterceptorBeanName the name of the entity interceptor in
+ * the bean factory
+ * @see #setBeanFactory
+ * @see #setEntityInterceptor
+ */
+ public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
+ this.entityInterceptor = entityInterceptorBeanName;
+ }
+
+ /**
+ * Set a Hibernate entity interceptor that allows to inspect and change
+ * property values before writing to and reading from the database.
+ * Will get applied to any new Session created by this transaction manager.
+ *
Such an interceptor can either be set at the SessionFactory level,
+ * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
+ * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
+ * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
+ * to avoid repeated configuration and guarantee consistent behavior in transactions.
+ * @see LocalSessionFactoryBean#setEntityInterceptor
+ * @see HibernateTemplate#setEntityInterceptor
+ * @see HibernateInterceptor#setEntityInterceptor
+ */
+ public void setEntityInterceptor(Interceptor entityInterceptor) {
+ this.entityInterceptor = entityInterceptor;
+ }
+
+ /**
+ * Return the current Hibernate entity interceptor, or null if none.
+ * Resolves an entity interceptor bean name via the bean factory,
+ * if necessary.
+ * @throws IllegalStateException if bean name specified but no bean factory set
+ * @throws BeansException if bean name resolution via the bean factory failed
+ * @see #setEntityInterceptor
+ * @see #setEntityInterceptorBeanName
+ * @see #setBeanFactory
+ */
+ public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
+ if (this.entityInterceptor instanceof Interceptor) {
+ return (Interceptor) entityInterceptor;
+ }
+ else if (this.entityInterceptor instanceof String) {
+ if (this.beanFactory == null) {
+ throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
+ }
+ String beanName = (String) this.entityInterceptor;
+ return (Interceptor) this.beanFactory.getBean(beanName, Interceptor.class);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Set the JDBC exception translator for this transaction manager.
+ *
Applied to any SQLException root cause of a Hibernate JDBCException that
+ * is thrown on flush, overriding Hibernate's default SQLException translation
+ * (which is based on Hibernate's Dialect for a specific target database).
+ * @param jdbcExceptionTranslator the exception translator
+ * @see java.sql.SQLException
+ * @see org.hibernate.JDBCException
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ */
+ public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
+ this.jdbcExceptionTranslator = jdbcExceptionTranslator;
+ }
+
+ /**
+ * Return the JDBC exception translator for this transaction manager, if any.
+ */
+ public SQLExceptionTranslator getJdbcExceptionTranslator() {
+ return this.jdbcExceptionTranslator;
+ }
+
+ /**
+ * The bean factory just needs to be known for resolving entity interceptor
+ * bean names. It does not need to be set for any other mode of operation.
+ * @see #setEntityInterceptorBeanName
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ public void afterPropertiesSet() {
+ if (getSessionFactory() == null) {
+ throw new IllegalArgumentException("Property 'sessionFactory' is required");
+ }
+ if (this.entityInterceptor instanceof String && this.beanFactory == null) {
+ throw new IllegalArgumentException("Property 'beanFactory' is required for 'entityInterceptorBeanName'");
+ }
+
+ // Check for SessionFactory's DataSource.
+ if (this.autodetectDataSource && getDataSource() == null) {
+ DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory());
+ if (sfds != null) {
+ // Use the SessionFactory's DataSource for exposing transactions to JDBC code.
+ if (logger.isInfoEnabled()) {
+ logger.info("Using DataSource [" + sfds +
+ "] of Hibernate SessionFactory for HibernateTransactionManager");
+ }
+ setDataSource(sfds);
+ }
+ }
+ }
+
+
+ public Object getResourceFactory() {
+ return getSessionFactory();
+ }
+
+ protected Object doGetTransaction() {
+ HibernateTransactionObject txObject = new HibernateTransactionObject();
+ txObject.setSavepointAllowed(isNestedTransactionAllowed());
+
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
+ if (sessionHolder != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found thread-bound Session [" +
+ SessionFactoryUtils.toString(sessionHolder.getSession()) + "] for Hibernate transaction");
+ }
+ txObject.setSessionHolder(sessionHolder);
+ }
+ else if (this.hibernateManagedSession) {
+ try {
+ Session session = getSessionFactory().getCurrentSession();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found Hibernate-managed Session [" +
+ SessionFactoryUtils.toString(session) + "] for Spring-managed transaction");
+ }
+ txObject.setExistingSession(session);
+ }
+ catch (HibernateException ex) {
+ throw new DataAccessResourceFailureException(
+ "Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
+ }
+ }
+
+ if (getDataSource() != null) {
+ ConnectionHolder conHolder = (ConnectionHolder)
+ TransactionSynchronizationManager.getResource(getDataSource());
+ txObject.setConnectionHolder(conHolder);
+ }
+
+ return txObject;
+ }
+
+ protected boolean isExistingTransaction(Object transaction) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+ return (txObject.hasSpringManagedTransaction() ||
+ (this.hibernateManagedSession && txObject.hasHibernateManagedTransaction()));
+ }
+
+ protected void doBegin(Object transaction, TransactionDefinition definition) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+
+ if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
+ throw new IllegalTransactionStateException(
+ "Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
+ "running within DataSourceTransactionManager if told to manage the DataSource itself. " +
+ "It is recommended to use a single HibernateTransactionManager for all transactions " +
+ "on a single DataSource, no matter whether Hibernate or JDBC access.");
+ }
+
+ Session session = null;
+
+ try {
+ if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
+ Interceptor entityInterceptor = getEntityInterceptor();
+ Session newSession = (entityInterceptor != null ?
+ getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
+ if (logger.isDebugEnabled()) {
+ logger.debug("Opened new Session [" + SessionFactoryUtils.toString(newSession) +
+ "] for Hibernate transaction");
+ }
+ txObject.setSession(newSession);
+ }
+
+ session = txObject.getSessionHolder().getSession();
+
+ if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
+ // We're allowed to change the transaction settings of the JDBC Connection.
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
+ }
+ Connection con = session.connection();
+ Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
+ txObject.setPreviousIsolationLevel(previousIsolationLevel);
+ }
+ else {
+ // Not allowed to change the transaction settings of the JDBC Connection.
+ if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
+ // We should set a specific isolation level but are not allowed to...
+ throw new InvalidIsolationLevelException(
+ "HibernateTransactionManager is not allowed to support custom isolation levels: " +
+ "make sure that its 'prepareConnection' flag is on (the default) and that the " +
+ "Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " +
+ "Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " +
+ "Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!");
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Not preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]");
+ }
+ }
+
+ if (definition.isReadOnly() && txObject.isNewSession()) {
+ // Just set to NEVER in case of a new Session for this transaction.
+ session.setFlushMode(FlushMode.NEVER);
+ }
+
+ if (!definition.isReadOnly() && !txObject.isNewSession()) {
+ // We need AUTO or COMMIT for a non-read-only transaction.
+ FlushMode flushMode = session.getFlushMode();
+ if (flushMode.lessThan(FlushMode.COMMIT)) {
+ session.setFlushMode(FlushMode.AUTO);
+ txObject.getSessionHolder().setPreviousFlushMode(flushMode);
+ }
+ }
+
+ Transaction hibTx = null;
+
+ // Register transaction timeout.
+ int timeout = determineTimeout(definition);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ // Use Hibernate's own transaction timeout mechanism on Hibernate 3.1
+ // Applies to all statements, also to inserts, updates and deletes!
+ hibTx = session.getTransaction();
+ hibTx.setTimeout(timeout);
+ hibTx.begin();
+ }
+ else {
+ // Open a plain Hibernate transaction without specified timeout.
+ hibTx = session.beginTransaction();
+ }
+
+ // Add the Hibernate transaction to the session holder.
+ txObject.getSessionHolder().setTransaction(hibTx);
+
+ // Register the Hibernate Session's JDBC Connection for the DataSource, if set.
+ if (getDataSource() != null) {
+ Connection con = session.connection();
+ ConnectionHolder conHolder = new ConnectionHolder(con);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ conHolder.setTimeoutInSeconds(timeout);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
+ }
+ TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
+ txObject.setConnectionHolder(conHolder);
+ }
+
+ // Bind the session holder to the thread.
+ if (txObject.isNewSessionHolder()) {
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
+ }
+ txObject.getSessionHolder().setSynchronizedWithTransaction(true);
+ }
+
+ catch (Exception ex) {
+ if (txObject.isNewSession()) {
+ try {
+ if (session.getTransaction().isActive()) {
+ session.getTransaction().rollback();
+ }
+ }
+ catch (Throwable ex2) {
+ logger.debug("Could not rollback Session after failed transaction begin", ex);
+ }
+ finally {
+ SessionFactoryUtils.closeSession(session);
+ }
+ }
+ throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
+ }
+ }
+
+ protected Object doSuspend(Object transaction) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+ txObject.setSessionHolder(null);
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ txObject.setConnectionHolder(null);
+ ConnectionHolder connectionHolder = null;
+ if (getDataSource() != null) {
+ connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
+ }
+ return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
+ }
+
+ protected void doResume(Object transaction, Object suspendedResources) {
+ SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
+ if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
+ // From non-transactional code running in active transaction synchronization
+ // -> can be safely removed, will be closed on transaction completion.
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
+ if (getDataSource() != null) {
+ TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
+ }
+ }
+
+ protected void prepareForCommit(DefaultTransactionStatus status) {
+ if (this.earlyFlushBeforeCommit && status.isNewTransaction()) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
+ Session session = txObject.getSessionHolder().getSession();
+ if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
+ logger.debug("Performing an early flush for Hibernate transaction");
+ try {
+ session.flush();
+ }
+ catch (HibernateException ex) {
+ throw convertHibernateAccessException(ex);
+ }
+ finally {
+ session.setFlushMode(FlushMode.NEVER);
+ }
+ }
+ }
+ }
+
+ protected void doCommit(DefaultTransactionStatus status) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Committing Hibernate transaction on Session [" +
+ SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
+ }
+ try {
+ txObject.getSessionHolder().getTransaction().commit();
+ }
+ catch (org.hibernate.TransactionException ex) {
+ // assumably from commit call to the underlying JDBC connection
+ throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
+ }
+ catch (HibernateException ex) {
+ // assumably failed to flush changes to database
+ throw convertHibernateAccessException(ex);
+ }
+ }
+
+ protected void doRollback(DefaultTransactionStatus status) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Rolling back Hibernate transaction on Session [" +
+ SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "]");
+ }
+ try {
+ txObject.getSessionHolder().getTransaction().rollback();
+ }
+ catch (org.hibernate.TransactionException ex) {
+ throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
+ }
+ catch (HibernateException ex) {
+ // Shouldn't really happen, as a rollback doesn't cause a flush.
+ throw convertHibernateAccessException(ex);
+ }
+ finally {
+ if (!txObject.isNewSession() && !this.hibernateManagedSession) {
+ // Clear all pending inserts/updates/deletes in the Session.
+ // Necessary for pre-bound Sessions, to avoid inconsistent state.
+ txObject.getSessionHolder().getSession().clear();
+ }
+ }
+ }
+
+ protected void doSetRollbackOnly(DefaultTransactionStatus status) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Setting Hibernate transaction on Session [" +
+ SessionFactoryUtils.toString(txObject.getSessionHolder().getSession()) + "] rollback-only");
+ }
+ txObject.setRollbackOnly();
+ }
+
+ protected void doCleanupAfterCompletion(Object transaction) {
+ HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
+
+ // Remove the session holder from the thread.
+ if (txObject.isNewSessionHolder()) {
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+
+ // Remove the JDBC connection holder from the thread, if exposed.
+ if (getDataSource() != null) {
+ TransactionSynchronizationManager.unbindResource(getDataSource());
+ }
+
+ Session session = txObject.getSessionHolder().getSession();
+ if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
+ // We're running with connection release mode "on_close": We're able to reset
+ // the isolation level and/or read-only flag of the JDBC Connection here.
+ // Else, we need to rely on the connection pool to perform proper cleanup.
+ try {
+ Connection con = session.connection();
+ DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
+ }
+ catch (HibernateException ex) {
+ logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
+ }
+ }
+
+ if (txObject.isNewSession()) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Closing Hibernate Session [" + SessionFactoryUtils.toString(session) +
+ "] after transaction");
+ }
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Not closing pre-bound Hibernate Session [" +
+ SessionFactoryUtils.toString(session) + "] after transaction");
+ }
+ if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
+ session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
+ }
+ if (!this.hibernateManagedSession) {
+ session.disconnect();
+ }
+ }
+ txObject.getSessionHolder().clear();
+ }
+
+ /**
+ * Return whether the given Hibernate Session will always hold the same
+ * JDBC Connection. This is used to check whether the transaction manager
+ * can safely prepare and clean up the JDBC Connection used for a transaction.
+ *
Default implementation checks the Session's connection release mode
+ * to be "on_close". Unfortunately, this requires casting to SessionImpl,
+ * as of Hibernate 3.1. If that cast doesn't work, we'll simply assume
+ * we're safe and return true.
+ * @param session the Hibernate Session to check
+ * @see org.hibernate.impl.SessionImpl#getConnectionReleaseMode()
+ * @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
+ */
+ protected boolean isSameConnectionForEntireSession(Session session) {
+ if (!(session instanceof SessionImpl)) {
+ // The best we can do is to assume we're safe.
+ return true;
+ }
+ ConnectionReleaseMode releaseMode = ((SessionImpl) session).getConnectionReleaseMode();
+ return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
+ }
+
+
+ /**
+ * Convert the given HibernateException to an appropriate exception
+ * from the org.springframework.dao hierarchy.
+ *
Will automatically apply a specified SQLExceptionTranslator to a
+ * Hibernate JDBCException, else rely on Hibernate's default translation.
+ * @param ex HibernateException that occured
+ * @return a corresponding DataAccessException
+ * @see SessionFactoryUtils#convertHibernateAccessException
+ * @see #setJdbcExceptionTranslator
+ */
+ protected DataAccessException convertHibernateAccessException(HibernateException ex) {
+ if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
+ return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
+ }
+ else if (GenericJDBCException.class.equals(ex.getClass())) {
+ return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
+ }
+ return SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+
+ /**
+ * Convert the given Hibernate JDBCException to an appropriate exception
+ * from the org.springframework.dao hierarchy, using the
+ * given SQLExceptionTranslator.
+ * @param ex Hibernate JDBCException that occured
+ * @param translator the SQLExceptionTranslator to use
+ * @return a corresponding DataAccessException
+ */
+ protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
+ return translator.translate("Hibernate flushing: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
+ }
+
+ /**
+ * Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
+ *
Creates a default
+ * {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
+ * for the SessionFactory's underlying DataSource.
+ */
+ protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
+ if (this.defaultJdbcExceptionTranslator == null) {
+ if (getDataSource() != null) {
+ this.defaultJdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(getDataSource());
+ }
+ else {
+ this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
+ }
+ }
+ return this.defaultJdbcExceptionTranslator;
+ }
+
+
+ /**
+ * Hibernate transaction object, representing a SessionHolder.
+ * Used as transaction object by HibernateTransactionManager.
+ */
+ private static class HibernateTransactionObject extends JdbcTransactionObjectSupport {
+
+ private SessionHolder sessionHolder;
+
+ private boolean newSessionHolder;
+
+ private boolean newSession;
+
+ public void setSession(Session session) {
+ this.sessionHolder = new SessionHolder(session);
+ this.newSessionHolder = true;
+ this.newSession = true;
+ }
+
+ public void setExistingSession(Session session) {
+ this.sessionHolder = new SessionHolder(session);
+ this.newSessionHolder = true;
+ this.newSession = false;
+ }
+
+ public void setSessionHolder(SessionHolder sessionHolder) {
+ this.sessionHolder = sessionHolder;
+ this.newSessionHolder = false;
+ this.newSession = false;
+ }
+
+ public SessionHolder getSessionHolder() {
+ return this.sessionHolder;
+ }
+
+ public boolean isNewSessionHolder() {
+ return this.newSessionHolder;
+ }
+
+ public boolean isNewSession() {
+ return this.newSession;
+ }
+
+ public boolean hasSpringManagedTransaction() {
+ return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
+ }
+
+ public boolean hasHibernateManagedTransaction() {
+ return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
+ }
+
+ public void setRollbackOnly() {
+ getSessionHolder().setRollbackOnly();
+ if (hasConnectionHolder()) {
+ getConnectionHolder().setRollbackOnly();
+ }
+ }
+
+ public boolean isRollbackOnly() {
+ return getSessionHolder().isRollbackOnly() ||
+ (hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
+ }
+ }
+
+
+ /**
+ * Holder for suspended resources.
+ * Used internally by doSuspend and doResume.
+ */
+ private static class SuspendedResourcesHolder {
+
+ private final SessionHolder sessionHolder;
+
+ private final ConnectionHolder connectionHolder;
+
+ private SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) {
+ this.sessionHolder = sessionHolder;
+ this.connectionHolder = conHolder;
+ }
+
+ private SessionHolder getSessionHolder() {
+ return this.sessionHolder;
+ }
+
+ private ConnectionHolder getConnectionHolder() {
+ return this.connectionHolder;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.util.Properties;
+
+import org.hibernate.cache.Cache;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CacheProvider;
+
+/**
+ * Proxy for a Hibernate CacheProvider, delegating to a Spring-managed
+ * CacheProvider instance, determined by LocalSessionFactoryBean's
+ * "cacheProvider" property.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.1
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setCacheProvider
+ */
+public class LocalCacheProviderProxy implements CacheProvider {
+
+ private final CacheProvider cacheProvider;
+
+
+ public LocalCacheProviderProxy() {
+ CacheProvider cp = LocalSessionFactoryBean.getConfigTimeCacheProvider();
+ // absolutely needs thread-bound CacheProvider to initialize
+ if (cp == null) {
+ throw new IllegalStateException("No Hibernate CacheProvider found - " +
+ "'cacheProvider' property must be set on LocalSessionFactoryBean");
+ }
+ this.cacheProvider = cp;
+ }
+
+
+ public Cache buildCache(String regionName, Properties properties) throws CacheException {
+ return this.cacheProvider.buildCache(regionName, properties);
+ }
+
+ public long nextTimestamp() {
+ return this.cacheProvider.nextTimestamp();
+ }
+
+ public void start(Properties properties) throws CacheException {
+ this.cacheProvider.start(properties);
+ }
+
+ public void stop() {
+ this.cacheProvider.stop();
+ }
+
+ public boolean isMinimalPutsEnabledByDefault() {
+ return this.cacheProvider.isMinimalPutsEnabledByDefault();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.hibernate.HibernateException;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.util.JDBCExceptionReporter;
+
+/**
+ * Hibernate connection provider for local DataSource instances
+ * in an application context. This provider will be used if
+ * LocalSessionFactoryBean's "dataSource" property is set
+ * without a Hibernate TransactionManagerLookup.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see LocalSessionFactoryBean#setDataSource
+ */
+public class LocalDataSourceConnectionProvider implements ConnectionProvider {
+
+ private DataSource dataSource;
+
+ private DataSource dataSourceToUse;
+
+
+ public void configure(Properties props) throws HibernateException {
+ this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource();
+ // absolutely needs thread-bound DataSource to initialize
+ if (this.dataSource == null) {
+ throw new HibernateException("No local DataSource found for configuration - " +
+ "'dataSource' property must be set on LocalSessionFactoryBean");
+ }
+ this.dataSourceToUse = getDataSourceToUse(this.dataSource);
+ }
+
+ /**
+ * Return the DataSource to use for retrieving Connections.
+ *
This implementation returns the passed-in DataSource as-is.
+ * @param originalDataSource the DataSource as configured by the user
+ * on LocalSessionFactoryBean
+ * @return the DataSource to actually retrieve Connections from
+ * (potentially wrapped)
+ * @see LocalSessionFactoryBean#setDataSource
+ */
+ protected DataSource getDataSourceToUse(DataSource originalDataSource) {
+ return originalDataSource;
+ }
+
+ /**
+ * Return the DataSource that this ConnectionProvider wraps.
+ */
+ public DataSource getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * This implementation delegates to the underlying DataSource.
+ * @see javax.sql.DataSource#getConnection()
+ */
+ public Connection getConnection() throws SQLException {
+ try {
+ return this.dataSourceToUse.getConnection();
+ }
+ catch (SQLException ex) {
+ JDBCExceptionReporter.logExceptions(ex);
+ throw ex;
+ }
+ }
+
+ /**
+ * This implementation simply calls Connection.close.
+ * @see java.sql.Connection#close()
+ */
+ public void closeConnection(Connection con) throws SQLException {
+ try {
+ con.close();
+ }
+ catch (SQLException ex) {
+ JDBCExceptionReporter.logExceptions(ex);
+ throw ex;
+ }
+ }
+
+ /**
+ * This implementation does nothing:
+ * We're dealing with an externally managed DataSource.
+ */
+ public void close() {
+ }
+
+ /**
+ * This implementation returns false: We cannot guarantee
+ * to receive the same Connection within a transaction, not even when
+ * dealing with a JNDI DataSource.
+ */
+ public boolean supportsAggressiveRelease() {
+ return false;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+/**
+ * Subclass of LocalDataSourceConnectionProvider that will be used
+ * if LocalSessionFactoryBean's "dataSource" property is set
+ * in combination with a Hibernate TransactionManagerLookup.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.1
+ */
+public class LocalJtaDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
+
+ /**
+ * This implementation returns true,
+ * since we're assuming a JTA DataSource.
+ */
+ public boolean supportsAggressiveRelease() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,1024 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.cache.CacheProvider;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.event.EventListeners;
+import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
+import org.hibernate.transaction.JTATransactionFactory;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.jdbc.support.JdbcUtils;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that creates a
+ * Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to
+ * set up a shared Hibernate SessionFactory in a Spring application context;
+ * the SessionFactory can then be passed to Hibernate-based DAOs via
+ * dependency injection.
+ *
+ *
Configuration settings can either be read from a Hibernate XML file,
+ * specified as "configLocation", or completely via this class. A typical
+ * local configuration consists of one or more "mappingResources", various
+ * "hibernateProperties" (not strictly necessary), and a "dataSource" that the
+ * SessionFactory should use. The latter can also be specified via Hibernate
+ * properties, but "dataSource" supports any Spring-configured DataSource,
+ * instead of relying on Hibernate's own connection providers.
+ *
+ *
This SessionFactory handling strategy is appropriate for most types of
+ * applications, from Hibernate-only single database apps to ones that need
+ * distributed transactions. Either {@link HibernateTransactionManager} or
+ * {@link org.springframework.transaction.jta.JtaTransactionManager} can be
+ * used for transaction demarcation, with the latter only necessary for
+ * transactions which span multiple databases.
+ *
+ *
This factory bean will by default expose a transaction-aware SessionFactory
+ * proxy, letting data access code work with the plain Hibernate SessionFactory
+ * and its getCurrentSession() method, while still being able to
+ * participate in current Spring-managed transactions: with any transaction
+ * management strategy, either local or JTA / EJB CMT, and any transaction
+ * synchronization mechanism, either Spring or JTA. Furthermore,
+ * getCurrentSession() will also seamlessly work with
+ * a request-scoped Session managed by
+ * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter} /
+ * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
+ *
+ *
Requires Hibernate 3.1 or later. Note that this factory will use
+ * "on_close" as default Hibernate connection release mode, unless in the
+ * case of a "jtaTransactionManager" specified, for the reason that
+ * this is appropriate for most Spring-based applications (in particular when
+ * using Spring's HibernateTransactionManager). Hibernate 3.0 used "on_close"
+ * as its own default too; however, Hibernate 3.1 changed this to "auto"
+ * (i.e. "after_statement" or "after_transaction").
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see HibernateTemplate#setSessionFactory
+ * @see HibernateTransactionManager#setSessionFactory
+ * @see #setExposeTransactionAwareSessionFactory
+ * @see #setJtaTransactionManager
+ * @see org.hibernate.SessionFactory#getCurrentSession()
+ * @see HibernateTransactionManager
+ */
+public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implements BeanClassLoaderAware {
+
+ private static final ThreadLocal configTimeDataSourceHolder = new ThreadLocal();
+
+ private static final ThreadLocal configTimeTransactionManagerHolder = new ThreadLocal();
+
+ private static final ThreadLocal configTimeCacheProviderHolder = new ThreadLocal();
+
+ private static final ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
+
+ /**
+ * Return the DataSource for the currently configured Hibernate SessionFactory,
+ * to be used by LocalDataSourceConnectionProvoder.
+ *
This instance will be set before initialization of the corresponding
+ * SessionFactory, and reset immediately afterwards. It is thus only available
+ * during configuration.
+ * @see #setDataSource
+ * @see LocalDataSourceConnectionProvider
+ */
+ public static DataSource getConfigTimeDataSource() {
+ return (DataSource) configTimeDataSourceHolder.get();
+ }
+
+ /**
+ * Return the JTA TransactionManager for the currently configured Hibernate
+ * SessionFactory, to be used by LocalTransactionManagerLookup.
+ *
This instance will be set before initialization of the corresponding
+ * SessionFactory, and reset immediately afterwards. It is thus only available
+ * during configuration.
+ * @see #setJtaTransactionManager
+ * @see LocalTransactionManagerLookup
+ */
+ public static TransactionManager getConfigTimeTransactionManager() {
+ return (TransactionManager) configTimeTransactionManagerHolder.get();
+ }
+
+ /**
+ * Return the CacheProvider for the currently configured Hibernate SessionFactory,
+ * to be used by LocalCacheProviderProxy.
+ *
This instance will be set before initialization of the corresponding
+ * SessionFactory, and reset immediately afterwards. It is thus only available
+ * during configuration.
+ * @see #setCacheProvider
+ */
+ public static CacheProvider getConfigTimeCacheProvider() {
+ return (CacheProvider) configTimeCacheProviderHolder.get();
+ }
+
+ /**
+ * Return the LobHandler for the currently configured Hibernate SessionFactory,
+ * to be used by UserType implementations like ClobStringType.
+ *
This instance will be set before initialization of the corresponding
+ * SessionFactory, and reset immediately afterwards. It is thus only available
+ * during configuration.
+ * @see #setLobHandler
+ * @see org.springframework.orm.hibernate3.support.ClobStringType
+ * @see org.springframework.orm.hibernate3.support.BlobByteArrayType
+ * @see org.springframework.orm.hibernate3.support.BlobSerializableType
+ */
+ public static LobHandler getConfigTimeLobHandler() {
+ return (LobHandler) configTimeLobHandlerHolder.get();
+ }
+
+
+ private Class configurationClass = Configuration.class;
+
+ private Resource[] configLocations;
+
+ private String[] mappingResources;
+
+ private Resource[] mappingLocations;
+
+ private Resource[] cacheableMappingLocations;
+
+ private Resource[] mappingJarLocations;
+
+ private Resource[] mappingDirectoryLocations;
+
+ private Properties hibernateProperties;
+
+ private TransactionManager jtaTransactionManager;
+
+ private CacheProvider cacheProvider;
+
+ private LobHandler lobHandler;
+
+ private Interceptor entityInterceptor;
+
+ private NamingStrategy namingStrategy;
+
+ private TypeDefinitionBean[] typeDefinitions;
+
+ private FilterDefinition[] filterDefinitions;
+
+ private Properties entityCacheStrategies;
+
+ private Properties collectionCacheStrategies;
+
+ private Map eventListeners;
+
+ private boolean schemaUpdate = false;
+
+ private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
+
+ private Configuration configuration;
+
+
+ /**
+ * Specify the Hibernate Configuration class to use.
+ * Default is "org.hibernate.cfg.Configuration"; any subclass of
+ * this default Hibernate Configuration class can be specified.
+ *
Can be set to "org.hibernate.cfg.AnnotationConfiguration" for
+ * using Hibernate3 annotation support (initially only available as
+ * alpha download separate from the main Hibernate3 distribution).
+ *
Annotated packages and annotated classes can be specified via the
+ * corresponding tags in "hibernate.cfg.xml" then, so this will usually
+ * be combined with a "configLocation" property that points at such a
+ * standard Hibernate configuration file.
+ * @see #setConfigLocation
+ * @see org.hibernate.cfg.Configuration
+ * @see org.hibernate.cfg.AnnotationConfiguration
+ */
+ public void setConfigurationClass(Class configurationClass) {
+ if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
+ throw new IllegalArgumentException(
+ "configurationClass must be assignable to [org.hibernate.cfg.Configuration]");
+ }
+ this.configurationClass = configurationClass;
+ }
+
+ /**
+ * Set the location of a single Hibernate XML config file, for example as
+ * classpath resource "classpath:hibernate.cfg.xml".
+ *
Note: Can be omitted when all necessary properties and mapping
+ * resources are specified locally via this bean.
+ * @see org.hibernate.cfg.Configuration#configure(java.net.URL)
+ */
+ public void setConfigLocation(Resource configLocation) {
+ this.configLocations = new Resource[] {configLocation};
+ }
+
+ /**
+ * Set the locations of multiple Hibernate XML config files, for example as
+ * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
+ *
Note: Can be omitted when all necessary properties and mapping
+ * resources are specified locally via this bean.
+ * @see org.hibernate.cfg.Configuration#configure(java.net.URL)
+ */
+ public void setConfigLocations(Resource[] configLocations) {
+ this.configLocations = configLocations;
+ }
+
+ /**
+ * Set Hibernate mapping resources to be found in the class path,
+ * like "example.hbm.xml" or "mypackage/example.hbm.xml".
+ * Analogous to mapping entries in a Hibernate XML config file.
+ * Alternative to the more generic setMappingLocations method.
+ *
Can be used to add to mappings from a Hibernate XML config file,
+ * or to specify all mappings locally.
+ * @see #setMappingLocations
+ * @see org.hibernate.cfg.Configuration#addResource
+ */
+ public void setMappingResources(String[] mappingResources) {
+ this.mappingResources = mappingResources;
+ }
+
+ /**
+ * Set locations of Hibernate mapping files, for example as classpath
+ * resource "classpath:example.hbm.xml". Supports any resource location
+ * via Spring's resource abstraction, for example relative paths like
+ * "WEB-INF/mappings/example.hbm.xml" when running in an application context.
+ *
Can be used to add to mappings from a Hibernate XML config file,
+ * or to specify all mappings locally.
+ * @see org.hibernate.cfg.Configuration#addInputStream
+ */
+ public void setMappingLocations(Resource[] mappingLocations) {
+ this.mappingLocations = mappingLocations;
+ }
+
+ /**
+ * Set locations of cacheable Hibernate mapping files, for example as web app
+ * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
+ * via Spring's resource abstraction, as long as the resource can be resolved
+ * in the file system.
+ *
Can be used to add to mappings from a Hibernate XML config file,
+ * or to specify all mappings locally.
+ * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File)
+ */
+ public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) {
+ this.cacheableMappingLocations = cacheableMappingLocations;
+ }
+
+ /**
+ * Set locations of jar files that contain Hibernate mapping resources,
+ * like "WEB-INF/lib/example.hbm.jar".
+ *
Can be used to add to mappings from a Hibernate XML config file,
+ * or to specify all mappings locally.
+ * @see org.hibernate.cfg.Configuration#addJar(java.io.File)
+ */
+ public void setMappingJarLocations(Resource[] mappingJarLocations) {
+ this.mappingJarLocations = mappingJarLocations;
+ }
+
+ /**
+ * Set locations of directories that contain Hibernate mapping resources,
+ * like "WEB-INF/mappings".
+ *
Can be used to add to mappings from a Hibernate XML config file,
+ * or to specify all mappings locally.
+ * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File)
+ */
+ public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
+ this.mappingDirectoryLocations = mappingDirectoryLocations;
+ }
+
+ /**
+ * Set Hibernate properties, such as "hibernate.dialect".
+ *
Can be used to override values in a Hibernate XML config file,
+ * or to specify all necessary properties locally.
+ *
Note: Do not specify a transaction provider here when using
+ * Spring-driven transactions. It is also advisable to omit connection
+ * provider settings and use a Spring-set DataSource instead.
+ * @see #setDataSource
+ */
+ public void setHibernateProperties(Properties hibernateProperties) {
+ this.hibernateProperties = hibernateProperties;
+ }
+
+ /**
+ * Return the Hibernate properties, if any. Mainly available for
+ * configuration through property paths that specify individual keys.
+ */
+ public Properties getHibernateProperties() {
+ if (this.hibernateProperties == null) {
+ this.hibernateProperties = new Properties();
+ }
+ return this.hibernateProperties;
+ }
+
+ /**
+ * Set the JTA TransactionManager to be used for Hibernate's
+ * TransactionManagerLookup. Allows for using a Spring-managed
+ * JTA TransactionManager for Hibernate's cache synchronization.
+ *
Note: If this is set, the Hibernate settings should not define a
+ * transaction manager lookup to avoid meaningless double configuration.
+ * @see LocalTransactionManagerLookup
+ */
+ public void setJtaTransactionManager(TransactionManager jtaTransactionManager) {
+ this.jtaTransactionManager = jtaTransactionManager;
+ }
+
+ /**
+ * Set the Hibernate CacheProvider to use for the SessionFactory.
+ * Allows for using a Spring-managed CacheProvider instance.
+ *
Note: If this is set, the Hibernate settings should not define a
+ * cache provider to avoid meaningless double configuration.
+ * @see LocalCacheProviderProxy
+ */
+ public void setCacheProvider(CacheProvider cacheProvider) {
+ this.cacheProvider = cacheProvider;
+ }
+
+ /**
+ * Set the LobHandler to be used by the SessionFactory.
+ * Will be exposed at config time for UserType implementations.
+ * @see #getConfigTimeLobHandler
+ * @see org.hibernate.usertype.UserType
+ * @see org.springframework.orm.hibernate3.support.ClobStringType
+ * @see org.springframework.orm.hibernate3.support.BlobByteArrayType
+ * @see org.springframework.orm.hibernate3.support.BlobSerializableType
+ */
+ public void setLobHandler(LobHandler lobHandler) {
+ this.lobHandler = lobHandler;
+ }
+
+ /**
+ * Set a Hibernate entity interceptor that allows to inspect and change
+ * property values before writing to and reading from the database.
+ * Will get applied to any new Session created by this factory.
+ *
Such an interceptor can either be set at the SessionFactory level, i.e. on
+ * LocalSessionFactoryBean, or at the Session level, i.e. on HibernateTemplate,
+ * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set
+ * it on LocalSessionFactoryBean or HibernateTransactionManager to avoid repeated
+ * configuration and guarantee consistent behavior in transactions.
+ * @see HibernateTemplate#setEntityInterceptor
+ * @see HibernateInterceptor#setEntityInterceptor
+ * @see HibernateTransactionManager#setEntityInterceptor
+ * @see org.hibernate.cfg.Configuration#setInterceptor
+ */
+ public void setEntityInterceptor(Interceptor entityInterceptor) {
+ this.entityInterceptor = entityInterceptor;
+ }
+
+ /**
+ * Set a Hibernate NamingStrategy for the SessionFactory, determining the
+ * physical column and table names given the info in the mapping document.
+ * @see org.hibernate.cfg.Configuration#setNamingStrategy
+ */
+ public void setNamingStrategy(NamingStrategy namingStrategy) {
+ this.namingStrategy = namingStrategy;
+ }
+
+ /**
+ * Specify the Hibernate type definitions to register with the SessionFactory,
+ * as Spring TypeDefinitionBean instances. This is an alternative to specifying
+ * <<typedef> elements in Hibernate mapping files.
+ *
Unfortunately, Hibernate itself does not define a complete object that
+ * represents a type definition, hence the need for Spring's TypeDefinitionBean.
+ * @see TypeDefinitionBean
+ * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
+ */
+ public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) {
+ this.typeDefinitions = typeDefinitions;
+ }
+
+ /**
+ * Specify the Hibernate FilterDefinitions to register with the SessionFactory.
+ * This is an alternative to specifying <<filter-def> elements in
+ * Hibernate mapping files.
+ *
Typically, the passed-in FilterDefinition objects will have been defined
+ * as Spring FilterDefinitionFactoryBeans, probably as inner beans within the
+ * LocalSessionFactoryBean definition.
+ * @see FilterDefinitionFactoryBean
+ * @see org.hibernate.cfg.Configuration#addFilterDefinition
+ */
+ public void setFilterDefinitions(FilterDefinition[] filterDefinitions) {
+ this.filterDefinitions = filterDefinitions;
+ }
+
+ /**
+ * Specify the cache strategies for entities (persistent classes or named entities).
+ * This configuration setting corresponds to the <class-cache> entry
+ * in the "hibernate.cfg.xml" configuration format.
+ *
+ * Note that appending a cache region name (with a comma separator) is only
+ * supported on Hibernate 3.1, where this functionality is publically available.
+ * @param entityCacheStrategies properties that define entity cache strategies,
+ * with class names as keys and cache concurrency strategies as values
+ * @see org.hibernate.cfg.Configuration#setCacheConcurrencyStrategy(String, String)
+ */
+ public void setEntityCacheStrategies(Properties entityCacheStrategies) {
+ this.entityCacheStrategies = entityCacheStrategies;
+ }
+
+ /**
+ * Specify the cache strategies for persistent collections (with specific roles).
+ * This configuration setting corresponds to the <collection-cache> entry
+ * in the "hibernate.cfg.xml" configuration format.
+ *
+ * Note that appending a cache region name (with a comma separator) is only
+ * supported on Hibernate 3.1, where this functionality is publically available.
+ * @param collectionCacheStrategies properties that define collection cache strategies,
+ * with collection roles as keys and cache concurrency strategies as values
+ * @see org.hibernate.cfg.Configuration#setCollectionCacheConcurrencyStrategy(String, String)
+ */
+ public void setCollectionCacheStrategies(Properties collectionCacheStrategies) {
+ this.collectionCacheStrategies = collectionCacheStrategies;
+ }
+
+ /**
+ * Specify the Hibernate event listeners to register, with listener types
+ * as keys and listener objects as values.
+ *
Instead of a single listener object, you can also pass in a list
+ * or set of listeners objects as value. However, this is only supported
+ * on Hibernate 3.1.
+ *
See the Hibernate documentation for further details on listener types
+ * and associated listener interfaces.
+ * @param eventListeners Map with listener type Strings as keys and
+ * listener objects as values
+ * @see org.hibernate.cfg.Configuration#setListener(String, Object)
+ */
+ public void setEventListeners(Map eventListeners) {
+ this.eventListeners = eventListeners;
+ }
+
+ /**
+ * Set whether to execute a schema update after SessionFactory initialization.
+ *
For details on how to make schema update scripts work, see the Hibernate
+ * documentation, as this class leverages the same schema update script support
+ * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
+ * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
+ * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
+ */
+ public void setSchemaUpdate(boolean schemaUpdate) {
+ this.schemaUpdate = schemaUpdate;
+ }
+
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ this.beanClassLoader = beanClassLoader;
+ }
+
+
+ protected SessionFactory buildSessionFactory() throws Exception {
+ // Create Configuration instance.
+ Configuration config = newConfiguration();
+
+ DataSource dataSource = getDataSource();
+ if (dataSource != null) {
+ // Make given DataSource available for SessionFactory configuration.
+ configTimeDataSourceHolder.set(dataSource);
+ }
+ if (this.jtaTransactionManager != null) {
+ // Make Spring-provided JTA TransactionManager available.
+ configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
+ }
+ if (this.cacheProvider != null) {
+ // Make Spring-provided Hibernate CacheProvider available.
+ configTimeCacheProviderHolder.set(this.cacheProvider);
+ }
+ if (this.lobHandler != null) {
+ // Make given LobHandler available for SessionFactory configuration.
+ // Do early because because mapping resource might refer to custom types.
+ configTimeLobHandlerHolder.set(this.lobHandler);
+ }
+
+ // Analogous to Hibernate EntityManager's Ejb3Configuration:
+ // Hibernate doesn't allow setting the bean ClassLoader explicitly,
+ // so we need to expose it as thread context ClassLoader accordingly.
+ Thread currentThread = Thread.currentThread();
+ ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
+ boolean overrideClassLoader =
+ (this.beanClassLoader != null && !this.beanClassLoader.equals(threadContextClassLoader));
+ if (overrideClassLoader) {
+ currentThread.setContextClassLoader(this.beanClassLoader);
+ }
+
+ try {
+ if (isExposeTransactionAwareSessionFactory()) {
+ // Set Hibernate 3.1 CurrentSessionContext implementation,
+ // providing the Spring-managed Session as current Session.
+ // Can be overridden by a custom value for the corresponding Hibernate property.
+ config.setProperty(
+ Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
+ }
+
+ if (this.jtaTransactionManager != null) {
+ // Set Spring-provided JTA TransactionManager as Hibernate property.
+ config.setProperty(
+ Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
+ config.setProperty(
+ Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
+ }
+ else {
+ // Makes the Hibernate Session aware of the presence of a Spring-managed transaction.
+ // Also sets connection release mode to ON_CLOSE by default.
+ config.setProperty(
+ Environment.TRANSACTION_STRATEGY, SpringTransactionFactory.class.getName());
+ }
+
+ if (this.entityInterceptor != null) {
+ // Set given entity interceptor at SessionFactory level.
+ config.setInterceptor(this.entityInterceptor);
+ }
+
+ if (this.namingStrategy != null) {
+ // Pass given naming strategy to Hibernate Configuration.
+ config.setNamingStrategy(this.namingStrategy);
+ }
+
+ if (this.typeDefinitions != null) {
+ // Register specified Hibernate type definitions.
+ Mappings mappings = config.createMappings();
+ for (int i = 0; i < this.typeDefinitions.length; i++) {
+ TypeDefinitionBean typeDef = this.typeDefinitions[i];
+ mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
+ }
+ }
+
+ if (this.filterDefinitions != null) {
+ // Register specified Hibernate FilterDefinitions.
+ for (int i = 0; i < this.filterDefinitions.length; i++) {
+ config.addFilterDefinition(this.filterDefinitions[i]);
+ }
+ }
+
+ if (this.configLocations != null) {
+ for (int i = 0; i < this.configLocations.length; i++) {
+ // Load Hibernate configuration from given location.
+ config.configure(this.configLocations[i].getURL());
+ }
+ }
+
+ if (this.hibernateProperties != null) {
+ // Add given Hibernate properties to Configuration.
+ config.addProperties(this.hibernateProperties);
+ }
+
+ if (dataSource != null) {
+ Class providerClass = LocalDataSourceConnectionProvider.class;
+ if (isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy) {
+ providerClass = TransactionAwareDataSourceConnectionProvider.class;
+ }
+ else if (config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY) != null) {
+ providerClass = LocalJtaDataSourceConnectionProvider.class;
+ }
+ // Set Spring-provided DataSource as Hibernate ConnectionProvider.
+ config.setProperty(Environment.CONNECTION_PROVIDER, providerClass.getName());
+ }
+
+ if (this.cacheProvider != null) {
+ // Expose Spring-provided Hibernate CacheProvider.
+ config.setProperty(Environment.CACHE_PROVIDER, LocalCacheProviderProxy.class.getName());
+ }
+
+ if (this.mappingResources != null) {
+ // Register given Hibernate mapping definitions, contained in resource files.
+ for (int i = 0; i < this.mappingResources.length; i++) {
+ Resource resource = new ClassPathResource(this.mappingResources[i].trim(), this.beanClassLoader);
+ config.addInputStream(resource.getInputStream());
+ }
+ }
+
+ if (this.mappingLocations != null) {
+ // Register given Hibernate mapping definitions, contained in resource files.
+ for (int i = 0; i < this.mappingLocations.length; i++) {
+ config.addInputStream(this.mappingLocations[i].getInputStream());
+ }
+ }
+
+ if (this.cacheableMappingLocations != null) {
+ // Register given cacheable Hibernate mapping definitions, read from the file system.
+ for (int i = 0; i < this.cacheableMappingLocations.length; i++) {
+ config.addCacheableFile(this.cacheableMappingLocations[i].getFile());
+ }
+ }
+
+ if (this.mappingJarLocations != null) {
+ // Register given Hibernate mapping definitions, contained in jar files.
+ for (int i = 0; i < this.mappingJarLocations.length; i++) {
+ Resource resource = this.mappingJarLocations[i];
+ config.addJar(resource.getFile());
+ }
+ }
+
+ if (this.mappingDirectoryLocations != null) {
+ // Register all Hibernate mapping definitions in the given directories.
+ for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
+ File file = this.mappingDirectoryLocations[i].getFile();
+ if (!file.isDirectory()) {
+ throw new IllegalArgumentException(
+ "Mapping directory location [" + this.mappingDirectoryLocations[i] +
+ "] does not denote a directory");
+ }
+ config.addDirectory(file);
+ }
+ }
+
+ // Tell Hibernate to eagerly compile the mappings that we registered,
+ // for availability of the mapping information in further processing.
+ postProcessMappings(config);
+ config.buildMappings();
+
+ if (this.entityCacheStrategies != null) {
+ // Register cache strategies for mapped entities.
+ for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
+ String className = (String) classNames.nextElement();
+ String[] strategyAndRegion =
+ StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className));
+ if (strategyAndRegion.length > 1) {
+ config.setCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]);
+ }
+ else if (strategyAndRegion.length > 0) {
+ config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);
+ }
+ }
+ }
+
+ if (this.collectionCacheStrategies != null) {
+ // Register cache strategies for mapped collections.
+ for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
+ String collRole = (String) collRoles.nextElement();
+ String[] strategyAndRegion =
+ StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole));
+ if (strategyAndRegion.length > 1) {
+ config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]);
+ }
+ else if (strategyAndRegion.length > 0) {
+ config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);
+ }
+ }
+ }
+
+ if (this.eventListeners != null) {
+ // Register specified Hibernate event listeners.
+ for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");
+ String listenerType = (String) entry.getKey();
+ Object listenerObject = entry.getValue();
+ if (listenerObject instanceof Collection) {
+ Collection listeners = (Collection) listenerObject;
+ EventListeners listenerRegistry = config.getEventListeners();
+ Object[] listenerArray =
+ (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
+ listenerArray = listeners.toArray(listenerArray);
+ config.setListeners(listenerType, listenerArray);
+ }
+ else {
+ config.setListener(listenerType, listenerObject);
+ }
+ }
+ }
+
+ // Perform custom post-processing in subclasses.
+ postProcessConfiguration(config);
+
+ // Build SessionFactory instance.
+ logger.info("Building new Hibernate SessionFactory");
+ this.configuration = config;
+ return newSessionFactory(config);
+ }
+
+ finally {
+ if (dataSource != null) {
+ // Reset DataSource holder.
+ configTimeDataSourceHolder.set(null);
+ }
+ if (this.jtaTransactionManager != null) {
+ // Reset TransactionManager holder.
+ configTimeTransactionManagerHolder.set(null);
+ }
+ if (this.cacheProvider != null) {
+ // Reset CacheProvider holder.
+ configTimeCacheProviderHolder.set(null);
+ }
+ if (this.lobHandler != null) {
+ // Reset LobHandler holder.
+ configTimeLobHandlerHolder.set(null);
+ }
+ if (overrideClassLoader) {
+ // Reset original thread context ClassLoader.
+ currentThread.setContextClassLoader(threadContextClassLoader);
+ }
+ }
+ }
+
+ /**
+ * Subclasses can override this method to perform custom initialization
+ * of the Configuration instance used for SessionFactory creation.
+ * The properties of this LocalSessionFactoryBean will be applied to
+ * the Configuration object that gets returned here.
+ *
The default implementation creates a new Configuration instance.
+ * A custom implementation could prepare the instance in a specific way,
+ * or use a custom Configuration subclass.
+ * @return the Configuration instance
+ * @throws HibernateException in case of Hibernate initialization errors
+ * @see org.hibernate.cfg.Configuration#Configuration()
+ */
+ protected Configuration newConfiguration() throws HibernateException {
+ return (Configuration) BeanUtils.instantiateClass(this.configurationClass);
+ }
+
+ /**
+ * To be implemented by subclasses that want to to register further mappings
+ * on the Configuration object after this FactoryBean registered its specified
+ * mappings.
+ *
Invoked before the Configuration.buildMappings() call,
+ * so that it can still extend and modify the mapping information.
+ * @param config the current Configuration object
+ * @throws HibernateException in case of Hibernate initialization errors
+ * @see org.hibernate.cfg.Configuration#buildMappings()
+ */
+ protected void postProcessMappings(Configuration config) throws HibernateException {
+ }
+
+ /**
+ * To be implemented by subclasses that want to to perform custom
+ * post-processing of the Configuration object after this FactoryBean
+ * performed its default initialization.
+ *
Invoked after the Configuration.buildMappings() call,
+ * so that it can operate on the completed and fully parsed mapping information.
+ * @param config the current Configuration object
+ * @throws HibernateException in case of Hibernate initialization errors
+ * @see org.hibernate.cfg.Configuration#buildMappings()
+ */
+ protected void postProcessConfiguration(Configuration config) throws HibernateException {
+ }
+
+ /**
+ * Subclasses can override this method to perform custom initialization
+ * of the SessionFactory instance, creating it via the given Configuration
+ * object that got prepared by this LocalSessionFactoryBean.
+ *
The default implementation invokes Configuration's buildSessionFactory.
+ * A custom implementation could prepare the instance in a specific way,
+ * or use a custom SessionFactoryImpl subclass.
+ * @param config Configuration prepared by this LocalSessionFactoryBean
+ * @return the SessionFactory instance
+ * @throws HibernateException in case of Hibernate initialization errors
+ * @see org.hibernate.cfg.Configuration#buildSessionFactory
+ */
+ protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
+ return config.buildSessionFactory();
+ }
+
+ /**
+ * Return the Configuration object used to build the SessionFactory.
+ * Allows access to configuration metadata stored there (rarely needed).
+ * @throws IllegalStateException if the Configuration object has not been initialized yet
+ */
+ public final Configuration getConfiguration() {
+ if (this.configuration == null) {
+ throw new IllegalStateException("Configuration not initialized yet");
+ }
+ return this.configuration;
+ }
+
+ /**
+ * Executes schema update if requested.
+ * @see #setSchemaUpdate
+ * @see #updateDatabaseSchema()
+ */
+ protected void afterSessionFactoryCreation() throws Exception {
+ if (this.schemaUpdate) {
+ DataSource dataSource = getDataSource();
+ if (dataSource != null) {
+ // Make given DataSource available for the schema update,
+ // which unfortunately reinstantiates a ConnectionProvider.
+ configTimeDataSourceHolder.set(dataSource);
+ }
+ try {
+ updateDatabaseSchema();
+ }
+ finally {
+ if (dataSource != null) {
+ // Reset DataSource holder.
+ configTimeDataSourceHolder.set(null);
+ }
+ }
+ }
+ }
+
+ /**
+ * Allows for schema export on shutdown.
+ */
+ public void destroy() throws HibernateException {
+ DataSource dataSource = getDataSource();
+ if (dataSource != null) {
+ // Make given DataSource available for potential SchemaExport,
+ // which unfortunately reinstantiates a ConnectionProvider.
+ configTimeDataSourceHolder.set(dataSource);
+ }
+ try {
+ super.destroy();
+ }
+ finally {
+ if (dataSource != null) {
+ // Reset DataSource holder.
+ configTimeDataSourceHolder.set(null);
+ }
+ }
+ }
+
+
+ /**
+ * Execute schema drop script, determined by the Configuration object
+ * used for creating the SessionFactory. A replacement for Hibernate's
+ * SchemaExport class, to be invoked on application setup.
+ *
Fetch the LocalSessionFactoryBean itself rather than the exposed
+ * SessionFactory to be able to invoke this method, e.g. via
+ * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");.
+ *
Uses the SessionFactory that this bean generates for accessing a JDBC
+ * connection to perform the script.
+ * @throws org.springframework.dao.DataAccessException in case of script execution errors
+ * @see org.hibernate.cfg.Configuration#generateDropSchemaScript
+ * @see org.hibernate.tool.hbm2ddl.SchemaExport#drop
+ */
+ public void dropDatabaseSchema() throws DataAccessException {
+ logger.info("Dropping database schema for Hibernate SessionFactory");
+ HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
+ hibernateTemplate.execute(
+ new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException, SQLException {
+ Connection con = session.connection();
+ Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
+ String[] sql = getConfiguration().generateDropSchemaScript(dialect);
+ executeSchemaScript(con, sql);
+ return null;
+ }
+ }
+ );
+ }
+
+ /**
+ * Execute schema creation script, determined by the Configuration object
+ * used for creating the SessionFactory. A replacement for Hibernate's
+ * SchemaExport class, to be invoked on application setup.
+ *
Fetch the LocalSessionFactoryBean itself rather than the exposed
+ * SessionFactory to be able to invoke this method, e.g. via
+ * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");.
+ *
Uses the SessionFactory that this bean generates for accessing a JDBC
+ * connection to perform the script.
+ * @throws DataAccessException in case of script execution errors
+ * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript
+ * @see org.hibernate.tool.hbm2ddl.SchemaExport#create
+ */
+ public void createDatabaseSchema() throws DataAccessException {
+ logger.info("Creating database schema for Hibernate SessionFactory");
+ HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
+ hibernateTemplate.execute(
+ new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException, SQLException {
+ Connection con = session.connection();
+ Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
+ String[] sql = getConfiguration().generateSchemaCreationScript(dialect);
+ executeSchemaScript(con, sql);
+ return null;
+ }
+ }
+ );
+ }
+
+ /**
+ * Execute schema update script, determined by the Configuration object
+ * used for creating the SessionFactory. A replacement for Hibernate's
+ * SchemaUpdate class, for automatically executing schema update scripts
+ * on application startup. Can also be invoked manually.
+ *
Fetch the LocalSessionFactoryBean itself rather than the exposed
+ * SessionFactory to be able to invoke this method, e.g. via
+ * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");.
+ *
Uses the SessionFactory that this bean generates for accessing a JDBC
+ * connection to perform the script.
+ * @throws DataAccessException in case of script execution errors
+ * @see #setSchemaUpdate
+ * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
+ * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
+ */
+ public void updateDatabaseSchema() throws DataAccessException {
+ logger.info("Updating database schema for Hibernate SessionFactory");
+ HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
+ hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
+ hibernateTemplate.execute(
+ new HibernateCallback() {
+ public Object doInHibernate(Session session) throws HibernateException, SQLException {
+ Connection con = session.connection();
+ Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
+ DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
+ String[] sql = getConfiguration().generateSchemaUpdateScript(dialect, metadata);
+ executeSchemaScript(con, sql);
+ return null;
+ }
+ }
+ );
+ }
+
+ /**
+ * Execute the given schema script on the given JDBC Connection.
+ *
Note that the default implementation will log unsuccessful statements
+ * and continue to execute. Override the executeSchemaStatement
+ * method to treat failures differently.
+ * @param con the JDBC Connection to execute the script on
+ * @param sql the SQL statements to execute
+ * @throws SQLException if thrown by JDBC methods
+ * @see #executeSchemaStatement
+ */
+ protected void executeSchemaScript(Connection con, String[] sql) throws SQLException {
+ if (sql != null && sql.length > 0) {
+ boolean oldAutoCommit = con.getAutoCommit();
+ if (!oldAutoCommit) {
+ con.setAutoCommit(true);
+ }
+ try {
+ Statement stmt = con.createStatement();
+ try {
+ for (int i = 0; i < sql.length; i++) {
+ executeSchemaStatement(stmt, sql[i]);
+ }
+ }
+ finally {
+ JdbcUtils.closeStatement(stmt);
+ }
+ }
+ finally {
+ if (!oldAutoCommit) {
+ con.setAutoCommit(false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Execute the given schema SQL on the given JDBC Statement.
+ *
Note that the default implementation will log unsuccessful statements
+ * and continue to execute. Override this method to treat failures differently.
+ * @param stmt the JDBC Statement to execute the SQL on
+ * @param sql the SQL statement to execute
+ * @throws SQLException if thrown by JDBC methods (and considered fatal)
+ */
+ protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Executing schema statement: " + sql);
+ }
+ try {
+ stmt.executeUpdate(sql);
+ }
+ catch (SQLException ex) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Unsuccessful schema statement: " + sql, ex);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.util.Properties;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * Implementation of Hibernate's {@link TransactionManagerLookup} interface
+ * that returns a Spring-managed JTA {@link TransactionManager}, determined
+ * by LocalSessionFactoryBean's "jtaTransactionManager" property.
+ *
+ *
The main advantage of this TransactionManagerLookup is that it avoids
+ * double configuration of JTA specifics. A single TransactionManager bean can
+ * be used for both JtaTransactionManager and LocalSessionFactoryBean, with no
+ * JTA setup in Hibernate configuration.
+ *
+ *
Alternatively, use Hibernate's own TransactionManagerLookup implementations:
+ * Spring's JtaTransactionManager only requires a TransactionManager for suspending
+ * and resuming transactions, so you might not need to apply such special Spring
+ * configuration at all.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see LocalSessionFactoryBean#setJtaTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
+ */
+public class LocalTransactionManagerLookup implements TransactionManagerLookup {
+
+ private final TransactionManager transactionManager;
+
+
+ public LocalTransactionManagerLookup() {
+ TransactionManager tm = LocalSessionFactoryBean.getConfigTimeTransactionManager();
+ // absolutely needs thread-bound TransactionManager to initialize
+ if (tm == null) {
+ throw new IllegalStateException("No JTA TransactionManager found - " +
+ "'jtaTransactionManager' property must be set on LocalSessionFactoryBean");
+ }
+ this.transactionManager = tm;
+ }
+
+ public TransactionManager getTransactionManager(Properties props) {
+ return this.transactionManager;
+ }
+
+ public String getUserTransactionName() {
+ return null;
+ }
+
+ public Object getTransactionIdentifier(Transaction transaction) {
+ return transaction;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionFactoryUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionFactoryUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionFactoryUtils.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,802 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.sql.DataSource;
+import javax.transaction.Status;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.Criteria;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.JDBCException;
+import org.hibernate.NonUniqueResultException;
+import org.hibernate.ObjectDeletedException;
+import org.hibernate.PersistentObjectException;
+import org.hibernate.PropertyValueException;
+import org.hibernate.Query;
+import org.hibernate.QueryException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.TransientObjectException;
+import org.hibernate.UnresolvableObjectException;
+import org.hibernate.WrongClassException;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.exception.DataException;
+import org.hibernate.exception.JDBCConnectionException;
+import org.hibernate.exception.LockAcquisitionException;
+import org.hibernate.exception.SQLGrammarException;
+
+import org.springframework.core.NamedThreadLocal;
+import org.springframework.dao.CannotAcquireLockException;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.dao.InvalidDataAccessResourceUsageException;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
+import org.springframework.transaction.jta.SpringJtaSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class featuring methods for Hibernate Session handling,
+ * allowing for reuse of Hibernate Session instances within transactions.
+ * Also provides support for exception translation.
+ *
+ *
Supports synchronization with both Spring-managed JTA transactions
+ * (see {@link org.springframework.transaction.jta.JtaTransactionManager})
+ * and non-Spring JTA transactions (i.e. plain JTA or EJB CMT),
+ * transparently providing transaction-scoped Hibernate Sessions.
+ * Note that for non-Spring JTA transactions, a JTA TransactionManagerLookup
+ * has to be specified in the Hibernate configuration.
+ *
+ *
Used internally by {@link HibernateTemplate}, {@link HibernateInterceptor}
+ * and {@link HibernateTransactionManager}. Can also be used directly in
+ * application code.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #getSession
+ * @see #releaseSession
+ * @see HibernateTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public abstract class SessionFactoryUtils {
+
+ /**
+ * Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
+ * Returns DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100
+ * to execute Session cleanup before JDBC Connection cleanup, if any.
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
+ */
+ public static final int SESSION_SYNCHRONIZATION_ORDER =
+ DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
+
+ static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
+
+ private static final ThreadLocal deferredCloseHolder =
+ new NamedThreadLocal("Hibernate Sessions registered for deferred close");
+
+
+ /**
+ * Determine the DataSource of the given SessionFactory.
+ * @param sessionFactory the SessionFactory to check
+ * @return the DataSource, or null if none found
+ * @see org.hibernate.engine.SessionFactoryImplementor#getConnectionProvider
+ * @see LocalDataSourceConnectionProvider
+ */
+ public static DataSource getDataSource(SessionFactory sessionFactory) {
+ if (sessionFactory instanceof SessionFactoryImplementor) {
+ ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider();
+ if (cp instanceof LocalDataSourceConnectionProvider) {
+ return ((LocalDataSourceConnectionProvider) cp).getDataSource();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create an appropriate SQLExceptionTranslator for the given SessionFactory.
+ * If a DataSource is found, a SQLErrorCodeSQLExceptionTranslator for the DataSource
+ * is created; else, a SQLStateSQLExceptionTranslator as fallback.
+ * @param sessionFactory the SessionFactory to create the translator for
+ * @return the SQLExceptionTranslator
+ * @see #getDataSource
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ */
+ public static SQLExceptionTranslator newJdbcExceptionTranslator(SessionFactory sessionFactory) {
+ DataSource ds = getDataSource(sessionFactory);
+ if (ds != null) {
+ return new SQLErrorCodeSQLExceptionTranslator(ds);
+ }
+ return new SQLStateSQLExceptionTranslator();
+ }
+
+ /**
+ * Try to retrieve the JTA TransactionManager from the given SessionFactory
+ * and/or Session. Check the passed-in SessionFactory for implementing
+ * SessionFactoryImplementor (the usual case), falling back to the
+ * SessionFactory reference that the Session itself carries.
+ * @param sessionFactory Hibernate SessionFactory
+ * @param session Hibernate Session (can also be null)
+ * @return the JTA TransactionManager, if any
+ * @see javax.transaction.TransactionManager
+ * @see SessionFactoryImplementor#getTransactionManager
+ * @see Session#getSessionFactory
+ * @see org.hibernate.impl.SessionFactoryImpl
+ */
+ public static TransactionManager getJtaTransactionManager(SessionFactory sessionFactory, Session session) {
+ SessionFactoryImplementor sessionFactoryImpl = null;
+ if (sessionFactory instanceof SessionFactoryImplementor) {
+ sessionFactoryImpl = ((SessionFactoryImplementor) sessionFactory);
+ }
+ else if (session != null) {
+ SessionFactory internalFactory = session.getSessionFactory();
+ if (internalFactory instanceof SessionFactoryImplementor) {
+ sessionFactoryImpl = (SessionFactoryImplementor) internalFactory;
+ }
+ }
+ return (sessionFactoryImpl != null ? sessionFactoryImpl.getTransactionManager() : null);
+ }
+
+
+ /**
+ * Get a Hibernate Session for the given SessionFactory. Is aware of and will
+ * return any existing corresponding Session bound to the current thread, for
+ * example when using {@link HibernateTransactionManager}. Will create a new
+ * Session otherwise, if "allowCreate" is true.
+ *
This is the getSession method used by typical data access code,
+ * in combination with releaseSession called when done with
+ * the Session. Note that HibernateTemplate allows to write data access code
+ * without caring about such resource handling.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @param allowCreate whether a non-transactional Session should be created
+ * when no transactional Session can be found for the current thread
+ * @return the Hibernate Session
+ * @throws DataAccessResourceFailureException if the Session couldn't be created
+ * @throws IllegalStateException if no thread-bound Session found and
+ * "allowCreate" is false
+ * @see #getSession(SessionFactory, Interceptor, SQLExceptionTranslator)
+ * @see #releaseSession
+ * @see HibernateTemplate
+ */
+ public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
+ throws DataAccessResourceFailureException, IllegalStateException {
+
+ try {
+ return doGetSession(sessionFactory, null, null, allowCreate);
+ }
+ catch (HibernateException ex) {
+ throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
+ }
+ }
+
+ /**
+ * Get a Hibernate Session for the given SessionFactory. Is aware of and will
+ * return any existing corresponding Session bound to the current thread, for
+ * example when using {@link HibernateTransactionManager}. Will always create
+ * a new Session otherwise.
+ *
Supports setting a Session-level Hibernate entity interceptor that allows
+ * to inspect and change property values before writing to and reading from the
+ * database. Such an interceptor can also be set at the SessionFactory level
+ * (i.e. on LocalSessionFactoryBean), on HibernateTransactionManager, or on
+ * HibernateInterceptor/HibernateTemplate.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @param entityInterceptor Hibernate entity interceptor, or null if none
+ * @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
+ * Session on transaction synchronization (may be null; only used
+ * when actually registering a transaction synchronization)
+ * @return the Hibernate Session
+ * @throws DataAccessResourceFailureException if the Session couldn't be created
+ * @see LocalSessionFactoryBean#setEntityInterceptor
+ * @see HibernateInterceptor#setEntityInterceptor
+ * @see HibernateTemplate#setEntityInterceptor
+ */
+ public static Session getSession(
+ SessionFactory sessionFactory, Interceptor entityInterceptor,
+ SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
+
+ try {
+ return doGetSession(sessionFactory, entityInterceptor, jdbcExceptionTranslator, true);
+ }
+ catch (HibernateException ex) {
+ throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
+ }
+ }
+
+ /**
+ * Get a Hibernate Session for the given SessionFactory. Is aware of and will
+ * return any existing corresponding Session bound to the current thread, for
+ * example when using {@link HibernateTransactionManager}. Will create a new
+ * Session otherwise, if "allowCreate" is true.
+ *
Throws the original HibernateException, in contrast to {@link #getSession}.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @param allowCreate whether a non-transactional Session should be created
+ * when no transactional Session can be found for the current thread
+ * @return the Hibernate Session
+ * @throws HibernateException if the Session couldn't be created
+ * @throws IllegalStateException if no thread-bound Session found and allowCreate false
+ */
+ public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
+ throws HibernateException, IllegalStateException {
+
+ return doGetSession(sessionFactory, null, null, allowCreate);
+ }
+
+ /**
+ * Get a Hibernate Session for the given SessionFactory. Is aware of and will
+ * return any existing corresponding Session bound to the current thread, for
+ * example when using {@link HibernateTransactionManager}. Will create a new
+ * Session otherwise, if "allowCreate" is true.
+ *
Same as {@link #getSession}, but throwing the original HibernateException.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @param entityInterceptor Hibernate entity interceptor, or null if none
+ * @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
+ * Session on transaction synchronization (may be null)
+ * @param allowCreate whether a non-transactional Session should be created
+ * when no transactional Session can be found for the current thread
+ * @return the Hibernate Session
+ * @throws HibernateException if the Session couldn't be created
+ * @throws IllegalStateException if no thread-bound Session found and
+ * "allowCreate" is false
+ */
+ private static Session doGetSession(
+ SessionFactory sessionFactory, Interceptor entityInterceptor,
+ SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
+ throws HibernateException, IllegalStateException {
+
+ Assert.notNull(sessionFactory, "No SessionFactory specified");
+
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ if (sessionHolder != null && !sessionHolder.isEmpty()) {
+ // pre-bound Hibernate Session
+ Session session = null;
+ if (TransactionSynchronizationManager.isSynchronizationActive() &&
+ sessionHolder.doesNotHoldNonDefaultSession()) {
+ // Spring transaction management is active ->
+ // register pre-bound Session with it for transactional flushing.
+ session = sessionHolder.getValidatedSession();
+ if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {
+ logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");
+ TransactionSynchronizationManager.registerSynchronization(
+ new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));
+ sessionHolder.setSynchronizedWithTransaction(true);
+ // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
+ // with FlushMode.NEVER, which needs to allow flushing within the transaction.
+ FlushMode flushMode = session.getFlushMode();
+ if (flushMode.lessThan(FlushMode.COMMIT) &&
+ !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
+ session.setFlushMode(FlushMode.AUTO);
+ sessionHolder.setPreviousFlushMode(flushMode);
+ }
+ }
+ }
+ else {
+ // No Spring transaction management active -> try JTA transaction synchronization.
+ session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);
+ }
+ if (session != null) {
+ return session;
+ }
+ }
+
+ logger.debug("Opening Hibernate Session");
+ Session session = (entityInterceptor != null ?
+ sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());
+
+ // Use same Session for further Hibernate actions within the transaction.
+ // Thread object will get removed by synchronization at transaction completion.
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ // We're within a Spring-managed transaction, possibly from JtaTransactionManager.
+ logger.debug("Registering Spring transaction synchronization for new Hibernate Session");
+ SessionHolder holderToUse = sessionHolder;
+ if (holderToUse == null) {
+ holderToUse = new SessionHolder(session);
+ }
+ else {
+ holderToUse.addSession(session);
+ }
+ if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
+ session.setFlushMode(FlushMode.NEVER);
+ }
+ TransactionSynchronizationManager.registerSynchronization(
+ new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));
+ holderToUse.setSynchronizedWithTransaction(true);
+ if (holderToUse != sessionHolder) {
+ TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
+ }
+ }
+ else {
+ // No Spring transaction management active -> try JTA transaction synchronization.
+ registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);
+ }
+
+ // Check whether we are allowed to return the Session.
+ if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {
+ closeSession(session);
+ throw new IllegalStateException("No Hibernate Session bound to thread, " +
+ "and configuration does not allow creation of non-transactional one here");
+ }
+
+ return session;
+ }
+
+ /**
+ * Retrieve a Session from the given SessionHolder, potentially from a
+ * JTA transaction synchronization.
+ * @param sessionHolder the SessionHolder to check
+ * @param sessionFactory the SessionFactory to get the JTA TransactionManager from
+ * @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
+ * Session on transaction synchronization (may be null)
+ * @return the associated Session, if any
+ * @throws DataAccessResourceFailureException if the Session couldn't be created
+ */
+ private static Session getJtaSynchronizedSession(
+ SessionHolder sessionHolder, SessionFactory sessionFactory,
+ SQLExceptionTranslator jdbcExceptionTranslator) throws DataAccessResourceFailureException {
+
+ // JTA synchronization is only possible with a javax.transaction.TransactionManager.
+ // We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
+ // in Hibernate configuration, it will contain a TransactionManager reference.
+ TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
+ if (jtaTm != null) {
+ // Check whether JTA transaction management is active ->
+ // fetch pre-bound Session for the current JTA transaction, if any.
+ // (just necessary for JTA transaction suspension, with an individual
+ // Hibernate Session per currently active/suspended transaction)
+ try {
+ // Look for transaction-specific Session.
+ Transaction jtaTx = jtaTm.getTransaction();
+ if (jtaTx != null) {
+ int jtaStatus = jtaTx.getStatus();
+ if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
+ Session session = sessionHolder.getValidatedSession(jtaTx);
+ if (session == null && !sessionHolder.isSynchronizedWithTransaction()) {
+ // No transaction-specific Session found: If not already marked as
+ // synchronized with transaction, register the default thread-bound
+ // Session as JTA-transactional. If there is no default Session,
+ // we're a new inner JTA transaction with an outer one being suspended:
+ // In that case, we'll return null to trigger opening of a new Session.
+ session = sessionHolder.getValidatedSession();
+ if (session != null) {
+ logger.debug("Registering JTA transaction synchronization for existing Hibernate Session");
+ sessionHolder.addSession(jtaTx, session);
+ jtaTx.registerSynchronization(
+ new SpringJtaSynchronizationAdapter(
+ new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false),
+ jtaTm));
+ sessionHolder.setSynchronizedWithTransaction(true);
+ // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
+ // with FlushMode.NEVER, which needs to allow flushing within the transaction.
+ FlushMode flushMode = session.getFlushMode();
+ if (flushMode.lessThan(FlushMode.COMMIT)) {
+ session.setFlushMode(FlushMode.AUTO);
+ sessionHolder.setPreviousFlushMode(flushMode);
+ }
+ }
+ }
+ return session;
+ }
+ }
+ // No transaction active -> simply return default thread-bound Session, if any
+ // (possibly from OpenSessionInViewFilter/Interceptor).
+ return sessionHolder.getValidatedSession();
+ }
+ catch (Throwable ex) {
+ throw new DataAccessResourceFailureException("Could not check JTA transaction", ex);
+ }
+ }
+ else {
+ // No JTA TransactionManager -> simply return default thread-bound Session, if any
+ // (possibly from OpenSessionInViewFilter/Interceptor).
+ return sessionHolder.getValidatedSession();
+ }
+ }
+
+ /**
+ * Register a JTA synchronization for the given Session, if any.
+ * @param sessionHolder the existing thread-bound SessionHolder, if any
+ * @param session the Session to register
+ * @param sessionFactory the SessionFactory that the Session was created with
+ * @param jdbcExceptionTranslator SQLExcepionTranslator to use for flushing the
+ * Session on transaction synchronization (may be null)
+ */
+ private static void registerJtaSynchronization(Session session, SessionFactory sessionFactory,
+ SQLExceptionTranslator jdbcExceptionTranslator, SessionHolder sessionHolder) {
+
+ // JTA synchronization is only possible with a javax.transaction.TransactionManager.
+ // We'll check the Hibernate SessionFactory: If a TransactionManagerLookup is specified
+ // in Hibernate configuration, it will contain a TransactionManager reference.
+ TransactionManager jtaTm = getJtaTransactionManager(sessionFactory, session);
+ if (jtaTm != null) {
+ try {
+ Transaction jtaTx = jtaTm.getTransaction();
+ if (jtaTx != null) {
+ int jtaStatus = jtaTx.getStatus();
+ if (jtaStatus == Status.STATUS_ACTIVE || jtaStatus == Status.STATUS_MARKED_ROLLBACK) {
+ logger.debug("Registering JTA transaction synchronization for new Hibernate Session");
+ SessionHolder holderToUse = sessionHolder;
+ // Register JTA Transaction with existing SessionHolder.
+ // Create a new SessionHolder if none existed before.
+ if (holderToUse == null) {
+ holderToUse = new SessionHolder(jtaTx, session);
+ }
+ else {
+ holderToUse.addSession(jtaTx, session);
+ }
+ jtaTx.registerSynchronization(
+ new SpringJtaSynchronizationAdapter(
+ new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true),
+ jtaTm));
+ holderToUse.setSynchronizedWithTransaction(true);
+ if (holderToUse != sessionHolder) {
+ TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);
+ }
+ }
+ }
+ }
+ catch (Throwable ex) {
+ throw new DataAccessResourceFailureException(
+ "Could not register synchronization with JTA TransactionManager", ex);
+ }
+ }
+ }
+
+
+ /**
+ * Get a new Hibernate Session from the given SessionFactory.
+ * Will return a new Session even if there already is a pre-bound
+ * Session for the given SessionFactory.
+ *
Within a transaction, this method will create a new Session
+ * that shares the transaction's JDBC Connection. More specifically,
+ * it will use the same JDBC Connection as the pre-bound Hibernate Session.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @return the new Session
+ */
+ public static Session getNewSession(SessionFactory sessionFactory) {
+ return getNewSession(sessionFactory, null);
+ }
+
+ /**
+ * Get a new Hibernate Session from the given SessionFactory.
+ * Will return a new Session even if there already is a pre-bound
+ * Session for the given SessionFactory.
+ *
Within a transaction, this method will create a new Session
+ * that shares the transaction's JDBC Connection. More specifically,
+ * it will use the same JDBC Connection as the pre-bound Hibernate Session.
+ * @param sessionFactory Hibernate SessionFactory to create the session with
+ * @param entityInterceptor Hibernate entity interceptor, or null if none
+ * @return the new Session
+ */
+ public static Session getNewSession(SessionFactory sessionFactory, Interceptor entityInterceptor) {
+ Assert.notNull(sessionFactory, "No SessionFactory specified");
+
+ try {
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ if (sessionHolder != null && !sessionHolder.isEmpty()) {
+ if (entityInterceptor != null) {
+ return sessionFactory.openSession(sessionHolder.getAnySession().connection(), entityInterceptor);
+ }
+ else {
+ return sessionFactory.openSession(sessionHolder.getAnySession().connection());
+ }
+ }
+ else {
+ if (entityInterceptor != null) {
+ return sessionFactory.openSession(entityInterceptor);
+ }
+ else {
+ return sessionFactory.openSession();
+ }
+ }
+ }
+ catch (HibernateException ex) {
+ throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
+ }
+ }
+
+
+ /**
+ * Stringify the given Session for debug logging.
+ * Returns output equivalent to Object.toString():
+ * the fully qualified class name + "@" + the identity hash code.
+ *
The sole reason why this is necessary is because Hibernate3's
+ * Session.toString() implementation is broken (and won't be fixed):
+ * it logs the toString representation of all persistent objects in the Session,
+ * which might lead to ConcurrentModificationExceptions if the persistent objects
+ * in turn refer to the Session (for example, for lazy loading).
+ * @param session the Hibernate Session to stringify
+ * @return the String representation of the given Session
+ */
+ public static String toString(Session session) {
+ return session.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(session));
+ }
+
+ /**
+ * Return whether there is a transactional Hibernate Session for the current thread,
+ * that is, a Session bound to the current thread by Spring's transaction facilities.
+ * @param sessionFactory Hibernate SessionFactory to check (may be null)
+ * @return whether there is a transactional Session for current thread
+ */
+ public static boolean hasTransactionalSession(SessionFactory sessionFactory) {
+ if (sessionFactory == null) {
+ return false;
+ }
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ return (sessionHolder != null && !sessionHolder.isEmpty());
+ }
+
+ /**
+ * Return whether the given Hibernate Session is transactional, that is,
+ * bound to the current thread by Spring's transaction facilities.
+ * @param session the Hibernate Session to check
+ * @param sessionFactory Hibernate SessionFactory that the Session was created with
+ * (may be null)
+ * @return whether the Session is transactional
+ */
+ public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
+ if (sessionFactory == null) {
+ return false;
+ }
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ return (sessionHolder != null && sessionHolder.containsSession(session));
+ }
+
+ /**
+ * Apply the current transaction timeout, if any, to the given
+ * Hibernate Query object.
+ * @param query the Hibernate Query object
+ * @param sessionFactory Hibernate SessionFactory that the Query was created for
+ * (may be null)
+ * @see org.hibernate.Query#setTimeout
+ */
+ public static void applyTransactionTimeout(Query query, SessionFactory sessionFactory) {
+ Assert.notNull(query, "No Query object specified");
+ if (sessionFactory != null) {
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ if (sessionHolder != null && sessionHolder.hasTimeout()) {
+ query.setTimeout(sessionHolder.getTimeToLiveInSeconds());
+ }
+ }
+ }
+
+ /**
+ * Apply the current transaction timeout, if any, to the given
+ * Hibernate Criteria object.
+ * @param criteria the Hibernate Criteria object
+ * @param sessionFactory Hibernate SessionFactory that the Criteria was created for
+ * @see org.hibernate.Criteria#setTimeout
+ */
+ public static void applyTransactionTimeout(Criteria criteria, SessionFactory sessionFactory) {
+ Assert.notNull(criteria, "No Criteria object specified");
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
+ if (sessionHolder != null && sessionHolder.hasTimeout()) {
+ criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
+ }
+ }
+
+ /**
+ * Convert the given HibernateException to an appropriate exception
+ * from the org.springframework.dao hierarchy.
+ * @param ex HibernateException that occured
+ * @return the corresponding DataAccessException instance
+ * @see HibernateAccessor#convertHibernateAccessException
+ * @see HibernateTransactionManager#convertHibernateAccessException
+ */
+ public static DataAccessException convertHibernateAccessException(HibernateException ex) {
+ if (ex instanceof JDBCConnectionException) {
+ return new DataAccessResourceFailureException(ex.getMessage(), ex);
+ }
+ if (ex instanceof SQLGrammarException) {
+ return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof LockAcquisitionException) {
+ return new CannotAcquireLockException(ex.getMessage(), ex);
+ }
+ if (ex instanceof ConstraintViolationException) {
+ return new DataIntegrityViolationException(ex.getMessage(), ex);
+ }
+ if (ex instanceof DataException) {
+ return new DataIntegrityViolationException(ex.getMessage(), ex);
+ }
+ if (ex instanceof JDBCException) {
+ return new HibernateJdbcException((JDBCException) ex);
+ }
+ if (ex instanceof PropertyValueException) {
+ return new DataIntegrityViolationException(ex.getMessage(), ex);
+ }
+ if (ex instanceof PersistentObjectException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof TransientObjectException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof ObjectDeletedException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof QueryException) {
+ return new HibernateQueryException((QueryException) ex);
+ }
+ if (ex instanceof UnresolvableObjectException) {
+ return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
+ }
+ if (ex instanceof WrongClassException) {
+ return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
+ }
+ if (ex instanceof NonUniqueResultException) {
+ return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1);
+ }
+ if (ex instanceof StaleObjectStateException) {
+ return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
+ }
+ if (ex instanceof StaleStateException) {
+ return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
+ }
+
+ // fallback
+ return new HibernateSystemException(ex);
+ }
+
+
+ /**
+ * Determine whether deferred close is active for the current thread
+ * and the given SessionFactory.
+ * @param sessionFactory the Hibernate SessionFactory to check
+ * @return whether deferred close is active
+ */
+ public static boolean isDeferredCloseActive(SessionFactory sessionFactory) {
+ Assert.notNull(sessionFactory, "No SessionFactory specified");
+ Map holderMap = (Map) deferredCloseHolder.get();
+ return (holderMap != null && holderMap.containsKey(sessionFactory));
+ }
+
+ /**
+ * Initialize deferred close for the current thread and the given SessionFactory.
+ * Sessions will not be actually closed on close calls then, but rather at a
+ * {@link #processDeferredClose} call at a finishing point (like request completion).
+ *
Used by {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter}
+ * and {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}
+ * when not configured for a single session.
+ * @param sessionFactory the Hibernate SessionFactory to initialize deferred close for
+ * @see #processDeferredClose
+ * @see #releaseSession
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter#setSingleSession
+ * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor#setSingleSession
+ */
+ public static void initDeferredClose(SessionFactory sessionFactory) {
+ Assert.notNull(sessionFactory, "No SessionFactory specified");
+ logger.debug("Initializing deferred close of Hibernate Sessions");
+ Map holderMap = (Map) deferredCloseHolder.get();
+ if (holderMap == null) {
+ holderMap = new HashMap();
+ deferredCloseHolder.set(holderMap);
+ }
+ holderMap.put(sessionFactory, new LinkedHashSet(4));
+ }
+
+ /**
+ * Process all Hibernate Sessions that have been registered for deferred close
+ * for the given SessionFactory.
+ * @param sessionFactory the Hibernate SessionFactory to process deferred close for
+ * @see #initDeferredClose
+ * @see #releaseSession
+ */
+ public static void processDeferredClose(SessionFactory sessionFactory) {
+ Assert.notNull(sessionFactory, "No SessionFactory specified");
+
+ Map holderMap = (Map) deferredCloseHolder.get();
+ if (holderMap == null || !holderMap.containsKey(sessionFactory)) {
+ throw new IllegalStateException("Deferred close not active for SessionFactory [" + sessionFactory + "]");
+ }
+
+ logger.debug("Processing deferred close of Hibernate Sessions");
+ Set sessions = (Set) holderMap.remove(sessionFactory);
+ for (Iterator it = sessions.iterator(); it.hasNext();) {
+ closeSession((Session) it.next());
+ }
+
+ if (holderMap.isEmpty()) {
+ deferredCloseHolder.set(null);
+ }
+ }
+
+ /**
+ * Close the given Session, created via the given factory,
+ * if it is not managed externally (i.e. not bound to the thread).
+ * @param session the Hibernate Session to close (may be null)
+ * @param sessionFactory Hibernate SessionFactory that the Session was created with
+ * (may be null)
+ */
+ public static void releaseSession(Session session, SessionFactory sessionFactory) {
+ if (session == null) {
+ return;
+ }
+ // Only close non-transactional Sessions.
+ if (!isSessionTransactional(session, sessionFactory)) {
+ closeSessionOrRegisterDeferredClose(session, sessionFactory);
+ }
+ }
+
+ /**
+ * Close the given Session or register it for deferred close.
+ * @param session the Hibernate Session to close
+ * @param sessionFactory Hibernate SessionFactory that the Session was created with
+ * (may be null)
+ * @see #initDeferredClose
+ * @see #processDeferredClose
+ */
+ static void closeSessionOrRegisterDeferredClose(Session session, SessionFactory sessionFactory) {
+ Map holderMap = (Map) deferredCloseHolder.get();
+ if (holderMap != null && sessionFactory != null && holderMap.containsKey(sessionFactory)) {
+ logger.debug("Registering Hibernate Session for deferred close");
+ // Switch Session to FlushMode.NEVER for remaining lifetime.
+ session.setFlushMode(FlushMode.NEVER);
+ Set sessions = (Set) holderMap.get(sessionFactory);
+ sessions.add(session);
+ }
+ else {
+ closeSession(session);
+ }
+ }
+
+ /**
+ * Perform actual closing of the Hibernate Session,
+ * catching and logging any cleanup exceptions thrown.
+ * @param session the Hibernate Session to close (may be null)
+ * @see org.hibernate.Session#close()
+ */
+ public static void closeSession(Session session) {
+ if (session != null) {
+ logger.debug("Closing Hibernate Session");
+ try {
+ session.close();
+ }
+ catch (HibernateException ex) {
+ logger.debug("Could not close Hibernate Session", ex);
+ }
+ catch (Throwable ex) {
+ logger.debug("Unexpected exception on closing Hibernate Session", ex);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/SessionHolder.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+
+import org.springframework.transaction.support.ResourceHolderSupport;
+import org.springframework.util.Assert;
+
+/**
+ * Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
+ * HibernateTransactionManager binds instances of this class to the thread,
+ * for a given SessionFactory.
+ *
+ *
Note: This is an SPI class, not intended to be used by applications.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see HibernateTransactionManager
+ * @see SessionFactoryUtils
+ */
+public class SessionHolder extends ResourceHolderSupport {
+
+ private static final Object DEFAULT_KEY = new Object();
+
+ /**
+ * This Map needs to be synchronized because there might be multi-threaded
+ * access in the case of JTA with remote transaction propagation.
+ */
+ private final Map sessionMap = Collections.synchronizedMap(new HashMap(1));
+
+ private Transaction transaction;
+
+ private FlushMode previousFlushMode;
+
+
+ public SessionHolder(Session session) {
+ addSession(session);
+ }
+
+ public SessionHolder(Object key, Session session) {
+ addSession(key, session);
+ }
+
+
+ public Session getSession() {
+ return getSession(DEFAULT_KEY);
+ }
+
+ public Session getSession(Object key) {
+ return (Session) this.sessionMap.get(key);
+ }
+
+ public Session getValidatedSession() {
+ return getValidatedSession(DEFAULT_KEY);
+ }
+
+ public Session getValidatedSession(Object key) {
+ Session session = (Session) this.sessionMap.get(key);
+ // Check for dangling Session that's around but already closed.
+ // Effectively an assertion: that should never happen in practice.
+ // We'll seamlessly remove the Session here, to not let it cause
+ // any side effects.
+ if (session != null && !session.isOpen()) {
+ this.sessionMap.remove(key);
+ session = null;
+ }
+ return session;
+ }
+
+ public Session getAnySession() {
+ synchronized (this.sessionMap) {
+ if (!this.sessionMap.isEmpty()) {
+ return (Session) this.sessionMap.values().iterator().next();
+ }
+ return null;
+ }
+ }
+
+ public void addSession(Session session) {
+ addSession(DEFAULT_KEY, session);
+ }
+
+ public void addSession(Object key, Session session) {
+ Assert.notNull(key, "Key must not be null");
+ Assert.notNull(session, "Session must not be null");
+ this.sessionMap.put(key, session);
+ }
+
+ public Session removeSession(Object key) {
+ return (Session) this.sessionMap.remove(key);
+ }
+
+ public boolean containsSession(Session session) {
+ return this.sessionMap.containsValue(session);
+ }
+
+ public boolean isEmpty() {
+ return this.sessionMap.isEmpty();
+ }
+
+ public boolean doesNotHoldNonDefaultSession() {
+ synchronized (this.sessionMap) {
+ return this.sessionMap.isEmpty() ||
+ (this.sessionMap.size() == 1 && this.sessionMap.containsKey(DEFAULT_KEY));
+ }
+ }
+
+
+ public void setTransaction(Transaction transaction) {
+ this.transaction = transaction;
+ }
+
+ public Transaction getTransaction() {
+ return this.transaction;
+ }
+
+ public void setPreviousFlushMode(FlushMode previousFlushMode) {
+ this.previousFlushMode = previousFlushMode;
+ }
+
+ public FlushMode getPreviousFlushMode() {
+ return this.previousFlushMode;
+ }
+
+
+ public void clear() {
+ super.clear();
+ this.transaction = null;
+ this.previousFlushMode = null;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionContext.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionContext.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionContext.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import org.hibernate.HibernateException;
+import org.hibernate.classic.Session;
+import org.hibernate.context.CurrentSessionContext;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Implementation of Hibernate 3.1's CurrentSessionContext interface
+ * that delegates to Spring's SessionFactoryUtils for providing a
+ * Spring-managed current Session.
+ *
+ *
Used by Spring's {@link LocalSessionFactoryBean} when told to expose a
+ * transaction-aware SessionFactory. This is the default as of Spring 2.5.
+ *
+ *
This CurrentSessionContext implementation can also be specified in custom
+ * SessionFactory setup through the "hibernate.current_session_context_class"
+ * property, with the fully qualified name of this class as value.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see SessionFactoryUtils#doGetSession
+ * @see LocalSessionFactoryBean#setExposeTransactionAwareSessionFactory
+ */
+public class SpringSessionContext implements CurrentSessionContext {
+
+ private final SessionFactoryImplementor sessionFactory;
+
+
+ /**
+ * Create a new SpringSessionContext for the given Hibernate SessionFactory.
+ * @param sessionFactory the SessionFactory to provide current Sessions for
+ */
+ public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+
+ /**
+ * Retrieve the Spring-managed Session for the current thread, if any.
+ */
+ public Session currentSession() throws HibernateException {
+ try {
+ return (org.hibernate.classic.Session) SessionFactoryUtils.doGetSession(this.sessionFactory, false);
+ }
+ catch (IllegalStateException ex) {
+ throw new HibernateException(ex.getMessage());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionSynchronization.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionSynchronization.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringSessionSynchronization.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.engine.SessionImplementor;
+
+import org.springframework.core.Ordered;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * Callback for resource cleanup at the end of a Spring-managed JTA transaction,
+ * that is, when participating in a JtaTransactionManager transaction.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see SessionFactoryUtils
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
+
+ private final SessionHolder sessionHolder;
+
+ private final SessionFactory sessionFactory;
+
+ private final SQLExceptionTranslator jdbcExceptionTranslator;
+
+ private final boolean newSession;
+
+ /**
+ * Whether Hibernate has a looked-up JTA TransactionManager that it will
+ * automatically register CacheSynchronizations with on Session connect.
+ */
+ private boolean hibernateTransactionCompletion = false;
+
+ private Transaction jtaTransaction;
+
+ private boolean holderActive = true;
+
+
+ public SpringSessionSynchronization(
+ SessionHolder sessionHolder, SessionFactory sessionFactory,
+ SQLExceptionTranslator jdbcExceptionTranslator, boolean newSession) {
+
+ this.sessionHolder = sessionHolder;
+ this.sessionFactory = sessionFactory;
+ this.jdbcExceptionTranslator = jdbcExceptionTranslator;
+ this.newSession = newSession;
+
+ // Check whether the SessionFactory has a JTA TransactionManager.
+ TransactionManager jtaTm =
+ SessionFactoryUtils.getJtaTransactionManager(sessionFactory, sessionHolder.getAnySession());
+ if (jtaTm != null) {
+ this.hibernateTransactionCompletion = true;
+ // Fetch current JTA Transaction object
+ // (just necessary for JTA transaction suspension, with an individual
+ // Hibernate Session per currently active/suspended transaction).
+ try {
+ this.jtaTransaction = jtaTm.getTransaction();
+ }
+ catch (SystemException ex) {
+ throw new DataAccessResourceFailureException("Could not access JTA transaction", ex);
+ }
+ }
+ }
+
+ /**
+ * Check whether there is a Hibernate Session for the current JTA
+ * transaction. Else, fall back to the default thread-bound Session.
+ */
+ private Session getCurrentSession() {
+ Session session = null;
+ if (this.jtaTransaction != null) {
+ session = this.sessionHolder.getSession(this.jtaTransaction);
+ }
+ if (session == null) {
+ session = this.sessionHolder.getSession();
+ }
+ return session;
+ }
+
+
+ public int getOrder() {
+ return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
+ }
+
+ public void suspend() {
+ if (this.holderActive) {
+ TransactionSynchronizationManager.unbindResource(this.sessionFactory);
+ // Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
+ getCurrentSession().disconnect();
+ }
+ }
+
+ public void resume() {
+ if (this.holderActive) {
+ TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
+ }
+ }
+
+ public void beforeCommit(boolean readOnly) throws DataAccessException {
+ if (!readOnly) {
+ Session session = getCurrentSession();
+ // Read-write transaction -> flush the Hibernate Session.
+ // Further check: only flush when not FlushMode.NEVER/MANUAL.
+ if (!session.getFlushMode().lessThan(FlushMode.COMMIT)) {
+ try {
+ SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
+ session.flush();
+ }
+ catch (HibernateException ex) {
+ if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
+ JDBCException jdbcEx = (JDBCException) ex;
+ throw this.jdbcExceptionTranslator.translate(
+ "Hibernate flushing: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
+ }
+ throw SessionFactoryUtils.convertHibernateAccessException(ex);
+ }
+ }
+ }
+ }
+
+ public void beforeCompletion() {
+ if (this.jtaTransaction != null) {
+ // Typically in case of a suspended JTA transaction:
+ // Remove the Session for the current JTA transaction, but keep the holder.
+ Session session = this.sessionHolder.removeSession(this.jtaTransaction);
+ if (session != null) {
+ if (this.sessionHolder.isEmpty()) {
+ // No Sessions for JTA transactions bound anymore -> could remove it.
+ TransactionSynchronizationManager.unbindResourceIfPossible(this.sessionFactory);
+ this.holderActive = false;
+ }
+ // Do not close a pre-bound Session. In that case, we'll find the
+ // transaction-specific Session the same as the default Session.
+ if (session != this.sessionHolder.getSession()) {
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
+ }
+ else {
+ if (this.sessionHolder.getPreviousFlushMode() != null) {
+ // In case of pre-bound Session, restore previous flush mode.
+ session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
+ }
+ // Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
+ session.disconnect();
+ }
+ return;
+ }
+ }
+ // We'll only get here if there was no specific JTA transaction to handle.
+ if (this.newSession) {
+ // Default behavior: unbind and close the thread-bound Hibernate Session.
+ TransactionSynchronizationManager.unbindResource(this.sessionFactory);
+ this.holderActive = false;
+ if (this.hibernateTransactionCompletion) {
+ // Close the Hibernate Session here in case of a Hibernate TransactionManagerLookup:
+ // Hibernate will automatically defer the actual closing until JTA transaction completion.
+ // Else, the Session will be closed in the afterCompletion method, to provide the
+ // correct transaction status for releasing the Session's cache locks.
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(this.sessionHolder.getSession(), this.sessionFactory);
+ }
+ }
+ else {
+ Session session = this.sessionHolder.getSession();
+ if (this.sessionHolder.getPreviousFlushMode() != null) {
+ // In case of pre-bound Session, restore previous flush mode.
+ session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
+ }
+ if (this.hibernateTransactionCompletion) {
+ // Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
+ // We know that this is appropriate if a TransactionManagerLookup has been specified.
+ session.disconnect();
+ }
+ }
+ }
+
+ public void afterCommit() {
+ }
+
+ public void afterCompletion(int status) {
+ if (!this.hibernateTransactionCompletion || !this.newSession) {
+ // No Hibernate TransactionManagerLookup: apply afterTransactionCompletion callback.
+ // Always perform explicit afterTransactionCompletion callback for pre-bound Session,
+ // even with Hibernate TransactionManagerLookup (which only applies to new Sessions).
+ Session session = this.sessionHolder.getSession();
+ // Provide correct transaction status for releasing the Session's cache locks,
+ // if possible. Else, closing will release all cache locks assuming a rollback.
+ if (session instanceof SessionImplementor) {
+ ((SessionImplementor) session).afterTransactionCompletion(status == STATUS_COMMITTED, null);
+ }
+ // Close the Hibernate Session here if necessary
+ // (closed in beforeCompletion in case of TransactionManagerLookup).
+ if (this.newSession) {
+ SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, this.sessionFactory);
+ }
+ else if (!this.hibernateTransactionCompletion) {
+ session.disconnect();
+ }
+ }
+ if (!this.newSession && status != STATUS_COMMITTED) {
+ // Clear all pending inserts/updates/deletes in the Session.
+ // Necessary for pre-bound Sessions, to avoid inconsistent state.
+ this.sessionHolder.getSession().clear();
+ }
+ if (this.sessionHolder.doesNotHoldNonDefaultSession()) {
+ this.sessionHolder.setSynchronizedWithTransaction(false);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringTransactionFactory.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringTransactionFactory.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/SpringTransactionFactory.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3;
+
+import java.util.Properties;
+
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Transaction;
+import org.hibernate.jdbc.JDBCContext;
+import org.hibernate.transaction.JDBCTransaction;
+import org.hibernate.transaction.TransactionFactory;
+
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * Spring-aware implementation of the Hibernate TransactionFactory interface, aware of
+ * Spring-synchronized transactions (in particular Spring-managed JTA transactions)
+ * and asking for default release mode ON_CLOSE. Otherwise identical to Hibernate's
+ * default {@link org.hibernate.transaction.JDBCTransactionFactory} implementation.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5.4
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ * @see org.hibernate.transaction.JDBCTransactionFactory
+ */
+public class SpringTransactionFactory implements TransactionFactory {
+
+ /**
+ * Sets connection release mode "on_close" as default.
+ *
This was the case for Hibernate 3.0; Hibernate 3.1 changed
+ * it to "auto" (i.e. "after_statement" or "after_transaction").
+ * However, for Spring's resource management (in particular for
+ * HibernateTransactionManager), "on_close" is the better default.
+ */
+ public ConnectionReleaseMode getDefaultReleaseMode() {
+ return ConnectionReleaseMode.ON_CLOSE;
+ }
+
+ public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext) {
+ return new JDBCTransaction(jdbcContext, transactionContext);
+ }
+
+ public void configure(Properties props) {
+ }
+
+ public boolean isTransactionManagerRequired() {
+ return false;
+ }
+
+ public boolean areCallbacksLocalToHibernateTransactions() {
+ return true;
+ }
+
+ public boolean isTransactionInProgress(
+ JDBCContext jdbcContext, Context transactionContext, Transaction transaction) {
+
+ return (transaction != null && transaction.isActive()) ||
+ TransactionSynchronizationManager.isActualTransactionActive();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3;
+
+import javax.sql.DataSource;
+
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+
+/**
+ * Subclass of LocalDataSourceConnectionProvider that returns a
+ * transaction-aware proxy for the exposed DataSource. Used if
+ * LocalSessionFactoryBean's "useTransactionAwareDataSource" flag is on.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see LocalSessionFactoryBean#setUseTransactionAwareDataSource
+ */
+public class TransactionAwareDataSourceConnectionProvider extends LocalDataSourceConnectionProvider {
+
+ /**
+ * Return a TransactionAwareDataSourceProxy for the given DataSource,
+ * provided that it isn't a TransactionAwareDataSourceProxy already.
+ */
+ protected DataSource getDataSourceToUse(DataSource originalDataSource) {
+ if (originalDataSource instanceof TransactionAwareDataSourceProxy) {
+ return originalDataSource;
+ }
+ return new TransactionAwareDataSourceProxy(originalDataSource);
+ }
+
+ /**
+ * This implementation returns true: We can guarantee
+ * to receive the same Connection within a transaction, as we are
+ * exposing a TransactionAwareDataSourceProxy.
+ */
+ public boolean supportsAggressiveRelease() {
+ return true;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/TypeDefinitionBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/TypeDefinitionBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/TypeDefinitionBean.java 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3;
+
+import java.util.Properties;
+
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Bean that encapsulates a Hibernate type definition.
+ *
+ *
Typically defined as inner bean within a LocalSessionFactoryBean
+ * definition, as list element for the "typeDefinitions" bean property.
+ * For example:
+ *
+ *
+ *
+ * Alternatively, specify a bean id (or name) attribute for the inner bean,
+ * instead of the "typeName" property.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see LocalSessionFactoryBean#setTypeDefinitions(TypeDefinitionBean[])
+ */
+public class TypeDefinitionBean implements BeanNameAware, InitializingBean {
+
+ private String typeName;
+
+ private String typeClass;
+
+ private Properties parameters = new Properties();
+
+
+ /**
+ * Set the name of the type.
+ * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
+ */
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ /**
+ * Return the name of the type.
+ */
+ public String getTypeName() {
+ return typeName;
+ }
+
+ /**
+ * Set the type implementation class.
+ * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
+ */
+ public void setTypeClass(String typeClass) {
+ this.typeClass = typeClass;
+ }
+
+ /**
+ * Return the type implementation class.
+ */
+ public String getTypeClass() {
+ return typeClass;
+ }
+
+ /**
+ * Specify default parameters for the type.
+ * This only applies to parameterized types.
+ * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
+ * @see org.hibernate.usertype.ParameterizedType
+ */
+ public void setParameters(Properties parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Return the default parameters for the type.
+ */
+ public Properties getParameters() {
+ return parameters;
+ }
+
+
+ /**
+ * If no explicit type name has been specified, the bean name of
+ * the TypeDefinitionBean will be used.
+ * @see #setTypeName
+ */
+ public void setBeanName(String name) {
+ if (this.typeName == null) {
+ this.typeName = name;
+ }
+ }
+
+ public void afterPropertiesSet() {
+ if (this.typeName == null) {
+ throw new IllegalArgumentException("typeName is required");
+ }
+ if (this.typeClass == null) {
+ throw new IllegalArgumentException("typeClass is required");
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/package.html 17 Aug 2012 15:16:07 -0000 1.1
@@ -0,0 +1,16 @@
+
+
+
+Package providing integration of
+Hibernate3
+with Spring concepts.
+
+
Contains SessionFactory helper classes, a template plus callback
+for Hibernate access, and an implementation of Spring's transaction SPI
+for local Hibernate transactions.
+
+
This package supports Hibernate 3.x only.
+See the org.springframework.orm.hibernate package for Hibernate 2.1 support.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3.annotation;
+
+import java.io.IOException;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.AnnotationConfiguration;
+import org.hibernate.cfg.Configuration;
+
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternUtils;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.AnnotationTypeFilter;
+import org.springframework.core.type.filter.TypeFilter;
+import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Subclass of Spring's standard LocalSessionFactoryBean for Hibernate,
+ * supporting JDK 1.5+ annotation metadata for mappings.
+ *
+ *
Note: This class requires Hibernate 3.2 or higher, with the
+ * Java Persistence API and the Hibernate Annotations add-on present.
+ *
+ *
Example for an AnnotationSessionFactoryBean bean definition:
+ *
+ *
+ *
+ * @author Juergen Hoeller
+ * @since 1.2.2
+ * @see #setDataSource
+ * @see #setHibernateProperties
+ * @see #setAnnotatedClasses
+ * @see #setAnnotatedPackages
+ */
+public class AnnotationSessionFactoryBean extends LocalSessionFactoryBean implements ResourceLoaderAware {
+
+ private static final String RESOURCE_PATTERN = "**/*.class";
+
+
+ private Class[] annotatedClasses;
+
+ private String[] annotatedPackages;
+
+ private String[] packagesToScan;
+
+ private TypeFilter[] entityTypeFilters = new TypeFilter[] {
+ new AnnotationTypeFilter(Entity.class, false),
+ new AnnotationTypeFilter(Embeddable.class, false),
+ new AnnotationTypeFilter(MappedSuperclass.class, false)};
+
+ private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+
+
+ public AnnotationSessionFactoryBean() {
+ setConfigurationClass(AnnotationConfiguration.class);
+ }
+
+
+ public void setConfigurationClass(Class configurationClass) {
+ if (configurationClass == null || !AnnotationConfiguration.class.isAssignableFrom(configurationClass)) {
+ throw new IllegalArgumentException(
+ "AnnotationSessionFactoryBean only supports AnnotationConfiguration or subclasses");
+ }
+ super.setConfigurationClass(configurationClass);
+ }
+
+ /**
+ * Specify annotated classes, for which mappings will be read from
+ * class-level JDK 1.5+ annotation metadata.
+ * @see org.hibernate.cfg.AnnotationConfiguration#addAnnotatedClass(Class)
+ */
+ public void setAnnotatedClasses(Class[] annotatedClasses) {
+ this.annotatedClasses = annotatedClasses;
+ }
+
+ /**
+ * Specify the names of annotated packages, for which package-level
+ * JDK 1.5+ annotation metadata will be read.
+ * @see org.hibernate.cfg.AnnotationConfiguration#addPackage(String)
+ */
+ public void setAnnotatedPackages(String[] annotatedPackages) {
+ this.annotatedPackages = annotatedPackages;
+ }
+
+ /**
+ * Set whether to use Spring-based scanning for entity classes in the classpath
+ * instead of listing annotated classes explicitly.
+ *
Default is none. Specify packages to search for autodetection of your entity
+ * classes in the classpath. This is analogous to Spring's component-scan feature
+ * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
+ */
+ public void setPackagesToScan(String[] packagesToScan) {
+ this.packagesToScan = packagesToScan;
+ }
+
+ /**
+ * Specify custom type filters for Spring-based scanning for entity classes.
+ *
Default is to search all specified packages for classes annotated with
+ * @javax.persistence.Entity, @javax.persistence.Embeddable
+ * or @javax.persistence.MappedSuperclass.
+ * @see #setPackagesToScan
+ */
+ public void setEntityTypeFilters(TypeFilter[] entityTypeFilters) {
+ this.entityTypeFilters = entityTypeFilters;
+ }
+
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourcePatternResolver = (resourceLoader != null ?
+ ResourcePatternUtils.getResourcePatternResolver(resourceLoader) :
+ new PathMatchingResourcePatternResolver());
+ }
+
+
+ /**
+ * Reads metadata from annotated classes and packages into the
+ * AnnotationConfiguration instance.
+ */
+ protected void postProcessMappings(Configuration config) throws HibernateException {
+ AnnotationConfiguration annConfig = (AnnotationConfiguration) config;
+ if (this.annotatedClasses != null) {
+ for (int i = 0; i < this.annotatedClasses.length; i++) {
+ annConfig.addAnnotatedClass(this.annotatedClasses[i]);
+ }
+ }
+ if (this.annotatedPackages != null) {
+ for (int i = 0; i < this.annotatedPackages.length; i++) {
+ annConfig.addPackage(this.annotatedPackages[i]);
+ }
+ }
+ scanPackages(annConfig);
+ }
+
+ /**
+ * Perform Spring-based scanning for entity classes.
+ * @see #setPackagesToScan
+ */
+ protected void scanPackages(AnnotationConfiguration config) {
+ if (this.packagesToScan != null) {
+ try {
+ for (String pkg : this.packagesToScan) {
+ String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
+ ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
+ Resource[] resources = this.resourcePatternResolver.getResources(pattern);
+ MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
+ for (Resource resource : resources) {
+ if (resource.isReadable()) {
+ MetadataReader reader = readerFactory.getMetadataReader(resource);
+ String className = reader.getClassMetadata().getClassName();
+ if (matchesFilter(reader, readerFactory)) {
+ config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className));
+ }
+ }
+ }
+ }
+ }
+ catch (IOException ex) {
+ throw new MappingException("Failed to scan classpath for unlisted classes", ex);
+ }
+ catch (ClassNotFoundException ex) {
+ throw new MappingException("Failed to load annotated classes from classpath", ex);
+ }
+ }
+ }
+
+ /**
+ * Check whether any of the configured entity type filters matches
+ * the current class descriptor contained in the metadata reader.
+ */
+ private boolean matchesFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
+ if (this.entityTypeFilters != null) {
+ for (TypeFilter filter : this.entityTypeFilters) {
+ if (filter.match(reader, readerFactory)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Delegates to {@link #postProcessAnnotationConfiguration}.
+ */
+ protected final void postProcessConfiguration(Configuration config) throws HibernateException {
+ postProcessAnnotationConfiguration((AnnotationConfiguration) config);
+ }
+
+ /**
+ * To be implemented by subclasses that want to to perform custom
+ * post-processing of the AnnotationConfiguration object after this
+ * FactoryBean performed its default initialization.
+ * @param config the current AnnotationConfiguration object
+ * @throws HibernateException in case of Hibernate initialization errors
+ */
+ protected void postProcessAnnotationConfiguration(AnnotationConfiguration config)
+ throws HibernateException {
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/annotation/package.html 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Support package for the Hibernate3 Annotation add-on,
+which supports EJB3-compliant JDK 1.5+ annotations for mappings.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/AbstractLobType.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/AbstractLobType.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/AbstractLobType.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2002-2006 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.orm.hibernate3.support;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.UserType;
+import org.hibernate.util.EqualsHelper;
+
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.jdbc.support.lob.JtaLobCreatorSynchronization;
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.jdbc.support.lob.SpringLobCreatorSynchronization;
+import org.springframework.jdbc.support.lob.LobCreatorUtils;
+import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * Abstract base class for Hibernate UserType implementations that map to LOBs.
+ * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
+ *
+ *
For writing LOBs, either an active Spring transaction synchronization
+ * or an active JTA transaction (with "jtaTransactionManager" specified on
+ * LocalSessionFactoryBean or a Hibernate TransactionManagerLookup configured
+ * through the corresponding Hibernate property) is required.
+ *
+ *
Offers template methods for setting parameters and getting result values,
+ * passing in the LobHandler or LobCreator to use.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.jdbc.support.lob.LobHandler
+ * @see org.springframework.jdbc.support.lob.LobCreator
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setJtaTransactionManager
+ */
+public abstract class AbstractLobType implements UserType {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private final LobHandler lobHandler;
+
+ private final TransactionManager jtaTransactionManager;
+
+
+ /**
+ * Constructor used by Hibernate: fetches config-time LobHandler and
+ * config-time JTA TransactionManager from LocalSessionFactoryBean.
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
+ */
+ protected AbstractLobType() {
+ this(LocalSessionFactoryBean.getConfigTimeLobHandler(),
+ LocalSessionFactoryBean.getConfigTimeTransactionManager());
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler
+ * and an explicit JTA TransactionManager (can be null).
+ */
+ protected AbstractLobType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
+ this.lobHandler = lobHandler;
+ this.jtaTransactionManager = jtaTransactionManager;
+ }
+
+
+ /**
+ * This implementation returns false.
+ */
+ public boolean isMutable() {
+ return false;
+ }
+
+ /**
+ * This implementation delegates to the Hibernate EqualsHelper.
+ * @see org.hibernate.util.EqualsHelper#equals
+ */
+ public boolean equals(Object x, Object y) throws HibernateException {
+ return EqualsHelper.equals(x, y);
+ }
+
+ /**
+ * This implementation returns the hashCode of the given objectz.
+ */
+ public int hashCode(Object x) throws HibernateException {
+ return x.hashCode();
+ }
+
+ /**
+ * This implementation returns the passed-in value as-is.
+ */
+ public Object deepCopy(Object value) throws HibernateException {
+ return value;
+ }
+
+ /**
+ * This implementation returns the passed-in value as-is.
+ */
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) value;
+ }
+
+ /**
+ * This implementation returns the passed-in value as-is.
+ */
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return cached;
+ }
+
+ /**
+ * This implementation returns the passed-in original as-is.
+ */
+ public Object replace(Object original, Object target, Object owner) throws HibernateException {
+ return original;
+ }
+
+
+ /**
+ * This implementation delegates to nullSafeGetInternal,
+ * passing in the LobHandler of this type.
+ * @see #nullSafeGetInternal
+ */
+ public final Object nullSafeGet(ResultSet rs, String[] names, Object owner)
+ throws HibernateException, SQLException {
+
+ if (this.lobHandler == null) {
+ throw new IllegalStateException("No LobHandler found for configuration - " +
+ "lobHandler property must be set on LocalSessionFactoryBean");
+ }
+
+ try {
+ return nullSafeGetInternal(rs, names, owner, this.lobHandler);
+ }
+ catch (IOException ex) {
+ throw new HibernateException("I/O errors during LOB access", ex);
+ }
+ }
+
+ /**
+ * This implementation delegates to nullSafeSetInternal,
+ * passing in a transaction-synchronized LobCreator for the
+ * LobHandler of this type.
+ * @see #nullSafeSetInternal
+ */
+ public final void nullSafeSet(PreparedStatement st, Object value, int index)
+ throws HibernateException, SQLException {
+
+ if (this.lobHandler == null) {
+ throw new IllegalStateException("No LobHandler found for configuration - " +
+ "lobHandler property must be set on LocalSessionFactoryBean");
+ }
+
+ LobCreator lobCreator = this.lobHandler.getLobCreator();
+ try {
+ nullSafeSetInternal(st, index, value, lobCreator);
+ }
+ catch (IOException ex) {
+ throw new HibernateException("I/O errors during LOB access", ex);
+ }
+ LobCreatorUtils.registerTransactionSynchronization(lobCreator, this.jtaTransactionManager);
+ }
+
+ /**
+ * Template method to extract a value from the given result set.
+ * @param rs the ResultSet to extract from
+ * @param names the column names
+ * @param owner the containing entity
+ * @param lobHandler the LobHandler to use
+ * @return the extracted value
+ * @throws SQLException if thrown by JDBC methods
+ * @throws IOException if thrown by streaming methods
+ * @throws HibernateException in case of any other exceptions
+ */
+ protected abstract Object nullSafeGetInternal(
+ ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
+ throws SQLException, IOException, HibernateException;
+
+ /**
+ * Template method to set the given parameter value on the given statement.
+ * @param ps the PreparedStatement to set on
+ * @param index the statement parameter index
+ * @param value the value to set
+ * @param lobCreator the LobCreator to use
+ * @throws SQLException if thrown by JDBC methods
+ * @throws IOException if thrown by streaming methods
+ * @throws HibernateException in case of any other exceptions
+ */
+ protected abstract void nullSafeSetInternal(
+ PreparedStatement ps, int index, Object value, LobCreator lobCreator)
+ throws SQLException, IOException, HibernateException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobByteArrayType.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobByteArrayType.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobByteArrayType.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3.support;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+
+import javax.transaction.TransactionManager;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * Hibernate UserType implementation for byte arrays that get mapped to BLOBs.
+ * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
+ *
+ *
Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
+ */
+public class BlobByteArrayType extends AbstractLobType {
+
+ /**
+ * Constructor used by Hibernate: fetches config-time LobHandler and
+ * config-time JTA TransactionManager from LocalSessionFactoryBean.
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
+ */
+ public BlobByteArrayType() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler
+ * and an explicit JTA TransactionManager (can be null).
+ */
+ protected BlobByteArrayType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
+ super(lobHandler, jtaTransactionManager);
+ }
+
+ public int[] sqlTypes() {
+ return new int[] {Types.BLOB};
+ }
+
+ public Class returnedClass() {
+ return byte[].class;
+ }
+
+ public boolean isMutable() {
+ return true;
+ }
+
+ public boolean equals(Object x, Object y) {
+ return (x == y) ||
+ (x instanceof byte[] && y instanceof byte[] && Arrays.equals((byte[]) x, (byte[]) y));
+ }
+
+ public Object deepCopy(Object value) {
+ if (value == null) {
+ return null;
+ }
+ byte[] original = (byte[]) value;
+ byte[] copy = new byte[original.length];
+ System.arraycopy(original, 0, copy, 0, original.length);
+ return copy;
+ }
+
+ protected Object nullSafeGetInternal(
+ ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
+ throws SQLException {
+
+ return lobHandler.getBlobAsBytes(rs, names[0]);
+ }
+
+ protected void nullSafeSetInternal(
+ PreparedStatement ps, int index, Object value, LobCreator lobCreator)
+ throws SQLException {
+
+ lobCreator.setBlobAsBytes(ps, index, (byte[]) value);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobSerializableType.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobSerializableType.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobSerializableType.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3.support;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs.
+ * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
+ *
+ *
Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
+ */
+public class BlobSerializableType extends AbstractLobType {
+
+ /**
+ * Initial size for ByteArrayOutputStreams used for serialization output.
+ *
If a serialized object is larger than these 1024 bytes, the size of
+ * the byte array used by the output stream will be doubled each time the
+ * limit is reached.
+ */
+ private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024;
+
+ /**
+ * Constructor used by Hibernate: fetches config-time LobHandler and
+ * config-time JTA TransactionManager from LocalSessionFactoryBean.
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
+ */
+ public BlobSerializableType() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler
+ * and an explicit JTA TransactionManager (can be null).
+ */
+ protected BlobSerializableType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
+ super(lobHandler, jtaTransactionManager);
+ }
+
+ public int[] sqlTypes() {
+ return new int[] {Types.BLOB};
+ }
+
+ public Class returnedClass() {
+ return Serializable.class;
+ }
+
+ public boolean isMutable() {
+ return true;
+ }
+
+ public Object deepCopy(Object value) throws HibernateException {
+ try {
+ // Write to new byte array to clone.
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ oos.writeObject(value);
+ }
+ finally {
+ oos.close();
+ }
+
+ // Read it back and return a true copy.
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ try {
+ return ois.readObject();
+ }
+ finally {
+ ois.close();
+ }
+ }
+ catch (ClassNotFoundException ex) {
+ throw new HibernateException("Couldn't clone BLOB contents", ex);
+ }
+ catch (IOException ex) {
+ throw new HibernateException("Couldn't clone BLOB contents", ex);
+ }
+ }
+
+ protected Object nullSafeGetInternal(
+ ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
+ throws SQLException, IOException, HibernateException {
+
+ InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]);
+ if (is != null) {
+ ObjectInputStream ois = new ObjectInputStream(is);
+ try {
+ return ois.readObject();
+ }
+ catch (ClassNotFoundException ex) {
+ throw new HibernateException("Could not deserialize BLOB contents", ex);
+ }
+ finally {
+ ois.close();
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ protected void nullSafeSetInternal(
+ PreparedStatement ps, int index, Object value, LobCreator lobCreator)
+ throws SQLException, IOException {
+
+ if (value != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ oos.writeObject(value);
+ oos.flush();
+ lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
+ }
+ finally {
+ oos.close();
+ }
+ }
+ else {
+ lobCreator.setBlobAsBytes(ps, index, null);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobStringType.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobStringType.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/BlobStringType.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2002-2006 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.orm.hibernate3.support;
+
+import java.io.UnsupportedEncodingException;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import javax.transaction.TransactionManager;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * Hibernate UserType implementation for Strings that get mapped to BLOBs.
+ * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
+ *
+ *
This is intended for the (arguably unnatural, but still common) case
+ * where character data is stored in a binary LOB. This requires encoding
+ * and decoding the characters within this UserType; see the javadoc of the
+ * getCharacterEncoding() method.
+ *
+ *
Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2.7
+ * @see #getCharacterEncoding()
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
+ */
+public class BlobStringType extends AbstractLobType {
+
+ /**
+ * Constructor used by Hibernate: fetches config-time LobHandler and
+ * config-time JTA TransactionManager from LocalSessionFactoryBean.
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
+ */
+ public BlobStringType() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler
+ * and an explicit JTA TransactionManager (can be null).
+ */
+ protected BlobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
+ super(lobHandler, jtaTransactionManager);
+ }
+
+ public int[] sqlTypes() {
+ return new int[] {Types.BLOB};
+ }
+
+ public Class returnedClass() {
+ return String.class;
+ }
+
+ protected Object nullSafeGetInternal(
+ ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
+ throws SQLException, UnsupportedEncodingException {
+
+ byte[] bytes = lobHandler.getBlobAsBytes(rs, names[0]);
+ if (bytes != null) {
+ String encoding = getCharacterEncoding();
+ return (encoding != null ? new String(bytes, encoding) : new String(bytes));
+ }
+ else {
+ return null;
+ }
+ }
+
+ protected void nullSafeSetInternal(
+ PreparedStatement ps, int index, Object value, LobCreator lobCreator)
+ throws SQLException, UnsupportedEncodingException {
+
+ if (value != null) {
+ String str = (String) value;
+ String encoding = getCharacterEncoding();
+ byte[] bytes = (encoding != null ? str.getBytes(encoding) : str.getBytes());
+ lobCreator.setBlobAsBytes(ps, index, bytes);
+ }
+ else {
+ lobCreator.setBlobAsBytes(ps, index, null);
+ }
+ }
+
+ /**
+ * Determine the character encoding to apply to the BLOB's bytes
+ * to turn them into a String.
+ *
Default is null, indicating to use the platform
+ * default encoding. To be overridden in subclasses for a specific
+ * encoding such as "ISO-8859-1" or "UTF-8".
+ * @return the character encoding to use, or null
+ * to use the platform default encoding
+ * @see java.lang.String#String(byte[], String)
+ * @see java.lang.String#getBytes(String)
+ */
+ protected String getCharacterEncoding() {
+ return null;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ClobStringType.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ClobStringType.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ClobStringType.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2005 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.orm.hibernate3.support;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import javax.transaction.TransactionManager;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * Hibernate UserType implementation for Strings that get mapped to CLOBs.
+ * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time.
+ *
+ *
Particularly useful for storing Strings with more than 4000 characters in an
+ * Oracle database (only possible via CLOBs), in combination with OracleLobHandler.
+ *
+ *
Can also be defined in generic Hibernate mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be CLOB: For databases like MySQL and MS SQL Server, any
+ * large enough character type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler
+ */
+public class ClobStringType extends AbstractLobType {
+
+ /**
+ * Constructor used by Hibernate: fetches config-time LobHandler and
+ * config-time JTA TransactionManager from LocalSessionFactoryBean.
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager
+ */
+ public ClobStringType() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler
+ * and an explicit JTA TransactionManager (can be null).
+ */
+ protected ClobStringType(LobHandler lobHandler, TransactionManager jtaTransactionManager) {
+ super(lobHandler, jtaTransactionManager);
+ }
+
+ public int[] sqlTypes() {
+ return new int[] {Types.CLOB};
+ }
+
+ public Class returnedClass() {
+ return String.class;
+ }
+
+ protected Object nullSafeGetInternal(
+ ResultSet rs, String[] names, Object owner, LobHandler lobHandler)
+ throws SQLException {
+
+ return lobHandler.getClobAsString(rs, names[0]);
+ }
+
+ protected void nullSafeSetInternal(
+ PreparedStatement ps, int index, Object value, LobCreator lobCreator)
+ throws SQLException {
+
+ lobCreator.setClobAsString(ps, index, (String) value);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2002-2008 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.orm.hibernate3.support;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.support.DaoSupport;
+import org.springframework.orm.hibernate3.HibernateTemplate;
+import org.springframework.orm.hibernate3.SessionFactoryUtils;
+
+/**
+ * Convenient super class for Hibernate-based data access objects.
+ *
+ *
Requires a {@link org.hibernate.SessionFactory} to be set, providing a
+ * {@link org.springframework.orm.hibernate3.HibernateTemplate} based on it to
+ * subclasses through the {@link #getHibernateTemplate()} method.
+ * Can alternatively be initialized directly with a HibernateTemplate,
+ * in order to reuse the latter's settings such as the SessionFactory,
+ * exception translator, flush mode, etc.
+ *
+ *
This base class is mainly intended for HibernateTemplate usage but can
+ * also be used when working with a Hibernate Session directly, for example
+ * when relying on transactional Sessions. Convenience {@link #getSession}
+ * and {@link #releaseSession} methods are provided for that usage style.
+ *
+ *
This class will create its own HibernateTemplate instance if a SessionFactory
+ * is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
+ * by default. A custom HibernateTemplate instance can be used through overriding
+ * {@link #createHibernateTemplate}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setSessionFactory
+ * @see #getHibernateTemplate
+ * @see org.springframework.orm.hibernate3.HibernateTemplate
+ */
+public abstract class HibernateDaoSupport extends DaoSupport {
+
+ private HibernateTemplate hibernateTemplate;
+
+
+ /**
+ * Set the Hibernate SessionFactory to be used by this DAO.
+ * Will automatically create a HibernateTemplate for the given SessionFactory.
+ * @see #createHibernateTemplate
+ * @see #setHibernateTemplate
+ */
+ public final void setSessionFactory(SessionFactory sessionFactory) {
+ if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
+ this.hibernateTemplate = createHibernateTemplate(sessionFactory);
+ }
+ }
+
+ /**
+ * Create a HibernateTemplate for the given SessionFactory.
+ * Only invoked if populating the DAO with a SessionFactory reference!
+ *
Can be overridden in subclasses to provide a HibernateTemplate instance
+ * with different configuration, or a custom HibernateTemplate subclass.
+ * @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
+ * @return the new HibernateTemplate instance
+ * @see #setSessionFactory
+ */
+ protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
+ return new HibernateTemplate(sessionFactory);
+ }
+
+ /**
+ * Return the Hibernate SessionFactory used by this DAO.
+ */
+ public final SessionFactory getSessionFactory() {
+ return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
+ }
+
+ /**
+ * Set the HibernateTemplate for this DAO explicitly,
+ * as an alternative to specifying a SessionFactory.
+ * @see #setSessionFactory
+ */
+ public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
+ this.hibernateTemplate = hibernateTemplate;
+ }
+
+ /**
+ * Return the HibernateTemplate for this DAO,
+ * pre-initialized with the SessionFactory or set explicitly.
+ *
Note: The returned HibernateTemplate is a shared instance.
+ * You may introspect its configuration, but not modify the configuration
+ * (other than from within an {@link #initDao} implementation).
+ * Consider creating a custom HibernateTemplate instance via
+ * new HibernateTemplate(getSessionFactory()), in which
+ * case you're allowed to customize the settings on the resulting instance.
+ */
+ public final HibernateTemplate getHibernateTemplate() {
+ return this.hibernateTemplate;
+ }
+
+ protected final void checkDaoConfig() {
+ if (this.hibernateTemplate == null) {
+ throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
+ }
+ }
+
+
+ /**
+ * Obtain a Hibernate Session, either from the current transaction or
+ * a new one. The latter is only allowed if the
+ * {@link org.springframework.orm.hibernate3.HibernateTemplate#setAllowCreate "allowCreate"}
+ * setting of this bean's {@link #setHibernateTemplate HibernateTemplate} is "true".
+ *
Note that this is not meant to be invoked from HibernateTemplate code
+ * but rather just in plain Hibernate code. Either rely on a thread-bound
+ * Session or use it in combination with {@link #releaseSession}.
+ *
In general, it is recommended to use HibernateTemplate, either with
+ * the provided convenience operations or with a custom HibernateCallback
+ * that provides you with a Session to work on. HibernateTemplate will care
+ * for all resource management and for proper exception conversion.
+ * @return the Hibernate Session
+ * @throws DataAccessResourceFailureException if the Session couldn't be created
+ * @throws IllegalStateException if no thread-bound Session found and allowCreate=false
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
+ */
+ protected final Session getSession()
+ throws DataAccessResourceFailureException, IllegalStateException {
+
+ return getSession(this.hibernateTemplate.isAllowCreate());
+ }
+
+ /**
+ * Obtain a Hibernate Session, either from the current transaction or
+ * a new one. The latter is only allowed if "allowCreate" is true.
+ *
Note that this is not meant to be invoked from HibernateTemplate code
+ * but rather just in plain Hibernate code. Either rely on a thread-bound
+ * Session or use it in combination with {@link #releaseSession}.
+ *
In general, it is recommended to use
+ * {@link #getHibernateTemplate() HibernateTemplate}, either with
+ * the provided convenience operations or with a custom
+ * {@link org.springframework.orm.hibernate3.HibernateCallback} that
+ * provides you with a Session to work on. HibernateTemplate will care
+ * for all resource management and for proper exception conversion.
+ * @param allowCreate if a non-transactional Session should be created when no
+ * transactional Session can be found for the current thread
+ * @return the Hibernate Session
+ * @throws DataAccessResourceFailureException if the Session couldn't be created
+ * @throws IllegalStateException if no thread-bound Session found and allowCreate=false
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
+ */
+ protected final Session getSession(boolean allowCreate)
+ throws DataAccessResourceFailureException, IllegalStateException {
+
+ return (!allowCreate ?
+ SessionFactoryUtils.getSession(getSessionFactory(), false) :
+ SessionFactoryUtils.getSession(
+ getSessionFactory(),
+ this.hibernateTemplate.getEntityInterceptor(),
+ this.hibernateTemplate.getJdbcExceptionTranslator()));
+ }
+
+ /**
+ * Convert the given HibernateException to an appropriate exception from the
+ * org.springframework.dao hierarchy. Will automatically detect
+ * wrapped SQLExceptions and convert them accordingly.
+ *
Delegates to the
+ * {@link org.springframework.orm.hibernate3.HibernateTemplate#convertHibernateAccessException}
+ * method of this DAO's HibernateTemplate.
+ *
Typically used in plain Hibernate code, in combination with
+ * {@link #getSession} and {@link #releaseSession}.
+ * @param ex HibernateException that occured
+ * @return the corresponding DataAccessException instance
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException
+ */
+ protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
+ return this.hibernateTemplate.convertHibernateAccessException(ex);
+ }
+
+ /**
+ * Close the given Hibernate Session, created via this DAO's SessionFactory,
+ * if it isn't bound to the thread (i.e. isn't a transactional Session).
+ *
Typically used in plain Hibernate code, in combination with
+ * {@link #getSession} and {@link #convertHibernateAccessException}.
+ * @param session the Session to close
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession
+ */
+ protected final void releaseSession(Session session) {
+ SessionFactoryUtils.releaseSession(session, getSessionFactory());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3.support;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.MergeEvent;
+import org.hibernate.event.def.DefaultMergeEventListener;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Extension of Hibernate's DefaultMergeEventListener, transferring the ids
+ * of newly saved objects to the corresponding original objects (that are part
+ * of the detached object graph passed into the merge method).
+ *
+ *
Transferring newly assigned ids to the original graph allows for continuing
+ * to use the original object graph, despite merged copies being registered with
+ * the current Hibernate Session. This is particularly useful for web applications
+ * that might want to store an object graph and then render it in a web view,
+ * with links that include the id of certain (potentially newly saved) objects.
+ *
+ *
The merge behavior given by this MergeEventListener is nearly identical
+ * to TopLink's merge behavior. See PetClinic for an example, which relies on
+ * ids being available for newly saved objects: the HibernateClinic
+ * and TopLinkClinic DAO implementations both use straight merge
+ * calls, with the Hibernate SessionFactory configuration specifying an
+ * IdTransferringMergeEventListener.
+ *
+ *
Typically specified as entry for LocalSessionFactoryBean's "eventListeners"
+ * map, with key "merge".
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setEventListeners(java.util.Map)
+ */
+public class IdTransferringMergeEventListener extends DefaultMergeEventListener {
+
+ /**
+ * Hibernate 3.1 implementation of ID transferral.
+ */
+ protected void entityIsTransient(MergeEvent event, Map copyCache) {
+ super.entityIsTransient(event, copyCache);
+ SessionImplementor session = event.getSession();
+ EntityPersister persister = session.getEntityPersister(event.getEntityName(), event.getEntity());
+ // Extract id from merged copy (which is currently registered with Session).
+ Serializable id = persister.getIdentifier(event.getResult(), session.getEntityMode());
+ // Set id on original object (which remains detached).
+ persister.setIdentifier(event.getOriginal(), id, session.getEntityMode());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3.support;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.orm.hibernate3.SessionFactoryUtils;
+import org.springframework.orm.hibernate3.SessionHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+/**
+ * Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire
+ * processing of the request. Intended for the "Open Session in View" pattern,
+ * i.e. to allow for lazy loading in web views despite the original transactions
+ * already being completed.
+ *
+ *
This filter makes Hibernate Sessions available via the current thread, which
+ * will be autodetected by transaction managers. It is suitable for service layer
+ * transactions via {@link org.springframework.orm.hibernate3.HibernateTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
+ * as for non-transactional execution (if configured appropriately).
+ *
+ *
NOTE: This filter will by default not flush the Hibernate Session,
+ * with the flush mode set to FlushMode.NEVER. It assumes to be used
+ * in combination with service layer transactions that care for the flushing: The
+ * active transaction manager will temporarily change the flush mode to
+ * FlushMode.AUTO during a read-write transaction, with the flush
+ * mode reset to FlushMode.NEVER at the end of each transaction.
+ * If you intend to use this filter without transactions, consider changing
+ * the default flush mode (through the "flushMode" property).
+ *
+ *
WARNING: Applying this filter to existing logic can cause issues that
+ * have not appeared before, through the use of a single Hibernate Session for the
+ * processing of an entire request. In particular, the reassociation of persistent
+ * objects with a Hibernate Session has to occur at the very beginning of request
+ * processing, to avoid clashes with already loaded instances of the same objects.
+ *
+ *
Alternatively, turn this filter into deferred close mode, by specifying
+ * "singleSession"="false": It will not use a single session per request then,
+ * but rather let each data access operation or transaction use its own session
+ * (like without Open Session in View). Each of those sessions will be registered
+ * for deferred close, though, actually processed at request completion.
+ *
+ *
A single session per request allows for most efficient first-level caching,
+ * but can cause side effects, for example on saveOrUpdate or when
+ * continuing after a rolled-back transaction. The deferred close strategy is as safe
+ * as no Open Session in View in that respect, while still allowing for lazy loading
+ * in views (but not providing a first-level cache for the entire request).
+ *
+ *
Looks up the SessionFactory in Spring's root web application context.
+ * Supports a "sessionFactoryBeanName" filter init-param in web.xml;
+ * the default bean name is "sessionFactory". Looks up the SessionFactory on each
+ * request, to avoid initialization order issues (when using ContextLoaderServlet,
+ * the root application context will get initialized after this filter).
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setSingleSession
+ * @see #setFlushMode
+ * @see #lookupSessionFactory
+ * @see OpenSessionInViewInterceptor
+ * @see org.springframework.orm.hibernate3.HibernateInterceptor
+ * @see org.springframework.orm.hibernate3.HibernateTransactionManager
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenSessionInViewFilter extends OncePerRequestFilter {
+
+ public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
+
+
+ private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
+
+ private boolean singleSession = true;
+
+ private FlushMode flushMode = FlushMode.NEVER;
+
+
+ /**
+ * Set the bean name of the SessionFactory to fetch from Spring's
+ * root application context. Default is "sessionFactory".
+ * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
+ */
+ public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
+ this.sessionFactoryBeanName = sessionFactoryBeanName;
+ }
+
+ /**
+ * Return the bean name of the SessionFactory to fetch from Spring's
+ * root application context.
+ */
+ protected String getSessionFactoryBeanName() {
+ return this.sessionFactoryBeanName;
+ }
+
+ /**
+ * Set whether to use a single session for each request. Default is "true".
+ *
If set to "false", each data access operation or transaction will use
+ * its own session (like without Open Session in View). Each of those
+ * sessions will be registered for deferred close, though, actually
+ * processed at request completion.
+ * @see SessionFactoryUtils#initDeferredClose
+ * @see SessionFactoryUtils#processDeferredClose
+ */
+ public void setSingleSession(boolean singleSession) {
+ this.singleSession = singleSession;
+ }
+
+ /**
+ * Return whether to use a single session for each request.
+ */
+ protected boolean isSingleSession() {
+ return this.singleSession;
+ }
+
+ /**
+ * Specify the Hibernate FlushMode to apply to this filter's
+ * {@link org.hibernate.Session}. Only applied in single session mode.
+ *
Can be populated with the corresponding constant name in XML bean
+ * definitions: e.g. "AUTO".
+ *
The default is "NEVER". Specify "AUTO" if you intend to use
+ * this filter without service layer transactions.
+ * @see org.hibernate.Session#setFlushMode
+ * @see org.hibernate.FlushMode#NEVER
+ * @see org.hibernate.FlushMode#AUTO
+ */
+ public void setFlushMode(FlushMode flushMode) {
+ this.flushMode = flushMode;
+ }
+
+ /**
+ * Return the Hibernate FlushMode that this filter applies to its
+ * {@link org.hibernate.Session} (in single session mode).
+ */
+ protected FlushMode getFlushMode() {
+ return this.flushMode;
+ }
+
+
+ protected void doFilterInternal(
+ HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+
+ SessionFactory sessionFactory = lookupSessionFactory(request);
+ boolean participate = false;
+
+ if (isSingleSession()) {
+ // single session mode
+ if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
+ // Do not modify the Session: just set the participate flag.
+ participate = true;
+ }
+ else {
+ logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
+ Session session = getSession(sessionFactory);
+ TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
+ }
+ }
+ else {
+ // deferred close mode
+ if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
+ // Do not modify deferred close: just set the participate flag.
+ participate = true;
+ }
+ else {
+ SessionFactoryUtils.initDeferredClose(sessionFactory);
+ }
+ }
+
+ try {
+ filterChain.doFilter(request, response);
+ }
+
+ finally {
+ if (!participate) {
+ if (isSingleSession()) {
+ // single session mode
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
+ logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
+ closeSession(sessionHolder.getSession(), sessionFactory);
+ }
+ else {
+ // deferred close mode
+ SessionFactoryUtils.processDeferredClose(sessionFactory);
+ }
+ }
+ }
+ }
+
+ /**
+ * Look up the SessionFactory that this filter should use,
+ * taking the current HTTP request as argument.
+ *
The default implementation delegates to the {@link #lookupSessionFactory()}
+ * variant without arguments.
+ * @param request the current request
+ * @return the SessionFactory to use
+ */
+ protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
+ return lookupSessionFactory();
+ }
+
+ /**
+ * Look up the SessionFactory that this filter should use.
+ *
The default implementation looks for a bean with the specified name
+ * in Spring's root application context.
+ * @return the SessionFactory to use
+ * @see #getSessionFactoryBeanName
+ */
+ protected SessionFactory lookupSessionFactory() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
+ }
+ WebApplicationContext wac =
+ WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+ return (SessionFactory) wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
+ }
+
+ /**
+ * Get a Session for the SessionFactory that this filter uses.
+ * Note that this just applies in single session mode!
+ *
The default implementation delegates to the
+ * SessionFactoryUtils.getSession method and
+ * sets the Session's flush mode to "NEVER".
+ *
Can be overridden in subclasses for creating a Session with a
+ * custom entity interceptor or JDBC exception translator.
+ * @param sessionFactory the SessionFactory that this filter uses
+ * @return the Session to use
+ * @throws DataAccessResourceFailureException if the Session could not be created
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
+ * @see org.hibernate.FlushMode#NEVER
+ */
+ protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
+ Session session = SessionFactoryUtils.getSession(sessionFactory, true);
+ FlushMode flushMode = getFlushMode();
+ if (flushMode != null) {
+ session.setFlushMode(flushMode);
+ }
+ return session;
+ }
+
+ /**
+ * Close the given Session.
+ * Note that this just applies in single session mode!
+ *
Can be overridden in subclasses, e.g. for flushing the Session before
+ * closing it. See class-level javadoc for a discussion of flush handling.
+ * Note that you should also override getSession accordingly, to set
+ * the flush mode to something else than NEVER.
+ * @param session the Session used for filtering
+ * @param sessionFactory the SessionFactory that this filter uses
+ */
+ protected void closeSession(Session session, SessionFactory sessionFactory) {
+ SessionFactoryUtils.closeSession(session);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3.support;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.orm.hibernate3.HibernateAccessor;
+import org.springframework.orm.hibernate3.SessionFactoryUtils;
+import org.springframework.orm.hibernate3.SessionHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+
+/**
+ * Spring web request interceptor that binds a Hibernate Session to the
+ * thread for the entire processing of the request.
+ *
+ *
This class is a concrete expression of the "Open Session in View" pattern, which
+ * is a pattern that allows for the lazy loading of associations in web views despite
+ * the original transactions already being completed.
+ *
+ *
This interceptor makes Hibernate Sessions available via the current
+ * thread, which will be autodetected by transaction managers. It is suitable for
+ * service layer transactions via
+ * {@link org.springframework.orm.hibernate3.HibernateTransactionManager} or
+ * {@link org.springframework.transaction.jta.JtaTransactionManager} as well as for
+ * non-transactional execution (if configured appropriately).
+ *
+ *
NOTE: This interceptor will by default not flush the Hibernate
+ * Session, with the flush mode being set to FlushMode.NEVER.
+ * It assumes that it will be used in combination with service layer transactions
+ * that handle the flushing: the active transaction manager will temporarily change
+ * the flush mode to FlushMode.AUTO during a read-write transaction,
+ * with the flush mode reset to FlushMode.NEVER at the end of each
+ * transaction. If you intend to use this interceptor without transactions, consider
+ * changing the default flush mode (through the
+ * {@link #setFlushMode(int) "flushMode"} property).
+ *
+ *
In contrast to {@link OpenSessionInViewFilter}, this interceptor is
+ * configured in a Spring application context and can thus take advantage of bean
+ * wiring. It inherits common Hibernate configuration properties from
+ * {@link org.springframework.orm.hibernate3.HibernateAccessor},
+ * to be configured in a bean definition.
+ *
+ *
WARNING: Applying this interceptor to existing logic can cause issues
+ * that have not appeared before, through the use of a single Hibernate
+ * Session for the processing of an entire request. In particular, the
+ * reassociation of persistent objects with a Hibernate Session has to
+ * occur at the very beginning of request processing, to avoid clashes with already
+ * loaded instances of the same objects.
+ *
+ *
Alternatively, turn this interceptor into deferred close mode, by specifying
+ * "singleSession"="false": It will not use a single session per request then,
+ * but rather let each data access operation or transaction use its own session
+ * (as would be the case without Open Session in View). Each of those sessions will
+ * be registered for deferred close though, which will actually be processed at
+ * request completion.
+ *
+ *
A single session per request allows for the most efficient first-level caching,
+ * but can cause side effects, for example on saveOrUpdate or when
+ * continuing after a rolled-back transaction. The deferred close strategy is as safe
+ * as no Open Session in View in that respect, while still allowing for lazy loading
+ * in views (but not providing a first-level cache for the entire request).
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see #setSingleSession
+ * @see #setFlushMode
+ * @see OpenSessionInViewFilter
+ * @see org.springframework.orm.hibernate3.HibernateInterceptor
+ * @see org.springframework.orm.hibernate3.HibernateTransactionManager
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenSessionInViewInterceptor extends HibernateAccessor implements WebRequestInterceptor {
+
+ /**
+ * Suffix that gets appended to the SessionFactory
+ * toString() representation for the "participate in existing
+ * session handling" request attribute.
+ * @see #getParticipateAttributeName
+ */
+ public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
+
+
+ private boolean singleSession = true;
+
+
+ /**
+ * Create a new OpenSessionInViewInterceptor,
+ * turning the default flushMode to FLUSH_NEVER.
+ * @see #setFlushMode
+ */
+ public OpenSessionInViewInterceptor() {
+ setFlushMode(FLUSH_NEVER);
+ }
+
+ /**
+ * Set whether to use a single session for each request. Default is "true".
+ *
If set to false, each data access operation or transaction will use
+ * its own session (like without Open Session in View). Each of those
+ * sessions will be registered for deferred close, though, actually
+ * processed at request completion.
+ * @see SessionFactoryUtils#initDeferredClose
+ * @see SessionFactoryUtils#processDeferredClose
+ */
+ public void setSingleSession(boolean singleSession) {
+ this.singleSession = singleSession;
+ }
+
+ /**
+ * Return whether to use a single session for each request.
+ */
+ protected boolean isSingleSession() {
+ return singleSession;
+ }
+
+
+ /**
+ * Open a new Hibernate Session according to the settings of this
+ * HibernateAccessor and bind it to the thread via the
+ * {@link TransactionSynchronizationManager}.
+ * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
+ */
+ public void preHandle(WebRequest request) throws DataAccessException {
+ if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
+ SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
+ // Do not modify the Session: just mark the request accordingly.
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ int newCount = (count != null) ? count.intValue() + 1 : 1;
+ request.setAttribute(getParticipateAttributeName(), new Integer(newCount), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ if (isSingleSession()) {
+ // single session mode
+ logger.debug("Opening single Hibernate Session in OpenSessionInViewInterceptor");
+ Session session = SessionFactoryUtils.getSession(
+ getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
+ applyFlushMode(session, false);
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
+ }
+ else {
+ // deferred close mode
+ SessionFactoryUtils.initDeferredClose(getSessionFactory());
+ }
+ }
+ }
+
+ /**
+ * Flush the Hibernate Session before view rendering, if necessary.
+ *
Note that this just applies in {@link #isSingleSession() single session mode}!
+ *
The default is FLUSH_NEVER to avoid this extra flushing,
+ * assuming that service layer transactions have flushed their changes on commit.
+ * @see #setFlushMode
+ */
+ public void postHandle(WebRequest request, ModelMap model) throws DataAccessException {
+ if (isSingleSession()) {
+ // Only potentially flush in single session mode.
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
+ logger.debug("Flushing single Hibernate Session in OpenSessionInViewInterceptor");
+ try {
+ flushIfNecessary(sessionHolder.getSession(), false);
+ }
+ catch (HibernateException ex) {
+ throw convertHibernateAccessException(ex);
+ }
+ }
+ }
+
+ /**
+ * Unbind the Hibernate Session from the thread and close it (in
+ * single session mode), or process deferred close for all sessions that have
+ * been opened during the current request (in deferred close mode).
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+ public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ if (count != null) {
+ // Do not modify the Session: just clear the marker.
+ if (count.intValue() > 1) {
+ request.setAttribute(participateAttributeName, new Integer(count.intValue() - 1), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ }
+ }
+ else {
+ if (isSingleSession()) {
+ // single session mode
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ logger.debug("Closing single Hibernate Session in OpenSessionInViewInterceptor");
+ SessionFactoryUtils.closeSession(sessionHolder.getSession());
+ }
+ else {
+ // deferred close mode
+ SessionFactoryUtils.processDeferredClose(getSessionFactory());
+ }
+ }
+ }
+
+ /**
+ * Return the name of the request attribute that identifies that a request is
+ * already intercepted.
+ *
The default implementation takes the toString() representation
+ * of the SessionFactory instance and appends {@link #PARTICIPATE_SUFFIX}.
+ */
+ protected String getParticipateAttributeName() {
+ return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2007 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.orm.hibernate3.support;
+
+import org.hibernate.EmptyInterceptor;
+
+import org.springframework.aop.scope.ScopedObject;
+import org.springframework.aop.support.AopUtils;
+
+/**
+ * Hibernate3 interceptor used for getting the proper entity name for scoped
+ * beans. As scoped bean classes are proxies generated at runtime, they are
+ * unrecognized by the persisting framework. Using this interceptor, the
+ * original scoped bean class is retrieved end exposed to Hibernate for
+ * persisting.
+ *
+ *
+ *
+ * @author Costin Leau
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public class ScopedBeanInterceptor extends EmptyInterceptor {
+
+ public String getEntityName(Object entity) {
+ if (entity instanceof ScopedObject) {
+ // Determine underlying object's type.
+ Object targetObject = ((ScopedObject) entity).getTargetObject();
+ return AopUtils.getTargetClass(targetObject).getName();
+ }
+
+ // Any other object: delegate to the default implementation.
+ return super.getEntityName(entity);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/hibernate3/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/hibernate3/support/package.html 17 Aug 2012 15:16:14 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Classes supporting the org.springframework.orm.hibernate3 package.
+Contains a DAO base class for HibernateTemplate usage.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientCallback.java 17 Aug 2012 15:16:06 -0000 1.1
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-2006 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.orm.ibatis;
+
+import java.sql.SQLException;
+
+import com.ibatis.sqlmap.client.SqlMapExecutor;
+
+/**
+ * Callback interface for data access code that works with the iBATIS
+ * {@link com.ibatis.sqlmap.client.SqlMapExecutor} interface. To be used
+ * with {@link SqlMapClientTemplate}'s execute method,
+ * assumably often as anonymous classes within a method implementation.
+ *
+ * @author Juergen Hoeller
+ * @since 24.02.2004
+ * @see SqlMapClientTemplate
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ */
+public interface SqlMapClientCallback {
+
+ /**
+ * Gets called by SqlMapClientTemplate.execute with an active
+ * SqlMapExecutor. Does not need to care about activating
+ * or closing the SqlMapExecutor, or handling transactions.
+ *
+ *
If called without a thread-bound JDBC transaction (initiated by
+ * DataSourceTransactionManager), the code will simply get executed on the
+ * underlying JDBC connection with its transactional semantics. If using
+ * a JTA-aware DataSource, the JDBC connection and thus the callback code
+ * will be transactional if a JTA transaction is active.
+ *
+ *
Allows for returning a result object created within the callback,
+ * i.e. a domain object or a collection of domain objects.
+ * A thrown custom RuntimeException is treated as an application exception:
+ * It gets propagated to the caller of the template.
+ *
+ * @param executor an active iBATIS SqlMapSession, passed-in as
+ * SqlMapExecutor interface here to avoid manual lifecycle handling
+ * @return a result object, or null if none
+ * @throws SQLException if thrown by the iBATIS SQL Maps API
+ * @see SqlMapClientTemplate#execute
+ * @see SqlMapClientTemplate#executeWithListResult
+ * @see SqlMapClientTemplate#executeWithMapResult
+ */
+ Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientFactoryBean.java 17 Aug 2012 15:16:06 -0000 1.1
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2002-2008 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.orm.ibatis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import com.ibatis.common.xml.NodeletException;
+import com.ibatis.sqlmap.client.SqlMapClient;
+import com.ibatis.sqlmap.client.SqlMapClientBuilder;
+import com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser;
+import com.ibatis.sqlmap.engine.builder.xml.SqlMapParser;
+import com.ibatis.sqlmap.engine.builder.xml.XmlParserState;
+import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
+import com.ibatis.sqlmap.engine.transaction.TransactionConfig;
+import com.ibatis.sqlmap.engine.transaction.TransactionManager;
+import com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.NestedIOException;
+import org.springframework.core.io.Resource;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that creates an
+ * iBATIS {@link com.ibatis.sqlmap.client.SqlMapClient}. This is the usual
+ * way to set up a shared iBATIS SqlMapClient in a Spring application context;
+ * the SqlMapClient can then be passed to iBATIS-based DAOs via dependency
+ * injection.
+ *
+ *
Either {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} can be
+ * used for transaction demarcation in combination with a SqlMapClient,
+ * with JTA only necessary for transactions which span multiple databases.
+ *
+ *
Allows for specifying a DataSource at the SqlMapClient level. This
+ * is preferable to per-DAO DataSource references, as it allows for lazy
+ * loading and avoids repeated DataSource references in every DAO.
+ *
+ *
Note: As of Spring 2.5.5, this class (finally) requires iBATIS 2.3
+ * or higher. The new "mappingLocations" feature requires iBATIS 2.3.2.
+ *
+ * @author Juergen Hoeller
+ * @since 24.02.2004
+ * @see #setConfigLocation
+ * @see #setDataSource
+ * @see SqlMapClientTemplate#setSqlMapClient
+ * @see SqlMapClientTemplate#setDataSource
+ */
+public class SqlMapClientFactoryBean implements FactoryBean, InitializingBean {
+
+ private static final ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
+
+ /**
+ * Return the LobHandler for the currently configured iBATIS SqlMapClient,
+ * to be used by TypeHandler implementations like ClobStringTypeHandler.
+ *
This instance will be set before initialization of the corresponding
+ * SqlMapClient, and reset immediately afterwards. It is thus only available
+ * during configuration.
+ * @see #setLobHandler
+ * @see org.springframework.orm.ibatis.support.ClobStringTypeHandler
+ * @see org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler
+ * @see org.springframework.orm.ibatis.support.BlobSerializableTypeHandler
+ */
+ public static LobHandler getConfigTimeLobHandler() {
+ return (LobHandler) configTimeLobHandlerHolder.get();
+ }
+
+
+ private Resource[] configLocations;
+
+ private Resource[] mappingLocations;
+
+ private Properties sqlMapClientProperties;
+
+ private DataSource dataSource;
+
+ private boolean useTransactionAwareDataSource = true;
+
+ private Class transactionConfigClass = ExternalTransactionConfig.class;
+
+ private Properties transactionConfigProperties;
+
+ private LobHandler lobHandler;
+
+ private SqlMapClient sqlMapClient;
+
+
+ public SqlMapClientFactoryBean() {
+ this.transactionConfigProperties = new Properties();
+ this.transactionConfigProperties.setProperty("SetAutoCommitAllowed", "false");
+ }
+
+ /**
+ * Set the location of the iBATIS SqlMapClient config file.
+ * A typical value is "WEB-INF/sql-map-config.xml".
+ * @see #setConfigLocations
+ */
+ public void setConfigLocation(Resource configLocation) {
+ this.configLocations = (configLocation != null ? new Resource[] {configLocation} : null);
+ }
+
+ /**
+ * Set multiple locations of iBATIS SqlMapClient config files that
+ * are going to be merged into one unified configuration at runtime.
+ */
+ public void setConfigLocations(Resource[] configLocations) {
+ this.configLocations = configLocations;
+ }
+
+ /**
+ * Set locations of iBATIS sql-map mapping files that are going to be
+ * merged into the SqlMapClient configuration at runtime.
+ *
This is an alternative to specifying "<sqlMap>" entries
+ * in a sql-map-client config file. This property being based on Spring's
+ * resource abstraction also allows for specifying resource patterns here:
+ * e.g. "/myApp/*-map.xml".
+ *
Note that this feature requires iBATIS 2.3.2; it will not work
+ * with any previous iBATIS version.
+ */
+ public void setMappingLocations(Resource[] mappingLocations) {
+ this.mappingLocations = mappingLocations;
+ }
+
+ /**
+ * Set optional properties to be passed into the SqlMapClientBuilder, as
+ * alternative to a <properties> tag in the sql-map-config.xml
+ * file. Will be used to resolve placeholders in the config file.
+ * @see #setConfigLocation
+ * @see com.ibatis.sqlmap.client.SqlMapClientBuilder#buildSqlMapClient(java.io.InputStream, java.util.Properties)
+ */
+ public void setSqlMapClientProperties(Properties sqlMapClientProperties) {
+ this.sqlMapClientProperties = sqlMapClientProperties;
+ }
+
+ /**
+ * Set the DataSource to be used by iBATIS SQL Maps. This will be passed to the
+ * SqlMapClient as part of a TransactionConfig instance.
+ *
If specified, this will override corresponding settings in the SqlMapClient
+ * properties. Usually, you will specify DataSource and transaction configuration
+ * either here or in SqlMapClient properties.
+ *
Specifying a DataSource for the SqlMapClient rather than for each individual
+ * DAO allows for lazy loading, for example when using PaginatedList results.
+ *
With a DataSource passed in here, you don't need to specify one for each DAO.
+ * Passing the SqlMapClient to the DAOs is enough, as it already carries a DataSource.
+ * Thus, it's recommended to specify the DataSource at this central location only.
+ *
Thanks to Brandon Goodin from the iBATIS team for the hint on how to make
+ * this work with Spring's integration strategy!
+ * @see #setTransactionConfigClass
+ * @see #setTransactionConfigProperties
+ * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
+ * @see SqlMapClientTemplate#setDataSource
+ * @see SqlMapClientTemplate#queryForPaginatedList
+ */
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ /**
+ * Set whether to use a transaction-aware DataSource for the SqlMapClient,
+ * i.e. whether to automatically wrap the passed-in DataSource with Spring's
+ * TransactionAwareDataSourceProxy.
+ *
Default is "true": When the SqlMapClient performs direct database operations
+ * outside of Spring's SqlMapClientTemplate (for example, lazy loading or direct
+ * SqlMapClient access), it will still participate in active Spring-managed
+ * transactions.
+ *
As a further effect, using a transaction-aware DataSource will apply
+ * remaining transaction timeouts to all created JDBC Statements. This means
+ * that all operations performed by the SqlMapClient will automatically
+ * participate in Spring-managed transaction timeouts.
+ *
Turn this flag off to get raw DataSource handling, without Spring transaction
+ * checks. Operations on Spring's SqlMapClientTemplate will still detect
+ * Spring-managed transactions, but lazy loading or direct SqlMapClient access won't.
+ * @see #setDataSource
+ * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ * @see SqlMapClientTemplate
+ * @see com.ibatis.sqlmap.client.SqlMapClient
+ */
+ public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
+ this.useTransactionAwareDataSource = useTransactionAwareDataSource;
+ }
+
+ /**
+ * Set the iBATIS TransactionConfig class to use. Default is
+ * com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig.
+ *
Will only get applied when using a Spring-managed DataSource.
+ * An instance of this class will get populated with the given DataSource
+ * and initialized with the given properties.
+ *
The default ExternalTransactionConfig is appropriate if there is
+ * external transaction management that the SqlMapClient should participate
+ * in: be it Spring transaction management, EJB CMT or plain JTA. This
+ * should be the typical scenario. If there is no active transaction,
+ * SqlMapClient operations will execute SQL statements non-transactionally.
+ *
JdbcTransactionConfig or JtaTransactionConfig is only necessary
+ * when using the iBATIS SqlMapTransactionManager API instead of external
+ * transactions. If there is no explicit transaction, SqlMapClient operations
+ * will automatically start a transaction for their own scope (in contrast
+ * to the external transaction mode, see above).
+ *
It is strongly recommended to use iBATIS SQL Maps with Spring
+ * transaction management (or EJB CMT). In this case, the default
+ * ExternalTransactionConfig is fine. Lazy loading and SQL Maps operations
+ * without explicit transaction demarcation will execute non-transactionally.
+ *
Even with Spring transaction management, it might be desirable to
+ * specify JdbcTransactionConfig: This will still participate in existing
+ * Spring-managed transactions, but lazy loading and operations without
+ * explicit transaction demaration will execute in their own auto-started
+ * transactions. However, this is usually not necessary.
+ * @see #setDataSource
+ * @see #setTransactionConfigProperties
+ * @see com.ibatis.sqlmap.engine.transaction.TransactionConfig
+ * @see com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
+ * @see com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
+ * @see com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
+ * @see com.ibatis.sqlmap.client.SqlMapTransactionManager
+ */
+ public void setTransactionConfigClass(Class transactionConfigClass) {
+ if (transactionConfigClass == null || !TransactionConfig.class.isAssignableFrom(transactionConfigClass)) {
+ throw new IllegalArgumentException("Invalid transactionConfigClass: does not implement " +
+ "com.ibatis.sqlmap.engine.transaction.TransactionConfig");
+ }
+ this.transactionConfigClass = transactionConfigClass;
+ }
+
+ /**
+ * Set properties to be passed to the TransactionConfig instance used
+ * by this SqlMapClient. Supported properties depend on the concrete
+ * TransactionConfig implementation used:
+ *
+ *
ExternalTransactionConfig supports "DefaultAutoCommit"
+ * (default: false) and "SetAutoCommitAllowed" (default: true).
+ * Note that Spring uses SetAutoCommitAllowed = false as default,
+ * in contrast to the iBATIS default, to always keep the original
+ * autoCommit value as provided by the connection pool.
+ *
JdbcTransactionConfig does not supported any properties.
+ *
JtaTransactionConfig supports "UserTransaction"
+ * (no default), specifying the JNDI location of the JTA UserTransaction
+ * (usually "java:comp/UserTransaction").
+ *
+ * @see com.ibatis.sqlmap.engine.transaction.TransactionConfig#initialize
+ * @see com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
+ * @see com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
+ * @see com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
+ */
+ public void setTransactionConfigProperties(Properties transactionConfigProperties) {
+ this.transactionConfigProperties = transactionConfigProperties;
+ }
+
+ /**
+ * Set the LobHandler to be used by the SqlMapClient.
+ * Will be exposed at config time for TypeHandler implementations.
+ * @see #getConfigTimeLobHandler
+ * @see com.ibatis.sqlmap.engine.type.TypeHandler
+ * @see org.springframework.orm.ibatis.support.ClobStringTypeHandler
+ * @see org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler
+ * @see org.springframework.orm.ibatis.support.BlobSerializableTypeHandler
+ */
+ public void setLobHandler(LobHandler lobHandler) {
+ this.lobHandler = lobHandler;
+ }
+
+
+ public void afterPropertiesSet() throws Exception {
+ if (this.lobHandler != null) {
+ // Make given LobHandler available for SqlMapClient configuration.
+ // Do early because because mapping resource might refer to custom types.
+ configTimeLobHandlerHolder.set(this.lobHandler);
+ }
+
+ try {
+ this.sqlMapClient = buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties);
+
+ // Tell the SqlMapClient to use the given DataSource, if any.
+ if (this.dataSource != null) {
+ TransactionConfig transactionConfig = (TransactionConfig) this.transactionConfigClass.newInstance();
+ DataSource dataSourceToUse = this.dataSource;
+ if (this.useTransactionAwareDataSource && !(this.dataSource instanceof TransactionAwareDataSourceProxy)) {
+ dataSourceToUse = new TransactionAwareDataSourceProxy(this.dataSource);
+ }
+ transactionConfig.setDataSource(dataSourceToUse);
+ transactionConfig.initialize(this.transactionConfigProperties);
+ applyTransactionConfig(this.sqlMapClient, transactionConfig);
+ }
+ }
+
+ finally {
+ if (this.lobHandler != null) {
+ // Reset LobHandler holder.
+ configTimeLobHandlerHolder.set(null);
+ }
+ }
+ }
+
+ /**
+ * Build a SqlMapClient instance based on the given standard configuration.
+ *
The default implementation uses the standard iBATIS {@link SqlMapClientBuilder}
+ * API to build a SqlMapClient instance based on an InputStream (if possible,
+ * on iBATIS 2.3 and higher) or on a Reader (on iBATIS up to version 2.2).
+ * @param configLocations the config files to load from
+ * @param properties the SqlMapClient properties (if any)
+ * @return the SqlMapClient instance (never null)
+ * @throws IOException if loading the config file failed
+ * @see com.ibatis.sqlmap.client.SqlMapClientBuilder#buildSqlMapClient
+ */
+ protected SqlMapClient buildSqlMapClient(
+ Resource[] configLocations, Resource[] mappingLocations, Properties properties)
+ throws IOException {
+
+ if (ObjectUtils.isEmpty(configLocations)) {
+ throw new IllegalArgumentException("At least 1 'configLocation' entry is required");
+ }
+
+ SqlMapClient client = null;
+ SqlMapConfigParser configParser = new SqlMapConfigParser();
+ for (int i = 0; i < configLocations.length; i++) {
+ InputStream is = configLocations[i].getInputStream();
+ try {
+ client = configParser.parse(is, properties);
+ }
+ catch (RuntimeException ex) {
+ throw new NestedIOException("Failed to parse config resource: " + configLocations[i], ex.getCause());
+ }
+ }
+
+ if (mappingLocations != null) {
+ SqlMapParser mapParser = SqlMapParserFactory.createSqlMapParser(configParser);
+ for (int i = 0; i < mappingLocations.length; i++) {
+ try {
+ mapParser.parse(mappingLocations[i].getInputStream());
+ }
+ catch (NodeletException ex) {
+ throw new NestedIOException("Failed to parse mapping resource: " + mappingLocations[i], ex);
+ }
+ }
+ }
+
+ return client;
+ }
+
+ /**
+ * Apply the given iBATIS TransactionConfig to the SqlMapClient.
+ *
The default implementation casts to ExtendedSqlMapClient, retrieves the maximum
+ * number of concurrent transactions from the SqlMapExecutorDelegate, and sets
+ * an iBATIS TransactionManager with the given TransactionConfig.
+ * @param sqlMapClient the SqlMapClient to apply the TransactionConfig to
+ * @param transactionConfig the iBATIS TransactionConfig to apply
+ * @see com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient
+ * @see com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate#getMaxTransactions
+ * @see com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate#setTxManager
+ */
+ protected void applyTransactionConfig(SqlMapClient sqlMapClient, TransactionConfig transactionConfig) {
+ if (!(sqlMapClient instanceof ExtendedSqlMapClient)) {
+ throw new IllegalArgumentException(
+ "Cannot set TransactionConfig with DataSource for SqlMapClient if not of type " +
+ "ExtendedSqlMapClient: " + sqlMapClient);
+ }
+ ExtendedSqlMapClient extendedClient = (ExtendedSqlMapClient) sqlMapClient;
+ transactionConfig.setMaximumConcurrentTransactions(extendedClient.getDelegate().getMaxTransactions());
+ extendedClient.getDelegate().setTxManager(new TransactionManager(transactionConfig));
+ }
+
+
+ public Object getObject() {
+ return this.sqlMapClient;
+ }
+
+ public Class getObjectType() {
+ return (this.sqlMapClient != null ? this.sqlMapClient.getClass() : SqlMapClient.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Inner class to avoid hard-coded iBATIS 2.3.2 dependency (XmlParserState class).
+ */
+ private static class SqlMapParserFactory {
+
+ public static SqlMapParser createSqlMapParser(SqlMapConfigParser configParser) {
+ // Ideally: XmlParserState state = configParser.getState();
+ // Should raise an enhancement request with iBATIS...
+ XmlParserState state = null;
+ try {
+ Field stateField = SqlMapConfigParser.class.getDeclaredField("state");
+ stateField.setAccessible(true);
+ state = (XmlParserState) stateField.get(configParser);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("iBATIS 2.3.2 'state' field not found in SqlMapConfigParser class - " +
+ "please upgrade to IBATIS 2.3.2 or higher in order to use the new 'mappingLocations' feature. " + ex);
+ }
+ return new SqlMapParser(state);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientOperations.java 17 Aug 2012 15:16:06 -0000 1.1
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2002-2006 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.orm.ibatis;
+
+import java.util.List;
+import java.util.Map;
+
+import com.ibatis.common.util.PaginatedList;
+import com.ibatis.sqlmap.client.event.RowHandler;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Interface that specifies a basic set of iBATIS SqlMapClient operations,
+ * implemented by {@link SqlMapClientTemplate}. Not often used, but a useful
+ * option to enhance testability, as it can easily be mocked or stubbed.
+ *
+ *
Defines SqlMapClientTemplate's convenience methods that mirror
+ * the iBATIS {@link com.ibatis.sqlmap.client.SqlMapExecutor}'s execution
+ * methods. Users are strongly encouraged to read the iBATIS javadocs
+ * for details on the semantics of those methods.
+ *
+ * @author Juergen Hoeller
+ * @since 24.02.2004
+ * @see SqlMapClientTemplate
+ * @see com.ibatis.sqlmap.client.SqlMapClient
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor
+ */
+public interface SqlMapClientOperations {
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForObject(String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Object queryForObject(String statementName) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForObject(String, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Object queryForObject(String statementName, Object parameterObject)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForObject(String, Object, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Object queryForObject(String statementName, Object parameterObject, Object resultObject)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForList(String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ List queryForList(String statementName) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForList(String, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ List queryForList(String statementName, Object parameterObject)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForList(String, int, int)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ List queryForList(String statementName, int skipResults, int maxResults)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForList(String, Object, int, int)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ List queryForList(String statementName, Object parameterObject, int skipResults, int maxResults)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryWithRowHandler(String, RowHandler)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ void queryWithRowHandler(String statementName, RowHandler rowHandler)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryWithRowHandler(String, Object, RowHandler)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ void queryWithRowHandler(String statementName, Object parameterObject, RowHandler rowHandler)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForPaginatedList(String, int)
+ * @deprecated as of iBATIS 2.3.0
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ PaginatedList queryForPaginatedList(String statementName, int pageSize)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForPaginatedList(String, Object, int)
+ * @deprecated as of iBATIS 2.3.0
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ PaginatedList queryForPaginatedList(String statementName, Object parameterObject, int pageSize)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForMap(String, Object, String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Map queryForMap(String statementName, Object parameterObject, String keyProperty)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#queryForMap(String, Object, String, String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Map queryForMap(String statementName, Object parameterObject, String keyProperty, String valueProperty)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#insert(String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Object insert(String statementName) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#insert(String, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ Object insert(String statementName, Object parameterObject) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#update(String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ int update(String statementName) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#update(String, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ int update(String statementName, Object parameterObject) throws DataAccessException;
+
+ /**
+ * Convenience method provided by Spring: execute an update operation
+ * with an automatic check that the update affected the given required
+ * number of rows.
+ * @param statementName the name of the mapped statement
+ * @param parameterObject the parameter object
+ * @param requiredRowsAffected the number of rows that the update is
+ * required to affect
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ void update(String statementName, Object parameterObject, int requiredRowsAffected)
+ throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#delete(String)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ int delete(String statementName) throws DataAccessException;
+
+ /**
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor#delete(String, Object)
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ int delete(String statementName, Object parameterObject) throws DataAccessException;
+
+ /**
+ * Convenience method provided by Spring: execute a delete operation
+ * with an automatic check that the delete affected the given required
+ * number of rows.
+ * @param statementName the name of the mapped statement
+ * @param parameterObject the parameter object
+ * @param requiredRowsAffected the number of rows that the delete is
+ * required to affect
+ * @throws org.springframework.dao.DataAccessException in case of errors
+ */
+ void delete(String statementName, Object parameterObject, int requiredRowsAffected)
+ throws DataAccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/SqlMapClientTemplate.java 17 Aug 2012 15:16:06 -0000 1.1
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2002-2007 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.orm.ibatis;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import com.ibatis.common.util.PaginatedList;
+import com.ibatis.sqlmap.client.SqlMapClient;
+import com.ibatis.sqlmap.client.SqlMapExecutor;
+import com.ibatis.sqlmap.client.SqlMapSession;
+import com.ibatis.sqlmap.client.event.RowHandler;
+import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.jdbc.CannotGetJdbcConnectionException;
+import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.jdbc.support.JdbcAccessor;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class that simplifies data access via the iBATIS
+ * {@link com.ibatis.sqlmap.client.SqlMapClient} API, converting checked
+ * SQLExceptions into unchecked DataAccessExceptions, following the
+ * org.springframework.dao exception hierarchy.
+ * Uses the same {@link org.springframework.jdbc.support.SQLExceptionTranslator}
+ * mechanism as {@link org.springframework.jdbc.core.JdbcTemplate}.
+ *
+ *
The main method of this class executes a callback that implements a
+ * data access action. Furthermore, this class provides numerous convenience
+ * methods that mirror {@link com.ibatis.sqlmap.client.SqlMapExecutor}'s
+ * execution methods.
+ *
+ *
It is generally recommended to use the convenience methods on this template
+ * for plain query/insert/update/delete operations. However, for more complex
+ * operations like batch updates, a custom SqlMapClientCallback must be implemented,
+ * usually as anonymous inner class. For example:
+ *
+ *
+ *
+ * The template needs a SqlMapClient to work on, passed in via the "sqlMapClient"
+ * property. A Spring context typically uses a {@link SqlMapClientFactoryBean}
+ * to build the SqlMapClient. The template an additionally be configured with a
+ * DataSource for fetching Connections, although this is not necessary if a
+ * DataSource is specified for the SqlMapClient itself (typically through
+ * SqlMapClientFactoryBean's "dataSource" property).
+ *
+ * @author Juergen Hoeller
+ * @since 24.02.2004
+ * @see #execute
+ * @see #setSqlMapClient
+ * @see #setDataSource
+ * @see #setExceptionTranslator
+ * @see SqlMapClientFactoryBean#setDataSource
+ * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
+ * @see com.ibatis.sqlmap.client.SqlMapExecutor
+ */
+public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {
+
+ private SqlMapClient sqlMapClient;
+
+ private boolean lazyLoadingAvailable = true;
+
+
+ /**
+ * Create a new SqlMapClientTemplate.
+ */
+ public SqlMapClientTemplate() {
+ }
+
+ /**
+ * Create a new SqlMapTemplate.
+ * @param sqlMapClient iBATIS SqlMapClient that defines the mapped statements
+ */
+ public SqlMapClientTemplate(SqlMapClient sqlMapClient) {
+ setSqlMapClient(sqlMapClient);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Create a new SqlMapTemplate.
+ * @param dataSource JDBC DataSource to obtain connections from
+ * @param sqlMapClient iBATIS SqlMapClient that defines the mapped statements
+ */
+ public SqlMapClientTemplate(DataSource dataSource, SqlMapClient sqlMapClient) {
+ setDataSource(dataSource);
+ setSqlMapClient(sqlMapClient);
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set the iBATIS Database Layer SqlMapClient that defines the mapped statements.
+ */
+ public void setSqlMapClient(SqlMapClient sqlMapClient) {
+ this.sqlMapClient = sqlMapClient;
+ }
+
+ /**
+ * Return the iBATIS Database Layer SqlMapClient that this template works with.
+ */
+ public SqlMapClient getSqlMapClient() {
+ return this.sqlMapClient;
+ }
+
+ /**
+ * If no DataSource specified, use SqlMapClient's DataSource.
+ * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource()
+ */
+ public DataSource getDataSource() {
+ DataSource ds = super.getDataSource();
+ return (ds != null ? ds : this.sqlMapClient.getDataSource());
+ }
+
+ public void afterPropertiesSet() {
+ if (this.sqlMapClient == null) {
+ throw new IllegalArgumentException("Property 'sqlMapClient' is required");
+ }
+ if (this.sqlMapClient instanceof ExtendedSqlMapClient) {
+ // Check whether iBATIS lazy loading is available, that is,
+ // whether a DataSource was specified on the SqlMapClient itself.
+ this.lazyLoadingAvailable = (((ExtendedSqlMapClient) this.sqlMapClient).getDelegate().getTxManager() != null);
+ }
+ super.afterPropertiesSet();
+ }
+
+
+ /**
+ * Execute the given data access action on a SqlMapExecutor.
+ * @param action callback object that specifies the data access action
+ * @return a result object returned by the action, or null
+ * @throws DataAccessException in case of SQL Maps errors
+ */
+ public Object execute(SqlMapClientCallback action) throws DataAccessException {
+ Assert.notNull(action, "Callback object must not be null");
+ Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
+
+ // We always needs to use a SqlMapSession, as we need to pass a Spring-managed
+ // Connection (potentially transactional) in. This shouldn't be necessary if
+ // we run against a TransactionAwareDataSourceProxy underneath, but unfortunately
+ // we still need it to make iBATIS batch execution work properly: If iBATIS
+ // doesn't recognize an existing transaction, it automatically executes the
+ // batch for every single statement...
+
+ SqlMapSession session = this.sqlMapClient.openSession();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
+ }
+ Connection ibatisCon = null;
+
+ try {
+ Connection springCon = null;
+ DataSource dataSource = getDataSource();
+ boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);
+
+ // Obtain JDBC Connection to operate on...
+ try {
+ ibatisCon = session.getCurrentConnection();
+ if (ibatisCon == null) {
+ springCon = (transactionAware ?
+ dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
+ session.setUserConnection(springCon);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
+ }
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
+ }
+ }
+ }
+ catch (SQLException ex) {
+ throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
+ }
+
+ // Execute given callback...
+ try {
+ return action.doInSqlMapClient(session);
+ }
+ catch (SQLException ex) {
+ throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
+ }
+ finally {
+ try {
+ if (springCon != null) {
+ if (transactionAware) {
+ springCon.close();
+ }
+ else {
+ DataSourceUtils.doReleaseConnection(springCon, dataSource);
+ }
+ }
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not close JDBC Connection", ex);
+ }
+ }
+
+ // Processing finished - potentially session still to be closed.
+ }
+ finally {
+ // Only close SqlMapSession if we know we've actually opened it
+ // at the present level.
+ if (ibatisCon == null) {
+ session.close();
+ }
+ }
+ }
+
+ /**
+ * Execute the given data access action on a SqlMapExecutor,
+ * expecting a List result.
+ * @param action callback object that specifies the data access action
+ * @return the List result
+ * @throws DataAccessException in case of SQL Maps errors
+ */
+ public List executeWithListResult(SqlMapClientCallback action) throws DataAccessException {
+ return (List) execute(action);
+ }
+
+ /**
+ * Execute the given data access action on a SqlMapExecutor,
+ * expecting a Map result.
+ * @param action callback object that specifies the data access action
+ * @return the Map result
+ * @throws DataAccessException in case of SQL Maps errors
+ */
+ public Map executeWithMapResult(SqlMapClientCallback action) throws DataAccessException {
+ return (Map) execute(action);
+ }
+
+
+ public Object queryForObject(String statementName) throws DataAccessException {
+ return queryForObject(statementName, null);
+ }
+
+ public Object queryForObject(final String statementName, final Object parameterObject)
+ throws DataAccessException {
+
+ return execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForObject(statementName, parameterObject);
+ }
+ });
+ }
+
+ public Object queryForObject(
+ final String statementName, final Object parameterObject, final Object resultObject)
+ throws DataAccessException {
+
+ return execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForObject(statementName, parameterObject, resultObject);
+ }
+ });
+ }
+
+ public List queryForList(String statementName) throws DataAccessException {
+ return queryForList(statementName, null);
+ }
+
+ public List queryForList(final String statementName, final Object parameterObject)
+ throws DataAccessException {
+
+ return executeWithListResult(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForList(statementName, parameterObject);
+ }
+ });
+ }
+
+ public List queryForList(String statementName, int skipResults, int maxResults)
+ throws DataAccessException {
+
+ return queryForList(statementName, null, skipResults, maxResults);
+ }
+
+ public List queryForList(
+ final String statementName, final Object parameterObject, final int skipResults, final int maxResults)
+ throws DataAccessException {
+
+ return executeWithListResult(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForList(statementName, parameterObject, skipResults, maxResults);
+ }
+ });
+ }
+
+ public void queryWithRowHandler(String statementName, RowHandler rowHandler)
+ throws DataAccessException {
+
+ queryWithRowHandler(statementName, null, rowHandler);
+ }
+
+ public void queryWithRowHandler(
+ final String statementName, final Object parameterObject, final RowHandler rowHandler)
+ throws DataAccessException {
+
+ execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ executor.queryWithRowHandler(statementName, parameterObject, rowHandler);
+ return null;
+ }
+ });
+ }
+
+ /**
+ * @deprecated as of iBATIS 2.3.0
+ */
+ public PaginatedList queryForPaginatedList(String statementName, int pageSize)
+ throws DataAccessException {
+
+ return queryForPaginatedList(statementName, null, pageSize);
+ }
+
+ /**
+ * @deprecated as of iBATIS 2.3.0
+ */
+ public PaginatedList queryForPaginatedList(
+ final String statementName, final Object parameterObject, final int pageSize)
+ throws DataAccessException {
+
+ // Throw exception if lazy loading will not work.
+ if (!this.lazyLoadingAvailable) {
+ throw new InvalidDataAccessApiUsageException(
+ "SqlMapClient needs to have DataSource to allow for lazy loading" +
+ " - specify SqlMapClientFactoryBean's 'dataSource' property");
+ }
+
+ return (PaginatedList) execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForPaginatedList(statementName, parameterObject, pageSize);
+ }
+ });
+ }
+
+ public Map queryForMap(
+ final String statementName, final Object parameterObject, final String keyProperty)
+ throws DataAccessException {
+
+ return executeWithMapResult(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForMap(statementName, parameterObject, keyProperty);
+ }
+ });
+ }
+
+ public Map queryForMap(
+ final String statementName, final Object parameterObject, final String keyProperty, final String valueProperty)
+ throws DataAccessException {
+
+ return executeWithMapResult(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.queryForMap(statementName, parameterObject, keyProperty, valueProperty);
+ }
+ });
+ }
+
+ public Object insert(String statementName) throws DataAccessException {
+ return insert(statementName, null);
+ }
+
+ public Object insert(final String statementName, final Object parameterObject)
+ throws DataAccessException {
+
+ return execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return executor.insert(statementName, parameterObject);
+ }
+ });
+ }
+
+ public int update(String statementName) throws DataAccessException {
+ return update(statementName, null);
+ }
+
+ public int update(final String statementName, final Object parameterObject)
+ throws DataAccessException {
+
+ Integer result = (Integer) execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return new Integer(executor.update(statementName, parameterObject));
+ }
+ });
+ return result.intValue();
+ }
+
+ public void update(String statementName, Object parameterObject, int requiredRowsAffected)
+ throws DataAccessException {
+
+ int actualRowsAffected = update(statementName, parameterObject);
+ if (actualRowsAffected != requiredRowsAffected) {
+ throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
+ statementName, requiredRowsAffected, actualRowsAffected);
+ }
+ }
+
+ public int delete(String statementName) throws DataAccessException {
+ return delete(statementName, null);
+ }
+
+ public int delete(final String statementName, final Object parameterObject)
+ throws DataAccessException {
+
+ Integer result = (Integer) execute(new SqlMapClientCallback() {
+ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
+ return new Integer(executor.delete(statementName, parameterObject));
+ }
+ });
+ return result.intValue();
+ }
+
+ public void delete(String statementName, Object parameterObject, int requiredRowsAffected)
+ throws DataAccessException {
+
+ int actualRowsAffected = delete(statementName, parameterObject);
+ if (actualRowsAffected != requiredRowsAffected) {
+ throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
+ statementName, requiredRowsAffected, actualRowsAffected);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/package.html 17 Aug 2012 15:16:06 -0000 1.1
@@ -0,0 +1,12 @@
+
+
+
+Package providing integration of
+iBATIS Database Layer
+with Spring concepts.
+
+
Contains resource helper classes and template classes for
+data access with the iBATIS SqlMapClient API.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/AbstractLobTypeHandler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/AbstractLobTypeHandler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/AbstractLobTypeHandler.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2002-2005 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.orm.ibatis.support;
+
+import java.io.IOException;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import com.ibatis.sqlmap.engine.type.BaseTypeHandler;
+
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+import org.springframework.orm.ibatis.SqlMapClientFactoryBean;
+import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * Abstract base class for iBATIS TypeHandler implementations that map to LOBs.
+ * Retrieves the LobHandler to use from SqlMapClientFactoryBean at config time.
+ *
+ *
For writing LOBs, an active Spring transaction synchronization is required,
+ * to be able to register a synchronization that closes the LobCreator.
+ *
+ *
Offers template methods for setting parameters and getting result values,
+ * passing in the LobHandler or LobCreator to use.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see org.springframework.jdbc.support.lob.LobHandler
+ * @see org.springframework.jdbc.support.lob.LobCreator
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#setLobHandler
+ */
+public abstract class AbstractLobTypeHandler extends BaseTypeHandler {
+
+ /**
+ * Order value for TransactionSynchronization objects that clean up LobCreators.
+ * Return DataSourceUtils.#CONNECTION_SYNCHRONIZATION_ORDER - 100 to execute
+ * LobCreator cleanup before JDBC Connection cleanup, if any.
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
+ */
+ public static final int LOB_CREATOR_SYNCHRONIZATION_ORDER =
+ DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 200;
+
+ private LobHandler lobHandler;
+
+
+ /**
+ * Constructor used by iBATIS: fetches config-time LobHandler from
+ * SqlMapClientFactoryBean.
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#getConfigTimeLobHandler
+ */
+ public AbstractLobTypeHandler() {
+ this(SqlMapClientFactoryBean.getConfigTimeLobHandler());
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler.
+ */
+ protected AbstractLobTypeHandler(LobHandler lobHandler) {
+ if (lobHandler == null) {
+ throw new IllegalStateException("No LobHandler found for configuration - " +
+ "lobHandler property must be set on SqlMapClientFactoryBean");
+ }
+ this.lobHandler = lobHandler;
+ }
+
+
+ /**
+ * This implementation delegates to setParameterInternal,
+ * passing in a transaction-synchronized LobCreator for the
+ * LobHandler of this type.
+ * @see #setParameterInternal
+ */
+ public final void setParameter(PreparedStatement ps, int i, Object parameter, String jdbcType)
+ throws SQLException {
+
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ throw new IllegalStateException("Spring transaction synchronization needs to be active for " +
+ "setting values in iBATIS TypeHandlers that delegate to a Spring LobHandler");
+ }
+ final LobCreator lobCreator = this.lobHandler.getLobCreator();
+ try {
+ setParameterInternal(ps, i, parameter, jdbcType, lobCreator);
+ }
+ catch (IOException ex) {
+ throw new SQLException("I/O errors during LOB access: " + ex.getMessage());
+ }
+
+ TransactionSynchronizationManager.registerSynchronization(
+ new LobCreatorSynchronization(lobCreator));
+ }
+
+ /**
+ * This implementation delegates to the getResult version
+ * that takes a column index.
+ * @see #getResult(java.sql.ResultSet, String)
+ * @see java.sql.ResultSet#findColumn
+ */
+ public final Object getResult(ResultSet rs, String columnName) throws SQLException {
+ return getResult(rs, rs.findColumn(columnName));
+ }
+
+ /**
+ * This implementation delegates to getResultInternal,
+ * passing in the LobHandler of this type.
+ * @see #getResultInternal
+ */
+ public final Object getResult(ResultSet rs, int columnIndex) throws SQLException {
+ try {
+ return getResultInternal(rs, columnIndex, this.lobHandler);
+ }
+ catch (IOException ex) {
+ throw new SQLException(
+ "I/O errors during LOB access: " + ex.getClass().getName() + ": " + ex.getMessage());
+ }
+ }
+
+ /**
+ * This implementation always throws a SQLException:
+ * retrieving LOBs from a CallableStatement is not supported.
+ */
+ public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
+ throw new SQLException("Retrieving LOBs from a CallableStatement is not supported");
+ }
+
+
+ /**
+ * Template method to set the given value on the given statement.
+ * @param ps the PreparedStatement to set on
+ * @param index the statement parameter index
+ * @param value the parameter value to set
+ * @param jdbcType the JDBC type of the parameter
+ * @param lobCreator the LobCreator to use
+ * @throws SQLException if thrown by JDBC methods
+ * @throws IOException if thrown by streaming methods
+ */
+ protected abstract void setParameterInternal(
+ PreparedStatement ps, int index, Object value, String jdbcType, LobCreator lobCreator)
+ throws SQLException, IOException;
+
+ /**
+ * Template method to extract a value from the given result set.
+ * @param rs the ResultSet to extract from
+ * @param index the index in the ResultSet
+ * @param lobHandler the LobHandler to use
+ * @return the extracted value
+ * @throws SQLException if thrown by JDBC methods
+ * @throws IOException if thrown by streaming methods
+ */
+ protected abstract Object getResultInternal(ResultSet rs, int index, LobHandler lobHandler)
+ throws SQLException, IOException;
+
+
+ /**
+ * Callback for resource cleanup at the end of a Spring transaction.
+ * Invokes LobCreator.close to clean up temporary LOBs that might have been created.
+ * @see org.springframework.jdbc.support.lob.LobCreator#close
+ */
+ private static class LobCreatorSynchronization extends TransactionSynchronizationAdapter {
+
+ private final LobCreator lobCreator;
+
+ public LobCreatorSynchronization(LobCreator lobCreator) {
+ this.lobCreator = lobCreator;
+ }
+
+ public int getOrder() {
+ return LOB_CREATOR_SYNCHRONIZATION_ORDER;
+ }
+
+ public void beforeCompletion() {
+ this.lobCreator.close();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobByteArrayTypeHandler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobByteArrayTypeHandler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobByteArrayTypeHandler.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2002-2005 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.orm.ibatis.support;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * iBATIS TypeHandler implementation for byte arrays that get mapped to BLOBs.
+ * Retrieves the LobHandler to use from SqlMapClientFactoryBean at config time.
+ *
+ *
Can also be defined in generic iBATIS mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#setLobHandler
+ */
+public class BlobByteArrayTypeHandler extends AbstractLobTypeHandler {
+
+ /**
+ * Constructor used by iBATIS: fetches config-time LobHandler from
+ * SqlMapClientFactoryBean.
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#getConfigTimeLobHandler
+ */
+ public BlobByteArrayTypeHandler() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler.
+ */
+ protected BlobByteArrayTypeHandler(LobHandler lobHandler) {
+ super(lobHandler);
+ }
+
+ protected void setParameterInternal(
+ PreparedStatement ps, int index, Object value, String jdbcType, LobCreator lobCreator)
+ throws SQLException {
+ lobCreator.setBlobAsBytes(ps, index, (byte[]) value);
+ }
+
+ protected Object getResultInternal(ResultSet rs, int index, LobHandler lobHandler)
+ throws SQLException {
+ return lobHandler.getBlobAsBytes(rs, index);
+ }
+
+ public Object valueOf(String s) {
+ return s.getBytes();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobSerializableTypeHandler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobSerializableTypeHandler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/BlobSerializableTypeHandler.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002-2005 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.orm.ibatis.support;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * iBATIS TypeHandler implementation for arbitrary objects that get serialized to BLOBs.
+ * Retrieves the LobHandler to use from SqlMapClientFactoryBean at config time.
+ *
+ *
Can also be defined in generic iBATIS mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#setLobHandler
+ */
+public class BlobSerializableTypeHandler extends AbstractLobTypeHandler {
+
+ /**
+ * Constructor used by iBATIS: fetches config-time LobHandler from
+ * SqlMapClientFactoryBean.
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#getConfigTimeLobHandler
+ */
+ public BlobSerializableTypeHandler() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler.
+ */
+ protected BlobSerializableTypeHandler(LobHandler lobHandler) {
+ super(lobHandler);
+ }
+
+ protected void setParameterInternal(
+ PreparedStatement ps, int index, Object value, String jdbcType, LobCreator lobCreator)
+ throws SQLException, IOException {
+
+ if (value != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ try {
+ oos.writeObject(value);
+ oos.flush();
+ lobCreator.setBlobAsBytes(ps, index, baos.toByteArray());
+ }
+ finally {
+ oos.close();
+ }
+ }
+ else {
+ lobCreator.setBlobAsBytes(ps, index, null);
+ }
+ }
+
+ protected Object getResultInternal(ResultSet rs, int index, LobHandler lobHandler)
+ throws SQLException, IOException {
+
+ InputStream is = lobHandler.getBlobAsBinaryStream(rs, index);
+ if (is != null) {
+ ObjectInputStream ois = new ObjectInputStream(is);
+ try {
+ return ois.readObject();
+ }
+ catch (ClassNotFoundException ex) {
+ throw new SQLException("Could not deserialize BLOB contents: " + ex.getMessage());
+ }
+ finally {
+ ois.close();
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public Object valueOf(String s) {
+ return s;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/ClobStringTypeHandler.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/ClobStringTypeHandler.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/ClobStringTypeHandler.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002-2005 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.orm.ibatis.support;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.springframework.jdbc.support.lob.LobCreator;
+import org.springframework.jdbc.support.lob.LobHandler;
+
+/**
+ * iBATIS TypeHandler implementation for Strings that get mapped to CLOBs.
+ * Retrieves the LobHandler to use from SqlMapClientFactoryBean at config time.
+ *
+ *
Particularly useful for storing Strings with more than 4000 characters in an
+ * Oracle database (only possible via CLOBs), in combination with OracleLobHandler.
+ *
+ *
Can also be defined in generic iBATIS mappings, as DefaultLobCreator will
+ * work with most JDBC-compliant database drivers. In this case, the field type
+ * does not have to be BLOB: For databases like MySQL and MS SQL Server, any
+ * large enough binary type will work.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.5
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#setLobHandler
+ */
+public class ClobStringTypeHandler extends AbstractLobTypeHandler {
+
+ /**
+ * Constructor used by iBATIS: fetches config-time LobHandler from
+ * SqlMapClientFactoryBean.
+ * @see org.springframework.orm.ibatis.SqlMapClientFactoryBean#getConfigTimeLobHandler
+ */
+ public ClobStringTypeHandler() {
+ super();
+ }
+
+ /**
+ * Constructor used for testing: takes an explicit LobHandler.
+ */
+ protected ClobStringTypeHandler(LobHandler lobHandler) {
+ super(lobHandler);
+ }
+
+ protected void setParameterInternal(
+ PreparedStatement ps, int index, Object value, String jdbcType, LobCreator lobCreator)
+ throws SQLException {
+ lobCreator.setClobAsString(ps, index, (String) value);
+ }
+
+ protected Object getResultInternal(ResultSet rs, int index, LobHandler lobHandler)
+ throws SQLException {
+ return lobHandler.getClobAsString(rs, index);
+ }
+
+ public Object valueOf(String s) {
+ return s;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/SqlMapClientDaoSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/SqlMapClientDaoSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/SqlMapClientDaoSupport.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2002-2008 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.orm.ibatis.support;
+
+import javax.sql.DataSource;
+
+import com.ibatis.sqlmap.client.SqlMapClient;
+
+import org.springframework.dao.support.DaoSupport;
+import org.springframework.orm.ibatis.SqlMapClientTemplate;
+import org.springframework.util.Assert;
+
+/**
+ * Convenient super class for iBATIS SqlMapClient data access objects.
+ * Requires a SqlMapClient to be set, providing a SqlMapClientTemplate
+ * based on it to subclasses.
+ *
+ *
Instead of a plain SqlMapClient, you can also pass a preconfigured
+ * SqlMapClientTemplate instance in. This allows you to share your
+ * SqlMapClientTemplate configuration for all your DAOs, for example
+ * a custom SQLExceptionTranslator to use.
+ *
+ * @author Juergen Hoeller
+ * @since 24.02.2004
+ * @see #setSqlMapClient
+ * @see #setSqlMapClientTemplate
+ * @see org.springframework.orm.ibatis.SqlMapClientTemplate
+ * @see org.springframework.orm.ibatis.SqlMapClientTemplate#setExceptionTranslator
+ */
+public abstract class SqlMapClientDaoSupport extends DaoSupport {
+
+ private SqlMapClientTemplate sqlMapClientTemplate = new SqlMapClientTemplate();
+
+ private boolean externalTemplate = false;
+
+
+ /**
+ * Set the JDBC DataSource to be used by this DAO.
+ * Not required: The SqlMapClient might carry a shared DataSource.
+ * @see #setSqlMapClient
+ */
+ public final void setDataSource(DataSource dataSource) {
+ if (!this.externalTemplate) {
+ this.sqlMapClientTemplate.setDataSource(dataSource);
+ }
+ }
+
+ /**
+ * Return the JDBC DataSource used by this DAO.
+ */
+ public final DataSource getDataSource() {
+ return this.sqlMapClientTemplate.getDataSource();
+ }
+
+ /**
+ * Set the iBATIS Database Layer SqlMapClient to work with.
+ * Either this or a "sqlMapClientTemplate" is required.
+ * @see #setSqlMapClientTemplate
+ */
+ public final void setSqlMapClient(SqlMapClient sqlMapClient) {
+ if (!this.externalTemplate) {
+ this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
+ }
+ }
+
+ /**
+ * Return the iBATIS Database Layer SqlMapClient that this template works with.
+ */
+ public final SqlMapClient getSqlMapClient() {
+ return this.sqlMapClientTemplate.getSqlMapClient();
+ }
+
+ /**
+ * Set the SqlMapClientTemplate for this DAO explicitly,
+ * as an alternative to specifying a SqlMapClient.
+ * @see #setSqlMapClient
+ */
+ public final void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
+ Assert.notNull(sqlMapClientTemplate, "SqlMapClientTemplate must not be null");
+ this.sqlMapClientTemplate = sqlMapClientTemplate;
+ this.externalTemplate = true;
+ }
+
+ /**
+ * Return the SqlMapClientTemplate for this DAO,
+ * pre-initialized with the SqlMapClient or set explicitly.
+ */
+ public final SqlMapClientTemplate getSqlMapClientTemplate() {
+ return this.sqlMapClientTemplate;
+ }
+
+ protected final void checkDaoConfig() {
+ if (!this.externalTemplate) {
+ this.sqlMapClientTemplate.afterPropertiesSet();
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/ibatis/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/ibatis/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/ibatis/support/package.html 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Classes supporting the org.springframework.orm.ibatis package.
+Contains a DAO base class for SqlMapClientTemplate usage.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/DefaultJdoDialect.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/DefaultJdoDialect.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/DefaultJdoDialect.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.jdbc.support.JdbcUtils;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+import org.springframework.transaction.InvalidIsolationLevelException;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+
+/**
+ * Default implementation of the {@link JdoDialect} interface.
+ * Updated to build on JDO 2.0 or higher, as of Spring 2.5.
+ * Used as default dialect by {@link JdoAccessor} and {@link JdoTransactionManager}.
+ *
+ *
Simply begins a standard JDO transaction in beginTransaction.
+ * Returns a handle for a JDO2 DataStoreConnection on getJdbcConnection.
+ * Calls the corresponding JDO2 PersistenceManager operation on flush
+ * Ignores a given query timeout in applyQueryTimeout.
+ * Uses a Spring SQLExceptionTranslator for exception translation, if applicable.
+ *
+ *
Note that, even with JDO2, vendor-specific subclasses are still necessary
+ * for special transaction semantics and more sophisticated exception translation.
+ * Furthermore, vendor-specific subclasses are encouraged to expose the native JDBC
+ * Connection on getJdbcConnection, rather than JDO2's wrapper handle.
+ *
+ *
This class also implements the PersistenceExceptionTranslator interface,
+ * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor,
+ * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
+ * Hence, the presence of a standard DefaultJdoDialect bean automatically enables
+ * a PersistenceExceptionTranslationPostProcessor to translate JDO exceptions.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see #setJdbcExceptionTranslator
+ * @see JdoAccessor#setJdoDialect
+ * @see JdoTransactionManager#setJdoDialect
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ */
+public class DefaultJdoDialect implements JdoDialect, PersistenceExceptionTranslator {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private SQLExceptionTranslator jdbcExceptionTranslator;
+
+
+ /**
+ * Create a new DefaultJdoDialect.
+ */
+ public DefaultJdoDialect() {
+ }
+
+ /**
+ * Create a new DefaultJdoDialect.
+ * @param connectionFactory the connection factory of the JDO PersistenceManagerFactory,
+ * which is used to initialize the default JDBC exception translator
+ * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory()
+ * @see PersistenceManagerFactoryUtils#newJdbcExceptionTranslator(Object)
+ */
+ DefaultJdoDialect(Object connectionFactory) {
+ this.jdbcExceptionTranslator = PersistenceManagerFactoryUtils.newJdbcExceptionTranslator(connectionFactory);
+ }
+
+ /**
+ * Set the JDBC exception translator for this dialect.
+ *
Applied to any SQLException root cause of a JDOException, if specified.
+ * The default is to rely on the JDO provider's native exception translation.
+ * @param jdbcExceptionTranslator exception translator
+ * @see java.sql.SQLException
+ * @see javax.jdo.JDOException#getCause()
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ */
+ public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
+ this.jdbcExceptionTranslator = jdbcExceptionTranslator;
+ }
+
+ /**
+ * Return the JDBC exception translator for this dialect, if any.
+ */
+ public SQLExceptionTranslator getJdbcExceptionTranslator() {
+ return this.jdbcExceptionTranslator;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Hooks for transaction management (used by JdoTransactionManager)
+ //-------------------------------------------------------------------------
+
+ /**
+ * This implementation invokes the standard JDO Transaction.begin
+ * method. Throws an InvalidIsolationLevelException if a non-default isolation
+ * level is set.
+ * @see javax.jdo.Transaction#begin
+ * @see org.springframework.transaction.InvalidIsolationLevelException
+ */
+ public Object beginTransaction(Transaction transaction, TransactionDefinition definition)
+ throws JDOException, SQLException, TransactionException {
+
+ if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
+ throw new InvalidIsolationLevelException(
+ "Standard JDO does not support custom isolation levels: " +
+ "use a special JdoDialect implementation for your JDO provider");
+ }
+ transaction.begin();
+ return null;
+ }
+
+ /**
+ * This implementation does nothing, as the default beginTransaction implementation
+ * does not require any cleanup.
+ * @see #beginTransaction
+ */
+ public void cleanupTransaction(Object transactionData) {
+ }
+
+ /**
+ * This implementation returns a DataStoreConnectionHandle for JDO2,
+ * which will also work on JDO1 until actually accessing the JDBC Connection.
+ *
For pre-JDO2 implementations, override this method to return the
+ * Connection through the corresponding vendor-specific mechanism, or null
+ * if the Connection is not retrievable.
+ *
NOTE: A JDO2 DataStoreConnection is always a wrapper,
+ * never the native JDBC Connection. If you need access to the native JDBC
+ * Connection (or the connection pool handle, to be unwrapped via a Spring
+ * NativeJdbcExtractor), override this method to return the native
+ * Connection through the corresponding vendor-specific mechanism.
+ *
A JDO2 DataStoreConnection is only "borrowed" from the PersistenceManager:
+ * it needs to be returned as early as possible. Effectively, JDO2 requires the
+ * fetched Connection to be closed before continuing PersistenceManager work.
+ * For this reason, the exposed ConnectionHandle eagerly releases its JDBC
+ * Connection at the end of each JDBC data access operation (that is, on
+ * DataSourceUtils.releaseConnection).
+ * @see javax.jdo.PersistenceManager#getDataStoreConnection()
+ * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
+ */
+ public ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly)
+ throws JDOException, SQLException {
+
+ return new DataStoreConnectionHandle(pm);
+ }
+
+ /**
+ * This implementation does nothing, assuming that the Connection
+ * will implicitly be closed with the PersistenceManager.
+ *
If the JDO provider returns a Connection handle that it
+ * expects the application to close, the dialect needs to invoke
+ * Connection.close here.
+ * @see java.sql.Connection#close()
+ */
+ public void releaseJdbcConnection(ConnectionHandle conHandle, PersistenceManager pm)
+ throws JDOException, SQLException {
+ }
+
+ /**
+ * This implementation delegates to JDO 2.0's flush method.
+ *
To be overridden for pre-JDO2 implementations, using the corresponding
+ * vendor-specific mechanism there.
+ * @see javax.jdo.PersistenceManager#flush()
+ */
+ public void flush(PersistenceManager pm) throws JDOException {
+ pm.flush();
+ }
+
+ /**
+ * This implementation logs a warning that it cannot apply a query timeout.
+ */
+ public void applyQueryTimeout(Query query, int remainingTimeInSeconds) throws JDOException {
+ logger.info("DefaultJdoDialect does not support query timeouts: ignoring remaining transaction time");
+ }
+
+
+ //-----------------------------------------------------------------------------------
+ // Hook for exception translation (used by JdoTransactionManager and JdoTemplate)
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * Implementation of the PersistenceExceptionTranslator interface,
+ * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
+ *
Converts the exception if it is a JDOException, using this JdoDialect.
+ * Else returns null to indicate an unknown exception.
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ * @see #translateException
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ if (ex instanceof JDOException) {
+ return translateException((JDOException) ex);
+ }
+ return null;
+ }
+
+ /**
+ * This implementation delegates to PersistenceManagerFactoryUtils.
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+ public DataAccessException translateException(JDOException ex) {
+ if (getJdbcExceptionTranslator() != null && ex.getCause() instanceof SQLException) {
+ return getJdbcExceptionTranslator().translate("JDO operation: " + ex.getMessage(),
+ extractSqlStringFromException(ex), (SQLException) ex.getCause());
+ }
+ return PersistenceManagerFactoryUtils.convertJdoAccessException(ex);
+ }
+
+ /**
+ * Template method for extracting a SQL String from the given exception.
+ *
Default implementation always returns null. Can be overridden in
+ * subclasses to extract SQL Strings for vendor-specific exception classes.
+ * @param ex the JDOException, containing a SQLException
+ * @return the SQL String, or null if none found
+ */
+ protected String extractSqlStringFromException(JDOException ex) {
+ return null;
+ }
+
+
+ /**
+ * ConnectionHandle implementation that fetches a new JDO2 DataStoreConnection
+ * for every getConnection call and closes the Connection on
+ * releaseConnection. This is necessary because JDO2 requires the
+ * fetched Connection to be closed before continuing PersistenceManager work.
+ * @see javax.jdo.PersistenceManager#getDataStoreConnection()
+ */
+ private static class DataStoreConnectionHandle implements ConnectionHandle {
+
+ private final PersistenceManager persistenceManager;
+
+ public DataStoreConnectionHandle(PersistenceManager persistenceManager) {
+ this.persistenceManager = persistenceManager;
+ }
+
+ public Connection getConnection() {
+ return (Connection) this.persistenceManager.getDataStoreConnection();
+ }
+
+ public void releaseConnection(Connection con) {
+ JdbcUtils.closeConnection(con);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoAccessor.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2002-2006 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.orm.jdo;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Base class for JdoTemplate and JdoInterceptor, defining common
+ * properties such as PersistenceManagerFactory and flushing behavior.
+ *
+ *
Note: With JDO, modifications to persistent objects are just possible
+ * within a transaction (in contrast to Hibernate). Therefore, eager flushing
+ * will just get applied when in a transaction. Furthermore, there is no
+ * explicit notion of flushing never, as this would not imply a performance
+ * gain due to JDO's field interception mechanism (which doesn't involve
+ * the overhead of snapshot comparisons).
+ *
+ *
Eager flushing is just available for specific JDO providers.
+ * You need to a corresponding JdoDialect to make eager flushing work.
+ *
+ *
Not intended to be used directly. See JdoTemplate and JdoInterceptor.
+ *
+ * @author Juergen Hoeller
+ * @since 02.11.2003
+ * @see JdoTemplate
+ * @see JdoInterceptor
+ * @see #setFlushEager
+ */
+public abstract class JdoAccessor implements InitializingBean {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private PersistenceManagerFactory persistenceManagerFactory;
+
+ private JdoDialect jdoDialect;
+
+ private boolean flushEager = false;
+
+
+ /**
+ * Set the JDO PersistenceManagerFactory that should be used to create
+ * PersistenceManagers.
+ */
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
+ }
+
+ /**
+ * Return the JDO PersistenceManagerFactory that should be used to create
+ * PersistenceManagers.
+ */
+ public PersistenceManagerFactory getPersistenceManagerFactory() {
+ return persistenceManagerFactory;
+ }
+
+ /**
+ * Set the JDO dialect to use for this accessor.
+ *
The dialect object can be used to retrieve the underlying JDBC
+ * connection and to eagerly flush changes to the database.
+ *
Default is a DefaultJdoDialect based on the PersistenceManagerFactory's
+ * underlying DataSource, if any.
+ */
+ public void setJdoDialect(JdoDialect jdoDialect) {
+ this.jdoDialect = jdoDialect;
+ }
+
+ /**
+ * Return the JDO dialect to use for this accessor.
+ *
Creates a default one for the specified PersistenceManagerFactory if none set.
+ */
+ public JdoDialect getJdoDialect() {
+ if (this.jdoDialect == null) {
+ this.jdoDialect = new DefaultJdoDialect();
+ }
+ return this.jdoDialect;
+ }
+
+ /**
+ * Set if this accessor should flush changes to the database eagerly.
+ *
Eager flushing leads to immediate synchronization with the database,
+ * even if in a transaction. This causes inconsistencies to show up and throw
+ * a respective exception immediately, and JDBC access code that participates
+ * in the same transaction will see the changes as the database is already
+ * aware of them then. But the drawbacks are:
+ *
+ *
additional communication roundtrips with the database, instead of a
+ * single batch at transaction commit;
+ *
the fact that an actual database rollback is needed if the JDO
+ * transaction rolls back (due to already submitted SQL statements).
+ *
+ */
+ public void setFlushEager(boolean flushEager) {
+ this.flushEager = flushEager;
+ }
+
+ /**
+ * Return if this accessor should flush changes to the database eagerly.
+ */
+ public boolean isFlushEager() {
+ return flushEager;
+ }
+
+ /**
+ * Eagerly initialize the JDO dialect, creating a default one
+ * for the specified PersistenceManagerFactory if none set.
+ */
+ public void afterPropertiesSet() {
+ if (getPersistenceManagerFactory() == null) {
+ throw new IllegalArgumentException("persistenceManagerFactory is required");
+ }
+ // Build default JdoDialect if none explicitly specified.
+ if (this.jdoDialect == null) {
+ this.jdoDialect = new DefaultJdoDialect(getPersistenceManagerFactory().getConnectionFactory());
+ }
+ }
+
+
+ /**
+ * Flush the given JDO persistence manager if necessary.
+ * @param pm the current JDO PersistenceManager
+ * @param existingTransaction if executing within an existing transaction
+ * (within an existing JDO PersistenceManager that won't be closed immediately)
+ * @throws JDOException in case of JDO flushing errors
+ */
+ protected void flushIfNecessary(PersistenceManager pm, boolean existingTransaction) throws JDOException {
+ if (isFlushEager()) {
+ logger.debug("Eagerly flushing JDO persistence manager");
+ getJdoDialect().flush(pm);
+ }
+ }
+
+ /**
+ * Convert the given JDOException to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ *
Default implementation delegates to the JdoDialect.
+ * May be overridden in subclasses.
+ * @param ex JDOException that occured
+ * @return the corresponding DataAccessException instance
+ * @see JdoDialect#translateException
+ */
+ public DataAccessException convertJdoAccessException(JDOException ex) {
+ return getJdoDialect().translateException(ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoCallback.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002-2006 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.orm.jdo;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+
+/**
+ * Callback interface for JDO code. To be used with {@link JdoTemplate}'s
+ * execution methods, often as anonymous classes within a method implementation.
+ * A typical implementation will call PersistenceManager CRUD to perform
+ * some operations on persistent objects.
+ *
+ *
Note that JDO works on bytecode-modified Java objects, to be able to
+ * perform dirty detection on each modification of a persistent instance field.
+ * In contrast to Hibernate, using returned objects outside of an active
+ * PersistenceManager poses a problem: To be able to read and modify fields
+ * e.g. in a web GUI, one has to explicitly make the instances "transient".
+ * Reassociation with a new PersistenceManager, e.g. for updates when coming
+ * back from the GUI, isn't possible, as the JDO instances have lost their
+ * identity when turned transient. This means that either value objects have
+ * to be used as parameters, or the contents of the outside-modified instance
+ * have to be copied to a freshly loaded active instance on reassociation.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see JdoTemplate
+ * @see JdoTransactionManager
+ */
+public interface JdoCallback {
+
+ /**
+ * Gets called by JdoTemplate.execute with an active JDO
+ * PersistenceManager. Does not need to care about activating
+ * or closing the PersistenceManager, or handling transactions.
+ *
+ *
Note that JDO callback code will not flush any modifications to the
+ * database if not executed within a transaction. Thus, you need to make
+ * sure that JdoTransactionManager has initiated a JDO transaction when
+ * the callback gets called, at least if you want to write to the database.
+ *
+ *
Allows for returning a result object created within the callback,
+ * i.e. a domain object or a collection of domain objects.
+ * A thrown custom RuntimeException is treated as an application exception:
+ * It gets propagated to the caller of the template.
+ *
+ * @param pm active PersistenceManager
+ * @return a result object, or null if none
+ * @throws JDOException if thrown by the JDO API
+ * @see JdoTemplate#execute
+ * @see JdoTemplate#executeFind
+ */
+ Object doInJdo(PersistenceManager pm) throws JDOException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoDialect.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoDialect.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoDialect.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo;
+
+import java.sql.SQLException;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+
+/**
+ * SPI strategy that allows for customizing integration with a specific JDO provider,
+ * in particular regarding transaction management and exception translation. To be
+ * implemented for specific JDO providers such as JPOX, Kodo, Lido, Versant Open Access.
+ *
+ *
JDO 2.0 defines standard ways for most of the functionality covered here.
+ * Hence, Spring's {@link DefaultJdoDialect} uses the corresponding JDO 2.0 methods
+ * by default, to be overridden in a vendor-specific fashion if necessary.
+ * Vendor-specific subclasses of {@link DefaultJdoDialect} are still required for special
+ * transaction semantics and more sophisticated exception translation (if needed).
+ *
+ *
In general, it is recommended to derive from {@link DefaultJdoDialect} instead
+ * of implementing this interface directly. This allows for inheriting common
+ * behavior (present and future) from {@link DefaultJdoDialect}, only overriding
+ * specific hooks to plug in concrete vendor-specific behavior.
+ *
+ * @author Juergen Hoeller
+ * @since 02.11.2003
+ * @see JdoTransactionManager#setJdoDialect
+ * @see JdoAccessor#setJdoDialect
+ * @see DefaultJdoDialect
+ */
+public interface JdoDialect {
+
+ //-------------------------------------------------------------------------
+ // Hooks for transaction management (used by JdoTransactionManager)
+ //-------------------------------------------------------------------------
+
+ /**
+ * Begin the given JDO transaction, applying the semantics specified by the
+ * given Spring transaction definition (in particular, an isolation level
+ * and a timeout). Invoked by JdoTransactionManager on transaction begin.
+ *
An implementation can configure the JDO Transaction object and then
+ * invoke begin, or invoke a special begin method that takes,
+ * for example, an isolation level.
+ *
An implementation can also apply read-only flag and isolation level to the
+ * underlying JDBC Connection before beginning the transaction. In that case,
+ * a transaction data object can be returned that holds the previous isolation
+ * level (and possibly other data), to be reset in cleanupTransaction.
+ *
Implementations can also use the Spring transaction name, as exposed by the
+ * passed-in TransactionDefinition, to optimize for specific data access use cases
+ * (effectively using the current transaction name as use case identifier).
+ * @param transaction the JDO transaction to begin
+ * @param definition the Spring transaction definition that defines semantics
+ * @return an arbitrary object that holds transaction data, if any
+ * (to be passed into cleanupTransaction)
+ * @throws JDOException if thrown by JDO methods
+ * @throws SQLException if thrown by JDBC methods
+ * @throws TransactionException in case of invalid arguments
+ * @see #cleanupTransaction
+ * @see javax.jdo.Transaction#begin
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction
+ */
+ Object beginTransaction(Transaction transaction, TransactionDefinition definition)
+ throws JDOException, SQLException, TransactionException;
+
+ /**
+ * Clean up the transaction via the given transaction data.
+ * Invoked by JdoTransactionManager on transaction cleanup.
+ *
An implementation can, for example, reset read-only flag and
+ * isolation level of the underlying JDBC Connection. Furthermore,
+ * an exposed data access use case can be reset here.
+ * @param transactionData arbitrary object that holds transaction data, if any
+ * (as returned by beginTransaction)
+ * @see #beginTransaction
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction
+ */
+ void cleanupTransaction(Object transactionData);
+
+ /**
+ * Retrieve the JDBC Connection that the given JDO PersistenceManager uses underneath,
+ * if accessing a relational database. This method will just get invoked if actually
+ * needing access to the underlying JDBC Connection, usually within an active JDO
+ * transaction (for example, by JdoTransactionManager). The returned handle will
+ * be passed into the releaseJdbcConnection method when not needed anymore.
+ *
Implementations are encouraged to return an unwrapped Connection object, i.e.
+ * the Connection as they got it from the connection pool. This makes it easier for
+ * application code to get at the underlying native JDBC Connection, like an
+ * OracleConnection, which is sometimes necessary for LOB handling etc. We assume
+ * that calling code knows how to properly handle the returned Connection object.
+ *
In a simple case where the returned Connection will be auto-closed with the
+ * PersistenceManager or can be released via the Connection object itself, an
+ * implementation can return a SimpleConnectionHandle that just contains the
+ * Connection. If some other object is needed in releaseJdbcConnection,
+ * an implementation should use a special handle that references that other object.
+ * @param pm the current JDO PersistenceManager
+ * @param readOnly whether the Connection is only needed for read-only purposes
+ * @return a handle for the JDBC Connection, to be passed into
+ * releaseJdbcConnection, or null
+ * if no JDBC Connection can be retrieved
+ * @throws JDOException if thrown by JDO methods
+ * @throws SQLException if thrown by JDBC methods
+ * @see #releaseJdbcConnection
+ * @see org.springframework.jdbc.datasource.ConnectionHandle#getConnection
+ * @see org.springframework.jdbc.datasource.SimpleConnectionHandle
+ * @see JdoTransactionManager#setDataSource
+ * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
+ */
+ ConnectionHandle getJdbcConnection(PersistenceManager pm, boolean readOnly)
+ throws JDOException, SQLException;
+
+ /**
+ * Release the given JDBC Connection, which has originally been retrieved
+ * via getJdbcConnection. This should be invoked in any case,
+ * to allow for proper release of the retrieved Connection handle.
+ *
An implementation might simply do nothing, if the Connection returned
+ * by getJdbcConnection will be implicitly closed when the JDO
+ * transaction completes or when the PersistenceManager is closed.
+ * @param conHandle the JDBC Connection handle to release
+ * @param pm the current JDO PersistenceManager
+ * @throws JDOException if thrown by JDO methods
+ * @throws SQLException if thrown by JDBC methods
+ * @see #getJdbcConnection
+ */
+ void releaseJdbcConnection(ConnectionHandle conHandle, PersistenceManager pm)
+ throws JDOException, SQLException;
+
+ /**
+ * Flush the given PersistenceManager, i.e. flush all changes (that have been
+ * applied to persistent objects) to the underlying database. This method will
+ * just get invoked when eager flushing is actually necessary, for example when
+ * JDBC access code needs to see changes within the same transaction.
+ * @param pm the current JDO PersistenceManager
+ * @throws JDOException in case of errors
+ * @see JdoAccessor#setFlushEager
+ */
+ void flush(PersistenceManager pm) throws JDOException;
+
+ /**
+ * Apply the given timeout to the given JDO query object.
+ *
Invoked with the remaining time of a specified transaction timeout, if any.
+ * @param query the JDO query object to apply the timeout to
+ * @param timeout the timeout value to apply
+ * @throws JDOException if thrown by JDO methods
+ * @see JdoTemplate#prepareQuery
+ */
+ void applyQueryTimeout(Query query, int timeout) throws JDOException;
+
+
+ //-----------------------------------------------------------------------------------
+ // Hook for exception translation (used by JdoTransactionManager and JdoTemplate)
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * Translate the given JDOException to a corresponding exception from Spring's
+ * generic DataAccessException hierarchy. An implementation should apply
+ * PersistenceManagerFactoryUtils' standard exception translation if can't do
+ * anything more specific.
+ *
Of particular importance is the correct translation to
+ * DataIntegrityViolationException, for example on constraint violation.
+ * Unfortunately, standard JDO does not allow for portable detection of this.
+ *
Can use a SQLExceptionTranslator for translating underlying SQLExceptions
+ * in a database-specific fashion.
+ * @param ex the JDOException thrown
+ * @return the corresponding DataAccessException (must not be null)
+ * @see JdoAccessor#convertJdoAccessException
+ * @see JdoTransactionManager#convertJdoAccessException
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ * @see org.springframework.dao.DataIntegrityViolationException
+ * @see org.springframework.jdbc.support.SQLExceptionTranslator
+ */
+ DataAccessException translateException(JDOException ex);
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoInterceptor.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2002-2006 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.orm.jdo;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * This interceptor binds a new JDO PersistenceManager to the thread before a method
+ * call, closing and removing it afterwards in case of any method outcome.
+ * If there already is a pre-bound PersistenceManager (e.g. from JdoTransactionManager,
+ * or from a surrounding JDO-intercepted method), the interceptor simply participates in it.
+ *
+ *
Application code must retrieve a JDO PersistenceManager via the
+ * PersistenceManagerFactoryUtils.getPersistenceManager method,
+ * to be able to detect a thread-bound PersistenceManager. It is preferable to use
+ * getPersistenceManager with allowCreate=false, if the code relies on
+ * the interceptor to provide proper PersistenceManager handling. Typically, the code
+ * will look like as follows:
+ *
+ *
Note that this interceptor automatically translates JDOExceptions, via
+ * delegating to the PersistenceManagerFactoryUtils.convertJdoAccessException
+ * method that converts them to exceptions that are compatible with the
+ * org.springframework.dao exception hierarchy (like JdoTemplate does).
+ * This can be turned off if the raw exceptions are preferred.
+ *
+ *
This class can be considered a declarative alternative to JdoTemplate's
+ * callback approach. The advantages are:
+ *
+ *
no anonymous classes necessary for callback implementations;
+ *
the possibility to throw any application exceptions from within data access code.
+ *
+ *
+ *
The drawback is the dependency on interceptor configuration. However, note
+ * that this interceptor is usually not necessary in scenarios where the
+ * data access code always executes within transactions. A transaction will always
+ * have a thread-bound PersistenceManager in the first place, so adding this interceptor
+ * to the configuration just adds value when fine-tuning PersistenceManager settings
+ * like the flush mode - or when relying on exception translation.
+ *
+ * @author Juergen Hoeller
+ * @since 13.06.2003
+ * @see PersistenceManagerFactoryUtils#getPersistenceManager
+ * @see JdoTransactionManager
+ * @see JdoTemplate
+ */
+public class JdoInterceptor extends JdoAccessor implements MethodInterceptor {
+
+ private boolean exceptionConversionEnabled = true;
+
+
+ /**
+ * Set whether to convert any JDOException raised to a Spring DataAccessException,
+ * compatible with the org.springframework.dao exception hierarchy.
+ *
Default is "true". Turn this flag off to let the caller receive raw exceptions
+ * as-is, without any wrapping.
+ * @see org.springframework.dao.DataAccessException
+ */
+ public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
+ this.exceptionConversionEnabled = exceptionConversionEnabled;
+ }
+
+
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+ boolean existingTransaction = false;
+ PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(getPersistenceManagerFactory(), true);
+ if (TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory())) {
+ logger.debug("Found thread-bound PersistenceManager for JDO interceptor");
+ existingTransaction = true;
+ }
+ else {
+ logger.debug("Using new PersistenceManager for JDO interceptor");
+ TransactionSynchronizationManager.bindResource(getPersistenceManagerFactory(), new PersistenceManagerHolder(pm));
+ }
+ try {
+ Object retVal = methodInvocation.proceed();
+ flushIfNecessary(pm, existingTransaction);
+ return retVal;
+ }
+ catch (JDOException ex) {
+ if (this.exceptionConversionEnabled) {
+ throw convertJdoAccessException(ex);
+ }
+ else {
+ throw ex;
+ }
+ }
+ finally {
+ if (existingTransaction) {
+ logger.debug("Not closing pre-bound JDO PersistenceManager after interceptor");
+ }
+ else {
+ TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory());
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoObjectRetrievalFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoObjectRetrievalFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoObjectRetrievalFailureException.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2006 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.orm.jdo;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOObjectNotFoundException;
+
+import org.springframework.orm.ObjectRetrievalFailureException;
+
+/**
+ * JDO-specific subclass of ObjectRetrievalFailureException.
+ * Converts JDO's JDOObjectNotFoundException.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+public class JdoObjectRetrievalFailureException extends ObjectRetrievalFailureException {
+
+ public JdoObjectRetrievalFailureException(JDOObjectNotFoundException ex) {
+ // Extract information about the failed object from the JDOException, if available.
+ super((ex.getFailedObject() != null ? ex.getFailedObject().getClass() : null),
+ (ex.getFailedObject() != null ? JDOHelper.getObjectId(ex.getFailedObject()) : null),
+ ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoOperations.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Interface that specifies a basic set of JDO operations,
+ * implemented by {@link JdoTemplate}. Not often used, but a useful
+ * option to enhance testability, as it can easily be mocked or stubbed.
+ *
+ *
Defines JdoTemplate's data access methods that mirror
+ * various JDO {@link javax.jdo.PersistenceManager} methods. Users are
+ * strongly encouraged to read the JDO PersistenceManager
+ * javadocs for details on the semantics of those methods.
+ *
+ *
Note that lazy loading will just work with an open JDO
+ * PersistenceManager, either within a managed transaction or within
+ * {@link org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter}/
+ * {@link org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor}.
+ * Furthermore, some operations just make sense within transactions,
+ * for example: evict, evictAll, flush.
+ *
+ *
Updated to build on JDO 2.0 or higher, as of Spring 2.5.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see JdoTemplate
+ * @see javax.jdo.PersistenceManager
+ * @see JdoTransactionManager
+ * @see JdoDialect
+ * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter
+ * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor
+ */
+public interface JdoOperations {
+
+ /**
+ * Execute the action specified by the given action object within a
+ * PersistenceManager. Application exceptions thrown by the action object
+ * get propagated to the caller (can only be unchecked). JDO exceptions
+ * are transformed into appropriate DAO ones. Allows for returning a
+ * result object, i.e. a domain object or a collection of domain objects.
+ *
Note: Callback code is not supposed to handle transactions itself!
+ * Use an appropriate transaction manager like JdoTransactionManager.
+ * @param action callback object that specifies the JDO action
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see JdoTransactionManager
+ * @see org.springframework.dao
+ * @see org.springframework.transaction
+ * @see javax.jdo.PersistenceManager
+ */
+ Object execute(JdoCallback action) throws DataAccessException;
+
+ /**
+ * Execute the specified action assuming that the result object is a
+ * Collection. This is a convenience method for executing JDO queries
+ * within an action.
+ * @param action callback object that specifies the JDO action
+ * @return a Collection result returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ */
+ Collection executeFind(JdoCallback action) throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for load, save, delete
+ //-------------------------------------------------------------------------
+
+ /**
+ * Return the persistent instance with the given JDO object id,
+ * throwing an exception if not found.
+ *
A JDO object id identifies both the persistent class and the id
+ * within the namespace of that class.
+ * @param objectId a JDO object id of the persistent instance
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#getObjectById(Object, boolean)
+ */
+ Object getObjectById(Object objectId) throws DataAccessException;
+
+ /**
+ * Return the persistent instance of the given entity class
+ * with the given id value, throwing an exception if not found.
+ *
The given id value is typically just unique within the namespace
+ * of the persistent class. Its toString value must correspond to the
+ * toString value of the corresponding JDO object id.
+ *
Usually, the passed-in value will have originated from the primary
+ * key field of a persistent object that uses JDO's application identity.
+ * @param entityClass a persistent class
+ * @param idValue an id value of the persistent instance
+ * @return the persistent instance
+ * @throws org.springframework.orm.ObjectRetrievalFailureException if not found
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#getObjectById(Object, boolean)
+ * @see javax.jdo.PersistenceManager#getObjectById(Class, Object)
+ */
+ Object getObjectById(Class entityClass, Object idValue) throws DataAccessException;
+
+ /**
+ * Remove the given object from the PersistenceManager cache.
+ * @param entity the persistent instance to evict
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#evict(Object)
+ */
+ void evict(Object entity) throws DataAccessException;
+
+ /**
+ * Remove all given objects from the PersistenceManager cache.
+ * @param entities the persistent instances to evict
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#evictAll(java.util.Collection)
+ */
+ void evictAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Remove all objects from the PersistenceManager cache.
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#evictAll()
+ */
+ void evictAll() throws DataAccessException;
+
+ /**
+ * Re-read the state of the given persistent instance.
+ * @param entity the persistent instance to re-read
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#refresh(Object)
+ */
+ void refresh(Object entity) throws DataAccessException;
+
+ /**
+ * Re-read the state of all given persistent instances.
+ * @param entities the persistent instances to re-read
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#refreshAll(java.util.Collection)
+ */
+ void refreshAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Re-read the state of all persistent instances.
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#refreshAll()
+ */
+ void refreshAll() throws DataAccessException;
+
+ /**
+ * Make the given transient instance persistent.
+ * Attach the given entity if the instance is detached.
+ * @param entity the transient instance to make persistent
+ * @return the persistent instance
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#makePersistent(Object)
+ */
+ Object makePersistent(Object entity) throws DataAccessException;
+
+ /**
+ * Make the given transient instances persistent.
+ * Attach the given entities if the instances are detached.
+ * @param entities the transient instances to make persistent
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#makePersistentAll(java.util.Collection)
+ */
+ Collection makePersistentAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Delete the given persistent instance.
+ * @param entity the persistent instance to delete
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#deletePersistent(Object)
+ */
+ void deletePersistent(Object entity) throws DataAccessException;
+
+ /**
+ * Delete all given persistent instances.
+ *
This can be combined with any of the find methods to delete by query
+ * in two lines of code.
+ * @param entities the persistent instances to delete
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#deletePersistentAll(java.util.Collection)
+ */
+ void deletePersistentAll(Collection entities) throws DataAccessException;
+
+ /**
+ * Detach a copy of the given persistent instance from the current JDO transaction,
+ * for use outside a JDO transaction (for example, as web form object).
+ * @param entity the persistent instance to detach
+ * @return the corresponding detached instance
+ * @see javax.jdo.PersistenceManager#detachCopy(Object)
+ */
+ Object detachCopy(Object entity);
+
+ /**
+ * Detach copies of the given persistent instances from the current JDO transaction,
+ * for use outside a JDO transaction (for example, as web form objects).
+ * @param entities the persistent instances to detach
+ * @return the corresponding detached instances
+ * @see javax.jdo.PersistenceManager#detachCopyAll(Collection)
+ */
+ Collection detachCopyAll(Collection entities);
+
+ /**
+ * Reattach the given detached instance (for example, a web form object) with
+ * the current JDO transaction, merging its changes into the current persistence
+ * instance that represents the corresponding entity.
+ *
Note that as of JDO 2.0 final, this operation is equivalent to a
+ * makePersistent call, with the latter method returning the
+ * persistence instance.
+ * @param detachedEntity the detached instance to attach
+ * @return the corresponding persistent instance
+ * @deprecated in favor of {@link #makePersistent(Object)}.
+ * To be removed in Spring 3.0.
+ */
+ Object attachCopy(Object detachedEntity);
+
+ /**
+ * Reattach the given detached instances (for example, web form objects) with
+ * the current JDO transaction, merging their changes into the current persistence
+ * instances that represent the corresponding entities.
+ *
Note that as of JDO 2.0 final, this operation is equivalent to a
+ * makePersistentAll call, with the latter method returning the
+ * persistence instance.
+ * @param detachedEntities the detached instances to reattach
+ * @return the corresponding persistent instances
+ * @deprecated in favor of {@link #makePersistentAll(java.util.Collection)}.
+ * To be removed in Spring 3.0.
+ */
+ Collection attachCopyAll(Collection detachedEntities);
+
+ /**
+ * Flush all transactional modifications to the database.
+ *
Only invoke this for selective eager flushing, for example when JDBC code
+ * needs to see certain changes within the same transaction. Else, it's preferable
+ * to rely on auto-flushing at transaction completion.
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#flush()
+ * @see JdoDialect#flush(javax.jdo.PersistenceManager)
+ */
+ void flush() throws DataAccessException;
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Find all persistent instances of the given class.
+ * @param entityClass a persistent class
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class)
+ */
+ Collection find(Class entityClass) throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match (or null if none)
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ */
+ Collection find(Class entityClass, String filter) throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter, with the given result ordering.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match (or null if none)
+ * @param ordering the ordering of the result (or null if none)
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ * @see javax.jdo.Query#setOrdering
+ */
+ Collection find(Class entityClass, String filter, String ordering) throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter, using the given parameter declarations and parameter values.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match
+ * @param parameters the JDOQL parameter declarations
+ * @param values the corresponding parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ * @see javax.jdo.Query#declareParameters
+ * @see javax.jdo.Query#executeWithArray
+ */
+ Collection find(Class entityClass, String filter, String parameters, Object[] values)
+ throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter, using the given parameter declarations and parameter values,
+ * with the given result ordering.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match
+ * @param parameters the JDOQL parameter declarations
+ * @param values the corresponding parameter values
+ * @param ordering the ordering of the result (or null if none)
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ * @see javax.jdo.Query#declareParameters
+ * @see javax.jdo.Query#executeWithArray
+ * @see javax.jdo.Query#setOrdering
+ */
+ Collection find(Class entityClass, String filter, String parameters, Object[] values, String ordering)
+ throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter, using the given parameter declarations and parameter values.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match
+ * @param parameters the JDOQL parameter declarations
+ * @param values a Map with parameter names as keys and parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ * @see javax.jdo.Query#declareParameters
+ * @see javax.jdo.Query#executeWithMap
+ */
+ Collection find(Class entityClass, String filter, String parameters, Map values)
+ throws DataAccessException;
+
+ /**
+ * Find all persistent instances of the given class that match the given
+ * JDOQL filter, using the given parameter declarations and parameter values,
+ * with the given result ordering.
+ * @param entityClass a persistent class
+ * @param filter the JDOQL filter to match
+ * @param parameters the JDOQL parameter declarations
+ * @param values a Map with parameter names as keys and parameter values
+ * @param ordering the ordering of the result (or null if none)
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(Class, String)
+ * @see javax.jdo.Query#declareParameters
+ * @see javax.jdo.Query#executeWithMap
+ * @see javax.jdo.Query#setOrdering
+ */
+ Collection find(Class entityClass, String filter, String parameters, Map values, String ordering)
+ throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given query object
+ * in the specified query language.
+ * @param language the query language (javax.jdo.Query#JDOQL
+ * or javax.jdo.Query#SQL, for example)
+ * @param queryObject the query object for the specified language
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(String, Object)
+ * @see javax.jdo.Query#JDOQL
+ * @see javax.jdo.Query#SQL
+ */
+ Collection find(String language, Object queryObject) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given single-string JDOQL query.
+ * @param queryString the single-string JDOQL query
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(String)
+ */
+ Collection find(String queryString) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given single-string JDOQL query.
+ * @param queryString the single-string JDOQL query
+ * @param values the corresponding parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(String)
+ */
+ Collection find(String queryString, Object[] values) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given single-string JDOQL query.
+ * @param queryString the single-string JDOQL query
+ * @param values a Map with parameter names as keys and parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newQuery(String)
+ */
+ Collection find(String queryString, Map values) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given named query.
+ * @param entityClass a persistent class
+ * @param queryName the name of the query
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newNamedQuery(Class, String)
+ */
+ Collection findByNamedQuery(Class entityClass, String queryName) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given named query.
+ * @param entityClass a persistent class
+ * @param queryName the name of the query
+ * @param values the corresponding parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newNamedQuery(Class, String)
+ */
+ Collection findByNamedQuery(Class entityClass, String queryName, Object[] values) throws DataAccessException;
+
+ /**
+ * Find persistent instances through the given named query.
+ * @param entityClass a persistent class
+ * @param queryName the name of the query
+ * @param values a Map with parameter names as keys and parameter values
+ * @return the persistent instances
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ * @see javax.jdo.PersistenceManager#newNamedQuery(Class, String)
+ */
+ Collection findByNamedQuery(Class entityClass, String queryName, Map values) throws DataAccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoOptimisticLockingFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoOptimisticLockingFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoOptimisticLockingFailureException.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-2006 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.orm.jdo;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOOptimisticVerificationException;
+
+import org.springframework.orm.ObjectOptimisticLockingFailureException;
+
+/**
+ * JDO-specific subclass of ObjectOptimisticLockingFailureException.
+ * Converts JDO's JDOOptimisticVerificationException.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+public class JdoOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
+
+ public JdoOptimisticLockingFailureException(JDOOptimisticVerificationException ex) {
+ // Extract information about the failed object from the JDOException, if available.
+ super((ex.getFailedObject() != null ? ex.getFailedObject().getClass() : null),
+ (ex.getFailedObject() != null ? JDOHelper.getObjectId(ex.getFailedObject()) : null),
+ ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoResourceFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoResourceFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoResourceFailureException.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2005 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.orm.jdo;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOFatalDataStoreException;
+
+import org.springframework.dao.DataAccessResourceFailureException;
+
+/**
+ * JDO-specific subclass of DataAccessResourceFailureException.
+ * Converts JDO's JDODataStoreException and JDOFatalDataStoreException.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+public class JdoResourceFailureException extends DataAccessResourceFailureException {
+
+ public JdoResourceFailureException(JDODataStoreException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+ public JdoResourceFailureException(JDOFatalDataStoreException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoSystemException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoSystemException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoSystemException.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2005 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.orm.jdo;
+
+import javax.jdo.JDOException;
+
+import org.springframework.dao.UncategorizedDataAccessException;
+
+/**
+ * JDO-specific subclass of UncategorizedDataAccessException,
+ * for JDO system errors that do not match any concrete
+ * org.springframework.dao exceptions.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+public class JdoSystemException extends UncategorizedDataAccessException {
+
+ public JdoSystemException(JDOException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoTemplate.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,621 @@
+/*
+ * Copyright 2002-2008 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.orm.jdo;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Helper class that simplifies JDO data access code, and converts
+ * JDOExceptions into Spring DataAccessExceptions, following the
+ * org.springframework.dao exception hierarchy.
+ *
+ *
The central method is execute, supporting JDO access code
+ * implementing the {@link JdoCallback} interface. It provides JDO PersistenceManager
+ * handling such that neither the JdoCallback implementation nor the calling
+ * code needs to explicitly care about retrieving/closing PersistenceManagers,
+ * or handling JDO lifecycle exceptions.
+ *
+ *
Typically used to implement data access or business logic services that
+ * use JDO within their implementation but are JDO-agnostic in their interface.
+ * The latter or code calling the latter only have to deal with business
+ * objects, query objects, and org.springframework.dao exceptions.
+ *
+ *
Can be used within a service implementation via direct instantiation
+ * with a PersistenceManagerFactory reference, or get prepared in an
+ * application context and given to services as bean reference.
+ * Note: The PersistenceManagerFactory should always be configured as bean in
+ * the application context, in the first case given to the service directly,
+ * in the second case to the prepared template.
+ *
+ *
This class can be considered as direct alternative to working with the
+ * raw JDO PersistenceManager API (through
+ * PersistenceManagerFactoryUtils.getPersistenceManager()).
+ * The major advantage is its automatic conversion to DataAccessExceptions, the
+ * major disadvantage that no checked application exceptions can get thrown from
+ * within data access code. Corresponding checks and the actual throwing of such
+ * exceptions can often be deferred to after callback execution, though.
+ *
+ *
{@link LocalPersistenceManagerFactoryBean} is the preferred way of obtaining
+ * a reference to a specific PersistenceManagerFactory, at least in a non-EJB
+ * environment. The Spring application context will manage its lifecycle,
+ * initializing and shutting down the factory as part of the application.
+ *
+ *
Note that lazy loading will just work with an open JDO PersistenceManager,
+ * either within a Spring-driven transaction (with JdoTransactionManager or
+ * JtaTransactionManager) or within OpenPersistenceManagerInViewFilter/Interceptor.
+ * Furthermore, some operations just make sense within transactions,
+ * for example: evict, evictAll, flush.
+ *
+ *
NOTE: This class requires JDO 2.0 or higher, as of Spring 2.5.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see #setPersistenceManagerFactory
+ * @see JdoCallback
+ * @see javax.jdo.PersistenceManager
+ * @see LocalPersistenceManagerFactoryBean
+ * @see JdoTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter
+ * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor
+ */
+public class JdoTemplate extends JdoAccessor implements JdoOperations {
+
+ private boolean allowCreate = true;
+
+ private boolean exposeNativePersistenceManager = false;
+
+
+ /**
+ * Create a new JdoTemplate instance.
+ */
+ public JdoTemplate() {
+ }
+
+ /**
+ * Create a new JdoTemplate instance.
+ * @param pmf PersistenceManagerFactory to create PersistenceManagers
+ */
+ public JdoTemplate(PersistenceManagerFactory pmf) {
+ setPersistenceManagerFactory(pmf);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Create a new JdoTemplate instance.
+ * @param pmf PersistenceManagerFactory to create PersistenceManagers
+ * @param allowCreate if a non-transactional PersistenceManager should be created
+ * when no transactional PersistenceManager can be found for the current thread
+ */
+ public JdoTemplate(PersistenceManagerFactory pmf, boolean allowCreate) {
+ setPersistenceManagerFactory(pmf);
+ setAllowCreate(allowCreate);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Set if a new PersistenceManager should be created when no transactional
+ * PersistenceManager can be found for the current thread.
+ *
JdoTemplate is aware of a corresponding PersistenceManager bound to the
+ * current thread, for example when using JdoTransactionManager.
+ * If allowCreate is true, a new non-transactional PersistenceManager will be
+ * created if none found, which needs to be closed at the end of the operation.
+ * If false, an IllegalStateException will get thrown in this case.
+ * @see PersistenceManagerFactoryUtils#getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean)
+ */
+ public void setAllowCreate(boolean allowCreate) {
+ this.allowCreate = allowCreate;
+ }
+
+ /**
+ * Return if a new PersistenceManager should be created if no thread-bound found.
+ */
+ public boolean isAllowCreate() {
+ return this.allowCreate;
+ }
+
+ /**
+ * Set whether to expose the native JDO PersistenceManager to JdoCallback
+ * code. Default is "false": a PersistenceManager proxy will be returned,
+ * suppressing close calls and automatically applying transaction
+ * timeouts (if any).
+ *
As there is often a need to cast to a provider-specific PersistenceManager
+ * class in DAOs that use provider-specific functionality, the exposed proxy
+ * implements all interfaces implemented by the original PersistenceManager.
+ * If this is not sufficient, turn this flag to "true".
+ * @see JdoCallback
+ * @see javax.jdo.PersistenceManager
+ * @see #prepareQuery
+ */
+ public void setExposeNativePersistenceManager(boolean exposeNativePersistenceManager) {
+ this.exposeNativePersistenceManager = exposeNativePersistenceManager;
+ }
+
+ /**
+ * Return whether to expose the native JDO PersistenceManager to JdoCallback
+ * code, or rather a PersistenceManager proxy.
+ */
+ public boolean isExposeNativePersistenceManager() {
+ return this.exposeNativePersistenceManager;
+ }
+
+
+ public Object execute(JdoCallback action) throws DataAccessException {
+ return execute(action, isExposeNativePersistenceManager());
+ }
+
+ public Collection executeFind(JdoCallback action) throws DataAccessException {
+ Object result = execute(action, isExposeNativePersistenceManager());
+ if (result != null && !(result instanceof Collection)) {
+ throw new InvalidDataAccessApiUsageException(
+ "Result object returned from JdoCallback isn't a Collection: [" + result + "]");
+ }
+ return (Collection) result;
+ }
+
+ /**
+ * Execute the action specified by the given action object within a
+ * PersistenceManager.
+ * @param action callback object that specifies the JDO action
+ * @param exposeNativePersistenceManager whether to expose the native
+ * JDO persistence manager to callback code
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of JDO errors
+ */
+ public Object execute(JdoCallback action, boolean exposeNativePersistenceManager) throws DataAccessException {
+ Assert.notNull(action, "Callback object must not be null");
+
+ PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(
+ getPersistenceManagerFactory(), isAllowCreate());
+ boolean existingTransaction =
+ TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory());
+ try {
+ PersistenceManager pmToExpose = (exposeNativePersistenceManager ? pm : createPersistenceManagerProxy(pm));
+ Object result = action.doInJdo(pmToExpose);
+ flushIfNecessary(pm, existingTransaction);
+ return postProcessResult(result, pm, existingTransaction);
+ }
+ catch (JDOException ex) {
+ throw convertJdoAccessException(ex);
+ }
+ catch (RuntimeException ex) {
+ // callback code threw application exception
+ throw ex;
+ }
+ finally {
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
+ }
+ }
+
+ /**
+ * Create a close-suppressing proxy for the given JDO PersistenceManager.
+ * Called by the execute method.
+ *
The proxy also prepares returned JDO Query objects.
+ * @param pm the JDO PersistenceManager to create a proxy for
+ * @return the PersistenceManager proxy, implementing all interfaces
+ * implemented by the passed-in PersistenceManager object (that is,
+ * also implementing all provider-specific extension interfaces)
+ * @see javax.jdo.PersistenceManager#close()
+ * @see #execute(JdoCallback, boolean)
+ * @see #prepareQuery
+ */
+ protected PersistenceManager createPersistenceManagerProxy(PersistenceManager pm) {
+ Class[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), getClass().getClassLoader());
+ return (PersistenceManager) Proxy.newProxyInstance(
+ pm.getClass().getClassLoader(), ifcs, new CloseSuppressingInvocationHandler(pm));
+ }
+
+ /**
+ * Post-process the given result object, which might be a Collection.
+ * Called by the execute method.
+ *
Default implementation always returns the passed-in Object as-is.
+ * Subclasses might override this to automatically detach result
+ * collections or even single result objects.
+ * @param pm the current JDO PersistenceManager
+ * @param result the result object (might be a Collection)
+ * @param existingTransaction if executing within an existing transaction
+ * (within an existing JDO PersistenceManager that won't be closed immediately)
+ * @return the post-processed result object (can be simply be the passed-in object)
+ * @see #execute(JdoCallback, boolean)
+ */
+ protected Object postProcessResult(Object result, PersistenceManager pm, boolean existingTransaction) {
+ return result;
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for load, save, delete
+ //-------------------------------------------------------------------------
+
+ public Object getObjectById(final Object objectId) throws DataAccessException {
+ return execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.getObjectById(objectId, true);
+ }
+ }, true);
+ }
+
+ public Object getObjectById(final Class entityClass, final Object idValue) throws DataAccessException {
+ return execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.getObjectById(entityClass, idValue);
+ }
+ }, true);
+ }
+
+ public void evict(final Object entity) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.evict(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ public void evictAll(final Collection entities) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.evictAll(entities);
+ return null;
+ }
+ }, true);
+ }
+
+ public void evictAll() throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.evictAll();
+ return null;
+ }
+ }, true);
+ }
+
+ public void refresh(final Object entity) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.refresh(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ public void refreshAll(final Collection entities) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.refreshAll(entities);
+ return null;
+ }
+ }, true);
+ }
+
+ public void refreshAll() throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.refreshAll();
+ return null;
+ }
+ }, true);
+ }
+
+ public Object makePersistent(final Object entity) throws DataAccessException {
+ return execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.makePersistent(entity);
+ }
+ }, true);
+ }
+
+ public Collection makePersistentAll(final Collection entities) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.makePersistentAll(entities);
+ }
+ }, true);
+ }
+
+ public void deletePersistent(final Object entity) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.deletePersistent(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ public void deletePersistentAll(final Collection entities) throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ pm.deletePersistentAll(entities);
+ return null;
+ }
+ }, true);
+ }
+
+ public Object detachCopy(final Object entity) {
+ return execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.detachCopy(entity);
+ }
+ }, true);
+ }
+
+ public Collection detachCopyAll(final Collection entities) {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ return pm.detachCopyAll(entities);
+ }
+ }, true);
+ }
+
+ /**
+ * @deprecated in favor of {@link #makePersistent(Object)}.
+ * To be removed in Spring 3.0.
+ */
+ public Object attachCopy(Object detachedEntity) {
+ return makePersistent(detachedEntity);
+ }
+
+ /**
+ * @deprecated in favor of {@link #makePersistentAll(java.util.Collection)}.
+ * To be removed in Spring 3.0.
+ */
+ public Collection attachCopyAll(Collection detachedEntities) {
+ return makePersistentAll(detachedEntities);
+ }
+
+ public void flush() throws DataAccessException {
+ execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ getJdoDialect().flush(pm);
+ return null;
+ }
+ }, true);
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods
+ //-------------------------------------------------------------------------
+
+ public Collection find(Class entityClass) throws DataAccessException {
+ return find(entityClass, null, null);
+ }
+
+ public Collection find(Class entityClass, String filter) throws DataAccessException {
+ return find(entityClass, filter, null);
+ }
+
+ public Collection find(final Class entityClass, final String filter, final String ordering)
+ throws DataAccessException {
+
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = (filter != null ? pm.newQuery(entityClass, filter) : pm.newQuery(entityClass));
+ prepareQuery(query);
+ if (ordering != null) {
+ query.setOrdering(ordering);
+ }
+ return query.execute();
+ }
+ }, true);
+ }
+
+ public Collection find(Class entityClass, String filter, String parameters, Object[] values)
+ throws DataAccessException {
+
+ return find(entityClass, filter, parameters, values, null);
+ }
+
+ public Collection find(
+ final Class entityClass, final String filter, final String parameters, final Object[] values,
+ final String ordering) throws DataAccessException {
+
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(entityClass, filter);
+ prepareQuery(query);
+ query.declareParameters(parameters);
+ if (ordering != null) {
+ query.setOrdering(ordering);
+ }
+ return query.executeWithArray(values);
+ }
+ }, true);
+ }
+
+ public Collection find(Class entityClass, String filter, String parameters, Map values)
+ throws DataAccessException {
+
+ return find(entityClass, filter, parameters, values, null);
+ }
+
+ public Collection find(
+ final Class entityClass, final String filter, final String parameters, final Map values,
+ final String ordering) throws DataAccessException {
+
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(entityClass, filter);
+ prepareQuery(query);
+ query.declareParameters(parameters);
+ if (ordering != null) {
+ query.setOrdering(ordering);
+ }
+ return query.executeWithMap(values);
+ }
+ }, true);
+ }
+
+ public Collection find(final String language, final Object queryObject) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(language, queryObject);
+ prepareQuery(query);
+ return query.execute();
+ }
+ }, true);
+ }
+
+ public Collection find(final String queryString) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(queryString);
+ prepareQuery(query);
+ return query.execute();
+ }
+ }, true);
+ }
+
+ public Collection find(final String queryString, final Object[] values) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(queryString);
+ prepareQuery(query);
+ return query.executeWithArray(values);
+ }
+ }, true);
+ }
+
+ public Collection find(final String queryString, final Map values) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newQuery(queryString);
+ prepareQuery(query);
+ return query.executeWithMap(values);
+ }
+ }, true);
+ }
+
+ public Collection findByNamedQuery(final Class entityClass, final String queryName) throws DataAccessException {
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newNamedQuery(entityClass, queryName);
+ prepareQuery(query);
+ return query.execute();
+ }
+ }, true);
+ }
+
+ public Collection findByNamedQuery(final Class entityClass, final String queryName, final Object[] values)
+ throws DataAccessException {
+
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newNamedQuery(entityClass, queryName);
+ prepareQuery(query);
+ return query.executeWithArray(values);
+ }
+ }, true);
+ }
+
+ public Collection findByNamedQuery(final Class entityClass, final String queryName, final Map values)
+ throws DataAccessException {
+
+ return (Collection) execute(new JdoCallback() {
+ public Object doInJdo(PersistenceManager pm) throws JDOException {
+ Query query = pm.newNamedQuery(entityClass, queryName);
+ prepareQuery(query);
+ return query.executeWithMap(values);
+ }
+ }, true);
+ }
+
+
+ /**
+ * Prepare the given JDO query object. To be used within a JdoCallback.
+ * Applies a transaction timeout, if any. If you don't use such timeouts,
+ * the call is a no-op.
+ *
In general, prefer a proxied PersistenceManager instead, which will
+ * automatically apply the transaction timeout (through the use of a special
+ * PersistenceManager proxy). You need to set the "exposeNativePersistenceManager"
+ * property to "false" to activate this. Note that you won't be able to cast
+ * to a provider-specific JDO PersistenceManager class anymore then.
+ * @param query the JDO query object
+ * @throws JDOException if the query could not be properly prepared
+ * @see JdoCallback#doInJdo
+ * @see PersistenceManagerFactoryUtils#applyTransactionTimeout
+ * @see #setExposeNativePersistenceManager
+ */
+ public void prepareQuery(Query query) throws JDOException {
+ PersistenceManagerFactoryUtils.applyTransactionTimeout(
+ query, getPersistenceManagerFactory(), getJdoDialect());
+ }
+
+
+ /**
+ * Invocation handler that suppresses close calls on JDO PersistenceManagers.
+ * Also prepares returned Query objects.
+ * @see javax.jdo.PersistenceManager#close()
+ */
+ private class CloseSuppressingInvocationHandler implements InvocationHandler {
+
+ private final PersistenceManager target;
+
+ public CloseSuppressingInvocationHandler(PersistenceManager target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on PersistenceManager interface (or provider-specific extension) coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of PersistenceManager proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: suppress, not valid.
+ return null;
+ }
+
+ // Invoke method on target PersistenceManager.
+ try {
+ Object retVal = method.invoke(this.target, args);
+
+ // If return value is a JDO Query object, apply transaction timeout.
+ if (retVal instanceof Query) {
+ prepareQuery(((Query) retVal));
+ }
+
+ return retVal;
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoTransactionManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoTransactionManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoTransactionManager.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,587 @@
+/*
+ * Copyright 2002-2008 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.orm.jdo;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Transaction;
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.jdbc.datasource.ConnectionHolder;
+import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.transaction.CannotCreateTransactionException;
+import org.springframework.transaction.IllegalTransactionStateException;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+import org.springframework.transaction.TransactionSystemException;
+import org.springframework.transaction.support.AbstractPlatformTransactionManager;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+import org.springframework.transaction.support.ResourceTransactionManager;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * {@link org.springframework.transaction.PlatformTransactionManager} implementation
+ * for a single JDO {@link javax.jdo.PersistenceManagerFactory}. Binds a JDO
+ * PersistenceManager from the specified factory to the thread, potentially allowing
+ * for one thread-bound PersistenceManager per factory.
+ * {@link PersistenceManagerFactoryUtils} and {@link JdoTemplate} are aware of
+ * thread-bound persistence managers and participate in such transactions automatically.
+ * Using either of those (or going through a {@link TransactionAwarePersistenceManagerFactoryProxy}
+ * is required for JDO access code supporting this transaction management mechanism.
+ *
+ *
This transaction manager is appropriate for applications that use a single
+ * JDO PersistenceManagerFactory for transactional data access. JTA (usually through
+ * {@link org.springframework.transaction.jta.JtaTransactionManager}) is necessary
+ * for accessing multiple transactional resources within the same transaction.
+ * Note that you need to configure your JDO provider accordingly in order to make
+ * it participate in JTA transactions.
+ *
+ *
This transaction manager also supports direct DataSource access within a
+ * transaction (i.e. plain JDBC code working with the same DataSource).
+ * This allows for mixing services which access JDO and services which use plain
+ * JDBC (without being aware of JDO)! Application code needs to stick to the
+ * same simple Connection lookup pattern as with
+ * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
+ * (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
+ * or going through a
+ * {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
+ *
+ *
Note: To be able to register a DataSource's Connection for plain JDBC code,
+ * this instance needs to be aware of the DataSource ({@link #setDataSource}).
+ * The given DataSource should obviously match the one used by the given
+ * PersistenceManagerFactory. This transaction manager will autodetect the DataSource
+ * that acts as "connectionFactory" of the PersistenceManagerFactory, so you usually
+ * don't need to explicitly specify the "dataSource" property.
+ *
+ *
On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
+ * Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"}
+ * flag defaults to "false", though, as nested transactions will just apply to the
+ * JDBC Connection, not to the JDO PersistenceManager and its cached objects.
+ * You can manually set the flag to "true" if you want to use nested transactions
+ * for JDBC access code which participates in JDO transactions (provided that your
+ * JDBC driver supports Savepoints). Note that JDO itself does not support
+ * nested transactions! Hence, do not expect JDO access code to semantically
+ * participate in a nested transaction.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see #setPersistenceManagerFactory
+ * @see #setDataSource
+ * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory
+ * @see LocalPersistenceManagerFactoryBean
+ * @see PersistenceManagerFactoryUtils#getPersistenceManager
+ * @see PersistenceManagerFactoryUtils#releasePersistenceManager
+ * @see JdoTemplate
+ * @see TransactionAwarePersistenceManagerFactoryProxy
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+public class JdoTransactionManager extends AbstractPlatformTransactionManager
+ implements ResourceTransactionManager, InitializingBean {
+
+ private PersistenceManagerFactory persistenceManagerFactory;
+
+ private DataSource dataSource;
+
+ private boolean autodetectDataSource = true;
+
+ private JdoDialect jdoDialect;
+
+
+ /**
+ * Create a new JdoTransactionManager instance.
+ * A PersistenceManagerFactory has to be set to be able to use it.
+ * @see #setPersistenceManagerFactory
+ */
+ public JdoTransactionManager() {
+ }
+
+ /**
+ * Create a new JdoTransactionManager instance.
+ * @param pmf PersistenceManagerFactory to manage transactions for
+ */
+ public JdoTransactionManager(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set the PersistenceManagerFactory that this instance should manage transactions for.
+ *
The PersistenceManagerFactory specified here should be the target
+ * PersistenceManagerFactory to manage transactions for, not a
+ * TransactionAwarePersistenceManagerFactoryProxy. Only data access
+ * code may work with TransactionAwarePersistenceManagerFactoryProxy, while the
+ * transaction manager needs to work on the underlying target PersistenceManagerFactory.
+ * @see TransactionAwarePersistenceManagerFactoryProxy
+ */
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
+ }
+
+ /**
+ * Return the PersistenceManagerFactory that this instance should manage transactions for.
+ */
+ public PersistenceManagerFactory getPersistenceManagerFactory() {
+ return this.persistenceManagerFactory;
+ }
+
+ /**
+ * Set the JDBC DataSource that this instance should manage transactions for.
+ * The DataSource should match the one used by the JDO PersistenceManagerFactory:
+ * for example, you could specify the same JNDI DataSource for both.
+ *
If the PersistenceManagerFactory uses a DataSource as connection factory,
+ * the DataSource will be autodetected: You can still explictly specify the
+ * DataSource, but you don't need to in this case.
+ *
A transactional JDBC Connection for this DataSource will be provided to
+ * application code accessing this DataSource directly via DataSourceUtils
+ * or JdbcTemplate. The Connection will be taken from the JDO PersistenceManager.
+ *
Note that you need to use a JDO dialect for a specific JDO provider to
+ * allow for exposing JDO transactions as JDBC transactions.
+ *
The DataSource specified here should be the target DataSource to manage
+ * transactions for, not a TransactionAwareDataSourceProxy. Only data access
+ * code may work with TransactionAwareDataSourceProxy, while the transaction
+ * manager needs to work on the underlying target DataSource. If there's
+ * nevertheless a TransactionAwareDataSourceProxy passed in, it will be
+ * unwrapped to extract its target DataSource.
+ * @see #setAutodetectDataSource
+ * @see #setJdoDialect
+ * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory
+ * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
+ * @see org.springframework.jdbc.datasource.DataSourceUtils
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ */
+ public void setDataSource(DataSource dataSource) {
+ if (dataSource instanceof TransactionAwareDataSourceProxy) {
+ // If we got a TransactionAwareDataSourceProxy, we need to perform transactions
+ // for its underlying target DataSource, else data access code won't see
+ // properly exposed transactions (i.e. transactions for the target DataSource).
+ this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
+ }
+ else {
+ this.dataSource = dataSource;
+ }
+ }
+
+ /**
+ * Return the JDBC DataSource that this instance manages transactions for.
+ */
+ public DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * Set whether to autodetect a JDBC DataSource used by the JDO PersistenceManagerFactory,
+ * as returned by the getConnectionFactory() method. Default is "true".
+ *
Can be turned off to deliberately ignore an available DataSource,
+ * to not expose JDO transactions as JDBC transactions for that DataSource.
+ * @see #setDataSource
+ * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory
+ */
+ public void setAutodetectDataSource(boolean autodetectDataSource) {
+ this.autodetectDataSource = autodetectDataSource;
+ }
+
+ /**
+ * Set the JDO dialect to use for this transaction manager.
+ *
The dialect object can be used to retrieve the underlying JDBC connection
+ * and thus allows for exposing JDO transactions as JDBC transactions.
+ * @see JdoDialect#getJdbcConnection
+ */
+ public void setJdoDialect(JdoDialect jdoDialect) {
+ this.jdoDialect = jdoDialect;
+ }
+
+ /**
+ * Return the JDO dialect to use for this transaction manager.
+ *
Creates a default one for the specified PersistenceManagerFactory if none set.
+ */
+ public JdoDialect getJdoDialect() {
+ if (this.jdoDialect == null) {
+ this.jdoDialect = new DefaultJdoDialect();
+ }
+ return this.jdoDialect;
+ }
+
+ /**
+ * Eagerly initialize the JDO dialect, creating a default one
+ * for the specified PersistenceManagerFactory if none set.
+ * Auto-detect the PersistenceManagerFactory's DataSource, if any.
+ */
+ public void afterPropertiesSet() {
+ if (getPersistenceManagerFactory() == null) {
+ throw new IllegalArgumentException("Property 'persistenceManagerFactory' is required");
+ }
+ // Build default JdoDialect if none explicitly specified.
+ if (this.jdoDialect == null) {
+ this.jdoDialect = new DefaultJdoDialect(getPersistenceManagerFactory().getConnectionFactory());
+ }
+
+ // Check for DataSource as connection factory.
+ if (this.autodetectDataSource && getDataSource() == null) {
+ Object pmfcf = getPersistenceManagerFactory().getConnectionFactory();
+ if (pmfcf instanceof DataSource) {
+ // Use the PersistenceManagerFactory's DataSource for exposing transactions to JDBC code.
+ this.dataSource = (DataSource) pmfcf;
+ if (logger.isInfoEnabled()) {
+ logger.info("Using DataSource [" + this.dataSource +
+ "] of JDO PersistenceManagerFactory for JdoTransactionManager");
+ }
+ }
+ }
+ }
+
+
+ public Object getResourceFactory() {
+ return getPersistenceManagerFactory();
+ }
+
+ protected Object doGetTransaction() {
+ JdoTransactionObject txObject = new JdoTransactionObject();
+ txObject.setSavepointAllowed(isNestedTransactionAllowed());
+
+ PersistenceManagerHolder pmHolder = (PersistenceManagerHolder)
+ TransactionSynchronizationManager.getResource(getPersistenceManagerFactory());
+ if (pmHolder != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found thread-bound PersistenceManager [" +
+ pmHolder.getPersistenceManager() + "] for JDO transaction");
+ }
+ txObject.setPersistenceManagerHolder(pmHolder, false);
+ }
+
+ if (getDataSource() != null) {
+ ConnectionHolder conHolder = (ConnectionHolder)
+ TransactionSynchronizationManager.getResource(getDataSource());
+ txObject.setConnectionHolder(conHolder);
+ }
+
+ return txObject;
+ }
+
+ protected boolean isExistingTransaction(Object transaction) {
+ return ((JdoTransactionObject) transaction).hasTransaction();
+ }
+
+ protected void doBegin(Object transaction, TransactionDefinition definition) {
+ JdoTransactionObject txObject = (JdoTransactionObject) transaction;
+
+ if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
+ throw new IllegalTransactionStateException(
+ "Pre-bound JDBC Connection found! JdoTransactionManager does not support " +
+ "running within DataSourceTransactionManager if told to manage the DataSource itself. " +
+ "It is recommended to use a single JdoTransactionManager for all transactions " +
+ "on a single DataSource, no matter whether JDO or JDBC access.");
+ }
+
+ PersistenceManager pm = null;
+
+ try {
+ if (txObject.getPersistenceManagerHolder() == null ||
+ txObject.getPersistenceManagerHolder().isSynchronizedWithTransaction()) {
+ PersistenceManager newPm = getPersistenceManagerFactory().getPersistenceManager();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Opened new PersistenceManager [" + newPm + "] for JDO transaction");
+ }
+ txObject.setPersistenceManagerHolder(new PersistenceManagerHolder(newPm), true);
+ }
+
+ pm = txObject.getPersistenceManagerHolder().getPersistenceManager();
+
+ // Delegate to JdoDialect for actual transaction begin.
+ Object transactionData = getJdoDialect().beginTransaction(pm.currentTransaction(), definition);
+ txObject.setTransactionData(transactionData);
+
+ // Register transaction timeout.
+ int timeout = determineTimeout(definition);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ txObject.getPersistenceManagerHolder().setTimeoutInSeconds(timeout);
+ }
+
+ // Register the JDO PersistenceManager's JDBC Connection for the DataSource, if set.
+ if (getDataSource() != null) {
+ ConnectionHandle conHandle = getJdoDialect().getJdbcConnection(pm, definition.isReadOnly());
+ if (conHandle != null) {
+ ConnectionHolder conHolder = new ConnectionHolder(conHandle);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ conHolder.setTimeoutInSeconds(timeout);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Exposing JDO transaction as JDBC transaction [" + conHolder.getConnectionHandle() + "]");
+ }
+ TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
+ txObject.setConnectionHolder(conHolder);
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Not exposing JDO transaction [" + pm + "] as JDBC transaction because JdoDialect [" +
+ getJdoDialect() + "] does not support JDBC Connection retrieval");
+ }
+ }
+ }
+
+ // Bind the persistence manager holder to the thread.
+ if (txObject.isNewPersistenceManagerHolder()) {
+ TransactionSynchronizationManager.bindResource(
+ getPersistenceManagerFactory(), txObject.getPersistenceManagerHolder());
+ }
+ txObject.getPersistenceManagerHolder().setSynchronizedWithTransaction(true);
+ }
+
+ catch (TransactionException ex) {
+ closePersistenceManagerAfterFailedBegin(txObject);
+ throw ex;
+ }
+ catch (Exception ex) {
+ closePersistenceManagerAfterFailedBegin(txObject);
+ throw new CannotCreateTransactionException("Could not open JDO PersistenceManager for transaction", ex);
+ }
+ }
+
+ /**
+ * Close the current transaction's EntityManager.
+ * Called after a transaction begin attempt failed.
+ * @param txObject the current transaction
+ */
+ protected void closePersistenceManagerAfterFailedBegin(JdoTransactionObject txObject) {
+ if (txObject.isNewPersistenceManagerHolder()) {
+ PersistenceManager pm = txObject.getPersistenceManagerHolder().getPersistenceManager();
+ try {
+ if (pm.currentTransaction().isActive()) {
+ pm.currentTransaction().rollback();
+ }
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not rollback PersistenceManager after failed transaction begin", ex);
+ }
+ finally {
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
+ }
+ }
+ }
+
+ protected Object doSuspend(Object transaction) {
+ JdoTransactionObject txObject = (JdoTransactionObject) transaction;
+ txObject.setPersistenceManagerHolder(null, false);
+ PersistenceManagerHolder persistenceManagerHolder = (PersistenceManagerHolder)
+ TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory());
+ txObject.setConnectionHolder(null);
+ ConnectionHolder connectionHolder = null;
+ if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) {
+ connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
+ }
+ return new SuspendedResourcesHolder(persistenceManagerHolder, connectionHolder);
+ }
+
+ protected void doResume(Object transaction, Object suspendedResources) {
+ SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
+ TransactionSynchronizationManager.bindResource(
+ getPersistenceManagerFactory(), resourcesHolder.getPersistenceManagerHolder());
+ if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) {
+ TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
+ }
+ }
+
+ /**
+ * This implementation returns "true": a JDO2 commit will properly handle
+ * transactions that have been marked rollback-only at a global level.
+ */
+ protected boolean shouldCommitOnGlobalRollbackOnly() {
+ return true;
+ }
+
+ protected void doCommit(DefaultTransactionStatus status) {
+ JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Committing JDO transaction on PersistenceManager [" +
+ txObject.getPersistenceManagerHolder().getPersistenceManager() + "]");
+ }
+ try {
+ Transaction tx = txObject.getPersistenceManagerHolder().getPersistenceManager().currentTransaction();
+ tx.commit();
+ }
+ catch (JDOException ex) {
+ // Assumably failed to flush changes to database.
+ throw convertJdoAccessException(ex);
+ }
+ }
+
+ protected void doRollback(DefaultTransactionStatus status) {
+ JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Rolling back JDO transaction on PersistenceManager [" +
+ txObject.getPersistenceManagerHolder().getPersistenceManager() + "]");
+ }
+ try {
+ Transaction tx = txObject.getPersistenceManagerHolder().getPersistenceManager().currentTransaction();
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ catch (JDOException ex) {
+ throw new TransactionSystemException("Could not roll back JDO transaction", ex);
+ }
+ }
+
+ protected void doSetRollbackOnly(DefaultTransactionStatus status) {
+ JdoTransactionObject txObject = (JdoTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Setting JDO transaction on PersistenceManager [" +
+ txObject.getPersistenceManagerHolder().getPersistenceManager() + "] rollback-only");
+ }
+ txObject.setRollbackOnly();
+ }
+
+ protected void doCleanupAfterCompletion(Object transaction) {
+ JdoTransactionObject txObject = (JdoTransactionObject) transaction;
+
+ // Remove the persistence manager holder from the thread.
+ if (txObject.isNewPersistenceManagerHolder()) {
+ TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory());
+ }
+ txObject.getPersistenceManagerHolder().clear();
+
+ // Remove the JDBC connection holder from the thread, if exposed.
+ if (txObject.hasConnectionHolder()) {
+ TransactionSynchronizationManager.unbindResource(getDataSource());
+ try {
+ getJdoDialect().releaseJdbcConnection(txObject.getConnectionHolder().getConnectionHandle(),
+ txObject.getPersistenceManagerHolder().getPersistenceManager());
+ }
+ catch (Throwable ex) {
+ // Just log it, to keep a transaction-related exception.
+ logger.debug("Could not release JDBC connection after transaction", ex);
+ }
+ }
+
+ getJdoDialect().cleanupTransaction(txObject.getTransactionData());
+
+ if (txObject.isNewPersistenceManagerHolder()) {
+ PersistenceManager pm = txObject.getPersistenceManagerHolder().getPersistenceManager();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Closing JDO PersistenceManager [" + pm + "] after transaction");
+ }
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
+ }
+ else {
+ logger.debug("Not closing pre-bound JDO PersistenceManager after transaction");
+ }
+ }
+
+ /**
+ * Convert the given JDOException to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ *
Default implementation delegates to the JdoDialect.
+ * May be overridden in subclasses.
+ * @param ex JDOException that occured
+ * @return the corresponding DataAccessException instance
+ * @see JdoDialect#translateException
+ */
+ protected DataAccessException convertJdoAccessException(JDOException ex) {
+ return getJdoDialect().translateException(ex);
+ }
+
+
+ /**
+ * JDO transaction object, representing a PersistenceManagerHolder.
+ * Used as transaction object by JdoTransactionManager.
+ */
+ private static class JdoTransactionObject extends JdbcTransactionObjectSupport {
+
+ private PersistenceManagerHolder persistenceManagerHolder;
+
+ private boolean newPersistenceManagerHolder;
+
+ private Object transactionData;
+
+ public void setPersistenceManagerHolder(
+ PersistenceManagerHolder persistenceManagerHolder, boolean newPersistenceManagerHolder) {
+ this.persistenceManagerHolder = persistenceManagerHolder;
+ this.newPersistenceManagerHolder = newPersistenceManagerHolder;
+ }
+
+ public PersistenceManagerHolder getPersistenceManagerHolder() {
+ return persistenceManagerHolder;
+ }
+
+ public boolean isNewPersistenceManagerHolder() {
+ return newPersistenceManagerHolder;
+ }
+
+ public boolean hasTransaction() {
+ return (this.persistenceManagerHolder != null && this.persistenceManagerHolder.isTransactionActive());
+ }
+
+ public void setTransactionData(Object transactionData) {
+ this.transactionData = transactionData;
+ this.persistenceManagerHolder.setTransactionActive(true);
+ }
+
+ public Object getTransactionData() {
+ return transactionData;
+ }
+
+ public void setRollbackOnly() {
+ Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction();
+ if (tx.isActive()) {
+ tx.setRollbackOnly();
+ }
+ if (hasConnectionHolder()) {
+ getConnectionHolder().setRollbackOnly();
+ }
+ }
+
+ public boolean isRollbackOnly() {
+ Transaction tx = this.persistenceManagerHolder.getPersistenceManager().currentTransaction();
+ return tx.getRollbackOnly();
+ }
+ }
+
+
+ /**
+ * Holder for suspended resources.
+ * Used internally by doSuspend and doResume.
+ */
+ private static class SuspendedResourcesHolder {
+
+ private final PersistenceManagerHolder persistenceManagerHolder;
+
+ private final ConnectionHolder connectionHolder;
+
+ private SuspendedResourcesHolder(PersistenceManagerHolder pmHolder, ConnectionHolder conHolder) {
+ this.persistenceManagerHolder = pmHolder;
+ this.connectionHolder = conHolder;
+ }
+
+ private PersistenceManagerHolder getPersistenceManagerHolder() {
+ return this.persistenceManagerHolder;
+ }
+
+ private ConnectionHolder getConnectionHolder() {
+ return this.connectionHolder;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/JdoUsageException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/JdoUsageException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/JdoUsageException.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2005 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.orm.jdo;
+
+import javax.jdo.JDOFatalUserException;
+import javax.jdo.JDOUserException;
+
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+
+/**
+ * JDO-specific subclass of InvalidDataAccessApiUsageException.
+ * Converts JDO's JDOUserException and JDOFatalUserException.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+public class JdoUsageException extends InvalidDataAccessApiUsageException {
+
+ public JdoUsageException(JDOUserException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+ public JdoUsageException(JDOFatalUserException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/LocalPersistenceManagerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/LocalPersistenceManagerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/LocalPersistenceManagerFactoryBean.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jdo.JDOException;
+import javax.jdo.JDOHelper;
+import javax.jdo.PersistenceManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that creates a
+ * JDO {@link javax.jdo.PersistenceManagerFactory}. This is the usual way to
+ * set up a shared JDO PersistenceManagerFactory in a Spring application context;
+ * the PersistenceManagerFactory can then be passed to JDO-based DAOs via
+ * dependency injection. Note that switching to a JNDI lookup or to a bean-style
+ * PersistenceManagerFactory instance is just a matter of configuration!
+ *
+ *
Configuration settings can either be read from a properties file,
+ * specified as "configLocation", or locally specified. Properties
+ * specified as "jdoProperties" here will override any settings in a file.
+ * On JDO 2.1, you may alternatively specify a "persistenceManagerFactoryName",
+ * referring to a PMF definition in "META-INF/jdoconfig.xml"
+ * (see {@link #setPersistenceManagerFactoryName}).
+ *
+ *
NOTE: This class requires JDO 2.0 or higher, as of Spring 2.5.
+ *
+ *
This class also implements the
+ * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
+ * interface, as autodetected by Spring's
+ * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
+ * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
+ * Hence, the presence of a LocalPersistenceManagerFactoryBean automatically enables
+ * a PersistenceExceptionTranslationPostProcessor to translate JDO exceptions.
+ *
+ *
Alternative: Configuration of a PersistenceManagerFactory provider bean
+ *
+ *
As alternative to the properties-driven approach that this FactoryBean offers
+ * (which is analogous to using the standard JDOHelper class with a Properties
+ * object that is populated with standard JDO properties), you can set up an
+ * instance of your PersistenceManagerFactory implementation class directly.
+ *
+ *
Like a DataSource, a PersistenceManagerFactory is encouraged to
+ * support bean-style configuration, which makes it very easy to set up as
+ * Spring-managed bean. The implementation class becomes the bean class;
+ * the remaining properties are applied as bean properties (starting with
+ * lower-case characters, in contrast to the corresponding JDO properties).
+ *
+ *
Note that such direct setup of a PersistenceManagerFactory implementation
+ * is the only way to pass an external connection factory (i.e. a JDBC DataSource)
+ * into a JDO PersistenceManagerFactory. With the standard properties-driven approach,
+ * you can only use an internal connection pool or a JNDI DataSource.
+ *
+ *
The close() method is standardized in JDO; don't forget to
+ * specify it as "destroy-method" for any PersistenceManagerFactory instance.
+ * Note that this FactoryBean will automatically invoke close() for
+ * the PersistenceManagerFactory that it creates, without any special configuration.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see JdoTemplate#setPersistenceManagerFactory
+ * @see JdoTransactionManager#setPersistenceManagerFactory
+ * @see org.springframework.jndi.JndiObjectFactoryBean
+ * @see javax.jdo.JDOHelper#getPersistenceManagerFactory
+ * @see javax.jdo.PersistenceManagerFactory#setConnectionFactory
+ * @see javax.jdo.PersistenceManagerFactory#close()
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ */
+public class LocalPersistenceManagerFactoryBean
+ implements FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private String persistenceManagerFactoryName;
+
+ private Resource configLocation;
+
+ private final Map jdoPropertyMap = new HashMap();
+
+ private ClassLoader beanClassLoader;
+
+ private PersistenceManagerFactory persistenceManagerFactory;
+
+ private JdoDialect jdoDialect;
+
+
+ /**
+ * Specify the name of the desired PersistenceManagerFactory.
+ *
This may either be a properties resource in the classpath if such a resource exists
+ * (JDO 2.0), or a PMF definition with that name from "META-INF/jdoconfig.xml" (JDO 2.1),
+ * or a JPA EntityManagerFactory cast to a PersistenceManagerFactory based on the
+ * persistence-unit name from "META-INF/persistence.xml" (JDO 2.1 / JPA 1.0).
+ *
Default is none: Either 'persistenceManagerFactoryName' or 'configLocation'
+ * or 'jdoProperties' needs to be specified.
+ * @see #setConfigLocation
+ * @see #setJdoProperties
+ */
+ public void setPersistenceManagerFactoryName(String persistenceManagerFactoryName) {
+ this.persistenceManagerFactoryName = persistenceManagerFactoryName;
+ }
+
+ /**
+ * Set the location of the JDO properties config file, for example
+ * as classpath resource "classpath:kodo.properties".
+ *
Note: Can be omitted when all necessary properties are
+ * specified locally via this bean.
+ */
+ public void setConfigLocation(Resource configLocation) {
+ this.configLocation = configLocation;
+ }
+
+ /**
+ * Set JDO properties, such as"javax.jdo.PersistenceManagerFactoryClass".
+ *
Can be used to override values in a JDO properties config file,
+ * or to specify all necessary properties locally.
+ *
Can be populated with a String "value" (parsed via PropertiesEditor)
+ * or a "props" element in XML bean definitions.
+ */
+ public void setJdoProperties(Properties jdoProperties) {
+ CollectionUtils.mergePropertiesIntoMap(jdoProperties, this.jdoPropertyMap);
+ }
+
+ /**
+ * Specify JDO properties as a Map, to be passed into
+ * JDOHelper.getPersistenceManagerFactory (if any).
+ *
Can be populated with a "map" or "props" element in XML bean definitions.
+ * @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map)
+ */
+ public void setJdoPropertyMap(Map jdoProperties) {
+ if (jdoProperties != null) {
+ this.jdoPropertyMap.putAll(jdoProperties);
+ }
+ }
+
+ /**
+ * Allow Map access to the JDO properties to be passed to the JDOHelper,
+ * with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via
+ * "jdoPropertyMap[myKey]".
+ */
+ public Map getJdoPropertyMap() {
+ return this.jdoPropertyMap;
+ }
+ /**
+ * Set the JDO dialect to use for the PersistenceExceptionTranslator
+ * functionality of this factory.
+ *
Default is a DefaultJdoDialect based on the PersistenceManagerFactory's
+ * underlying DataSource, if any.
+ * @see JdoDialect#translateException
+ * @see #translateExceptionIfPossible
+ * @see org.springframework.dao.support.PersistenceExceptionTranslator
+ */
+ public void setJdoDialect(JdoDialect jdoDialect) {
+ this.jdoDialect = jdoDialect;
+ }
+
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ this.beanClassLoader = beanClassLoader;
+ }
+
+
+ /**
+ * Initialize the PersistenceManagerFactory for the given location.
+ * @throws IllegalArgumentException in case of illegal property values
+ * @throws IOException if the properties could not be loaded from the given location
+ * @throws JDOException in case of JDO initialization errors
+ */
+ public void afterPropertiesSet() throws IllegalArgumentException, IOException, JDOException {
+ if (this.persistenceManagerFactoryName != null) {
+ if (this.configLocation != null || !this.jdoPropertyMap.isEmpty()) {
+ throw new IllegalStateException("'configLocation'/'jdoProperties' not supported in " +
+ "combination with 'persistenceManagerFactoryName' - specify one or the other, not both");
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info("Building new JDO PersistenceManagerFactory for name '" +
+ this.persistenceManagerFactoryName + "'");
+ }
+ this.persistenceManagerFactory = newPersistenceManagerFactory(this.persistenceManagerFactoryName);
+ }
+
+ else {
+ Map mergedProps = new HashMap();
+
+ if (this.configLocation != null) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Loading JDO config from [" + this.configLocation + "]");
+ }
+ mergedProps.putAll(PropertiesLoaderUtils.loadProperties(this.configLocation));
+ }
+
+ mergedProps.putAll(this.jdoPropertyMap);
+
+ // Build PersistenceManagerFactory instance.
+ logger.info("Building new JDO PersistenceManagerFactory");
+ this.persistenceManagerFactory = newPersistenceManagerFactory(mergedProps);
+ }
+
+ // Build default JdoDialect if none explicitly specified.
+ if (this.jdoDialect == null) {
+ this.jdoDialect = new DefaultJdoDialect(this.persistenceManagerFactory.getConnectionFactory());
+ }
+ }
+
+ /**
+ * Subclasses can override this to perform custom initialization of the
+ * PersistenceManagerFactory instance, creating it for the specified name.
+ *
The default implementation invokes JDOHelper's
+ * getPersistenceManagerFactory(String) method.
+ * A custom implementation could prepare the instance in a specific way,
+ * or use a custom PersistenceManagerFactory implementation.
+ * @param name the name of the desired PersistenceManagerFactory
+ * @return the PersistenceManagerFactory instance
+ * @see javax.jdo.JDOHelper#getPersistenceManagerFactory(String)
+ */
+ protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
+ return JDOHelper.getPersistenceManagerFactory(name, this.beanClassLoader);
+ }
+
+ /**
+ * Subclasses can override this to perform custom initialization of the
+ * PersistenceManagerFactory instance, creating it via the given Properties
+ * that got prepared by this LocalPersistenceManagerFactoryBean.
+ *
The default implementation invokes JDOHelper's
+ * getPersistenceManagerFactory(Map) method.
+ * A custom implementation could prepare the instance in a specific way,
+ * or use a custom PersistenceManagerFactory implementation.
+ * @param props the merged properties prepared by this LocalPersistenceManagerFactoryBean
+ * @return the PersistenceManagerFactory instance
+ * @see javax.jdo.JDOHelper#getPersistenceManagerFactory(java.util.Map)
+ */
+ protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
+ return JDOHelper.getPersistenceManagerFactory(props, this.beanClassLoader);
+ }
+
+
+ /**
+ * Return the singleton PersistenceManagerFactory.
+ */
+ public Object getObject() {
+ return this.persistenceManagerFactory;
+ }
+
+ public Class getObjectType() {
+ return (this.persistenceManagerFactory != null ?
+ this.persistenceManagerFactory.getClass() : PersistenceManagerFactory.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Implementation of the PersistenceExceptionTranslator interface,
+ * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
+ *
Converts the exception if it is a JDOException, preferably using a specified
+ * JdoDialect. Else returns null to indicate an unknown exception.
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ * @see JdoDialect#translateException
+ * @see PersistenceManagerFactoryUtils#convertJdoAccessException
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ if (ex instanceof JDOException) {
+ if (this.jdoDialect != null) {
+ return this.jdoDialect.translateException((JDOException) ex);
+ }
+ else {
+ return PersistenceManagerFactoryUtils.convertJdoAccessException((JDOException) ex);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Close the PersistenceManagerFactory on bean factory shutdown.
+ */
+ public void destroy() {
+ logger.info("Closing JDO PersistenceManagerFactory");
+ this.persistenceManagerFactory.close();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerFactoryUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerFactoryUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerFactoryUtils.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2002-2008 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.orm.jdo;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOException;
+import javax.jdo.JDOFatalDataStoreException;
+import javax.jdo.JDOFatalUserException;
+import javax.jdo.JDOObjectNotFoundException;
+import javax.jdo.JDOOptimisticVerificationException;
+import javax.jdo.JDOUserException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.Ordered;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
+import org.springframework.jdbc.support.SQLExceptionTranslator;
+import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
+import org.springframework.transaction.support.ResourceHolder;
+import org.springframework.transaction.support.ResourceHolderSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+
+/**
+ * Helper class featuring methods for JDO PersistenceManager handling,
+ * allowing for reuse of PersistenceManager instances within transactions.
+ * Also provides support for exception translation.
+ *
+ *
Used internally by {@link JdoTemplate}, {@link JdoInterceptor} and
+ * {@link JdoTransactionManager}. Can also be used directly in application code.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see JdoTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public abstract class PersistenceManagerFactoryUtils {
+
+ /**
+ * Order value for TransactionSynchronization objects that clean up JDO
+ * PersistenceManagers. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100
+ * to execute PersistenceManager cleanup before JDBC Connection cleanup, if any.
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
+ */
+ public static final int PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER =
+ DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
+
+ private static final Log logger = LogFactory.getLog(PersistenceManagerFactoryUtils.class);
+
+
+ /**
+ * Create an appropriate SQLExceptionTranslator for the given PersistenceManagerFactory.
+ *
If a DataSource is found, creates a SQLErrorCodeSQLExceptionTranslator for the
+ * DataSource; else, falls back to a SQLStateSQLExceptionTranslator.
+ * @param connectionFactory the connection factory of the PersistenceManagerFactory
+ * (may be null)
+ * @return the SQLExceptionTranslator (never null)
+ * @see javax.jdo.PersistenceManagerFactory#getConnectionFactory()
+ * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
+ * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
+ */
+ static SQLExceptionTranslator newJdbcExceptionTranslator(Object connectionFactory) {
+ // Check for PersistenceManagerFactory's DataSource.
+ if (connectionFactory instanceof DataSource) {
+ return new SQLErrorCodeSQLExceptionTranslator((DataSource) connectionFactory);
+ }
+ else {
+ return new SQLStateSQLExceptionTranslator();
+ }
+ }
+
+ /**
+ * Obtain a JDO PersistenceManager via the given factory. Is aware of a
+ * corresponding PersistenceManager bound to the current thread,
+ * for example when using JdoTransactionManager. Will create a new
+ * PersistenceManager else, if "allowCreate" is true.
+ * @param pmf PersistenceManagerFactory to create the PersistenceManager with
+ * @param allowCreate if a non-transactional PersistenceManager should be created
+ * when no transactional PersistenceManager can be found for the current thread
+ * @return the PersistenceManager
+ * @throws DataAccessResourceFailureException if the PersistenceManager couldn't be obtained
+ * @throws IllegalStateException if no thread-bound PersistenceManager found and
+ * "allowCreate" is false
+ * @see JdoTransactionManager
+ */
+ public static PersistenceManager getPersistenceManager(PersistenceManagerFactory pmf, boolean allowCreate)
+ throws DataAccessResourceFailureException, IllegalStateException {
+
+ try {
+ return doGetPersistenceManager(pmf, allowCreate);
+ }
+ catch (JDOException ex) {
+ throw new DataAccessResourceFailureException("Could not obtain JDO PersistenceManager", ex);
+ }
+ }
+
+ /**
+ * Obtain a JDO PersistenceManager via the given factory. Is aware of a
+ * corresponding PersistenceManager bound to the current thread,
+ * for example when using JdoTransactionManager. Will create a new
+ * PersistenceManager else, if "allowCreate" is true.
+ *
Same as getPersistenceManager, but throwing the original JDOException.
+ * @param pmf PersistenceManagerFactory to create the PersistenceManager with
+ * @param allowCreate if a non-transactional PersistenceManager should be created
+ * when no transactional PersistenceManager can be found for the current thread
+ * @return the PersistenceManager
+ * @throws JDOException if the PersistenceManager couldn't be created
+ * @throws IllegalStateException if no thread-bound PersistenceManager found and
+ * "allowCreate" is false
+ * @see #getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean)
+ * @see JdoTransactionManager
+ */
+ public static PersistenceManager doGetPersistenceManager(PersistenceManagerFactory pmf, boolean allowCreate)
+ throws JDOException, IllegalStateException {
+
+ Assert.notNull(pmf, "No PersistenceManagerFactory specified");
+
+ PersistenceManagerHolder pmHolder =
+ (PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf);
+ if (pmHolder != null) {
+ if (!pmHolder.isSynchronizedWithTransaction() &&
+ TransactionSynchronizationManager.isSynchronizationActive()) {
+ pmHolder.setSynchronizedWithTransaction(true);
+ TransactionSynchronizationManager.registerSynchronization(
+ new PersistenceManagerSynchronization(pmHolder, pmf, false));
+ }
+ return pmHolder.getPersistenceManager();
+ }
+
+ if (!allowCreate && !TransactionSynchronizationManager.isSynchronizationActive()) {
+ throw new IllegalStateException("No JDO PersistenceManager bound to thread, " +
+ "and configuration does not allow creation of non-transactional one here");
+ }
+
+ logger.debug("Opening JDO PersistenceManager");
+ PersistenceManager pm = pmf.getPersistenceManager();
+
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ logger.debug("Registering transaction synchronization for JDO PersistenceManager");
+ // Use same PersistenceManager for further JDO actions within the transaction.
+ // Thread object will get removed by synchronization at transaction completion.
+ pmHolder = new PersistenceManagerHolder(pm);
+ pmHolder.setSynchronizedWithTransaction(true);
+ TransactionSynchronizationManager.registerSynchronization(
+ new PersistenceManagerSynchronization(pmHolder, pmf, true));
+ TransactionSynchronizationManager.bindResource(pmf, pmHolder);
+ }
+
+ return pm;
+ }
+
+ /**
+ * Return whether the given JDO PersistenceManager is transactional, that is,
+ * bound to the current thread by Spring's transaction facilities.
+ * @param pm the JDO PersistenceManager to check
+ * @param pmf JDO PersistenceManagerFactory that the PersistenceManager
+ * was created with (can be null)
+ * @return whether the PersistenceManager is transactional
+ */
+ public static boolean isPersistenceManagerTransactional(
+ PersistenceManager pm, PersistenceManagerFactory pmf) {
+
+ if (pmf == null) {
+ return false;
+ }
+ PersistenceManagerHolder pmHolder =
+ (PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf);
+ return (pmHolder != null && pm == pmHolder.getPersistenceManager());
+ }
+
+ /**
+ * Apply the current transaction timeout, if any, to the given JDO Query object.
+ * @param query the JDO Query object
+ * @param pmf JDO PersistenceManagerFactory that the Query was created for
+ * @param jdoDialect the JdoDialect to use for applying a query timeout
+ * (must not be null)
+ * @throws JDOException if thrown by JDO methods
+ * @see JdoDialect#applyQueryTimeout
+ */
+ public static void applyTransactionTimeout(
+ Query query, PersistenceManagerFactory pmf, JdoDialect jdoDialect) throws JDOException {
+
+ Assert.notNull(query, "No Query object specified");
+ PersistenceManagerHolder pmHolder =
+ (PersistenceManagerHolder) TransactionSynchronizationManager.getResource(pmf);
+ if (pmHolder != null && pmHolder.hasTimeout()) {
+ jdoDialect.applyQueryTimeout(query, pmHolder.getTimeToLiveInSeconds());
+ }
+ }
+
+ /**
+ * Convert the given JDOException to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ *
The most important cases like object not found or optimistic locking
+ * failure are covered here. For more fine-granular conversion, JdoAccessor and
+ * JdoTransactionManager support sophisticated translation of exceptions via a
+ * JdoDialect.
+ * @param ex JDOException that occured
+ * @return the corresponding DataAccessException instance
+ * @see JdoAccessor#convertJdoAccessException
+ * @see JdoTransactionManager#convertJdoAccessException
+ * @see JdoDialect#translateException
+ */
+ public static DataAccessException convertJdoAccessException(JDOException ex) {
+ if (ex instanceof JDOObjectNotFoundException) {
+ throw new JdoObjectRetrievalFailureException((JDOObjectNotFoundException) ex);
+ }
+ if (ex instanceof JDOOptimisticVerificationException) {
+ throw new JdoOptimisticLockingFailureException((JDOOptimisticVerificationException) ex);
+ }
+ if (ex instanceof JDODataStoreException) {
+ return new JdoResourceFailureException((JDODataStoreException) ex);
+ }
+ if (ex instanceof JDOFatalDataStoreException) {
+ return new JdoResourceFailureException((JDOFatalDataStoreException) ex);
+ }
+ if (ex instanceof JDOUserException) {
+ return new JdoUsageException((JDOUserException) ex);
+ }
+ if (ex instanceof JDOFatalUserException) {
+ return new JdoUsageException((JDOFatalUserException) ex);
+ }
+ // fallback
+ return new JdoSystemException(ex);
+ }
+
+ /**
+ * Close the given PersistenceManager, created via the given factory,
+ * if it is not managed externally (i.e. not bound to the thread).
+ * @param pm PersistenceManager to close
+ * @param pmf PersistenceManagerFactory that the PersistenceManager was created with
+ * (can be null)
+ */
+ public static void releasePersistenceManager(PersistenceManager pm, PersistenceManagerFactory pmf) {
+ try {
+ doReleasePersistenceManager(pm, pmf);
+ }
+ catch (JDOException ex) {
+ logger.debug("Could not close JDO PersistenceManager", ex);
+ }
+ catch (Throwable ex) {
+ logger.debug("Unexpected exception on closing JDO PersistenceManager", ex);
+ }
+ }
+
+ /**
+ * Actually release a PersistenceManager for the given factory.
+ * Same as releasePersistenceManager, but throwing the original JDOException.
+ * @param pm PersistenceManager to close
+ * @param pmf PersistenceManagerFactory that the PersistenceManager was created with
+ * (can be null)
+ * @throws JDOException if thrown by JDO methods
+ */
+ public static void doReleasePersistenceManager(PersistenceManager pm, PersistenceManagerFactory pmf)
+ throws JDOException {
+
+ if (pm == null) {
+ return;
+ }
+ // Only release non-transactional PersistenceManagers.
+ if (!isPersistenceManagerTransactional(pm, pmf)) {
+ logger.debug("Closing JDO PersistenceManager");
+ pm.close();
+ }
+ }
+
+
+ /**
+ * Callback for resource cleanup at the end of a non-JDO transaction
+ * (e.g. when participating in a JtaTransactionManager transaction).
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+ private static class PersistenceManagerSynchronization extends ResourceHolderSynchronization
+ implements Ordered {
+
+ private final boolean newPersistenceManager;
+
+ public PersistenceManagerSynchronization(
+ PersistenceManagerHolder pmHolder, PersistenceManagerFactory pmf, boolean newPersistenceManager) {
+ super(pmHolder, pmf);
+ this.newPersistenceManager = newPersistenceManager;
+ }
+
+ public int getOrder() {
+ return PERSISTENCE_MANAGER_SYNCHRONIZATION_ORDER;
+ }
+
+ protected boolean shouldUnbindAtCompletion() {
+ return this.newPersistenceManager;
+ }
+
+ protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
+ releasePersistenceManager(((PersistenceManagerHolder) resourceHolder).getPersistenceManager(),
+ (PersistenceManagerFactory) resourceKey);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/PersistenceManagerHolder.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo;
+
+import javax.jdo.PersistenceManager;
+
+import org.springframework.transaction.support.ResourceHolderSupport;
+import org.springframework.util.Assert;
+
+/**
+ * Holder wrapping a JDO PersistenceManager.
+ * JdoTransactionManager binds instances of this class
+ * to the thread, for a given PersistenceManagerFactory.
+ *
+ *
Note: This is an SPI class, not intended to be used by applications.
+ *
+ * @author Juergen Hoeller
+ * @since 03.06.2003
+ * @see JdoTransactionManager
+ * @see PersistenceManagerFactoryUtils
+ */
+public class PersistenceManagerHolder extends ResourceHolderSupport {
+
+ private final PersistenceManager persistenceManager;
+
+ private boolean transactionActive;
+
+
+ public PersistenceManagerHolder(PersistenceManager persistenceManager) {
+ Assert.notNull(persistenceManager, "PersistenceManager must not be null");
+ this.persistenceManager = persistenceManager;
+ }
+
+
+ public PersistenceManager getPersistenceManager() {
+ return this.persistenceManager;
+ }
+
+ protected void setTransactionActive(boolean transactionActive) {
+ this.transactionActive = transactionActive;
+ }
+
+ protected boolean isTransactionActive() {
+ return this.transactionActive;
+ }
+
+ public void clear() {
+ super.clear();
+ this.transactionActive = false;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/TransactionAwarePersistenceManagerFactoryProxy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/TransactionAwarePersistenceManagerFactoryProxy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/TransactionAwarePersistenceManagerFactoryProxy.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2002-2008 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.orm.jdo;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Proxy for a target JDO {@link javax.jdo.PersistenceManagerFactory},
+ * returning the current thread-bound PersistenceManager (the Spring-managed
+ * transactional PersistenceManager or a the single OpenPersistenceManagerInView
+ * PersistenceManager) on getPersistenceManager(), if any.
+ *
+ *
Essentially, getPersistenceManager() calls get seamlessly
+ * forwarded to {@link PersistenceManagerFactoryUtils#getPersistenceManager}.
+ * Furthermore, PersistenceManager.close calls get forwarded to
+ * {@link PersistenceManagerFactoryUtils#releasePersistenceManager}.
+ *
+ *
The main advantage of this proxy is that it allows DAOs to work with a
+ * plain JDO PersistenceManagerFactory reference, while still participating in
+ * Spring's (or a J2EE server's) resource and transaction management. DAOs will
+ * only rely on the JDO API in such a scenario, without any Spring dependencies.
+ *
+ *
Note that the behavior of this proxy matches the behavior that the JDO spec
+ * defines for a PersistenceManagerFactory as exposed by a JCA connector, when
+ * deployed in a J2EE server. Hence, DAOs could seamlessly switch between a JNDI
+ * PersistenceManagerFactory and this proxy for a local PersistenceManagerFactory,
+ * receiving the reference through Dependency Injection. This will work without
+ * any Spring API dependencies in the DAO code!
+ *
+ *
It is usually preferable to write your JDO-based DAOs with Spring's
+ * {@link JdoTemplate}, offering benefits such as consistent data access
+ * exceptions instead of JDOExceptions at the DAO layer. However, Spring's
+ * resource and transaction management (and Dependency Injection) will work
+ * for DAOs written against the plain JDO API as well.
+ *
+ *
Of course, you can still access the target PersistenceManagerFactory
+ * even when your DAOs go through this proxy, by defining a bean reference
+ * that points directly at your target PersistenceManagerFactory bean.
+ *
+ * @author Juergen Hoeller
+ * @since 1.2
+ * @see javax.jdo.PersistenceManagerFactory#getPersistenceManager()
+ * @see javax.jdo.PersistenceManager#close()
+ * @see PersistenceManagerFactoryUtils#getPersistenceManager
+ * @see PersistenceManagerFactoryUtils#releasePersistenceManager
+ */
+public class TransactionAwarePersistenceManagerFactoryProxy implements FactoryBean {
+
+ private PersistenceManagerFactory target;
+
+ private boolean allowCreate = true;
+
+ private PersistenceManagerFactory proxy;
+
+
+ /**
+ * Set the target JDO PersistenceManagerFactory that this proxy should
+ * delegate to. This should be the raw PersistenceManagerFactory, as
+ * accessed by JdoTransactionManager.
+ * @see org.springframework.orm.jdo.JdoTransactionManager
+ */
+ public void setTargetPersistenceManagerFactory(PersistenceManagerFactory target) {
+ Assert.notNull(target, "Target PersistenceManagerFactory must not be null");
+ this.target = target;
+ Class[] ifcs = ClassUtils.getAllInterfacesForClass(target.getClass(), getClass().getClassLoader());
+ this.proxy = (PersistenceManagerFactory) Proxy.newProxyInstance(
+ target.getClass().getClassLoader(), ifcs, new TransactionAwareFactoryInvocationHandler());
+ }
+
+ /**
+ * Return the target JDO PersistenceManagerFactory that this proxy delegates to.
+ */
+ public PersistenceManagerFactory getTargetPersistenceManagerFactory() {
+ return this.target;
+ }
+
+ /**
+ * Set whether the PersistenceManagerFactory proxy is allowed to create
+ * a non-transactional PersistenceManager when no transactional
+ * PersistenceManager can be found for the current thread.
+ *
Default is "true". Can be turned off to enforce access to
+ * transactional PersistenceManagers, which safely allows for DAOs
+ * written to get a PersistenceManager without explicit closing
+ * (i.e. a PersistenceManagerFactory.getPersistenceManager()
+ * call without corresponding PersistenceManager.close() call).
+ * @see PersistenceManagerFactoryUtils#getPersistenceManager(javax.jdo.PersistenceManagerFactory, boolean)
+ */
+ public void setAllowCreate(boolean allowCreate) {
+ this.allowCreate = allowCreate;
+ }
+
+ /**
+ * Return whether the PersistenceManagerFactory proxy is allowed to create
+ * a non-transactional PersistenceManager when no transactional
+ * PersistenceManager can be found for the current thread.
+ */
+ protected boolean isAllowCreate() {
+ return this.allowCreate;
+ }
+
+
+ public Object getObject() {
+ return this.proxy;
+ }
+
+ public Class getObjectType() {
+ return PersistenceManagerFactory.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Invocation handler that delegates getPersistenceManager calls on the
+ * PersistenceManagerFactory proxy to PersistenceManagerFactoryUtils
+ * for being aware of thread-bound transactions.
+ */
+ private class TransactionAwareFactoryInvocationHandler implements InvocationHandler {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on PersistenceManagerFactory interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of PersistenceManagerFactory proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("getPersistenceManager")) {
+ PersistenceManagerFactory target = getTargetPersistenceManagerFactory();
+ PersistenceManager pm =
+ PersistenceManagerFactoryUtils.doGetPersistenceManager(target, isAllowCreate());
+ Class[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), getClass().getClassLoader());
+ return (PersistenceManager) Proxy.newProxyInstance(
+ pm.getClass().getClassLoader(), ifcs, new TransactionAwareInvocationHandler(pm, target));
+ }
+
+ // Invoke method on target PersistenceManagerFactory.
+ try {
+ return method.invoke(getTargetPersistenceManagerFactory(), args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+
+ /**
+ * Invocation handler that delegates close calls on PersistenceManagers to
+ * PersistenceManagerFactoryUtils for being aware of thread-bound transactions.
+ */
+ private static class TransactionAwareInvocationHandler implements InvocationHandler {
+
+ private final PersistenceManager target;
+
+ private final PersistenceManagerFactory persistenceManagerFactory;
+
+ public TransactionAwareInvocationHandler(PersistenceManager target, PersistenceManagerFactory pmf) {
+ this.target = target;
+ this.persistenceManagerFactory = pmf;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on PersistenceManager interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of PersistenceManager proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: only close if not within a transaction.
+ if (this.persistenceManagerFactory != null) {
+ PersistenceManagerFactoryUtils.doReleasePersistenceManager(
+ this.target, this.persistenceManagerFactory);
+ }
+ return null;
+ }
+
+ // Invoke method on target PersistenceManager.
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/package.html 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
+Package providing integration of JDO (Java Date Objects) with Spring concepts.
+Contains PersistenceManagerFactory helper classes, a template plus callback for JDO
+access, and an implementation of Spring's transaction SPI for local JDO transactions.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/support/JdoDaoSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/support/JdoDaoSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/support/JdoDaoSupport.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2002-2008 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.orm.jdo.support;
+
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.support.DaoSupport;
+import org.springframework.orm.jdo.JdoTemplate;
+import org.springframework.orm.jdo.PersistenceManagerFactoryUtils;
+
+/**
+ * Convenient super class for JDO data access objects.
+ *
+ *
Requires a PersistenceManagerFactory to be set, providing a JdoTemplate
+ * based on it to subclasses. Can alternatively be initialized directly with a
+ * JdoTemplate, to reuse the latter's settings such as the PersistenceManagerFactory,
+ * JdoDialect, flush mode, etc.
+ *
+ *
This base class is mainly intended for JdoTemplate usage but can also
+ * be used when working with PersistenceManagerFactoryUtils directly, for example
+ * in combination with JdoInterceptor-managed PersistenceManagers. Convenience
+ * getPersistenceManager and releasePersistenceManager
+ * methods are provided for that usage style.
+ *
+ *
This class will create its own JdoTemplate if only a PersistenceManagerFactory
+ * is passed in. The "allowCreate" flag on that JdoTemplate will be "true" by default.
+ * A custom JdoTemplate instance can be used through overriding createJdoTemplate.
+ *
+ * @author Juergen Hoeller
+ * @since 28.07.2003
+ * @see #setPersistenceManagerFactory
+ * @see #setJdoTemplate
+ * @see #createJdoTemplate
+ * @see #getPersistenceManager
+ * @see #releasePersistenceManager
+ * @see org.springframework.orm.jdo.JdoTemplate
+ * @see org.springframework.orm.jdo.JdoInterceptor
+ */
+public abstract class JdoDaoSupport extends DaoSupport {
+
+ private JdoTemplate jdoTemplate;
+
+
+ /**
+ * Set the JDO PersistenceManagerFactory to be used by this DAO.
+ * Will automatically create a JdoTemplate for the given PersistenceManagerFactory.
+ * @see #createJdoTemplate
+ * @see #setJdoTemplate
+ */
+ public final void setPersistenceManagerFactory(PersistenceManagerFactory persistenceManagerFactory) {
+ if (this.jdoTemplate == null || persistenceManagerFactory != this.jdoTemplate.getPersistenceManagerFactory()) {
+ this.jdoTemplate = createJdoTemplate(persistenceManagerFactory);
+ }
+ }
+
+ /**
+ * Create a JdoTemplate for the given PersistenceManagerFactory.
+ * Only invoked if populating the DAO with a PersistenceManagerFactory reference!
+ *
Can be overridden in subclasses to provide a JdoTemplate instance
+ * with different configuration, or a custom JdoTemplate subclass.
+ * @param persistenceManagerFactory the JDO PersistenceManagerFactoryto create a JdoTemplate for
+ * @return the new JdoTemplate instance
+ * @see #setPersistenceManagerFactory
+ */
+ protected JdoTemplate createJdoTemplate(PersistenceManagerFactory persistenceManagerFactory) {
+ return new JdoTemplate(persistenceManagerFactory);
+ }
+
+ /**
+ * Return the JDO PersistenceManagerFactory used by this DAO.
+ */
+ public final PersistenceManagerFactory getPersistenceManagerFactory() {
+ return (this.jdoTemplate != null ? this.jdoTemplate.getPersistenceManagerFactory() : null);
+ }
+
+ /**
+ * Set the JdoTemplate for this DAO explicitly,
+ * as an alternative to specifying a PersistenceManagerFactory.
+ * @see #setPersistenceManagerFactory
+ */
+ public final void setJdoTemplate(JdoTemplate jdoTemplate) {
+ this.jdoTemplate = jdoTemplate;
+ }
+
+ /**
+ * Return the JdoTemplate for this DAO, pre-initialized
+ * with the PersistenceManagerFactory or set explicitly.
+ */
+ public final JdoTemplate getJdoTemplate() {
+ return jdoTemplate;
+ }
+
+ protected final void checkDaoConfig() {
+ if (this.jdoTemplate == null) {
+ throw new IllegalArgumentException("persistenceManagerFactory or jdoTemplate is required");
+ }
+ }
+
+
+ /**
+ * Get a JDO PersistenceManager, either from the current transaction or
+ * a new one. The latter is only allowed if the "allowCreate" setting
+ * of this bean's JdoTemplate is true.
+ * @return the JDO PersistenceManager
+ * @throws DataAccessResourceFailureException if the PersistenceManager couldn't be created
+ * @throws IllegalStateException if no thread-bound PersistenceManager found and allowCreate false
+ * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
+ */
+ protected final PersistenceManager getPersistenceManager() {
+ return getPersistenceManager(this.jdoTemplate.isAllowCreate());
+ }
+
+ /**
+ * Get a JDO PersistenceManager, either from the current transaction or
+ * a new one. The latter is only allowed if "allowCreate" is true.
+ * @param allowCreate if a non-transactional PersistenceManager should be created
+ * when no transactional PersistenceManager can be found for the current thread
+ * @return the JDO PersistenceManager
+ * @throws DataAccessResourceFailureException if the PersistenceManager couldn't be created
+ * @throws IllegalStateException if no thread-bound PersistenceManager found and allowCreate false
+ * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
+ */
+ protected final PersistenceManager getPersistenceManager(boolean allowCreate)
+ throws DataAccessResourceFailureException, IllegalStateException {
+
+ return PersistenceManagerFactoryUtils.getPersistenceManager(getPersistenceManagerFactory(), allowCreate);
+ }
+
+ /**
+ * Convert the given JDOException to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ *
Delegates to the convertJdoAccessException method of this DAO's JdoTemplate.
+ * @param ex JDOException that occured
+ * @return the corresponding DataAccessException instance
+ * @see #setJdoTemplate
+ * @see org.springframework.orm.jdo.JdoTemplate#convertJdoAccessException
+ */
+ protected final DataAccessException convertJdoAccessException(JDOException ex) {
+ return this.jdoTemplate.convertJdoAccessException(ex);
+ }
+
+ /**
+ * Close the given JDO PersistenceManager, created via this DAO's
+ * PersistenceManagerFactory, if it isn't bound to the thread.
+ * @param pm PersistenceManager to close
+ * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#releasePersistenceManager
+ */
+ protected final void releasePersistenceManager(PersistenceManager pm) {
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pm, getPersistenceManagerFactory());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewFilter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewFilter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewFilter.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo.support;
+
+import java.io.IOException;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.orm.jdo.PersistenceManagerFactoryUtils;
+import org.springframework.orm.jdo.PersistenceManagerHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+/**
+ * Servlet 2.3 Filter that binds a JDO PersistenceManager to the thread for the
+ * entire processing of the request. Intended for the "Open PersistenceManager in
+ * View" pattern, i.e. to allow for lazy loading in web views despite the
+ * original transactions already being completed.
+ *
+ *
This filter makes JDO PersistenceManagers available via the current thread,
+ * which will be autodetected by transaction managers. It is suitable for service
+ * layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
+ * as for non-transactional read-only execution.
+ *
+ *
Looks up the PersistenceManagerFactory in Spring's root web application context.
+ * Supports a "persistenceManagerFactoryBeanName" filter init-param in web.xml;
+ * the default bean name is "persistenceManagerFactory". Looks up the PersistenceManagerFactory
+ * on each request, to avoid initialization order issues (when using ContextLoaderServlet,
+ * the root application context will get initialized after this filter).
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see OpenPersistenceManagerInViewInterceptor
+ * @see org.springframework.orm.jdo.JdoInterceptor
+ * @see org.springframework.orm.jdo.JdoTransactionManager
+ * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenPersistenceManagerInViewFilter extends OncePerRequestFilter {
+
+ public static final String DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME = "persistenceManagerFactory";
+
+ private String persistenceManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME;
+
+
+ /**
+ * Set the bean name of the PersistenceManagerFactory to fetch from Spring's
+ * root application context. Default is "persistenceManagerFactory".
+ * @see #DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME
+ */
+ public void setPersistenceManagerFactoryBeanName(String persistenceManagerFactoryBeanName) {
+ this.persistenceManagerFactoryBeanName = persistenceManagerFactoryBeanName;
+ }
+
+ /**
+ * Return the bean name of the PersistenceManagerFactory to fetch from Spring's
+ * root application context.
+ */
+ protected String getPersistenceManagerFactoryBeanName() {
+ return this.persistenceManagerFactoryBeanName;
+ }
+
+
+ protected void doFilterInternal(
+ HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+
+ PersistenceManagerFactory pmf = lookupPersistenceManagerFactory(request);
+ boolean participate = false;
+
+ if (TransactionSynchronizationManager.hasResource(pmf)) {
+ // Do not modify the PersistenceManager: just set the participate flag.
+ participate = true;
+ }
+ else {
+ logger.debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewFilter");
+ PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(pmf, true);
+ TransactionSynchronizationManager.bindResource(pmf, new PersistenceManagerHolder(pm));
+ }
+
+ try {
+ filterChain.doFilter(request, response);
+ }
+
+ finally {
+ if (!participate) {
+ PersistenceManagerHolder pmHolder = (PersistenceManagerHolder)
+ TransactionSynchronizationManager.unbindResource(pmf);
+ logger.debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewFilter");
+ PersistenceManagerFactoryUtils.releasePersistenceManager(pmHolder.getPersistenceManager(), pmf);
+ }
+ }
+ }
+
+ /**
+ * Look up the PersistenceManagerFactory that this filter should use,
+ * taking the current HTTP request as argument.
+ *
Default implementation delegates to the lookupPersistenceManagerFactory
+ * without arguments.
+ * @return the PersistenceManagerFactory to use
+ * @see #lookupPersistenceManagerFactory()
+ */
+ protected PersistenceManagerFactory lookupPersistenceManagerFactory(HttpServletRequest request) {
+ return lookupPersistenceManagerFactory();
+ }
+
+ /**
+ * Look up the PersistenceManagerFactory that this filter should use.
+ * The default implementation looks for a bean with the specified name
+ * in Spring's root application context.
+ * @return the PersistenceManagerFactory to use
+ * @see #getPersistenceManagerFactoryBeanName
+ */
+ protected PersistenceManagerFactory lookupPersistenceManagerFactory() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using PersistenceManagerFactory '" + getPersistenceManagerFactoryBeanName() +
+ "' for OpenPersistenceManagerInViewFilter");
+ }
+ WebApplicationContext wac =
+ WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+ return (PersistenceManagerFactory)
+ wac.getBean(getPersistenceManagerFactoryBeanName(), PersistenceManagerFactory.class);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/support/OpenPersistenceManagerInViewInterceptor.java 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2002-2007 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.orm.jdo.support;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.orm.jdo.PersistenceManagerFactoryUtils;
+import org.springframework.orm.jdo.PersistenceManagerHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+
+/**
+ * Spring web request interceptor that binds a JDO PersistenceManager to the
+ * thread for the entire processing of the request. Intended for the "Open
+ * PersistenceManager in View" pattern, i.e. to allow for lazy loading in
+ * web views despite the original transactions already being completed.
+ *
+ *
This interceptor makes JDO PersistenceManagers available via the current thread,
+ * which will be autodetected by transaction managers. It is suitable for service
+ * layer transactions via {@link org.springframework.orm.jdo.JdoTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
+ * as for non-transactional read-only execution.
+ *
+ *
In contrast to {@link OpenPersistenceManagerInViewFilter}, this interceptor
+ * is set up in a Spring application context and can thus take advantage of
+ * bean wiring. It inherits common JDO configuration properties from
+ * {@link org.springframework.orm.jdo.JdoAccessor}, to be configured in a
+ * bean definition.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see OpenPersistenceManagerInViewFilter
+ * @see org.springframework.orm.jdo.JdoInterceptor
+ * @see org.springframework.orm.jdo.JdoTransactionManager
+ * @see org.springframework.orm.jdo.PersistenceManagerFactoryUtils#getPersistenceManager
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenPersistenceManagerInViewInterceptor implements WebRequestInterceptor {
+
+ /**
+ * Suffix that gets appended to the PersistenceManagerFactory toString
+ * representation for the "participate in existing persistence manager
+ * handling" request attribute.
+ * @see #getParticipateAttributeName
+ */
+ public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
+
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private PersistenceManagerFactory persistenceManagerFactory;
+
+
+ /**
+ * Set the JDO PersistenceManagerFactory that should be used to create
+ * PersistenceManagers.
+ */
+ public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
+ this.persistenceManagerFactory = pmf;
+ }
+
+ /**
+ * Return the JDO PersistenceManagerFactory that should be used to create
+ * PersistenceManagers.
+ */
+ public PersistenceManagerFactory getPersistenceManagerFactory() {
+ return persistenceManagerFactory;
+ }
+
+
+ public void preHandle(WebRequest request) throws DataAccessException {
+ if (TransactionSynchronizationManager.hasResource(getPersistenceManagerFactory())) {
+ // Do not modify the PersistenceManager: just mark the request accordingly.
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ int newCount = (count != null) ? count.intValue() + 1 : 1;
+ request.setAttribute(getParticipateAttributeName(), new Integer(newCount), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ logger.debug("Opening JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor");
+ PersistenceManager pm =
+ PersistenceManagerFactoryUtils.getPersistenceManager(getPersistenceManagerFactory(), true);
+ TransactionSynchronizationManager.bindResource(
+ getPersistenceManagerFactory(), new PersistenceManagerHolder(pm));
+ }
+ }
+
+ public void postHandle(WebRequest request, ModelMap model) {
+ }
+
+ public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ if (count != null) {
+ // Do not modify the PersistenceManager: just clear the marker.
+ if (count.intValue() > 1) {
+ request.setAttribute(participateAttributeName, new Integer(count.intValue() - 1), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ }
+ }
+ else {
+ PersistenceManagerHolder pmHolder = (PersistenceManagerHolder)
+ TransactionSynchronizationManager.unbindResource(getPersistenceManagerFactory());
+ logger.debug("Closing JDO PersistenceManager in OpenPersistenceManagerInViewInterceptor");
+ PersistenceManagerFactoryUtils.releasePersistenceManager(
+ pmHolder.getPersistenceManager(), getPersistenceManagerFactory());
+ }
+ }
+
+ /**
+ * Return the name of the request attribute that identifies that a request is
+ * already filtered. Default implementation takes the toString representation
+ * of the PersistenceManagerFactory instance and appends ".FILTERED".
+ * @see #PARTICIPATE_SUFFIX
+ */
+ protected String getParticipateAttributeName() {
+ return getPersistenceManagerFactory().toString() + PARTICIPATE_SUFFIX;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jdo/support/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jdo/support/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jdo/support/package.html 17 Aug 2012 15:16:17 -0000 1.1
@@ -0,0 +1,8 @@
+
+
+
+Classes supporting the org.springframework.orm.jdo package.
+Contains a DAO base class for JdoTemplate usage.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Abstract {@link org.springframework.beans.factory.FactoryBean} that
+ * creates a local JPA {@link javax.persistence.EntityManagerFactory}
+ * instance within a Spring application context.
+ *
+ *
Encapsulates the common functionality between the different JPA
+ * bootstrap contracts (standalone as well as container).
+ *
+ *
Implements support for standard JPA configuration as well as
+ * Spring's {@link JpaVendorAdapter} abstraction, and controls the
+ * EntityManagerFactory's lifecycle.
+ *
+ *
This class also implements the
+ * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
+ * interface, as autodetected by Spring's
+ * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
+ * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
+ * Hence, the presence of e.g. LocalEntityManagerFactoryBean automatically enables
+ * a PersistenceExceptionTranslationPostProcessor to translate JPA exceptions.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see LocalEntityManagerFactoryBean
+ * @see LocalContainerEntityManagerFactoryBean
+ */
+public abstract class AbstractEntityManagerFactoryBean implements
+ FactoryBean, BeanClassLoaderAware, InitializingBean, DisposableBean,
+ EntityManagerFactoryInfo, PersistenceExceptionTranslator {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private PersistenceProvider persistenceProvider;
+
+ private String persistenceUnitName;
+
+ private final Map jpaPropertyMap = new HashMap();
+
+ private Class extends EntityManagerFactory> entityManagerFactoryInterface;
+
+ private Class extends EntityManager> entityManagerInterface;
+
+ private JpaDialect jpaDialect;
+
+ private JpaVendorAdapter jpaVendorAdapter;
+
+ private ClassLoader beanClassLoader = getClass().getClassLoader();
+
+ /** Raw EntityManagerFactory as returned by the PersistenceProvider */
+ public EntityManagerFactory nativeEntityManagerFactory;
+
+ private EntityManagerFactory entityManagerFactory;
+
+
+ /**
+ * Set the PersistenceProvider implementation class to use for creating the
+ * EntityManagerFactory. If not specified, the persistence provider will be
+ * taken from the JpaVendorAdapter (if any) or retrieved through scanning
+ * (as far as possible).
+ * @see JpaVendorAdapter#getPersistenceProvider()
+ * @see javax.persistence.spi.PersistenceProvider
+ * @see javax.persistence.Persistence
+ */
+ public void setPersistenceProviderClass(Class extends PersistenceProvider> persistenceProviderClass) {
+ Assert.isAssignable(PersistenceProvider.class, persistenceProviderClass);
+ this.persistenceProvider = (PersistenceProvider) BeanUtils.instantiateClass(persistenceProviderClass);
+ }
+
+ /**
+ * Set the PersistenceProvider instance to use for creating the
+ * EntityManagerFactory. If not specified, the persistence provider
+ * will be taken from the JpaVendorAdapter (if any) or determined
+ * by the persistence unit deployment descriptor (as far as possible).
+ * @see JpaVendorAdapter#getPersistenceProvider()
+ * @see javax.persistence.spi.PersistenceProvider
+ * @see javax.persistence.Persistence
+ */
+ public void setPersistenceProvider(PersistenceProvider persistenceProvider) {
+ this.persistenceProvider = persistenceProvider;
+ }
+
+ public PersistenceProvider getPersistenceProvider() {
+ return this.persistenceProvider;
+ }
+
+ /**
+ * Specify the name of the EntityManagerFactory configuration.
+ *
Default is none, indicating the default EntityManagerFactory
+ * configuration. The persistence provider will throw an exception if
+ * ambiguous EntityManager configurations are found.
+ * @see javax.persistence.Persistence#createEntityManagerFactory(String)
+ */
+ public void setPersistenceUnitName(String persistenceUnitName) {
+ this.persistenceUnitName = persistenceUnitName;
+ }
+
+ public String getPersistenceUnitName() {
+ return this.persistenceUnitName;
+ }
+
+ /**
+ * Specify JPA properties, to be passed into
+ * Persistence.createEntityManagerFactory (if any).
+ *
Can be populated with a String "value" (parsed via PropertiesEditor) or a
+ * "props" element in XML bean definitions.
+ * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
+ * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
+ */
+ public void setJpaProperties(Properties jpaProperties) {
+ CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
+ }
+
+ /**
+ * Specify JPA properties as a Map, to be passed into
+ * Persistence.createEntityManagerFactory (if any).
+ *
Can be populated with a "map" or "props" element in XML bean definitions.
+ * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
+ * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
+ */
+ public void setJpaPropertyMap(Map jpaProperties) {
+ if (jpaProperties != null) {
+ this.jpaPropertyMap.putAll(jpaProperties);
+ }
+ }
+
+ /**
+ * Allow Map access to the JPA properties to be passed to the persistence
+ * provider, with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via
+ * "jpaPropertyMap[myKey]".
+ */
+ public Map getJpaPropertyMap() {
+ return this.jpaPropertyMap;
+ }
+
+ /**
+ * Specify the (potentially vendor-specific) EntityManagerFactory interface
+ * that this EntityManagerFactory proxy is supposed to implement.
+ *
The default will be taken from the specific JpaVendorAdapter, if any,
+ * or set to the standard javax.persistence.EntityManagerFactory
+ * interface else.
+ * @see JpaVendorAdapter#getEntityManagerFactoryInterface()
+ */
+ public void setEntityManagerFactoryInterface(Class extends EntityManagerFactory> emfInterface) {
+ Assert.isAssignable(EntityManagerFactory.class, emfInterface);
+ this.entityManagerFactoryInterface = emfInterface;
+ }
+
+ /**
+ * Specify the (potentially vendor-specific) EntityManager interface
+ * that this factory's EntityManagers are supposed to implement.
+ *
The default will be taken from the specific JpaVendorAdapter, if any,
+ * or set to the standard javax.persistence.EntityManager
+ * interface else.
+ * @see JpaVendorAdapter#getEntityManagerInterface()
+ * @see EntityManagerFactoryInfo#getEntityManagerInterface()
+ */
+ public void setEntityManagerInterface(Class extends EntityManager> emInterface) {
+ Assert.isAssignable(EntityManager.class, emInterface);
+ this.entityManagerInterface = emInterface;
+ }
+
+ public Class extends EntityManager> getEntityManagerInterface() {
+ return this.entityManagerInterface;
+ }
+
+ /**
+ * Specify the vendor-specific JpaDialect implementation to associate with
+ * this EntityManagerFactory. This will be exposed through the
+ * EntityManagerFactoryInfo interface, to be picked up as default dialect by
+ * accessors that intend to use JpaDialect functionality.
+ * @see EntityManagerFactoryInfo#getJpaDialect()
+ */
+ public void setJpaDialect(JpaDialect jpaDialect) {
+ this.jpaDialect = jpaDialect;
+ }
+
+ public JpaDialect getJpaDialect() {
+ return this.jpaDialect;
+ }
+
+ /**
+ * Specify the JpaVendorAdapter implementation for the desired JPA provider,
+ * if any. This will initialize appropriate defaults for the given provider,
+ * such as persistence provider class and JpaDialect, unless locally
+ * overridden in this FactoryBean.
+ */
+ public void setJpaVendorAdapter(JpaVendorAdapter jpaVendorAdapter) {
+ this.jpaVendorAdapter = jpaVendorAdapter;
+ }
+
+ /**
+ * Return the JpaVendorAdapter implementation for this
+ * EntityManagerFactory, or null if not known.
+ */
+ public JpaVendorAdapter getJpaVendorAdapter() {
+ return this.jpaVendorAdapter;
+ }
+
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ public ClassLoader getBeanClassLoader() {
+ return this.beanClassLoader;
+ }
+
+
+ public final void afterPropertiesSet() throws PersistenceException {
+ if (this.jpaVendorAdapter != null) {
+ if (this.persistenceProvider == null) {
+ this.persistenceProvider = this.jpaVendorAdapter.getPersistenceProvider();
+ }
+ Map vendorPropertyMap = this.jpaVendorAdapter.getJpaPropertyMap();
+ if (vendorPropertyMap != null) {
+ for (Iterator it = vendorPropertyMap.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ if (!this.jpaPropertyMap.containsKey(entry.getKey())) {
+ this.jpaPropertyMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ if (this.entityManagerFactoryInterface == null) {
+ this.entityManagerFactoryInterface = this.jpaVendorAdapter.getEntityManagerFactoryInterface();
+ if (!ClassUtils.isVisible(this.entityManagerFactoryInterface, this.beanClassLoader)) {
+ this.entityManagerFactoryInterface = EntityManagerFactory.class;
+ }
+ }
+ if (this.entityManagerInterface == null) {
+ this.entityManagerInterface = this.jpaVendorAdapter.getEntityManagerInterface();
+ if (!ClassUtils.isVisible(this.entityManagerInterface, this.beanClassLoader)) {
+ this.entityManagerInterface = EntityManager.class;
+ }
+ }
+ if (this.jpaDialect == null) {
+ this.jpaDialect = this.jpaVendorAdapter.getJpaDialect();
+ }
+ }
+
+ this.nativeEntityManagerFactory = createNativeEntityManagerFactory();
+ if (this.nativeEntityManagerFactory == null) {
+ throw new IllegalStateException(
+ "JPA PersistenceProvider returned null EntityManagerFactory - check your JPA provider setup!");
+ }
+ if (this.jpaVendorAdapter != null) {
+ this.jpaVendorAdapter.postProcessEntityManagerFactory(this.nativeEntityManagerFactory);
+ }
+
+ // Wrap the EntityManagerFactory in a factory implementing all its interfaces.
+ // This allows interception of createEntityManager methods to return an
+ // application-managed EntityManager proxy that automatically joins
+ // existing transactions.
+ this.entityManagerFactory = createEntityManagerFactoryProxy(this.nativeEntityManagerFactory);
+ }
+
+ /**
+ * Create a proxy of the given EntityManagerFactory. We do this to be able
+ * to return transaction-aware proxies for application-managed
+ * EntityManagers, and to introduce the NamedEntityManagerFactory interface
+ * @param emf EntityManagerFactory as returned by the persistence provider
+ * @return proxy entity manager
+ */
+ protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) {
+ Set ifcs = new LinkedHashSet();
+ if (this.entityManagerFactoryInterface != null) {
+ ifcs.add(this.entityManagerFactoryInterface);
+ }
+ else {
+ ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(emf.getClass(), this.beanClassLoader));
+ }
+ ifcs.add(EntityManagerFactoryInfo.class);
+ EntityManagerFactoryPlusOperations plusOperations = null;
+ if (getJpaDialect() != null && getJpaDialect().supportsEntityManagerFactoryPlusOperations()) {
+ plusOperations = getJpaDialect().getEntityManagerFactoryPlusOperations(emf);
+ ifcs.add(EntityManagerFactoryPlusOperations.class);
+ }
+ return (EntityManagerFactory) Proxy.newProxyInstance(
+ this.beanClassLoader, ifcs.toArray(new Class[ifcs.size()]),
+ new ManagedEntityManagerFactoryInvocationHandler(emf, this, plusOperations));
+ }
+
+ /**
+ * Subclasses must implement this method to create the EntityManagerFactory
+ * that will be returned by the getObject() method.
+ * @return EntityManagerFactory instance returned by this FactoryBean
+ * @throws PersistenceException if the EntityManager cannot be created
+ */
+ protected abstract EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException;
+
+
+ /**
+ * Implementation of the PersistenceExceptionTranslator interface, as
+ * autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
+ *
Uses the dialect's conversion if possible; otherwise falls back to
+ * standard JPA exception conversion.
+ * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
+ * @see JpaDialect#translateExceptionIfPossible
+ * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return (this.jpaDialect != null ? this.jpaDialect.translateExceptionIfPossible(ex) :
+ EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex));
+ }
+
+ public EntityManagerFactory getNativeEntityManagerFactory() {
+ return this.nativeEntityManagerFactory;
+ }
+
+ public PersistenceUnitInfo getPersistenceUnitInfo() {
+ return null;
+ }
+
+ public DataSource getDataSource() {
+ return null;
+ }
+
+
+ /**
+ * Return the singleton EntityManagerFactory.
+ */
+ public EntityManagerFactory getObject() {
+ return this.entityManagerFactory;
+ }
+
+ public Class getObjectType() {
+ return (this.entityManagerFactory != null ? this.entityManagerFactory.getClass() : EntityManagerFactory.class);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+
+ /**
+ * Close the EntityManagerFactory on bean factory shutdown.
+ */
+ public void destroy() {
+ if (logger.isInfoEnabled()) {
+ logger.info("Closing JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
+ }
+ this.entityManagerFactory.close();
+ }
+
+
+ /**
+ * Dynamic proxy invocation handler proxying an EntityManagerFactory to
+ * return a proxy EntityManager if necessary from createEntityManager()
+ * methods.
+ */
+ private static class ManagedEntityManagerFactoryInvocationHandler implements InvocationHandler {
+
+ private final EntityManagerFactory targetEntityManagerFactory;
+
+ private final EntityManagerFactoryInfo entityManagerFactoryInfo;
+
+ private final EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations;
+
+ public ManagedEntityManagerFactoryInvocationHandler(EntityManagerFactory targetEmf,
+ EntityManagerFactoryInfo emfInfo, EntityManagerFactoryPlusOperations entityManagerFactoryPlusOperations) {
+
+ this.targetEntityManagerFactory = targetEmf;
+ this.entityManagerFactoryInfo = emfInfo;
+ this.entityManagerFactoryPlusOperations = entityManagerFactoryPlusOperations;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ try {
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of EntityManagerFactory proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) {
+ return method.invoke(this.entityManagerFactoryInfo, args);
+ }
+ else if (method.getDeclaringClass().equals(EntityManagerFactoryPlusOperations.class)) {
+ return method.invoke(this.entityManagerFactoryPlusOperations, args);
+ }
+
+ Object retVal = method.invoke(this.targetEntityManagerFactory, args);
+ if (retVal instanceof EntityManager) {
+ EntityManager rawEntityManager = (EntityManager) retVal;
+ retVal = ExtendedEntityManagerCreator.createApplicationManagedEntityManager(
+ rawEntityManager, this.entityManagerFactoryInfo);
+ }
+ return retVal;
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/DefaultJpaDialect.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/DefaultJpaDialect.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/DefaultJpaDialect.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import java.io.Serializable;
+import java.sql.SQLException;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.transaction.InvalidIsolationLevelException;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+
+/**
+ * Default implementation of the {@link JpaDialect} interface.
+ * Used as default dialect by {@link JpaAccessor} and {@link JpaTransactionManager}.
+ *
+ *
Simply begins a standard JPA transaction in {@link #beginTransaction}
+ * and performs standard exception translation through {@link EntityManagerFactoryUtils}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see JpaAccessor#setJpaDialect
+ * @see JpaTransactionManager#setJpaDialect
+ */
+public class DefaultJpaDialect implements JpaDialect, Serializable {
+
+ //-------------------------------------------------------------------------
+ // Hooks for transaction management (used by JpaTransactionManager)
+ //-------------------------------------------------------------------------
+
+ /**
+ * This implementation invokes the standard JPA Transaction.begin
+ * method. Throws an InvalidIsolationLevelException if a non-default isolation
+ * level is set.
+ *
This implementation does not return any transaction data Object, since there
+ * is no state to be kept for a standard JPA transaction. Hence, subclasses do not
+ * have to care about the return value (null) of this implementation
+ * and are free to return their own transaction data Object.
+ * @see javax.persistence.EntityTransaction#begin
+ * @see org.springframework.transaction.InvalidIsolationLevelException
+ * @see #cleanupTransaction
+ */
+ public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
+ throws PersistenceException, SQLException, TransactionException {
+
+ if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
+ throw new InvalidIsolationLevelException(
+ "Standard JPA does not support custom isolation levels - " +
+ "use a special JpaDialect for your JPA implementation");
+ }
+ entityManager.getTransaction().begin();
+ return null;
+ }
+
+ public Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name)
+ throws PersistenceException {
+
+ return null;
+ }
+
+ /**
+ * This implementation does nothing, since the default beginTransaction
+ * implementation does not require any cleanup.
+ * @see #beginTransaction
+ */
+ public void cleanupTransaction(Object transactionData) {
+ }
+
+ /**
+ * This implementation always returns null,
+ * indicating that no JDBC Connection can be provided.
+ */
+ public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
+ throws PersistenceException, SQLException {
+
+ return null;
+ }
+
+ /**
+ * This implementation does nothing, assuming that the Connection
+ * will implicitly be closed with the EntityManager.
+ *
If the JPA implementation returns a Connection handle that it expects
+ * the application to close after use, the dialect implementation needs to invoke
+ * Connection.close() (or some other method with similar effect) here.
+ * @see java.sql.Connection#close()
+ */
+ public void releaseJdbcConnection(ConnectionHandle conHandle, EntityManager em)
+ throws PersistenceException, SQLException {
+ }
+
+
+ //-----------------------------------------------------------------------------------
+ // Hook for exception translation (used by JpaTransactionManager and JpaTemplate)
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * This implementation delegates to EntityManagerFactoryUtils.
+ * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
+ */
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
+ }
+
+
+ public boolean supportsEntityManagerFactoryPlusOperations() {
+ return false;
+ }
+
+ public boolean supportsEntityManagerPlusOperations() {
+ return false;
+ }
+
+ public EntityManagerFactoryPlusOperations getEntityManagerFactoryPlusOperations(EntityManagerFactory rawEntityManager) {
+ throw new UnsupportedOperationException(getClass().getName() + " does not support EntityManagerFactoryPlusOperations");
+ }
+
+ public EntityManagerPlusOperations getEntityManagerPlusOperations(EntityManager rawEntityManager) {
+ throw new UnsupportedOperationException(getClass().getName() + " does not support EntityManagerPlusOperations");
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Base class for any class that needs to access an EntityManagerFactory,
+ * usually in order to obtain an EntityManager. Defines common properties.
+ *
+ *
Not intended to be used directly. See {@link JpaAccessor}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see JpaAccessor
+ * @see EntityManagerFactoryUtils
+ */
+public abstract class EntityManagerFactoryAccessor {
+
+ /** Logger available to subclasses */
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ private EntityManagerFactory entityManagerFactory;
+
+ private final Map jpaPropertyMap = new HashMap();
+
+
+ /**
+ * Set the JPA EntityManagerFactory that should be used to create
+ * EntityManagers.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager()
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public void setEntityManagerFactory(EntityManagerFactory emf) {
+ this.entityManagerFactory = emf;
+ }
+
+ /**
+ * Return the JPA EntityManagerFactory that should be used to create
+ * EntityManagers.
+ */
+ public EntityManagerFactory getEntityManagerFactory() {
+ return this.entityManagerFactory;
+ }
+
+ /**
+ * Specify JPA properties, to be passed into
+ * EntityManagerFactory.createEntityManager(Map) (if any).
+ *
Can be populated with a String "value" (parsed via PropertiesEditor)
+ * or a "props" element in XML bean definitions.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public void setJpaProperties(Properties jpaProperties) {
+ CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
+ }
+
+ /**
+ * Specify JPA properties as a Map, to be passed into
+ * EntityManagerFactory.createEntityManager(Map) (if any).
+ *
Can be populated with a "map" or "props" element in XML bean definitions.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public void setJpaPropertyMap(Map jpaProperties) {
+ if (jpaProperties != null) {
+ this.jpaPropertyMap.putAll(jpaProperties);
+ }
+ }
+
+ /**
+ * Allow Map access to the JPA properties to be passed to the persistence
+ * provider, with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via "jpaPropertyMap[myKey]".
+ */
+ public Map getJpaPropertyMap() {
+ return this.jpaPropertyMap;
+ }
+
+
+ /**
+ * Obtain a new EntityManager from this accessor's EntityManagerFactory.
+ *
Can be overridden in subclasses to create specific EntityManager variants.
+ * @return a new EntityManager
+ * @throws IllegalStateException if this accessor is not configured with an EntityManagerFactory
+ * @see javax.persistence.EntityManagerFactory#createEntityManager()
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ protected EntityManager createEntityManager() throws IllegalStateException {
+ EntityManagerFactory emf = getEntityManagerFactory();
+ Assert.state(emf != null, "No EntityManagerFactory specified");
+ Map properties = getJpaPropertyMap();
+ return (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager());
+ }
+
+ /**
+ * Obtain the transactional EntityManager for this accessor's EntityManagerFactory, if any.
+ * @return the transactional EntityManager, or null if none
+ * @throws IllegalStateException if this accessor is not configured with an EntityManagerFactory
+ * @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
+ * @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory, java.util.Map)
+ */
+ protected EntityManager getTransactionalEntityManager() throws IllegalStateException{
+ EntityManagerFactory emf = getEntityManagerFactory();
+ Assert.state(emf != null, "No EntityManagerFactory specified");
+ return EntityManagerFactoryUtils.getTransactionalEntityManager(emf, getJpaPropertyMap());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryInfo.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryInfo.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryInfo.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.sql.DataSource;
+
+/**
+ * Metadata interface for a Spring-managed JPA {@link EntityManagerFactory}.
+ *
+ *
This facility can be obtained from Spring-managed EntityManagerFactory
+ * proxies through casting the EntityManagerFactory handle to this interface.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public interface EntityManagerFactoryInfo {
+
+ /**
+ * Return the raw underlying EntityManagerFactory.
+ * @return the unadorned EntityManagerFactory (never null)
+ */
+ EntityManagerFactory getNativeEntityManagerFactory();
+
+ /**
+ * Return the underlying PersistenceProvider that the underlying
+ * EntityManagerFactory was created with.
+ * @return the PersistenceProvider used to create this EntityManagerFactory,
+ * or null if the standard JPA provider autodetection process
+ * was used to configure the EntityManagerFactory
+ */
+ PersistenceProvider getPersistenceProvider();
+
+ /**
+ * Return the PersistenceUnitInfo used to create this
+ * EntityManagerFactory, if the in-container API was used.
+ * @return the PersistenceUnitInfo used to create this EntityManagerFactory,
+ * or null if the in-container contract was not used to
+ * configure the EntityManagerFactory
+ */
+ PersistenceUnitInfo getPersistenceUnitInfo();
+
+ /**
+ * Return the name of the persistence unit used to create this
+ * EntityManagerFactory, or null if
+ * it is an unnamed default. If getPersistenceUnitInfo()
+ * returns non-null, the return type of getPersistenceUnitName()
+ * must be equal to the value returned by
+ * PersistenceUnitInfo.getPersistenceUnitName().
+ * @see #getPersistenceUnitInfo()
+ * @see javax.persistence.spi.PersistenceUnitInfo#getPersistenceUnitName()
+ */
+ String getPersistenceUnitName();
+
+ /**
+ * Return the JDBC DataSource that this EntityManagerFactory
+ * obtains its JDBC Connections from.
+ * @return the JDBC DataSource, or null if not known
+ */
+ DataSource getDataSource();
+
+ /**
+ * Return the (potentially vendor-specific) EntityManager interface
+ * that this factory's EntityManagers will implement.
+ *
A null return value suggests that autodetection is supposed
+ * to happen: either based on a target EntityManager instance
+ * or simply defaulting to javax.persistence.EntityManager.
+ */
+ Class extends EntityManager> getEntityManagerInterface();
+
+ /**
+ * Return the vendor-specific JpaDialect implementation for this
+ * EntityManagerFactory, or null if not known.
+ */
+ JpaDialect getJpaDialect();
+
+ /**
+ * Return the ClassLoader that the application's beans are loaded with.
+ *
Proxies will be generated in this ClassLoader.
+ */
+ ClassLoader getBeanClassLoader();
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlus.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlus.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlus.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.EntityManagerFactory;
+
+/**
+ * Extension of the standard JPA EntityManagerFactory interface, linking in
+ * Spring's EntityManagerFactoryPlusOperations interface which defines
+ * additional operations (beyond JPA 1.0) in a vendor-independent fashion.
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see javax.persistence.EntityManager
+ */
+public interface EntityManagerFactoryPlus extends EntityManagerFactory, EntityManagerFactoryPlusOperations {
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlusOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlusOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryPlusOperations.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+/**
+ * Interface that defines common operations beyond the standard
+ * JPA EntityManagerFactory interface, in a vendor-independent fashion.
+ * To be adapted to specific JPA providers through a JpaDialect.
+ *
+ *
As of Spring 2.0, this interface does not define any operations yet.
+ * The pass-through mechanism to the underlying JpaDialect is already in
+ * place. Concrete operations will be added in the Spring 2.5 timeframe.
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see JpaDialect#getEntityManagerPlusOperations
+ * @see javax.persistence.EntityManagerFactory
+ */
+public interface EntityManagerFactoryPlusOperations {
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryUtils.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryUtils.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerFactoryUtils.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.util.Map;
+
+import javax.persistence.EntityExistsException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityNotFoundException;
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
+import javax.persistence.TransactionRequiredException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.core.Ordered;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.transaction.support.ResourceHolder;
+import org.springframework.transaction.support.ResourceHolderSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Helper class featuring methods for JPA EntityManager handling,
+ * allowing for reuse of EntityManager instances within transactions.
+ * Also provides support for exception translation.
+ *
+ *
Mainly intended for internal use within the framework.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public abstract class EntityManagerFactoryUtils {
+
+ /**
+ * Order value for TransactionSynchronization objects that clean up JPA
+ * EntityManagers. Return DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100
+ * to execute EntityManager cleanup before JDBC Connection cleanup, if any.
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
+ */
+ public static final int ENTITY_MANAGER_SYNCHRONIZATION_ORDER =
+ DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
+
+ private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class);
+
+
+ /**
+ * Find an EntityManagerFactory with the given name in the given
+ * Spring application context (represented as ListableBeanFactory).
+ *
The specified unit name will be matched against the configured
+ * peristence unit, provided that a discovered EntityManagerFactory
+ * implements the {@link EntityManagerFactoryInfo} interface. If not,
+ * the persistence unit name will be matched against the Spring bean name,
+ * assuming that the EntityManagerFactory bean names follow that convention.
+ * @param beanFactory the ListableBeanFactory to search
+ * @param unitName the name of the persistence unit (never empty)
+ * @return the EntityManagerFactory
+ * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
+ * @see EntityManagerFactoryInfo#getPersistenceUnitName()
+ */
+ public static EntityManagerFactory findEntityManagerFactory(
+ ListableBeanFactory beanFactory, String unitName) throws NoSuchBeanDefinitionException {
+
+ Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
+ Assert.hasLength(unitName, "Unit name must not be empty");
+
+ // See whether we can find an EntityManagerFactory with matching persistence unit name.
+ String[] candidateNames =
+ BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, EntityManagerFactory.class);
+ for (String candidateName : candidateNames) {
+ EntityManagerFactory emf = (EntityManagerFactory) beanFactory.getBean(candidateName);
+ if (emf instanceof EntityManagerFactoryInfo) {
+ if (unitName.equals(((EntityManagerFactoryInfo) emf).getPersistenceUnitName())) {
+ return emf;
+ }
+ }
+ }
+ // No matching persistence unit found - simply take the EntityManagerFactory
+ // with the persistence unit name as bean name (by convention).
+ return (EntityManagerFactory) beanFactory.getBean(unitName, EntityManagerFactory.class);
+ }
+
+ /**
+ * Obtain a JPA EntityManager from the given factory. Is aware of a
+ * corresponding EntityManager bound to the current thread,
+ * for example when using JpaTransactionManager.
+ *
Note: Will return null if no thread-bound EntityManager found!
+ * @param emf EntityManagerFactory to create the EntityManager with
+ * @return the EntityManager, or null if none found
+ * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
+ * @see JpaTransactionManager
+ */
+ public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf)
+ throws DataAccessResourceFailureException {
+
+ return getTransactionalEntityManager(emf, null);
+ }
+
+ /**
+ * Obtain a JPA EntityManager from the given factory. Is aware of a
+ * corresponding EntityManager bound to the current thread,
+ * for example when using JpaTransactionManager.
+ *
Note: Will return null if no thread-bound EntityManager found!
+ * @param emf EntityManagerFactory to create the EntityManager with
+ * @param properties the properties to be passed into the createEntityManager
+ * call (may be null)
+ * @return the EntityManager, or null if none found
+ * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
+ * @see JpaTransactionManager
+ */
+ public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf, Map properties)
+ throws DataAccessResourceFailureException {
+ try {
+ return doGetTransactionalEntityManager(emf, properties);
+ }
+ catch (PersistenceException ex) {
+ throw new DataAccessResourceFailureException("Could not obtain JPA EntityManager", ex);
+ }
+ }
+
+ /**
+ * Obtain a JPA EntityManager from the given factory. Is aware of a
+ * corresponding EntityManager bound to the current thread,
+ * for example when using JpaTransactionManager.
+ *
Same as getEntityManager, but throwing the original PersistenceException.
+ * @param emf EntityManagerFactory to create the EntityManager with
+ * @param properties the properties to be passed into the createEntityManager
+ * call (may be null)
+ * @return the EntityManager, or null if none found
+ * @throws javax.persistence.PersistenceException if the EntityManager couldn't be created
+ * @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
+ * @see JpaTransactionManager
+ */
+ public static EntityManager doGetTransactionalEntityManager(
+ EntityManagerFactory emf, Map properties) throws PersistenceException {
+
+ Assert.notNull(emf, "No EntityManagerFactory specified");
+
+ EntityManagerHolder emHolder =
+ (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
+ if (emHolder != null) {
+ if (!emHolder.isSynchronizedWithTransaction() &&
+ TransactionSynchronizationManager.isSynchronizationActive()) {
+ // Try to explicitly synchronize the EntityManager itself
+ // with an ongoing JTA transaction, if any.
+ try {
+ emHolder.getEntityManager().joinTransaction();
+ }
+ catch (TransactionRequiredException ex) {
+ logger.debug("Could not join JTA transaction because none was active", ex);
+ }
+ Object transactionData = prepareTransaction(emHolder.getEntityManager(), emf);
+ TransactionSynchronizationManager.registerSynchronization(
+ new EntityManagerSynchronization(emHolder, emf, transactionData, false));
+ emHolder.setSynchronizedWithTransaction(true);
+ }
+ return emHolder.getEntityManager();
+ }
+
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ // Indicate that we can't obtain a transactional EntityManager.
+ return null;
+ }
+
+ // Create a new EntityManager for use within the current transaction.
+ logger.debug("Opening JPA EntityManager");
+ EntityManager em =
+ (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager());
+
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ logger.debug("Registering transaction synchronization for JPA EntityManager");
+ // Use same EntityManager for further JPA actions within the transaction.
+ // Thread object will get removed by synchronization at transaction completion.
+ emHolder = new EntityManagerHolder(em);
+ Object transactionData = prepareTransaction(em, emf);
+ TransactionSynchronizationManager.registerSynchronization(
+ new EntityManagerSynchronization(emHolder, emf, transactionData, true));
+ emHolder.setSynchronizedWithTransaction(true);
+ TransactionSynchronizationManager.bindResource(emf, emHolder);
+ }
+
+ return em;
+ }
+
+ /**
+ * Prepare a transaction on the given EntityManager, if possible.
+ * @param em the EntityManager to prepare
+ * @param emf the EntityManagerFactory that the EntityManager has been created with
+ * @return an arbitrary object that holds transaction data, if any
+ * (to be passed into cleanupTransaction)
+ * @see JpaDialect#prepareTransaction
+ */
+ private static Object prepareTransaction(EntityManager em, EntityManagerFactory emf) {
+ if (emf instanceof EntityManagerFactoryInfo) {
+ EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
+ JpaDialect jpaDialect = emfInfo.getJpaDialect();
+ if (jpaDialect != null) {
+ return jpaDialect.prepareTransaction(em,
+ TransactionSynchronizationManager.isCurrentTransactionReadOnly(),
+ TransactionSynchronizationManager.getCurrentTransactionName());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Prepare a transaction on the given EntityManager, if possible.
+ * @param transactionData arbitrary object that holds transaction data, if any
+ * (as returned by prepareTransaction)
+ * @param emf the EntityManagerFactory that the EntityManager has been created with
+ * @see JpaDialect#cleanupTransaction
+ */
+ private static void cleanupTransaction(Object transactionData, EntityManagerFactory emf) {
+ if (emf instanceof EntityManagerFactoryInfo) {
+ EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
+ JpaDialect jpaDialect = emfInfo.getJpaDialect();
+ if (jpaDialect != null) {
+ jpaDialect.cleanupTransaction(transactionData);
+ }
+ }
+ }
+
+ /**
+ * Convert the given runtime exception to an appropriate exception from the
+ * org.springframework.dao hierarchy.
+ * Return null if no translation is appropriate: any other exception may
+ * have resulted from user code, and should not be translated.
+ *
The most important cases like object not found or optimistic locking
+ * failure are covered here. For more fine-granular conversion, JpaAccessor and
+ * JpaTransactionManager support sophisticated translation of exceptions via a
+ * JpaDialect.
+ * @param ex runtime exception that occured
+ * @return the corresponding DataAccessException instance,
+ * or null if the exception should not be translated
+ */
+ public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) {
+ // Following the JPA specification, a persistence provider can also
+ // throw these two exceptions, besides PersistenceException.
+ if (ex instanceof IllegalStateException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+ if (ex instanceof IllegalArgumentException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+
+ // Check for well-known PersistenceException subclasses.
+ if (ex instanceof EntityNotFoundException) {
+ return new JpaObjectRetrievalFailureException((EntityNotFoundException) ex);
+ }
+ if (ex instanceof NoResultException) {
+ return new EmptyResultDataAccessException(ex.getMessage(), 1);
+ }
+ if (ex instanceof NonUniqueResultException) {
+ return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1);
+ }
+ if (ex instanceof OptimisticLockException) {
+ return new JpaOptimisticLockingFailureException((OptimisticLockException) ex);
+ }
+ if (ex instanceof EntityExistsException) {
+ return new DataIntegrityViolationException(ex.getMessage(), ex);
+ }
+ if (ex instanceof TransactionRequiredException) {
+ return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
+ }
+
+ // If we have another kind of PersistenceException, throw it.
+ if (ex instanceof PersistenceException) {
+ return new JpaSystemException((PersistenceException) ex);
+ }
+
+ // If we get here, we have an exception that resulted from user code,
+ // rather than the persistence provider, so we return null to indicate
+ // that translation should not occur.
+ return null;
+ }
+
+ /**
+ * Close the given JPA EntityManager,
+ * catching and logging any cleanup exceptions thrown.
+ * @param em the JPA EntityManager to close (may be null)
+ * @see javax.persistence.EntityManager#close()
+ */
+ public static void closeEntityManager(EntityManager em) {
+ if (em != null) {
+ logger.debug("Closing JPA EntityManager");
+ try {
+ em.close();
+ }
+ catch (PersistenceException ex) {
+ logger.debug("Could not close JPA EntityManager", ex);
+ }
+ catch (Throwable ex) {
+ logger.debug("Unexpected exception on closing JPA EntityManager", ex);
+ }
+ }
+ }
+
+
+ /**
+ * Callback for resource cleanup at the end of a non-JPA transaction
+ * (e.g. when participating in a JtaTransactionManager transaction).
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+ private static class EntityManagerSynchronization extends ResourceHolderSynchronization implements Ordered {
+
+ private final Object transactionData;
+
+ private final boolean newEntityManager;
+
+ public EntityManagerSynchronization(
+ EntityManagerHolder emHolder, EntityManagerFactory emf, Object transactionData, boolean newEntityManager) {
+ super(emHolder, emf);
+ this.transactionData = transactionData;
+ this.newEntityManager = newEntityManager;
+ }
+
+ public int getOrder() {
+ return ENTITY_MANAGER_SYNCHRONIZATION_ORDER;
+ }
+
+ protected boolean shouldUnbindAtCompletion() {
+ return this.newEntityManager;
+ }
+
+ protected void releaseResource(ResourceHolder resourceHolder, Object resourceKey) {
+ closeEntityManager(((EntityManagerHolder) resourceHolder).getEntityManager());
+ }
+
+ protected void cleanupResource(ResourceHolder resourceHolder, Object resourceKey, boolean committed) {
+ if (!committed) {
+ // Clear all pending inserts/updates/deletes in the EntityManager.
+ // Necessary for pre-bound EntityManagers, to avoid inconsistent state.
+ ((EntityManagerHolder) resourceHolder).getEntityManager().clear();
+ }
+ cleanupTransaction(this.transactionData, (EntityManagerFactory) resourceKey);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerHolder.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerHolder.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerHolder.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+
+import org.springframework.transaction.SavepointManager;
+import org.springframework.transaction.support.ResourceHolderSupport;
+import org.springframework.util.Assert;
+
+/**
+ * Holder wrapping a JPA EntityManager.
+ * JpaTransactionManager binds instances of this class to the thread,
+ * for a given EntityManagerFactory.
+ *
+ *
Note: This is an SPI class, not intended to be used by applications.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see JpaTransactionManager
+ * @see EntityManagerFactoryUtils
+ */
+public class EntityManagerHolder extends ResourceHolderSupport {
+
+ private final EntityManager entityManager;
+
+ private boolean transactionActive;
+
+ private SavepointManager savepointManager;
+
+
+ public EntityManagerHolder(EntityManager entityManager) {
+ Assert.notNull(entityManager, "EntityManager must not be null");
+ this.entityManager = entityManager;
+ }
+
+
+ public EntityManager getEntityManager() {
+ return this.entityManager;
+ }
+
+ protected void setTransactionActive(boolean transactionActive) {
+ this.transactionActive = transactionActive;
+ }
+
+ protected boolean isTransactionActive() {
+ return this.transactionActive;
+ }
+
+ protected void setSavepointManager(SavepointManager savepointManager) {
+ this.savepointManager = savepointManager;
+ }
+
+ protected SavepointManager getSavepointManager() {
+ return this.savepointManager;
+ }
+
+ public void clear() {
+ super.clear();
+ this.transactionActive = false;
+ this.savepointManager = null;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlus.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlus.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlus.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+
+/**
+ * Extension of the standard JPA EntityManager interface, linking in
+ * Spring's EntityManagerPlusOperations interface which defines additional
+ * operations (beyond JPA 1.0) in a vendor-independent fashion.
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see javax.persistence.EntityManager
+ */
+public interface EntityManagerPlus extends EntityManager, EntityManagerPlusOperations {
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlusOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlusOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerPlusOperations.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+/**
+ * Interface that defines common operations beyond the standard
+ * JPA EntityManager interface, in a vendor-independent fashion.
+ * To be adapted to specific JPA providers through a JpaDialect.
+ *
+ *
As of Spring 2.0, this interface does not define any operations yet.
+ * The pass-through mechanism to the underlying JpaDialect is already in
+ * place. Concrete operations will be added in the Spring 2.5 timeframe.
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see JpaDialect#getEntityManagerPlusOperations
+ * @see javax.persistence.EntityManager
+ */
+public interface EntityManagerPlusOperations {
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerProxy.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerProxy.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/EntityManagerProxy.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+
+/**
+ * Subinterface of {@link javax.persistence.EntityManager} to be implemented by
+ * EntityManager proxies. Allows access to the underlying target EntityManager.
+ *
+ *
This interface is mainly intended for framework usage. Application code
+ * should prefer the use of the {@link javax.persistence.EntityManager#getDelegate()}
+ * method to access native functionality of the underlying resource.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public interface EntityManagerProxy extends EntityManager {
+
+ /**
+ * Return the underlying EntityManager that this proxy will delegate to.
+ *
In case of an extended EntityManager, this will be the associated
+ * raw EntityManager.
+ *
In case of a shared ("transactional") EntityManager, this will be
+ * the raw EntityManager that is currently associated with the transaction.
+ * Outside of a transaction, an IllegalStateException will be thrown.
+ * @return the underlying raw EntityManager (never null)
+ * @throws IllegalStateException if no underlying EntityManager is available
+ */
+ EntityManager getTargetEntityManager() throws IllegalStateException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.TransactionRequiredException;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.Ordered;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.transaction.support.ResourceHolderSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Factory for dynamic EntityManager proxies that follow the JPA spec's
+ * semantics for "extended" EntityManagers.
+ *
+ *
Supports explicit joining of a transaction through the
+ * joinTransaction() method ("application-managed extended
+ * EntityManager") as well as automatic joining on each operation
+ * ("container-managed extended EntityManager").
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+public abstract class ExtendedEntityManagerCreator {
+
+ /**
+ * Create an EntityManager that can join transactions with the
+ * joinTransaction() method, but is not automatically
+ * managed by the container.
+ * @param rawEntityManager raw EntityManager
+ * @param plusOperations an implementation of the EntityManagerPlusOperations
+ * interface, if those operations should be exposed (may be null)
+ * @return an application-managed EntityManager that can join transactions
+ * but does not participate in them automatically
+ */
+ public static EntityManager createApplicationManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerPlusOperations plusOperations) {
+
+ return createProxy(rawEntityManager, null, null, plusOperations, null, null, false);
+ }
+
+ /**
+ * Create an EntityManager that can join transactions with the
+ * joinTransaction() method, but is not automatically
+ * managed by the container.
+ * @param rawEntityManager raw EntityManager
+ * @param plusOperations an implementation of the EntityManagerPlusOperations
+ * interface, if those operations should be exposed (may be null)
+ * @param exceptionTranslator the exception translator to use for translating
+ * JPA commit/rollback exceptions during transaction synchronization
+ * (may be null)
+ * @return an application-managed EntityManager that can join transactions
+ * but does not participate in them automatically
+ */
+ public static EntityManager createApplicationManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerPlusOperations plusOperations,
+ PersistenceExceptionTranslator exceptionTranslator) {
+
+ return createProxy(rawEntityManager, null, null, plusOperations, exceptionTranslator, null, false);
+ }
+
+ /**
+ * Create an EntityManager that can join transactions with the
+ * joinTransaction() method, but is not automatically
+ * managed by the container.
+ * @param rawEntityManager raw EntityManager
+ * @param emfInfo the EntityManagerFactoryInfo to obtain the
+ * EntityManagerPlusOperations and PersistenceUnitInfo from
+ * @return an application-managed EntityManager that can join transactions
+ * but does not participate in them automatically
+ */
+ public static EntityManager createApplicationManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerFactoryInfo emfInfo) {
+
+ return createProxy(rawEntityManager, emfInfo, false);
+ }
+
+
+ /**
+ * Create an EntityManager that automatically joins transactions on each
+ * operation in a transaction.
+ * @param rawEntityManager raw EntityManager
+ * @param plusOperations an implementation of the EntityManagerPlusOperations
+ * interface, if those operations should be exposed (may be null)
+ * @return a container-managed EntityManager that will automatically participate
+ * in any managed transaction
+ */
+ public static EntityManager createContainerManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerPlusOperations plusOperations) {
+
+ return createProxy(rawEntityManager, null, null, plusOperations, null, null, true);
+ }
+
+ /**
+ * Create an EntityManager that automatically joins transactions on each
+ * operation in a transaction.
+ * @param rawEntityManager raw EntityManager
+ * @param plusOperations an implementation of the EntityManagerPlusOperations
+ * interface, if those operations should be exposed (may be null)
+ * @param exceptionTranslator the exception translator to use for translating
+ * JPA commit/rollback exceptions during transaction synchronization
+ * (may be null)
+ * @return a container-managed EntityManager that will automatically participate
+ * in any managed transaction
+ */
+ public static EntityManager createContainerManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerPlusOperations plusOperations,
+ PersistenceExceptionTranslator exceptionTranslator) {
+
+ return createProxy(rawEntityManager, null, null, plusOperations, exceptionTranslator, null, true);
+ }
+
+ /**
+ * Create an EntityManager that automatically joins transactions on each
+ * operation in a transaction.
+ * @param rawEntityManager raw EntityManager
+ * @param emfInfo the EntityManagerFactoryInfo to obtain the
+ * EntityManagerPlusOperations and PersistenceUnitInfo from
+ * @return a container-managed EntityManager that will automatically participate
+ * in any managed transaction
+ */
+ public static EntityManager createContainerManagedEntityManager(
+ EntityManager rawEntityManager, EntityManagerFactoryInfo emfInfo) {
+
+ return createProxy(rawEntityManager, emfInfo, true);
+ }
+
+
+ /**
+ * Create an EntityManager that automatically joins transactions on each
+ * operation in a transaction.
+ * @param emf the EntityManagerFactory to create the EntityManager with.
+ * If this implements the EntityManagerFactoryInfo interface, appropriate handling
+ * of the native EntityManagerFactory and available EntityManagerPlusOperations
+ * will automatically apply.
+ * @return a container-managed EntityManager that will automatically participate
+ * in any managed transaction
+ * @see javax.persistence.EntityManagerFactory#createEntityManager()
+ */
+ public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf) {
+ return createContainerManagedEntityManager(emf, null);
+ }
+
+ /**
+ * Create an EntityManager that automatically joins transactions on each
+ * operation in a transaction.
+ * @param emf the EntityManagerFactory to create the EntityManager with.
+ * If this implements the EntityManagerFactoryInfo interface, appropriate handling
+ * of the native EntityManagerFactory and available EntityManagerPlusOperations
+ * will automatically apply.
+ * @param properties the properties to be passed into the createEntityManager
+ * call (may be null)
+ * @return a container-managed EntityManager that will automatically participate
+ * in any managed transaction
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf, Map properties) {
+ Assert.notNull(emf, "EntityManagerFactory must not be null");
+ if (emf instanceof EntityManagerFactoryInfo) {
+ EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
+ EntityManagerFactory nativeEmf = emfInfo.getNativeEntityManagerFactory();
+ EntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ?
+ nativeEmf.createEntityManager(properties) : nativeEmf.createEntityManager());
+ return createProxy(rawEntityManager, emfInfo, true);
+ }
+ else {
+ EntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ?
+ emf.createEntityManager(properties) : emf.createEntityManager());
+ return createProxy(rawEntityManager, null, null, null, null, null, true);
+ }
+ }
+
+
+ /**
+ * Actually create the EntityManager proxy.
+ * @param rawEntityManager raw EntityManager
+ * @param emfInfo the EntityManagerFactoryInfo to obtain the
+ * EntityManagerPlusOperations and PersistenceUnitInfo from
+ * @param containerManaged whether to follow container-managed EntityManager
+ * or application-managed EntityManager semantics
+ * @return the EntityManager proxy
+ */
+ private static EntityManager createProxy(
+ EntityManager rawEntityManager, EntityManagerFactoryInfo emfInfo, boolean containerManaged) {
+
+ Assert.notNull(emfInfo, "EntityManagerFactoryInfo must not be null");
+ JpaDialect jpaDialect = emfInfo.getJpaDialect();
+ EntityManagerPlusOperations plusOperations = null;
+ if (jpaDialect != null && jpaDialect.supportsEntityManagerPlusOperations()) {
+ plusOperations = jpaDialect.getEntityManagerPlusOperations(rawEntityManager);
+ }
+ PersistenceUnitInfo pui = emfInfo.getPersistenceUnitInfo();
+ Boolean jta = (pui != null ? pui.getTransactionType() == PersistenceUnitTransactionType.JTA : null);
+ return createProxy(rawEntityManager, emfInfo.getEntityManagerInterface(),
+ emfInfo.getBeanClassLoader(), plusOperations, jpaDialect, jta, containerManaged);
+ }
+
+ /**
+ * Actually create the EntityManager proxy.
+ * @param rawEm raw EntityManager
+ * @param emIfc the (potentially vendor-specific) EntityManager
+ * interface to proxy, or null for default detection of all interfaces
+ * @param plusOperations an implementation of the EntityManagerPlusOperations
+ * interface, if those operations should be exposed (may be null)
+ * @param exceptionTranslator the PersistenceException translator to use
+ * @param jta whether to create a JTA-aware EntityManager
+ * (or null if not known in advance)
+ * @param containerManaged whether to follow container-managed EntityManager
+ * or application-managed EntityManager semantics
+ * @return the EntityManager proxy
+ */
+ private static EntityManager createProxy(
+ EntityManager rawEm, Class extends EntityManager> emIfc, ClassLoader cl,
+ EntityManagerPlusOperations plusOperations, PersistenceExceptionTranslator exceptionTranslator,
+ Boolean jta, boolean containerManaged) {
+
+ Assert.notNull(rawEm, "EntityManager must not be null");
+ Set ifcs = new LinkedHashSet();
+ if (emIfc != null) {
+ ifcs.add(emIfc);
+ }
+ else {
+ ifcs.addAll(ClassUtils.getAllInterfacesForClassAsSet(rawEm.getClass(), cl));
+ }
+ ifcs.add(EntityManagerProxy.class);
+ if (plusOperations != null) {
+ ifcs.add(EntityManagerPlusOperations.class);
+ }
+ return (EntityManager) Proxy.newProxyInstance(
+ (cl != null ? cl : ExtendedEntityManagerCreator.class.getClassLoader()),
+ ifcs.toArray(new Class[ifcs.size()]),
+ new ExtendedEntityManagerInvocationHandler(
+ rawEm, plusOperations, exceptionTranslator, jta, containerManaged));
+ }
+
+
+ /**
+ * InvocationHandler for extended EntityManagers as defined in the JPA spec.
+ */
+ private static class ExtendedEntityManagerInvocationHandler implements InvocationHandler, Serializable {
+
+ private static final Log logger = LogFactory.getLog(ExtendedEntityManagerInvocationHandler.class);
+
+ private final EntityManager target;
+
+ private final EntityManagerPlusOperations plusOperations;
+
+ private final PersistenceExceptionTranslator exceptionTranslator;
+
+ private final boolean containerManaged;
+
+ private boolean jta;
+
+ private ExtendedEntityManagerInvocationHandler(
+ EntityManager target, EntityManagerPlusOperations plusOperations,
+ PersistenceExceptionTranslator exceptionTranslator, Boolean jta, boolean containerManaged) {
+
+ this.target = target;
+ this.plusOperations = plusOperations;
+ this.exceptionTranslator = exceptionTranslator;
+ this.jta = (jta != null ? jta.booleanValue() : isJtaEntityManager());
+ this.containerManaged = containerManaged;
+ }
+
+ private boolean isJtaEntityManager() {
+ try {
+ this.target.getTransaction();
+ return false;
+ }
+ catch (IllegalStateException ex) {
+ logger.debug("Cannot access EntityTransaction handle - assuming we're in a JTA environment");
+ return true;
+ }
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on EntityManager interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0]);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of EntityManager proxy.
+ return hashCode();
+ }
+ else if (method.getName().equals("getTargetEntityManager")) {
+ return this.target;
+ }
+ else if (method.getName().equals("isOpen")) {
+ if (this.containerManaged) {
+ return true;
+ }
+ }
+ else if (method.getName().equals("close")) {
+ if (this.containerManaged) {
+ throw new IllegalStateException("Invalid usage: Cannot close a container-managed EntityManager");
+ }
+ }
+ else if (method.getName().equals("getTransaction")) {
+ if (this.containerManaged) {
+ throw new IllegalStateException(
+ "Cannot execute getTransaction() on a container-managed EntityManager");
+ }
+ }
+ else if (method.getName().equals("joinTransaction")) {
+ doJoinTransaction(true);
+ return null;
+ }
+
+ // Do automatic joining if required.
+ if (this.containerManaged && method.getDeclaringClass().isInterface()) {
+ doJoinTransaction(false);
+ }
+
+ // Invoke method on current EntityManager.
+ try {
+ if (method.getDeclaringClass().equals(EntityManagerPlusOperations.class)) {
+ return method.invoke(this.plusOperations, args);
+ }
+ else {
+ return method.invoke(this.target, args);
+ }
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ /**
+ * Join an existing transaction, if not already joined.
+ * @param enforce whether to enforce the transaction
+ * (i.e. whether failure to join is considered fatal)
+ */
+ private void doJoinTransaction(boolean enforce) {
+ if (this.jta) {
+ // Let's try whether we're in a JTA transaction.
+ try {
+ this.target.joinTransaction();
+ logger.debug("Joined JTA transaction");
+ }
+ catch (TransactionRequiredException ex) {
+ if (!enforce) {
+ logger.debug("No JTA transaction to join: " + ex);
+ }
+ else {
+ throw ex;
+ }
+ }
+ }
+ else {
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ if (!TransactionSynchronizationManager.hasResource(this.target) &&
+ !this.target.getTransaction().isActive()) {
+ enlistInCurrentTransaction();
+ }
+ logger.debug("Joined local transaction");
+ }
+ else {
+ if (!enforce) {
+ logger.debug("No local transaction to join");
+ }
+ else {
+ throw new TransactionRequiredException("No local transaction to join");
+ }
+ }
+ }
+ }
+
+ /**
+ * Enlist this application-managed EntityManager in the current transaction.
+ */
+ private void enlistInCurrentTransaction() {
+ // Resource local transaction, need to acquire the EntityTransaction,
+ // start a transaction now and enlist a synchronization for
+ // commit or rollback later.
+ EntityTransaction et = this.target.getTransaction();
+ et.begin();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Starting resource local transaction on application-managed " +
+ "EntityManager [" + this.target + "]");
+ }
+ ExtendedEntityManagerSynchronization extendedEntityManagerSynchronization =
+ new ExtendedEntityManagerSynchronization(this.target, this.exceptionTranslator);
+ TransactionSynchronizationManager.bindResource(this.target,
+ extendedEntityManagerSynchronization);
+ TransactionSynchronizationManager.registerSynchronization(extendedEntityManagerSynchronization);
+ }
+ }
+
+
+ /**
+ * TransactionSynchronization enlisting an extended EntityManager
+ * with a current Spring transaction.
+ */
+ private static class ExtendedEntityManagerSynchronization extends ResourceHolderSynchronization
+ implements Ordered {
+
+ private final EntityManager entityManager;
+
+ private final PersistenceExceptionTranslator exceptionTranslator;
+
+ public ExtendedEntityManagerSynchronization(
+ EntityManager em, PersistenceExceptionTranslator exceptionTranslator) {
+ super(new EntityManagerHolder(em), em);
+ this.entityManager = em;
+ this.exceptionTranslator = exceptionTranslator;
+ }
+
+ public int getOrder() {
+ return EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER + 1;
+ }
+
+ protected boolean shouldReleaseBeforeCompletion() {
+ return false;
+ }
+
+ public void afterCommit() {
+ super.afterCommit();
+ // Trigger commit here to let exceptions propagate to the caller.
+ try {
+ this.entityManager.getTransaction().commit();
+ }
+ catch (RuntimeException ex) {
+ throw convertCompletionException(ex);
+ }
+ }
+
+ public void afterCompletion(int status) {
+ super.afterCompletion(status);
+ if (status != STATUS_COMMITTED) {
+ // Haven't had an afterCommit call: trigger a rollback.
+ try {
+ this.entityManager.getTransaction().rollback();
+ }
+ catch (RuntimeException ex) {
+ throw convertCompletionException(ex);
+ }
+ }
+ }
+
+ private RuntimeException convertCompletionException(RuntimeException ex) {
+ DataAccessException daex = (this.exceptionTranslator != null) ?
+ this.exceptionTranslator.translateExceptionIfPossible(ex) :
+ EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
+ return (daex != null ? daex : ex);
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaAccessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaAccessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaAccessor.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.support.DataAccessUtils;
+
+/**
+ * Base class for JpaTemplate and JpaInterceptor, defining common
+ * properties such as EntityManagerFactory and flushing behavior.
+ *
+ *
Not intended to be used directly.
+ * See {@link JpaTemplate} and {@link JpaInterceptor}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setEntityManagerFactory
+ * @see #setEntityManager
+ * @see #setJpaDialect
+ * @see #setFlushEager
+ * @see JpaTemplate
+ * @see JpaInterceptor
+ * @see JpaDialect
+ */
+public abstract class JpaAccessor extends EntityManagerFactoryAccessor implements InitializingBean {
+
+ private EntityManager entityManager;
+
+ private JpaDialect jpaDialect = new DefaultJpaDialect();
+
+ private boolean flushEager = false;
+
+
+ /**
+ * Set the JPA EntityManager to use.
+ */
+ public void setEntityManager(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ }
+
+ /**
+ * Return the JPA EntityManager to use.
+ */
+ public EntityManager getEntityManager() {
+ return entityManager;
+ }
+
+ /**
+ * Set the JPA dialect to use for this accessor.
+ *
The dialect object can be used to retrieve the underlying JDBC
+ * connection, for example.
+ */
+ public void setJpaDialect(JpaDialect jpaDialect) {
+ this.jpaDialect = (jpaDialect != null ? jpaDialect : new DefaultJpaDialect());
+ }
+
+ /**
+ * Return the JPA dialect to use for this accessor.
+ *
Creates a default one for the specified EntityManagerFactory if none set.
+ */
+ public JpaDialect getJpaDialect() {
+ return this.jpaDialect;
+ }
+
+ /**
+ * Set if this accessor should flush changes to the database eagerly.
+ *
Eager flushing leads to immediate synchronization with the database,
+ * even if in a transaction. This causes inconsistencies to show up and throw
+ * a respective exception immediately, and JDBC access code that participates
+ * in the same transaction will see the changes as the database is already
+ * aware of them then. But the drawbacks are:
+ *
+ *
additional communication roundtrips with the database, instead of a
+ * single batch at transaction commit;
+ *
the fact that an actual database rollback is needed if the JPA
+ * transaction rolls back (due to already submitted SQL statements).
+ *
+ */
+ public void setFlushEager(boolean flushEager) {
+ this.flushEager = flushEager;
+ }
+
+ /**
+ * Return if this accessor should flush changes to the database eagerly.
+ */
+ public boolean isFlushEager() {
+ return this.flushEager;
+ }
+
+ /**
+ * Eagerly initialize the JPA dialect, creating a default one
+ * for the specified EntityManagerFactory if none set.
+ */
+ public void afterPropertiesSet() {
+ EntityManagerFactory emf = getEntityManagerFactory();
+ if (emf == null && getEntityManager() == null) {
+ throw new IllegalArgumentException("entityManagerFactory or entityManager is required");
+ }
+ if (emf instanceof EntityManagerFactoryInfo) {
+ JpaDialect jpaDialect = ((EntityManagerFactoryInfo) emf).getJpaDialect();
+ if (jpaDialect != null) {
+ setJpaDialect(jpaDialect);
+ }
+ }
+ }
+
+
+ /**
+ * Flush the given JPA entity manager if necessary.
+ * @param em the current JPA PersistenceManage
+ * @param existingTransaction if executing within an existing transaction
+ * @throws javax.persistence.PersistenceException in case of JPA flushing errors
+ */
+ protected void flushIfNecessary(EntityManager em, boolean existingTransaction) throws PersistenceException {
+ if (isFlushEager()) {
+ logger.debug("Eagerly flushing JPA entity manager");
+ em.flush();
+ }
+ }
+
+ /**
+ * Convert the given runtime exception to an appropriate exception from the
+ * org.springframework.dao hierarchy if necessary, or
+ * return the exception itself if it is not persistence related
+ *
Default implementation delegates to the JpaDialect.
+ * May be overridden in subclasses.
+ * @param ex runtime exception that occured, which may or may not
+ * be JPA-related
+ * @return the corresponding DataAccessException instance if
+ * wrapping should occur, otherwise the raw exception
+ * @see org.springframework.dao.support.DataAccessUtils#translateIfNecessary
+ */
+ public RuntimeException translateIfNecessary(RuntimeException ex) {
+ return DataAccessUtils.translateIfNecessary(ex, getJpaDialect());
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaCallback.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaCallback.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaCallback.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceException;
+
+/**
+ * Callback interface for JPA code. To be used with {@link JpaTemplate}'s
+ * execution method, often as anonymous classes within a method implementation.
+ * A typical implementation will call EntityManager.find/merge
+ * to perform some operations on persistent objects.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see org.springframework.orm.jpa.JpaTemplate
+ * @see org.springframework.orm.jpa.JpaTransactionManager
+ */
+public interface JpaCallback {
+
+ /**
+ * Gets called by JpaTemplate.execute with an active
+ * JPA EntityManager. Does not need to care about activating
+ * or closing the EntityManager, or handling transactions.
+ *
+ *
Note that JPA callback code will not flush any modifications to the
+ * database if not executed within a transaction. Thus, you need to make
+ * sure that JpaTransactionManager has initiated a JPA transaction when
+ * the callback gets called, at least if you want to write to the database.
+ *
+ *
Allows for returning a result object created within the callback,
+ * i.e. a domain object or a collection of domain objects.
+ * A thrown custom RuntimeException is treated as an application exception:
+ * It gets propagated to the caller of the template.
+ *
+ * @param em active EntityManager
+ * @return a result object, or null if none
+ * @throws PersistenceException if thrown by the JPA API
+ * @see org.springframework.orm.jpa.JpaTemplate#execute
+ * @see org.springframework.orm.jpa.JpaTemplate#executeFind
+ */
+ Object doInJpa(EntityManager em) throws PersistenceException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaDialect.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaDialect.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaDialect.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import java.sql.SQLException;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+
+/**
+ * SPI strategy that encapsulates certain functionality that standard JPA 1.0
+ * does not offer, such as access to the underlying JDBC Connection. This
+ * strategy is mainly intended for standalone usage of a JPA provider; most
+ * of its functionality is not relevant when running with JTA transactions.
+ *
+ *
Also allows for the provision of value-added methods for portable yet
+ * more capable EntityManager and EntityManagerFactory subinterfaces offered
+ * by Spring.
+ *
+ *
In general, it is recommended to derive from DefaultJpaDialect instead of
+ * implementing this interface directly. This allows for inheriting common
+ * behavior (present and future) from DefaultJpaDialect, only overriding
+ * specific hooks to plug in concrete vendor-specific behavior.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see DefaultJpaDialect
+ * @see JpaAccessor#setJpaDialect
+ * @see JpaTransactionManager#setJpaDialect
+ * @see JpaVendorAdapter#getJpaDialect()
+ * @see AbstractEntityManagerFactoryBean#setJpaDialect
+ * @see AbstractEntityManagerFactoryBean#setJpaVendorAdapter
+ */
+public interface JpaDialect extends PersistenceExceptionTranslator {
+
+ //-----------------------------------------------------------------------------------
+ // Hooks for non-standard persistence operations (used by EntityManagerFactory beans)
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * Return whether the EntityManagerFactoryPlus(Operations) interface is
+ * supported by this provider.
+ * @see EntityManagerFactoryPlusOperations
+ * @see EntityManagerFactoryPlus
+ */
+ boolean supportsEntityManagerFactoryPlusOperations();
+
+ /**
+ * Return whether the EntityManagerPlus(Operations) interface is
+ * supported by this provider.
+ * @see EntityManagerPlusOperations
+ * @see EntityManagerPlus
+ */
+ boolean supportsEntityManagerPlusOperations();
+
+ /**
+ * Return an EntityManagerFactoryPlusOperations implementation for
+ * the given raw EntityManagerFactory. This operations object can be
+ * used to serve the additional operations behind a proxy that
+ * implements the EntityManagerFactoryPlus interface.
+ * @param rawEntityManager the raw provider-specific EntityManagerFactory
+ * @return the EntityManagerFactoryPlusOperations implementation
+ */
+ EntityManagerFactoryPlusOperations getEntityManagerFactoryPlusOperations(EntityManagerFactory rawEntityManager);
+
+ /**
+ * Return an EntityManagerPlusOperations implementation for
+ * the given raw EntityManager. This operations object can be
+ * used to serve the additional operations behind a proxy that
+ * implements the EntityManagerPlus interface.
+ * @param rawEntityManager the raw provider-specific EntityManagerFactory
+ * @return the EntityManagerFactoryPlusOperations implementation
+ */
+ EntityManagerPlusOperations getEntityManagerPlusOperations(EntityManager rawEntityManager);
+
+
+ //-------------------------------------------------------------------------
+ // Hooks for transaction management (used by JpaTransactionManager)
+ //-------------------------------------------------------------------------
+
+ /**
+ * Begin the given JPA transaction, applying the semantics specified by the
+ * given Spring transaction definition (in particular, an isolation level
+ * and a timeout). Called by JpaTransactionManager on transaction begin.
+ *
An implementation can configure the JPA Transaction object and then
+ * invoke begin, or invoke a special begin method that takes,
+ * for example, an isolation level.
+ *
An implementation can apply the read-only flag as flush mode. In that case,
+ * a transaction data object can be returned that holds the previous flush mode
+ * (and possibly other data), to be reset in cleanupTransaction.
+ * It may also apply the read-only flag and isolation level to the underlying
+ * JDBC Connection before beginning the transaction.
+ *
Implementations can also use the Spring transaction name, as exposed by the
+ * passed-in TransactionDefinition, to optimize for specific data access use cases
+ * (effectively using the current transaction name as use case identifier).
+ *
This method also allows for exposing savepoint capabilities if supported by
+ * the persistence provider, through returning an Object that implements Spring's
+ * {@link org.springframework.transaction.SavepointManager} interface.
+ * {@link JpaTransactionManager} will use this capability if needed.
+ * @param entityManager the EntityManager to begin a JPA transaction on
+ * @param definition the Spring transaction definition that defines semantics
+ * @return an arbitrary object that holds transaction data, if any
+ * (to be passed into {@link #cleanupTransaction}). May implement the
+ * {@link org.springframework.transaction.SavepointManager} interface.
+ * @throws javax.persistence.PersistenceException if thrown by JPA methods
+ * @throws java.sql.SQLException if thrown by JDBC methods
+ * @throws org.springframework.transaction.TransactionException in case of invalid arguments
+ * @see #cleanupTransaction
+ * @see javax.persistence.EntityTransaction#begin
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction
+ */
+ Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
+ throws PersistenceException, SQLException, TransactionException;
+
+ /**
+ * Prepare a JPA transaction, applying the specified semantics. Called by
+ * EntityManagerFactoryUtils when enlisting an EntityManager in a JTA transaction.
+ *
An implementation can apply the read-only flag as flush mode. In that case,
+ * a transaction data object can be returned that holds the previous flush mode
+ * (and possibly other data), to be reset in cleanupTransaction.
+ *
Implementations can also use the Spring transaction name, as exposed by the
+ * passed-in TransactionDefinition, to optimize for specific data access use cases
+ * (effectively using the current transaction name as use case identifier).
+ * @param entityManager the EntityManager to begin a JPA transaction on
+ * @param readOnly whether the transaction is supposed to be read-only
+ * @param name the name of the transaction (if any)
+ * @return an arbitrary object that holds transaction data, if any
+ * (to be passed into cleanupTransaction)
+ * @throws javax.persistence.PersistenceException if thrown by JPA methods
+ * @see #cleanupTransaction
+ */
+ Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name)
+ throws PersistenceException;
+
+ /**
+ * Clean up the transaction via the given transaction data. Called by
+ * JpaTransactionManager and EntityManagerFactoryUtils on transaction cleanup.
+ *
An implementation can, for example, reset read-only flag and
+ * isolation level of the underlying JDBC Connection. Furthermore,
+ * an exposed data access use case can be reset here.
+ * @param transactionData arbitrary object that holds transaction data, if any
+ * (as returned by beginTransaction or prepareTransaction)
+ * @see #beginTransaction
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction
+ */
+ void cleanupTransaction(Object transactionData);
+
+ /**
+ * Retrieve the JDBC Connection that the given JPA EntityManager uses underneath,
+ * if accessing a relational database. This method will just get invoked if actually
+ * needing access to the underlying JDBC Connection, usually within an active JPA
+ * transaction (for example, by JpaTransactionManager). The returned handle will
+ * be passed into the releaseJdbcConnection method when not needed anymore.
+ *
This strategy is necessary as JPA 1.0 does not provide a standard way to retrieve
+ * the underlying JDBC Connection (due to the fact that a JPA implementation might not
+ * work with a relational database at all).
+ *
Implementations are encouraged to return an unwrapped Connection object, i.e.
+ * the Connection as they got it from the connection pool. This makes it easier for
+ * application code to get at the underlying native JDBC Connection, like an
+ * OracleConnection, which is sometimes necessary for LOB handling etc. We assume
+ * that calling code knows how to properly handle the returned Connection object.
+ *
In a simple case where the returned Connection will be auto-closed with the
+ * EntityManager or can be released via the Connection object itself, an
+ * implementation can return a SimpleConnectionHandle that just contains the
+ * Connection. If some other object is needed in releaseJdbcConnection,
+ * an implementation should use a special handle that references that other object.
+ * @param entityManager the current JPA EntityManager
+ * @param readOnly whether the Connection is only needed for read-only purposes
+ * @return a handle for the JDBC Connection, to be passed into
+ * releaseJdbcConnection, or null
+ * if no JDBC Connection can be retrieved
+ * @throws javax.persistence.PersistenceException if thrown by JPA methods
+ * @throws java.sql.SQLException if thrown by JDBC methods
+ * @see #releaseJdbcConnection
+ * @see org.springframework.jdbc.datasource.ConnectionHandle#getConnection
+ * @see org.springframework.jdbc.datasource.SimpleConnectionHandle
+ * @see JpaTransactionManager#setDataSource
+ * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
+ */
+ ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
+ throws PersistenceException, SQLException;
+
+ /**
+ * Release the given JDBC Connection, which has originally been retrieved
+ * via getJdbcConnection. This should be invoked in any case,
+ * to allow for proper release of the retrieved Connection handle.
+ *
An implementation might simply do nothing, if the Connection returned
+ * by getJdbcConnection will be implicitly closed when the JPA
+ * transaction completes or when the EntityManager is closed.
+ * @param conHandle the JDBC Connection handle to release
+ * @param entityManager the current JPA EntityManager
+ * @throws javax.persistence.PersistenceException if thrown by JPA methods
+ * @throws java.sql.SQLException if thrown by JDBC methods
+ * @see #getJdbcConnection
+ */
+ void releaseJdbcConnection(ConnectionHandle conHandle, EntityManager entityManager)
+ throws PersistenceException, SQLException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaInterceptor.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import javax.persistence.EntityManager;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * This interceptor binds a new JPA EntityManager to the thread before a method
+ * call, closing and removing it afterwards in case of any method outcome.
+ * If there already is a pre-bound EntityManager (e.g. from JpaTransactionManager,
+ * or from a surrounding JPA-intercepted method), the interceptor simply participates in it.
+ *
+ *
Application code must retrieve a JPA EntityManager via the
+ * EntityManagerFactoryUtils.getEntityManager method or - preferably -
+ * via a shared EntityManager reference, to be able to detect a
+ * thread-bound EntityManager. Typically, the code will look like as follows:
+ *
+ *
Note that this interceptor automatically translates PersistenceExceptions,
+ * via delegating to the EntityManagerFactoryUtils.convertJpaAccessException
+ * method that converts them to exceptions that are compatible with the
+ * org.springframework.dao exception hierarchy (like JpaTemplate does).
+ *
+ *
This class can be considered a declarative alternative to JpaTemplate's
+ * callback approach. The advantages are:
+ *
+ *
no anonymous classes necessary for callback implementations;
+ *
the possibility to throw any application exceptions from within data access code.
+ *
+ *
+ *
The drawback is the dependency on interceptor configuration. However, note
+ * that this interceptor is usually not necessary in scenarios where the
+ * data access code always executes within transactions. A transaction will always
+ * have a thread-bound EntityManager in the first place, so adding this interceptor
+ * to the configuration just adds value when fine-tuning EntityManager settings
+ * like the flush mode - or when relying on exception translation.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see JpaTransactionManager
+ * @see JpaTemplate
+ */
+public class JpaInterceptor extends JpaAccessor implements MethodInterceptor {
+
+ private boolean exceptionConversionEnabled = true;
+
+
+ /**
+ * Set whether to convert any PersistenceException raised to a Spring DataAccessException,
+ * compatible with the org.springframework.dao exception hierarchy.
+ *
Default is "true". Turn this flag off to let the caller receive raw exceptions
+ * as-is, without any wrapping.
+ * @see org.springframework.dao.DataAccessException
+ */
+ public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) {
+ this.exceptionConversionEnabled = exceptionConversionEnabled;
+ }
+
+
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+ // Determine current EntityManager: either the transactional one
+ // managed by the factory or a temporary one for the given invocation.
+ EntityManager em = getTransactionalEntityManager();
+ boolean isNewEm = false;
+ if (em == null) {
+ logger.debug("Creating new EntityManager for JpaInterceptor invocation");
+ em = createEntityManager();
+ isNewEm = true;
+ TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), new EntityManagerHolder(em));
+ }
+
+ try {
+ Object retVal = methodInvocation.proceed();
+ flushIfNecessary(em, !isNewEm);
+ return retVal;
+ }
+ catch (RuntimeException rawException) {
+ if (this.exceptionConversionEnabled) {
+ // Translation enabled. Translate if we understand the exception.
+ throw translateIfNecessary(rawException);
+ }
+ else {
+ // Translation not enabled. Don't try to translate.
+ throw rawException;
+ }
+ }
+ finally {
+ if (isNewEm) {
+ TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
+ EntityManagerFactoryUtils.closeEntityManager(em);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaObjectRetrievalFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaObjectRetrievalFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaObjectRetrievalFailureException.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.EntityNotFoundException;
+
+import org.springframework.orm.ObjectRetrievalFailureException;
+
+/**
+ * JPA-specific subclass of ObjectRetrievalFailureException.
+ * Converts JPA's EntityNotFoundException.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
+ */
+public class JpaObjectRetrievalFailureException extends ObjectRetrievalFailureException {
+
+ public JpaObjectRetrievalFailureException(EntityNotFoundException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaOperations.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaOperations.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaOperations.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.dao.DataAccessException;
+
+/**
+ * Interface that specifies a basic set of JPA operations,
+ * implemented by {@link JpaTemplate}. Not often used, but a useful
+ * option to enhance testability, as it can easily be mocked or stubbed.
+ *
+ *
Defines JpaTemplate's data access methods that mirror
+ * various {@link javax.persistence.EntityManager} methods. Users are
+ * strongly encouraged to read the JPA EntityManager
+ * javadocs for details on the semantics of those methods.
+ *
+ *
Note that lazy loading will just work with an open JPA
+ * EntityManager, either within a managed transaction or within
+ * {@link org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter}/
+ * {@link org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor}.
+ * Furthermore, some operations just make sense within transactions,
+ * for example: flush, clear.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see JpaTemplate
+ * @see javax.persistence.EntityManager
+ * @see JpaTransactionManager
+ * @see JpaDialect
+ * @see org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
+ * @see org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor
+ */
+public interface JpaOperations {
+
+ Object execute(JpaCallback action) throws DataAccessException;
+
+ List executeFind(JpaCallback action) throws DataAccessException;
+
+ T find(Class entityClass, Object id) throws DataAccessException;
+
+ T getReference(Class entityClass, Object id) throws DataAccessException;
+
+ boolean contains(Object entity) throws DataAccessException;
+
+ void refresh(Object entity) throws DataAccessException;
+
+ void persist(Object entity) throws DataAccessException;
+
+ T merge(T entity) throws DataAccessException;
+
+ void remove(Object entity) throws DataAccessException;
+
+ void flush() throws DataAccessException;
+
+ List find(String queryString) throws DataAccessException;
+
+ List find(String queryString, Object... values) throws DataAccessException;
+
+ List findByNamedParams(String queryString, Map params) throws DataAccessException;
+
+ List findByNamedQuery(String queryName) throws DataAccessException;
+
+ List findByNamedQuery(String queryName, Object... values) throws DataAccessException;
+
+ List findByNamedQueryAndNamedParams(String queryName, Map params) throws DataAccessException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaOptimisticLockingFailureException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaOptimisticLockingFailureException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaOptimisticLockingFailureException.java 17 Aug 2012 15:16:13 -0000 1.1
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.OptimisticLockException;
+
+import org.springframework.orm.ObjectOptimisticLockingFailureException;
+
+/**
+ * JPA-specific subclass of ObjectOptimisticLockingFailureException.
+ * Converts JPA's OptimisticLockException.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
+ */
+public class JpaOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
+
+ public JpaOptimisticLockingFailureException(OptimisticLockException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaSystemException.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaSystemException.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaSystemException.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa;
+
+import javax.persistence.PersistenceException;
+
+import org.springframework.dao.UncategorizedDataAccessException;
+
+/**
+ * JPA-specific subclass of UncategorizedDataAccessException,
+ * for JPA system errors that do not match any concrete
+ * org.springframework.dao exceptions.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see EntityManagerFactoryUtils#convertJpaAccessExceptionIfPossible
+ */
+public class JpaSystemException extends UncategorizedDataAccessException {
+
+ public JpaSystemException(PersistenceException ex) {
+ super(ex.getMessage(), ex);
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaTemplate.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaTemplate.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaTemplate.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+import javax.persistence.Query;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Helper class that allows for writing JPA data access code in the same style
+ * as with Spring's well-known JdoTemplate and HibernateTemplate classes.
+ * Automatically converts PersistenceExceptions into Spring DataAccessExceptions,
+ * following the org.springframework.dao exception hierarchy.
+ *
+ *
The central method is of this template is "execute", supporting JPA access code
+ * implementing the {@link JpaCallback} interface. It provides JPA EntityManager
+ * handling such that neither the JpaCallback implementation nor the calling code
+ * needs to explicitly care about retrieving/closing EntityManagers, or handling
+ * JPA lifecycle exceptions.
+ *
+ *
Can be used within a service implementation via direct instantiation with
+ * a EntityManagerFactory reference, or get prepared in an application context
+ * and given to services as bean reference. Note: The EntityManagerFactory should
+ * always be configured as bean in the application context, in the first case
+ * given to the service directly, in the second case to the prepared template.
+ *
+ *
NOTE: JpaTemplate mainly exists as a sibling of JdoTemplate and
+ * HibernateTemplate, offering the same style for people used to it. For newly
+ * started projects, consider adopting the standard JPA style of coding data
+ * access objects instead, based on a "shared EntityManager" reference injected
+ * via a Spring bean definition or the JPA PersistenceContext annotation.
+ * (Using Spring's SharedEntityManagerBean / PersistenceAnnotationBeanPostProcessor,
+ * or using a direct JNDI lookup for an EntityManager on a Java EE 5 server.)
+ *
+ *
JpaTemplate can be considered as direct alternative to working with the
+ * native JPA EntityManager API (through a shared EntityManager reference,
+ * as outlined above). The major advantage is its automatic conversion to
+ * DataAccessExceptions; the major disadvantage is that it introduces
+ * another thin layer on top of the native JPA API. Note that exception
+ * translation can also be achieved through AOP advice; check out
+ * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}.
+ *
+ *
{@link LocalContainerEntityManagerFactoryBean} is the preferred way of
+ * obtaining a reference to an EntityManagerFactory, at least outside of a full
+ * Java EE 5 environment. The Spring application context will manage its lifecycle,
+ * initializing and shutting down the factory as part of the application.
+ * Within a Java EE 5 environment, you will typically work with a server-managed
+ * EntityManagerFactory that is exposed via JNDI, obtained through Spring's
+ * {@link org.springframework.jndi.JndiObjectFactoryBean}.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setEntityManagerFactory
+ * @see JpaCallback
+ * @see javax.persistence.EntityManager
+ * @see LocalEntityManagerFactoryBean
+ * @see LocalContainerEntityManagerFactoryBean
+ * @see JpaTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ * @see org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
+ * @see org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor
+ */
+public class JpaTemplate extends JpaAccessor implements JpaOperations {
+
+ private boolean exposeNativeEntityManager = false;
+
+
+ /**
+ * Create a new JpaTemplate instance.
+ */
+ public JpaTemplate() {
+ }
+
+ /**
+ * Create a new JpaTemplate instance.
+ * @param emf EntityManagerFactory to create EntityManagers
+ */
+ public JpaTemplate(EntityManagerFactory emf) {
+ setEntityManagerFactory(emf);
+ afterPropertiesSet();
+ }
+
+ /**
+ * Create a new JpaTemplate instance.
+ * @param em EntityManager to use
+ */
+ public JpaTemplate(EntityManager em) {
+ setEntityManager(em);
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set whether to expose the native JPA EntityManager to JpaCallback
+ * code. Default is "false": a EntityManager proxy will be returned,
+ * suppressing close calls and automatically applying transaction
+ * timeouts (if any).
+ *
As there is often a need to cast to a provider-specific EntityManager
+ * class in DAOs that use the JPA 1.0 API, for JPA 2.0 previews and other
+ * provider-specific functionality, the exposed proxy implements all interfaces
+ * implemented by the original EntityManager. If this is not sufficient,
+ * turn this flag to "true".
+ * @see JpaCallback
+ * @see javax.persistence.EntityManager
+ */
+ public void setExposeNativeEntityManager(boolean exposeNativeEntityManager) {
+ this.exposeNativeEntityManager = exposeNativeEntityManager;
+ }
+
+ /**
+ * Return whether to expose the native JPA EntityManager to JpaCallback
+ * code, or rather an EntityManager proxy.
+ */
+ public boolean isExposeNativeEntityManager() {
+ return this.exposeNativeEntityManager;
+ }
+
+
+ public Object execute(JpaCallback action) throws DataAccessException {
+ return execute(action, isExposeNativeEntityManager());
+ }
+
+ public List executeFind(JpaCallback action) throws DataAccessException {
+ Object result = execute(action, isExposeNativeEntityManager());
+ if (!(result instanceof List)) {
+ throw new InvalidDataAccessApiUsageException(
+ "Result object returned from JpaCallback isn't a List: [" + result + "]");
+ }
+ return (List) result;
+ }
+
+ /**
+ * Execute the action specified by the given action object within a
+ * EntityManager.
+ * @param action callback object that specifies the JPA action
+ * @param exposeNativeEntityManager whether to expose the native
+ * JPA entity manager to callback code
+ * @return a result object returned by the action, or null
+ * @throws org.springframework.dao.DataAccessException in case of JPA errors
+ */
+ public Object execute(JpaCallback action, boolean exposeNativeEntityManager) throws DataAccessException {
+ Assert.notNull(action, "Callback object must not be null");
+
+ EntityManager em = getEntityManager();
+ boolean isNewEm = false;
+ if (em == null) {
+ em = getTransactionalEntityManager();
+ if (em == null) {
+ logger.debug("Creating new EntityManager for JpaTemplate execution");
+ em = createEntityManager();
+ isNewEm = true;
+ }
+ }
+
+ try {
+ EntityManager emToExpose = (exposeNativeEntityManager ? em : createEntityManagerProxy(em));
+ Object result = action.doInJpa(emToExpose);
+ flushIfNecessary(em, !isNewEm);
+ return result;
+ }
+ catch (RuntimeException ex) {
+ throw translateIfNecessary(ex);
+ }
+ finally {
+ if (isNewEm) {
+ logger.debug("Closing new EntityManager after JPA template execution");
+ EntityManagerFactoryUtils.closeEntityManager(em);
+ }
+ }
+ }
+
+ /**
+ * Create a close-suppressing proxy for the given JPA EntityManager.
+ * The proxy also prepares returned JPA Query objects.
+ * @param em the JPA EntityManager to create a proxy for
+ * @return the EntityManager proxy, implementing all interfaces
+ * implemented by the passed-in EntityManager object (that is,
+ * also implementing all provider-specific extension interfaces)
+ * @see javax.persistence.EntityManager#close
+ */
+ protected EntityManager createEntityManagerProxy(EntityManager em) {
+ Class[] ifcs = null;
+ EntityManagerFactory emf = getEntityManagerFactory();
+ if (emf instanceof EntityManagerFactoryInfo) {
+ Class entityManagerInterface = ((EntityManagerFactoryInfo) emf).getEntityManagerInterface();
+ if (entityManagerInterface != null) {
+ ifcs = new Class[] {entityManagerInterface};
+ }
+ }
+ if (ifcs == null) {
+ ifcs = ClassUtils.getAllInterfacesForClass(em.getClass());
+ }
+ return (EntityManager) Proxy.newProxyInstance(
+ em.getClass().getClassLoader(), ifcs, new CloseSuppressingInvocationHandler(em));
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience methods for load, save, delete
+ //-------------------------------------------------------------------------
+
+ @SuppressWarnings("unchecked")
+ public T find(final Class entityClass, final Object id) throws DataAccessException {
+ return (T) execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ return em.find(entityClass, id);
+ }
+ }, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getReference(final Class entityClass, final Object id) throws DataAccessException {
+ return (T) execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ return em.getReference(entityClass, id);
+ }
+ }, true);
+ }
+
+ public boolean contains(final Object entity) throws DataAccessException {
+ Boolean result = (Boolean) execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ return new Boolean(em.contains(entity));
+ }
+ }, true);
+ return result.booleanValue();
+ }
+
+ public void refresh(final Object entity) throws DataAccessException {
+ execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ em.refresh(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ public void persist(final Object entity) throws DataAccessException {
+ execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ em.persist(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public T merge(final T entity) throws DataAccessException {
+ return (T) execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ return em.merge(entity);
+ }
+ }, true);
+ }
+
+ public void remove(final Object entity) throws DataAccessException {
+ execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ em.remove(entity);
+ return null;
+ }
+ }, true);
+ }
+
+ public void flush() throws DataAccessException {
+ execute(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ em.flush();
+ return null;
+ }
+ }, true);
+ }
+
+
+ //-------------------------------------------------------------------------
+ // Convenience finder methods
+ //-------------------------------------------------------------------------
+
+ public List find(String queryString) throws DataAccessException {
+ return find(queryString, (Object[]) null);
+ }
+
+ public List find(final String queryString, final Object... values) throws DataAccessException {
+ return executeFind(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ Query queryObject = em.createQuery(queryString);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i + 1, values[i]);
+ }
+ }
+ return queryObject.getResultList();
+ }
+ });
+ }
+
+ public List findByNamedParams(final String queryString, final Map params) throws DataAccessException {
+ return executeFind(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ Query queryObject = em.createQuery(queryString);
+ if (params != null) {
+ for (Map.Entry entry : params.entrySet()) {
+ queryObject.setParameter(entry.getKey(), entry.getValue());
+ }
+ }
+ return queryObject.getResultList();
+ }
+ });
+ }
+
+ public List findByNamedQuery(String queryName) throws DataAccessException {
+ return findByNamedQuery(queryName, (Object[]) null);
+ }
+
+ public List findByNamedQuery(final String queryName, final Object... values) throws DataAccessException {
+ return executeFind(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ Query queryObject = em.createNamedQuery(queryName);
+ if (values != null) {
+ for (int i = 0; i < values.length; i++) {
+ queryObject.setParameter(i + 1, values[i]);
+ }
+ }
+ return queryObject.getResultList();
+ }
+ });
+ }
+
+ public List findByNamedQueryAndNamedParams(final String queryName, final Map params)
+ throws DataAccessException {
+
+ return executeFind(new JpaCallback() {
+ public Object doInJpa(EntityManager em) throws PersistenceException {
+ Query queryObject = em.createNamedQuery(queryName);
+ if (params != null) {
+ for (Map.Entry entry : params.entrySet()) {
+ queryObject.setParameter(entry.getKey(), entry.getValue());
+ }
+ }
+ return queryObject.getResultList();
+ }
+ });
+ }
+
+
+ /**
+ * Invocation handler that suppresses close calls on JPA EntityManagers.
+ * Also prepares returned Query and Criteria objects.
+ * @see javax.persistence.EntityManager#close
+ */
+ private class CloseSuppressingInvocationHandler implements InvocationHandler {
+
+ private final EntityManager target;
+
+ public CloseSuppressingInvocationHandler(EntityManager target) {
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on EntityManager interface (or provider-specific extension) coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of EntityManager proxy.
+ return new Integer(System.identityHashCode(proxy));
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: suppress, not valid.
+ return null;
+ }
+
+ // Invoke method on target EntityManager.
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaTransactionManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaTransactionManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaTransactionManager.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,652 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.PersistenceException;
+import javax.persistence.RollbackException;
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.DataAccessUtils;
+import org.springframework.jdbc.datasource.ConnectionHandle;
+import org.springframework.jdbc.datasource.ConnectionHolder;
+import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
+import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
+import org.springframework.transaction.CannotCreateTransactionException;
+import org.springframework.transaction.IllegalTransactionStateException;
+import org.springframework.transaction.NestedTransactionNotSupportedException;
+import org.springframework.transaction.SavepointManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionException;
+import org.springframework.transaction.TransactionSystemException;
+import org.springframework.transaction.support.AbstractPlatformTransactionManager;
+import org.springframework.transaction.support.DefaultTransactionStatus;
+import org.springframework.transaction.support.ResourceTransactionManager;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * {@link org.springframework.transaction.PlatformTransactionManager} implementation
+ * for a single JPA {@link javax.persistence.EntityManagerFactory}. Binds a JPA
+ * EntityManager from the specified factory to the thread, potentially allowing for
+ * one thread-bound EntityManager per factory. {@link SharedEntityManagerCreator}
+ * and {@link JpaTemplate} are aware of thread-bound entity managers and participate
+ * in such transactions automatically. Using either is required for JPA access code
+ * supporting this transaction management mechanism.
+ *
+ *
This transaction manager is appropriate for applications that use a single
+ * JPA EntityManagerFactory for transactional data access. JTA (usually through
+ * {@link org.springframework.transaction.jta.JtaTransactionManager}) is necessary
+ * for accessing multiple transactional resources within the same transaction.
+ * Note that you need to configure your JPA provider accordingly in order to make
+ * it participate in JTA transactions.
+ *
+ *
This transaction manager also supports direct DataSource access within a
+ * transaction (i.e. plain JDBC code working with the same DataSource).
+ * This allows for mixing services which access JPA and services which use plain
+ * JDBC (without being aware of JPA)! Application code needs to stick to the
+ * same simple Connection lookup pattern as with
+ * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
+ * (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
+ * or going through a
+ * {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
+ * Note that this requires a vendor-specific {@link JpaDialect} to be configured.
+ *
+ *
Note: To be able to register a DataSource's Connection for plain JDBC code,
+ * this instance needs to be aware of the DataSource ({@link #setDataSource}).
+ * The given DataSource should obviously match the one used by the given
+ * EntityManagerFactory. This transaction manager will autodetect the DataSource
+ * used as known connection factory of the EntityManagerFactory, so you usually
+ * don't need to explicitly specify the "dataSource" property.
+ *
+ *
On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
+ * Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"}
+ * flag defaults to "false", though, as nested transactions will just apply to the
+ * JDBC Connection, not to the JPA EntityManager and its cached objects.
+ * You can manually set the flag to "true" if you want to use nested transactions
+ * for JDBC access code which participates in JPA transactions (provided that your
+ * JDBC driver supports Savepoints). Note that JPA itself does not support
+ * nested transactions! Hence, do not expect JPA access code to semantically
+ * participate in a nested transaction.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setEntityManagerFactory
+ * @see #setDataSource
+ * @see LocalEntityManagerFactoryBean
+ * @see JpaTemplate#execute
+ * @see org.springframework.orm.jpa.support.SharedEntityManagerBean
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
+ * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
+ * @see org.springframework.transaction.jta.JtaTransactionManager
+ */
+public class JpaTransactionManager extends AbstractPlatformTransactionManager
+ implements ResourceTransactionManager, InitializingBean {
+
+ private EntityManagerFactory entityManagerFactory;
+
+ private final Map jpaPropertyMap = new HashMap();
+
+ private DataSource dataSource;
+
+ private JpaDialect jpaDialect = new DefaultJpaDialect();
+
+
+ /**
+ * Create a new JpaTransactionManager instance.
+ * A EntityManagerFactory has to be set to be able to use it.
+ * @see #setEntityManagerFactory
+ */
+ public JpaTransactionManager() {
+ setNestedTransactionAllowed(true);
+ }
+
+ /**
+ * Create a new JpaTransactionManager instance.
+ * @param emf EntityManagerFactory to manage transactions for
+ */
+ public JpaTransactionManager(EntityManagerFactory emf) {
+ this();
+ this.entityManagerFactory = emf;
+ afterPropertiesSet();
+ }
+
+
+ /**
+ * Set the EntityManagerFactory that this instance should manage transactions for.
+ */
+ public void setEntityManagerFactory(EntityManagerFactory emf) {
+ this.entityManagerFactory = emf;
+ }
+
+ /**
+ * Return the EntityManagerFactory that this instance should manage transactions for.
+ */
+ public EntityManagerFactory getEntityManagerFactory() {
+ return this.entityManagerFactory;
+ }
+
+ /**
+ * Specify JPA properties, to be passed into
+ * EntityManagerFactory.createEntityManager(Map) (if any).
+ *
Can be populated with a String "value" (parsed via PropertiesEditor)
+ * or a "props" element in XML bean definitions.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public void setJpaProperties(Properties jpaProperties) {
+ CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
+ }
+
+ /**
+ * Specify JPA properties as a Map, to be passed into
+ * EntityManagerFactory.createEntityManager(Map) (if any).
+ *
Can be populated with a "map" or "props" element in XML bean definitions.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
+ */
+ public void setJpaPropertyMap(Map jpaProperties) {
+ if (jpaProperties != null) {
+ this.jpaPropertyMap.putAll(jpaProperties);
+ }
+ }
+
+ /**
+ * Allow Map access to the JPA properties to be passed to the persistence
+ * provider, with the option to add or override specific entries.
+ *
Useful for specifying entries directly, for example via "jpaPropertyMap[myKey]".
+ */
+ public Map getJpaPropertyMap() {
+ return this.jpaPropertyMap;
+ }
+
+ /**
+ * Set the JDBC DataSource that this instance should manage transactions for.
+ * The DataSource should match the one used by the JPA EntityManagerFactory:
+ * for example, you could specify the same JNDI DataSource for both.
+ *
If the EntityManagerFactory uses a known DataSource as connection factory,
+ * the DataSource will be autodetected: You can still explictly specify the
+ * DataSource, but you don't need to in this case.
+ *
A transactional JDBC Connection for this DataSource will be provided to
+ * application code accessing this DataSource directly via DataSourceUtils
+ * or JdbcTemplate. The Connection will be taken from the JPA EntityManager.
+ *
Note that you need to use a JPA dialect for a specific JPA implementation
+ * to allow for exposing JPA transactions as JDBC transactions.
+ *
The DataSource specified here should be the target DataSource to manage
+ * transactions for, not a TransactionAwareDataSourceProxy. Only data access
+ * code may work with TransactionAwareDataSourceProxy, while the transaction
+ * manager needs to work on the underlying target DataSource. If there's
+ * nevertheless a TransactionAwareDataSourceProxy passed in, it will be
+ * unwrapped to extract its target DataSource.
+ * @see EntityManagerFactoryInfo#getDataSource()
+ * @see #setJpaDialect
+ * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
+ * @see org.springframework.jdbc.datasource.DataSourceUtils
+ * @see org.springframework.jdbc.core.JdbcTemplate
+ */
+ public void setDataSource(DataSource dataSource) {
+ if (dataSource instanceof TransactionAwareDataSourceProxy) {
+ // If we got a TransactionAwareDataSourceProxy, we need to perform transactions
+ // for its underlying target DataSource, else data access code won't see
+ // properly exposed transactions (i.e. transactions for the target DataSource).
+ this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
+ }
+ else {
+ this.dataSource = dataSource;
+ }
+ }
+
+ /**
+ * Return the JDBC DataSource that this instance manages transactions for.
+ */
+ public DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * Set the JPA dialect to use for this transaction manager.
+ * Used for vendor-specific transaction management and JDBC connection exposure.
+ *
If the EntityManagerFactory uses a known JpaDialect, it will be autodetected:
+ * You can still explictly specify the DataSource, but you don't need to in this case.
+ *
The dialect object can be used to retrieve the underlying JDBC connection
+ * and thus allows for exposing JPA transactions as JDBC transactions.
+ * @see EntityManagerFactoryInfo#getJpaDialect()
+ * @see JpaDialect#beginTransaction
+ * @see JpaDialect#getJdbcConnection
+ */
+ public void setJpaDialect(JpaDialect jpaDialect) {
+ this.jpaDialect = (jpaDialect != null ? jpaDialect : new DefaultJpaDialect());
+ }
+
+ /**
+ * Return the JPA dialect to use for this transaction manager.
+ */
+ public JpaDialect getJpaDialect() {
+ return this.jpaDialect;
+ }
+
+ /**
+ * Eagerly initialize the JPA dialect, creating a default one
+ * for the specified EntityManagerFactory if none set.
+ * Auto-detect the EntityManagerFactory's DataSource, if any.
+ */
+ public void afterPropertiesSet() {
+ if (getEntityManagerFactory() == null) {
+ throw new IllegalArgumentException("Property 'entityManagerFactory' is required");
+ }
+ if (getEntityManagerFactory() instanceof EntityManagerFactoryInfo) {
+ EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) getEntityManagerFactory();
+ DataSource dataSource = emfInfo.getDataSource();
+ if (dataSource != null) {
+ setDataSource(dataSource);
+ }
+ JpaDialect jpaDialect = emfInfo.getJpaDialect();
+ if (jpaDialect != null) {
+ setJpaDialect(jpaDialect);
+ }
+ }
+ }
+
+
+ public Object getResourceFactory() {
+ return getEntityManagerFactory();
+ }
+
+ protected Object doGetTransaction() {
+ JpaTransactionObject txObject = new JpaTransactionObject();
+ txObject.setSavepointAllowed(isNestedTransactionAllowed());
+
+ EntityManagerHolder emHolder = (EntityManagerHolder)
+ TransactionSynchronizationManager.getResource(getEntityManagerFactory());
+ if (emHolder != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found thread-bound EntityManager [" +
+ emHolder.getEntityManager() + "] for JPA transaction");
+ }
+ txObject.setEntityManagerHolder(emHolder, false);
+ }
+
+ if (getDataSource() != null) {
+ ConnectionHolder conHolder = (ConnectionHolder)
+ TransactionSynchronizationManager.getResource(getDataSource());
+ txObject.setConnectionHolder(conHolder);
+ }
+
+ return txObject;
+ }
+
+ protected boolean isExistingTransaction(Object transaction) {
+ return ((JpaTransactionObject) transaction).hasTransaction();
+ }
+
+ protected void doBegin(Object transaction, TransactionDefinition definition) {
+ JpaTransactionObject txObject = (JpaTransactionObject) transaction;
+
+ if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
+ throw new IllegalTransactionStateException(
+ "Pre-bound JDBC Connection found! JpaTransactionManager does not support " +
+ "running within DataSourceTransactionManager if told to manage the DataSource itself. " +
+ "It is recommended to use a single JpaTransactionManager for all transactions " +
+ "on a single DataSource, no matter whether JPA or JDBC access.");
+ }
+
+ EntityManager em = null;
+
+ try {
+ if (txObject.getEntityManagerHolder() == null ||
+ txObject.getEntityManagerHolder().isSynchronizedWithTransaction()) {
+ EntityManager newEm = createEntityManagerForTransaction();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Opened new EntityManager [" + newEm + "] for JPA transaction");
+ }
+ txObject.setEntityManagerHolder(new EntityManagerHolder(newEm), true);
+ }
+
+ em = txObject.getEntityManagerHolder().getEntityManager();
+
+ // Delegate to JpaDialect for actual transaction begin.
+ Object transactionData = getJpaDialect().beginTransaction(em, definition);
+ txObject.setTransactionData(transactionData);
+
+ // Register transaction timeout.
+ int timeout = determineTimeout(definition);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ txObject.getEntityManagerHolder().setTimeoutInSeconds(timeout);
+ }
+
+ // Register the JPA EntityManager's JDBC Connection for the DataSource, if set.
+ if (getDataSource() != null) {
+ ConnectionHandle conHandle = getJpaDialect().getJdbcConnection(em, definition.isReadOnly());
+ if (conHandle != null) {
+ ConnectionHolder conHolder = new ConnectionHolder(conHandle);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ conHolder.setTimeoutInSeconds(timeout);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Exposing JPA transaction as JDBC transaction [" + conHolder.getConnectionHandle() + "]");
+ }
+ TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
+ txObject.setConnectionHolder(conHolder);
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Not exposing JPA transaction [" + em + "] as JDBC transaction because JpaDialect [" +
+ getJpaDialect() + "] does not support JDBC Connection retrieval");
+ }
+ }
+ }
+
+ // Bind the entity manager holder to the thread.
+ if (txObject.isNewEntityManagerHolder()) {
+ TransactionSynchronizationManager.bindResource(
+ getEntityManagerFactory(), txObject.getEntityManagerHolder());
+ }
+ txObject.getEntityManagerHolder().setSynchronizedWithTransaction(true);
+ }
+
+ catch (TransactionException ex) {
+ closeEntityManagerAfterFailedBegin(txObject);
+ throw ex;
+ }
+ catch (Exception ex) {
+ closeEntityManagerAfterFailedBegin(txObject);
+ throw new CannotCreateTransactionException("Could not open JPA EntityManager for transaction", ex);
+ }
+ }
+
+ /**
+ * Create a JPA EntityManager to be used for a transaction.
+ *
The default implementation checks whether the EntityManagerFactory
+ * is a Spring proxy and unwraps it first.
+ * @see javax.persistence.EntityManagerFactory#createEntityManager()
+ * @see EntityManagerFactoryInfo#getNativeEntityManagerFactory()
+ */
+ protected EntityManager createEntityManagerForTransaction() {
+ EntityManagerFactory emf = getEntityManagerFactory();
+ if (emf instanceof EntityManagerFactoryInfo) {
+ emf = ((EntityManagerFactoryInfo) emf).getNativeEntityManagerFactory();
+ }
+ Map properties = getJpaPropertyMap();
+ return (!CollectionUtils.isEmpty(properties) ?
+ emf.createEntityManager(properties) : emf.createEntityManager());
+ }
+
+ /**
+ * Close the current transaction's EntityManager.
+ * Called after a transaction begin attempt failed.
+ * @param txObject the current transaction
+ */
+ protected void closeEntityManagerAfterFailedBegin(JpaTransactionObject txObject) {
+ if (txObject.isNewEntityManagerHolder()) {
+ EntityManager em = txObject.getEntityManagerHolder().getEntityManager();
+ try {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not rollback EntityManager after failed transaction begin", ex);
+ }
+ finally {
+ EntityManagerFactoryUtils.closeEntityManager(em);
+ }
+ }
+ }
+
+ protected Object doSuspend(Object transaction) {
+ JpaTransactionObject txObject = (JpaTransactionObject) transaction;
+ txObject.setEntityManagerHolder(null, false);
+ EntityManagerHolder entityManagerHolder = (EntityManagerHolder)
+ TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
+ txObject.setConnectionHolder(null);
+ ConnectionHolder connectionHolder = null;
+ if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) {
+ connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
+ }
+ return new SuspendedResourcesHolder(entityManagerHolder, connectionHolder);
+ }
+
+ protected void doResume(Object transaction, Object suspendedResources) {
+ SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
+ TransactionSynchronizationManager.bindResource(
+ getEntityManagerFactory(), resourcesHolder.getEntityManagerHolder());
+ if (getDataSource() != null && resourcesHolder.getConnectionHolder() != null) {
+ TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
+ }
+ }
+
+ /**
+ * This implementation returns "true": a JPA commit will properly handle
+ * transactions that have been marked rollback-only at a global level.
+ */
+ protected boolean shouldCommitOnGlobalRollbackOnly() {
+ return true;
+ }
+
+ protected void doCommit(DefaultTransactionStatus status) {
+ JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Committing JPA transaction on EntityManager [" +
+ txObject.getEntityManagerHolder().getEntityManager() + "]");
+ }
+ try {
+ EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
+ tx.commit();
+ }
+ catch (RollbackException ex) {
+ if (ex.getCause() instanceof RuntimeException) {
+ DataAccessException dex = getJpaDialect().translateExceptionIfPossible((RuntimeException) ex.getCause());
+ if (dex != null) {
+ throw dex;
+ }
+ }
+ throw new TransactionSystemException("Could not commit JPA transaction", ex);
+ }
+ catch (RuntimeException ex) {
+ // Assumably failed to flush changes to database.
+ throw DataAccessUtils.translateIfNecessary(ex, getJpaDialect());
+ }
+ }
+
+ protected void doRollback(DefaultTransactionStatus status) {
+ JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Rolling back JPA transaction on EntityManager [" +
+ txObject.getEntityManagerHolder().getEntityManager() + "]");
+ }
+ try {
+ EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ catch (PersistenceException ex) {
+ throw new TransactionSystemException("Could not roll back JPA transaction", ex);
+ }
+ finally {
+ if (!txObject.isNewEntityManagerHolder()) {
+ // Clear all pending inserts/updates/deletes in the EntityManager.
+ // Necessary for pre-bound EntityManagers, to avoid inconsistent state.
+ txObject.getEntityManagerHolder().getEntityManager().clear();
+ }
+ }
+ }
+
+ protected void doSetRollbackOnly(DefaultTransactionStatus status) {
+ JpaTransactionObject txObject = (JpaTransactionObject) status.getTransaction();
+ if (status.isDebug()) {
+ logger.debug("Setting JPA transaction on EntityManager [" +
+ txObject.getEntityManagerHolder().getEntityManager() + "] rollback-only");
+ }
+ txObject.setRollbackOnly();
+ }
+
+ protected void doCleanupAfterCompletion(Object transaction) {
+ JpaTransactionObject txObject = (JpaTransactionObject) transaction;
+
+ // Remove the entity manager holder from the thread.
+ if (txObject.isNewEntityManagerHolder()) {
+ TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
+ }
+ txObject.getEntityManagerHolder().clear();
+
+ // Remove the JDBC connection holder from the thread, if exposed.
+ if (txObject.hasConnectionHolder()) {
+ TransactionSynchronizationManager.unbindResource(getDataSource());
+ try {
+ getJpaDialect().releaseJdbcConnection(txObject.getConnectionHolder().getConnectionHandle(),
+ txObject.getEntityManagerHolder().getEntityManager());
+ }
+ catch (Exception ex) {
+ // Just log it, to keep a transaction-related exception.
+ logger.error("Could not close JDBC connection after transaction", ex);
+ }
+ }
+
+ getJpaDialect().cleanupTransaction(txObject.getTransactionData());
+
+ // Remove the entity manager holder from the thread.
+ if (txObject.isNewEntityManagerHolder()) {
+ EntityManager em = txObject.getEntityManagerHolder().getEntityManager();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Closing JPA EntityManager [" + em + "] after transaction");
+ }
+ EntityManagerFactoryUtils.closeEntityManager(em);
+ }
+ else {
+ logger.debug("Not closing pre-bound JPA EntityManager after transaction");
+ }
+ }
+
+
+ /**
+ * JPA transaction object, representing a EntityManagerHolder.
+ * Used as transaction object by JpaTransactionManager.
+ */
+ private static class JpaTransactionObject extends JdbcTransactionObjectSupport {
+
+ private EntityManagerHolder entityManagerHolder;
+
+ private boolean newEntityManagerHolder;
+
+ private Object transactionData;
+
+ public void setEntityManagerHolder(
+ EntityManagerHolder entityManagerHolder, boolean newEntityManagerHolder) {
+ this.entityManagerHolder = entityManagerHolder;
+ this.newEntityManagerHolder = newEntityManagerHolder;
+ }
+
+ public EntityManagerHolder getEntityManagerHolder() {
+ return this.entityManagerHolder;
+ }
+
+ public boolean isNewEntityManagerHolder() {
+ return this.newEntityManagerHolder;
+ }
+
+ public boolean hasTransaction() {
+ return (this.entityManagerHolder != null && this.entityManagerHolder.isTransactionActive());
+ }
+
+ public void setTransactionData(Object transactionData) {
+ this.transactionData = transactionData;
+ this.entityManagerHolder.setTransactionActive(true);
+ if (transactionData instanceof SavepointManager) {
+ this.entityManagerHolder.setSavepointManager((SavepointManager) transactionData);
+ }
+ }
+
+ public Object getTransactionData() {
+ return this.transactionData;
+ }
+
+ public void setRollbackOnly() {
+ EntityTransaction tx = this.entityManagerHolder.getEntityManager().getTransaction();
+ if (tx.isActive()) {
+ tx.setRollbackOnly();
+ }
+ if (hasConnectionHolder()) {
+ getConnectionHolder().setRollbackOnly();
+ }
+ }
+
+ public boolean isRollbackOnly() {
+ EntityTransaction tx = this.entityManagerHolder.getEntityManager().getTransaction();
+ return tx.getRollbackOnly();
+ }
+
+ public Object createSavepoint() throws TransactionException {
+ return getSavepointManager().createSavepoint();
+ }
+
+ public void rollbackToSavepoint(Object savepoint) throws TransactionException {
+ getSavepointManager().rollbackToSavepoint(savepoint);
+ }
+
+ public void releaseSavepoint(Object savepoint) throws TransactionException {
+ getSavepointManager().releaseSavepoint(savepoint);
+ }
+
+ private SavepointManager getSavepointManager() {
+ if (!isSavepointAllowed()) {
+ throw new NestedTransactionNotSupportedException(
+ "Transaction manager does not allow nested transactions");
+ }
+ SavepointManager savepointManager = getEntityManagerHolder().getSavepointManager();
+ if (savepointManager == null) {
+ throw new NestedTransactionNotSupportedException(
+ "JpaDialect does not support savepoints - check your JPA provider's capabilities");
+ }
+ return savepointManager;
+ }
+ }
+
+
+ /**
+ * Holder for suspended resources.
+ * Used internally by doSuspend and doResume.
+ */
+ private static class SuspendedResourcesHolder {
+
+ private final EntityManagerHolder entityManagerHolder;
+
+ private final ConnectionHolder connectionHolder;
+
+ private SuspendedResourcesHolder(EntityManagerHolder emHolder, ConnectionHolder conHolder) {
+ this.entityManagerHolder = emHolder;
+ this.connectionHolder = conHolder;
+ }
+
+ private EntityManagerHolder getEntityManagerHolder() {
+ return this.entityManagerHolder;
+ }
+
+ private ConnectionHolder getConnectionHolder() {
+ return this.connectionHolder;
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/JpaVendorAdapter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/JpaVendorAdapter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/JpaVendorAdapter.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceProvider;
+
+/**
+ * SPI interface that allows to plug in vendor-specific behavior
+ * into Spring's EntityManagerFactory creators. Serves as single
+ * configuration point for all vendor-specific properties.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see AbstractEntityManagerFactoryBean#setJpaVendorAdapter
+ */
+public interface JpaVendorAdapter {
+
+ /**
+ * Return the vendor-specific persistence provider.
+ */
+ PersistenceProvider getPersistenceProvider();
+
+ /**
+ * Return the name of the persistence provider's root package
+ * (e.g. "oracle.toplink.essentials"). Will be used for
+ * excluding provider classes from temporary class overriding.
+ * @since 2.5.2
+ */
+ String getPersistenceProviderRootPackage();
+
+ /**
+ * Return a Map of vendor-specific JPA properties,
+ * typically based on settings in this JpaVendorAdapter instance.
+ *
Note that there might be further JPA properties defined on
+ * the EntityManagerFactory bean, which might potentially override
+ * individual JPA property values specified here.
+ * @return a Map of JPA properties, as as accepted by the standard
+ * JPA bootstrap facilities, or null or an empty Map
+ * if there are no such properties to expose
+ * @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
+ * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
+ */
+ Map getJpaPropertyMap();
+
+ /**
+ * Return the vendor-specific JpaDialect implementation for this
+ * provider, or null if there is none.
+ */
+ JpaDialect getJpaDialect();
+
+ /**
+ * Return the vendor-specific EntityManagerFactory interface
+ * that the EntityManagerFactory proxy is supposed to implement.
+ *
If the provider does not offer any EntityManagerFactory extensions,
+ * the adapter should simply return the standard
+ * {@link javax.persistence.EntityManagerFactory} class here.
+ * @since 2.5.2
+ */
+ Class extends EntityManagerFactory> getEntityManagerFactoryInterface();
+
+ /**
+ * Return the vendor-specific EntityManager interface
+ * that this provider's EntityManagers will implement.
+ *
If the provider does not offer any EntityManager extensions,
+ * the adapter should simply return the standard
+ * {@link javax.persistence.EntityManager} class here.
+ */
+ Class extends EntityManager> getEntityManagerInterface();
+
+ /**
+ * Optional callback for post-processing the native EntityManagerFactory
+ * before active use.
+ *
This can be used for triggering vendor-specific initialization processes.
+ * While this is not expected to be used for most providers, it is included
+ * here as a general extension hook.
+ */
+ void postProcessEntityManagerFactory(EntityManagerFactory emf);
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.sql.DataSource;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.context.weaving.LoadTimeWeaverAware;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.instrument.classloading.LoadTimeWeaver;
+import org.springframework.jdbc.datasource.lookup.SingleDataSourceLookup;
+import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
+import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
+import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
+import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
+import org.springframework.util.ClassUtils;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that creates a JPA
+ * {@link javax.persistence.EntityManagerFactory} according to JPA's standard
+ * container bootstrap contract. This is the most powerful way to set
+ * up a shared JPA EntityManagerFactory in a Spring application context;
+ * the EntityManagerFactory can then be passed to JPA-based DAOs via
+ * dependency injection. Note that switching to a JNDI lookup or to a
+ * {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean}
+ * definition is just a matter of configuration!
+ *
+ *
As with {@link LocalEntityManagerFactoryBean}, configuration settings
+ * are usually read in from a META-INF/persistence.xml config file,
+ * residing in the class path, according to the general JPA configuration contract.
+ * However, this FactoryBean is more flexible in that you can override the location
+ * of the persistence.xml file, specify the JDBC DataSources to link to,
+ * etc. Furthermore, it allows for pluggable class instrumentation through Spring's
+ * {@link org.springframework.instrument.classloading.LoadTimeWeaver} abstraction,
+ * instead of being tied to a special VM agent specified on JVM startup.
+ *
+ *
Internally, this FactoryBean parses the persistence.xml file
+ * itself and creates a corresponding {@link javax.persistence.spi.PersistenceUnitInfo}
+ * object (with further configuration merged in, such as JDBC DataSources and the
+ * Spring LoadTimeWeaver), to be passed to the chosen JPA
+ * {@link javax.persistence.spi.PersistenceProvider}. This corresponds to a
+ * local JPA container with full support for the standard JPA container contract.
+ *
+ *
The exposed EntityManagerFactory object will implement all the interfaces of
+ * the underlying native EntityManagerFactory returned by the PersistenceProvider,
+ * plus the {@link EntityManagerFactoryInfo} interface which exposes additional
+ * metadata as assembled by this FactoryBean.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see #setPersistenceXmlLocation
+ * @see #setJpaProperties
+ * @see #setJpaVendorAdapter
+ * @see #setLoadTimeWeaver
+ * @see #setDataSource
+ * @see EntityManagerFactoryInfo
+ * @see LocalEntityManagerFactoryBean
+ * @see org.springframework.orm.jpa.support.SharedEntityManagerBean
+ * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory
+ */
+public class LocalContainerEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean
+ implements ResourceLoaderAware, LoadTimeWeaverAware {
+
+ private PersistenceUnitManager persistenceUnitManager;
+
+ private final DefaultPersistenceUnitManager internalPersistenceUnitManager =
+ new DefaultPersistenceUnitManager();
+
+ private PersistenceUnitInfo persistenceUnitInfo;
+
+
+ /**
+ * Set the PersistenceUnitManager to use for obtaining the JPA persistence unit
+ * that this FactoryBean is supposed to build an EntityManagerFactory for.
+ *
The default is to rely on the local settings specified on this FactoryBean,
+ * such as "persistenceXmlLocation", "dataSource" and "loadTimeWeaver".
+ *
For reuse of existing persistence unit configuration or more advanced forms
+ * of custom persistence unit handling, consider defining a separate
+ * PersistenceUnitManager bean (typically a DefaultPersistenceUnitManager instance)
+ * and linking it in here. persistence.xml location, DataSource
+ * configuration and LoadTimeWeaver will be defined on that separate
+ * DefaultPersistenceUnitManager bean in such a scenario.
+ * @see #setPersistenceXmlLocation
+ * @see #setDataSource
+ * @see #setLoadTimeWeaver
+ * @see org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager
+ */
+ public void setPersistenceUnitManager(PersistenceUnitManager persistenceUnitManager) {
+ this.persistenceUnitManager = persistenceUnitManager;
+ }
+
+ /**
+ * Set the location of the persistence.xml file
+ * we want to use. This is a Spring resource location.
+ *
Default is "classpath:META-INF/persistence.xml".
+ *
NOTE: Only applied if no external PersistenceUnitManager specified.
+ * @param persistenceXmlLocation a Spring resource String
+ * identifying the location of the persistence.xml file
+ * that this LocalContainerEntityManagerFactoryBean should parse
+ * @see #setPersistenceUnitManager
+ */
+ public void setPersistenceXmlLocation(String persistenceXmlLocation) {
+ this.internalPersistenceUnitManager.setPersistenceXmlLocations(new String[] {persistenceXmlLocation});
+ }
+
+ /**
+ * Specify the JDBC DataSource that the JPA persistence provider is supposed
+ * to use for accessing the database. This is an alternative to keeping the
+ * JDBC configuration in persistence.xml, passing in a Spring-managed
+ * DataSource instead.
+ *
In JPA speak, a DataSource passed in here will be used as "nonJtaDataSource"
+ * on the PersistenceUnitInfo passed to the PersistenceProvider, overriding
+ * data source configuration in persistence.xml (if any).
+ *
NOTE: Only applied if no external PersistenceUnitManager specified.
+ * @see javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource()
+ * @see #setPersistenceUnitManager
+ */
+ public void setDataSource(DataSource dataSource) {
+ this.internalPersistenceUnitManager.setDataSourceLookup(new SingleDataSourceLookup(dataSource));
+ this.internalPersistenceUnitManager.setDefaultDataSource(dataSource);
+ }
+
+ /**
+ * Set the PersistenceUnitPostProcessors to be applied to the
+ * PersistenceUnitInfo used for creating this EntityManagerFactory.
+ *
Such post-processors can, for example, register further entity
+ * classes and jar files, in addition to the metadata read in from
+ * persistence.xml.
+ *
NOTE: Only applied if no external PersistenceUnitManager specified.
+ * @see #setPersistenceUnitManager
+ */
+ public void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor[] postProcessors) {
+ this.internalPersistenceUnitManager.setPersistenceUnitPostProcessors(postProcessors);
+ }
+
+ /**
+ * Specify the Spring LoadTimeWeaver to use for class instrumentation according
+ * to the JPA class transformer contract.
+ *
It is a not required to specify a LoadTimeWeaver: Most providers will be
+ * able to provide a subset of their functionality without class instrumentation
+ * as well, or operate with their VM agent specified on JVM startup.
+ *
In terms of Spring-provided weaving options, the most important ones are
+ * InstrumentationLoadTimeWeaver, which requires a Spring-specific (but very general)
+ * VM agent specified on JVM startup, and ReflectiveLoadTimeWeaver, which interacts
+ * with an underlying ClassLoader based on specific extended methods being available
+ * on it (for example, interacting with Spring's TomcatInstrumentableClassLoader).
+ *
NOTE: As of Spring 2.5, the context's default LoadTimeWeaver (defined
+ * as bean with name "loadTimeWeaver") will be picked up automatically, if available,
+ * removing the need for LoadTimeWeaver configuration on each affected target bean.
+ * Consider using the context:load-time-weaver XML tag for creating
+ * such a shared LoadTimeWeaver (autodetecting the environment by default).
+ *
NOTE: Only applied if no external PersistenceUnitManager specified.
+ * Otherwise, the external {@link #setPersistenceUnitManager PersistenceUnitManager}
+ * is responsible for the weaving configuration.
+ * @see org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver
+ * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
+ * @see org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader
+ */
+ public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
+ this.internalPersistenceUnitManager.setLoadTimeWeaver(loadTimeWeaver);
+ }
+
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.internalPersistenceUnitManager.setResourceLoader(resourceLoader);
+ }
+
+
+ @Override
+ protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
+ PersistenceUnitManager managerToUse = this.persistenceUnitManager;
+ if (this.persistenceUnitManager == null) {
+ this.internalPersistenceUnitManager.afterPropertiesSet();
+ managerToUse = this.internalPersistenceUnitManager;
+ }
+
+ this.persistenceUnitInfo = determinePersistenceUnitInfo(managerToUse);
+ JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
+ if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof MutablePersistenceUnitInfo) {
+ ((MutablePersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName(
+ jpaVendorAdapter.getPersistenceProviderRootPackage());
+ }
+
+ PersistenceProvider provider = getPersistenceProvider();
+ if (provider == null) {
+ String providerClassName = this.persistenceUnitInfo.getPersistenceProviderClassName();
+ if (providerClassName == null) {
+ throw new IllegalArgumentException(
+ "No PersistenceProvider specified in EntityManagerFactory configuration, " +
+ "and chosen PersistenceUnitInfo does not specify a provider class name either");
+ }
+ Class providerClass = ClassUtils.resolveClassName(providerClassName, getBeanClassLoader());
+ provider = (PersistenceProvider) BeanUtils.instantiateClass(providerClass);
+ }
+ if (provider == null) {
+ throw new IllegalStateException("Unable to determine persistence provider. " +
+ "Please check configuration of " + getClass().getName() + "; " +
+ "ideally specify the appropriate JpaVendorAdapter class for this provider.");
+ }
+
+ if (logger.isInfoEnabled()) {
+ logger.info("Building JPA container EntityManagerFactory for persistence unit '" +
+ this.persistenceUnitInfo.getPersistenceUnitName() + "'");
+ }
+ this.nativeEntityManagerFactory =
+ provider.createContainerEntityManagerFactory(this.persistenceUnitInfo, getJpaPropertyMap());
+ postProcessEntityManagerFactory(this.nativeEntityManagerFactory, this.persistenceUnitInfo);
+
+ return this.nativeEntityManagerFactory;
+ }
+
+
+ /**
+ * Determine the PersistenceUnitInfo to use for the EntityManagerFactory
+ * created by this bean.
+ *
The default implementation reads in all persistence unit infos from
+ * persistence.xml, as defined in the JPA specification.
+ * If no entity manager name was specified, it takes the first info in the
+ * array as returned by the reader. Otherwise, it checks for a matching name.
+ * @param persistenceUnitManager the PersistenceUnitManager to obtain from
+ * @return the chosen PersistenceUnitInfo
+ */
+ protected PersistenceUnitInfo determinePersistenceUnitInfo(PersistenceUnitManager persistenceUnitManager) {
+ if (getPersistenceUnitName() != null) {
+ return persistenceUnitManager.obtainPersistenceUnitInfo(getPersistenceUnitName());
+ }
+ else {
+ return persistenceUnitManager.obtainDefaultPersistenceUnitInfo();
+ }
+ }
+
+ /**
+ * Hook method allowing subclasses to customize the EntityManagerFactory
+ * after its creation via the PersistenceProvider.
+ *
The default implementation is empty.
+ * @param emf the newly created EntityManagerFactory we are working with
+ * @param pui the PersistenceUnitInfo used to configure the EntityManagerFactory
+ * @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory
+ */
+ protected void postProcessEntityManagerFactory(EntityManagerFactory emf, PersistenceUnitInfo pui) {
+ }
+
+
+ public PersistenceUnitInfo getPersistenceUnitInfo() {
+ return this.persistenceUnitInfo;
+ }
+
+ public String getPersistenceUnitName() {
+ if (this.persistenceUnitInfo != null) {
+ return this.persistenceUnitInfo.getPersistenceUnitName();
+ }
+ return super.getPersistenceUnitName();
+ }
+
+ public DataSource getDataSource() {
+ if (this.persistenceUnitInfo != null) {
+ return this.persistenceUnitInfo.getNonJtaDataSource();
+ }
+ return this.internalPersistenceUnitManager.getDefaultDataSource();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceProvider;
+
+/**
+ * {@link org.springframework.beans.factory.FactoryBean} that creates a JPA
+ * {@link javax.persistence.EntityManagerFactory} according to JPA's standard
+ * standalone bootstrap contract. This is the simplest way to set up a
+ * shared JPA EntityManagerFactory in a Spring application context; the
+ * EntityManagerFactory can then be passed to JPA-based DAOs via
+ * dependency injection. Note that switching to a JNDI lookup or to a
+ * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
+ * definition is just a matter of configuration!
+ *
+ *
Configuration settings are usually read from a META-INF/persistence.xml
+ * config file, residing in the class path, according to the JPA standalone bootstrap
+ * contract. Additionally, most JPA providers will require a special VM agent
+ * (specified on JVM startup) that allows them to instrument application classes.
+ * See the Java Persistence API specification and your provider documentation
+ * for setup details.
+ *
+ *
This EntityManagerFactory bootstrap is appropriate for standalone applications
+ * which solely use JPA for data access. If you want to set up your persistence
+ * provider for an external DataSource and/or for global transactions which span
+ * multiple resources, you will need to either deploy it into a full Java EE 5
+ * application server and access the deployed EntityManagerFactory via JNDI,
+ * or use Spring's {@link LocalContainerEntityManagerFactoryBean} with appropriate
+ * configuration for local setup according to JPA's container contract.
+ *
+ *
Note: This FactoryBean has limited configuration power in terms of
+ * what configuration it is able to pass to the JPA provider. If you need more
+ * flexible configuration, for example passing a Spring-managed JDBC DataSource
+ * to the JPA provider, consider using Spring's more powerful
+ * {@link LocalContainerEntityManagerFactoryBean} instead.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see #setJpaProperties
+ * @see #setJpaVendorAdapter
+ * @see JpaTemplate#setEntityManagerFactory
+ * @see JpaTransactionManager#setEntityManagerFactory
+ * @see LocalContainerEntityManagerFactoryBean
+ * @see org.springframework.jndi.JndiObjectFactoryBean
+ * @see org.springframework.orm.jpa.support.SharedEntityManagerBean
+ * @see javax.persistence.Persistence#createEntityManagerFactory
+ * @see javax.persistence.spi.PersistenceProvider#createEntityManagerFactory
+ */
+public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean {
+
+ /**
+ * Initialize the EntityManagerFactory for the given configuration.
+ * @throws javax.persistence.PersistenceException in case of JPA initialization errors
+ */
+ protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
+ if (logger.isInfoEnabled()) {
+ logger.info("Building JPA EntityManagerFactory for persistence unit '" + getPersistenceUnitName() + "'");
+ }
+ PersistenceProvider provider = getPersistenceProvider();
+ if (provider != null) {
+ // Create EntityManagerFactory directly through PersistenceProvider.
+ EntityManagerFactory emf = provider.createEntityManagerFactory(getPersistenceUnitName(), getJpaPropertyMap());
+ if (emf == null) {
+ throw new IllegalStateException(
+ "PersistenceProvider [" + provider + "] did not return an EntityManagerFactory for name '" +
+ getPersistenceUnitName() + "'");
+ }
+ return emf;
+ }
+ else {
+ // Let JPA perform its standard PersistenceProvider autodetection.
+ return Persistence.createEntityManagerFactory(getPersistenceUnitName(), getJpaPropertyMap());
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/SharedEntityManagerCreator.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/SharedEntityManagerCreator.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/SharedEntityManagerCreator.java 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Query;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Factory for a shareable JPA {@link javax.persistence.EntityManager}
+ * for a given {@link javax.persistence.EntityManagerFactory}.
+ *
+ *
The shareable EntityManager will behave just like an EntityManager fetched
+ * from an application server's JNDI environment, as defined by the JPA
+ * specification. It will delegate all calls to the current transactional
+ * EntityManager, if any; otherwise it will fall back to a newly created
+ * EntityManager per operation.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean
+ * @see org.springframework.orm.jpa.JpaTransactionManager
+ */
+public abstract class SharedEntityManagerCreator {
+
+ /**
+ * Create a transactional EntityManager proxy for the given EntityManagerFactory.
+ * @param emf the EntityManagerFactory to delegate to.
+ * If this implements the {@link EntityManagerFactoryInfo} interface,
+ * appropriate handling of the native EntityManagerFactory and available
+ * {@link EntityManagerPlusOperations} will automatically apply.
+ * @return a shareable transaction EntityManager proxy
+ */
+ public static EntityManager createSharedEntityManager(EntityManagerFactory emf) {
+ return createSharedEntityManager(emf, null);
+ }
+
+ /**
+ * Create a transactional EntityManager proxy for the given EntityManagerFactory.
+ * @param emf the EntityManagerFactory to delegate to.
+ * If this implements the {@link EntityManagerFactoryInfo} interface,
+ * appropriate handling of the native EntityManagerFactory and available
+ * {@link EntityManagerPlusOperations} will automatically apply.
+ * @param properties the properties to be passed into the
+ * createEntityManager call (may be null)
+ * @return a shareable transaction EntityManager proxy
+ */
+ public static EntityManager createSharedEntityManager(EntityManagerFactory emf, Map properties) {
+ Class[] emIfcs = null;
+ if (emf instanceof EntityManagerFactoryInfo) {
+ EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
+ Class emIfc = emfInfo.getEntityManagerInterface();
+ if (emIfc == null) {
+ emIfc = EntityManager.class;
+ }
+ JpaDialect jpaDialect = emfInfo.getJpaDialect();
+ if (jpaDialect != null && jpaDialect.supportsEntityManagerPlusOperations()) {
+ emIfcs = new Class[] {emIfc, EntityManagerPlus.class};
+ }
+ else {
+ emIfcs = new Class[] {emIfc};
+ }
+ }
+ else {
+ emIfcs = new Class[] {EntityManager.class};
+ }
+ return createSharedEntityManager(emf, properties, emIfcs);
+ }
+
+ /**
+ * Create a transactional EntityManager proxy for the given EntityManagerFactory.
+ * @param emf EntityManagerFactory to obtain EntityManagers from as needed
+ * @param properties the properties to be passed into the
+ * createEntityManager call (may be null)
+ * @param entityManagerInterfaces the interfaces to be implemented by the
+ * EntityManager. Allows the addition or specification of proprietary interfaces.
+ * @return a shareable transactional EntityManager proxy
+ */
+ public static EntityManager createSharedEntityManager(
+ EntityManagerFactory emf, Map properties, Class... entityManagerInterfaces) {
+
+ ClassLoader cl = null;
+ if (emf instanceof EntityManagerFactoryInfo) {
+ cl = ((EntityManagerFactoryInfo) emf).getBeanClassLoader();
+ }
+ Class[] ifcs = new Class[entityManagerInterfaces.length + 1];
+ System.arraycopy(entityManagerInterfaces, 0, ifcs, 0, entityManagerInterfaces.length);
+ ifcs[entityManagerInterfaces.length] = EntityManagerProxy.class;
+ return (EntityManager) Proxy.newProxyInstance(
+ (cl != null ? cl : SharedEntityManagerCreator.class.getClassLoader()),
+ ifcs, new SharedEntityManagerInvocationHandler(emf, properties));
+ }
+
+
+ /**
+ * Invocation handler that delegates all calls to the current
+ * transactional EntityManager, if any; else, it will fall back
+ * to a newly created EntityManager per operation.
+ */
+ private static class SharedEntityManagerInvocationHandler implements InvocationHandler {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final EntityManagerFactory targetFactory;
+
+ private final Map properties;
+
+ public SharedEntityManagerInvocationHandler(EntityManagerFactory target, Map properties) {
+ this.targetFactory = target;
+ this.properties = properties;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on EntityManager interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0]);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of EntityManager proxy.
+ return hashCode();
+ }
+ else if (method.getName().equals("toString")) {
+ // Deliver toString without touching a target EntityManager.
+ return "Shared EntityManager proxy for target factory [" + this.targetFactory + "]";
+ }
+ else if (method.getName().equals("isOpen")) {
+ // Handle isOpen method: always return true.
+ return true;
+ }
+ else if (method.getName().equals("close")) {
+ // Handle close method: suppress, not valid.
+ return null;
+ }
+ else if (method.getName().equals("getTransaction")) {
+ throw new IllegalStateException(
+ "Not allowed to create transaction on shared EntityManager - " +
+ "use Spring transactions or EJB CMT instead");
+ }
+ else if (method.getName().equals("joinTransaction")) {
+ throw new IllegalStateException(
+ "Not allowed to join transaction on shared EntityManager - " +
+ "use Spring transactions or EJB CMT instead");
+ }
+
+ // Determine current EntityManager: either the transactional one
+ // managed by the factory or a temporary one for the given invocation.
+ EntityManager target =
+ EntityManagerFactoryUtils.doGetTransactionalEntityManager(this.targetFactory, this.properties);
+
+ // Handle EntityManagerProxy interface.
+ if (method.getName().equals("getTargetEntityManager")) {
+ if (target == null) {
+ throw new IllegalStateException("No transactional EntityManager available");
+ }
+ return target;
+ }
+
+ // Regular EntityManager operations.
+ boolean isNewEm = false;
+ if (target == null) {
+ logger.debug("Creating new EntityManager for shared EntityManager invocation");
+ target = (!CollectionUtils.isEmpty(this.properties) ?
+ this.targetFactory.createEntityManager(this.properties) :
+ this.targetFactory.createEntityManager());
+ isNewEm = true;
+ }
+
+ // Invoke method on current EntityManager.
+ try {
+ Object result = method.invoke(target, args);
+ if (isNewEm && result instanceof Query) {
+ result = Proxy.newProxyInstance(Query.class.getClassLoader(), new Class[] {Query.class},
+ new DeferredQueryInvocationHandler((Query) result, target));
+ isNewEm = false;
+ }
+ return result;
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ finally {
+ if (isNewEm) {
+ EntityManagerFactoryUtils.closeEntityManager(target);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Invocation handler that handles deferred Query objects created by
+ * non-transactional createQuery invocations on a shared EntityManager.
+ */
+ private static class DeferredQueryInvocationHandler implements InvocationHandler {
+
+ private final Query target;
+
+ private final EntityManager em;
+
+ private DeferredQueryInvocationHandler(Query target, EntityManager em) {
+ this.target = target;
+ this.em = em;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // Invocation on Query interface coming in...
+
+ if (method.getName().equals("equals")) {
+ // Only consider equal when proxies are identical.
+ return (proxy == args[0]);
+ }
+ else if (method.getName().equals("hashCode")) {
+ // Use hashCode of EntityManager proxy.
+ return hashCode();
+ }
+
+ // Invoke method on actual Query object.
+ try {
+ return method.invoke(this.target, args);
+ }
+ catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ finally {
+ if (method.getName().equals("getResultList") || method.getName().equals("getSingleResult") ||
+ method.getName().equals("executeUpdate")) {
+ EntityManagerFactoryUtils.closeEntityManager(this.em);
+ }
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/package.html 17 Aug 2012 15:16:12 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
+Package providing integration of JPA (Java Persistence API) with Spring concepts.
+Contains EntityManagerFactory helper classes, a template plus callback for JPA access,
+and an implementation of Spring's transaction SPI for local JPA transactions.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/ClassFileTransformerAdapter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/ClassFileTransformerAdapter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/ClassFileTransformerAdapter.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa.persistenceunit;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.security.ProtectionDomain;
+
+import javax.persistence.spi.ClassTransformer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.util.Assert;
+
+/**
+ * Simple adapter that implements the java.lang.instrument.ClassFileTransformer
+ * interface based on a JPA ClassTransformer which a JPA PersistenceProvider asks the
+ * PersistenceUnitInfo to install in the current runtime.
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see javax.persistence.spi.PersistenceUnitInfo#addTransformer(javax.persistence.spi.ClassTransformer)
+ */
+class ClassFileTransformerAdapter implements ClassFileTransformer {
+
+ private static final Log logger = LogFactory.getLog(ClassFileTransformerAdapter.class);
+
+ private final ClassTransformer classTransformer;
+
+
+ public ClassFileTransformerAdapter(ClassTransformer classTransformer) {
+ Assert.notNull(classTransformer, "ClassTransformer must not be null");
+ this.classTransformer = classTransformer;
+ }
+
+
+ public byte[] transform(
+ ClassLoader loader, String className, Class> classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer) {
+
+ try {
+ byte[] transformed = this.classTransformer.transform(
+ loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
+ if (transformed != null && logger.isDebugEnabled()) {
+ logger.debug("Transformer of class [" + this.classTransformer.getClass().getName() +
+ "] transformed class [" + className + "]; bytes in=" +
+ classfileBuffer.length + "; bytes out=" + transformed.length);
+ }
+ return transformed;
+ }
+ catch (ClassCircularityError ex) {
+ logger.error("Error weaving class [" + className + "] with " +
+ "transformer of class [" + this.classTransformer.getClass().getName() + "]", ex);
+ throw new IllegalStateException("Could not weave class [" + className + "]", ex);
+ }
+ catch (Throwable ex) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Error weaving class [" + className + "] with " +
+ "transformer of class [" + this.classTransformer.getClass().getName() + "]", ex);
+ }
+ // The exception will be ignored by the class loader, anyway...
+ throw new IllegalStateException("Could not weave class [" + className + "]", ex);
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return "Standard ClassFileTransformer wrapping JPA transformer: " + this.classTransformer;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.persistenceunit;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.PersistenceException;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.context.weaving.LoadTimeWeaverAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternUtils;
+import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
+import org.springframework.instrument.classloading.LoadTimeWeaver;
+import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
+import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
+import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Default implementation of the {@link PersistenceUnitManager} interface.
+ * Used as internal default by
+ * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}.
+ *
+ *
Supports standard JPA scanning for persistence.xml files,
+ * with configurable file locations, JDBC DataSource lookup and load-time weaving.
+ *
+ *
The default XML file location is classpath*:META-INF/persistence.xml,
+ * scanning for all matching files in the class path (as defined in the JPA specification).
+ * DataSource names are by default interpreted as JNDI names, and no load time weaving
+ * is available (which requires weaving to be turned off in the persistence provider).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setPersistenceXmlLocations
+ * @see #setDataSourceLookup
+ * @see #setLoadTimeWeaver
+ * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPersistenceUnitManager
+ */
+public class DefaultPersistenceUnitManager
+ implements PersistenceUnitManager, ResourceLoaderAware, LoadTimeWeaverAware, InitializingBean {
+
+ /**
+ * Default location of the persistence.xml file:
+ * "classpath*:META-INF/persistence.xml".
+ */
+ public final static String DEFAULT_PERSISTENCE_XML_LOCATION = "classpath*:META-INF/persistence.xml";
+
+ /**
+ * Default location for the persistence unit root URL:
+ * "classpath:", indicating the root of the class path.
+ */
+ public final static String ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION = "classpath:";
+
+
+ /** Location of persistence.xml file(s) */
+ private String[] persistenceXmlLocations = new String[] {DEFAULT_PERSISTENCE_XML_LOCATION};
+
+ private String defaultPersistenceUnitRootLocation = ORIGINAL_DEFAULT_PERSISTENCE_UNIT_ROOT_LOCATION;
+
+ private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
+
+ private DataSource defaultDataSource;
+
+ private PersistenceUnitPostProcessor[] persistenceUnitPostProcessors;
+
+ private LoadTimeWeaver loadTimeWeaver;
+
+ private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+
+ private final Set persistenceUnitInfoNames = new HashSet();
+
+ private final Map persistenceUnitInfos =
+ new HashMap();
+
+
+ /**
+ * Specify the location of the persistence.xml files to load.
+ * These can be specified as Spring resource locations and/or location patterns.
+ *
Default is "classpath*:META-INF/persistence.xml".
+ */
+ public void setPersistenceXmlLocation(String persistenceXmlLocation) {
+ this.persistenceXmlLocations = new String[] {persistenceXmlLocation};
+ }
+
+ /**
+ * Specify multiple locations of persistence.xml files to load.
+ * These can be specified as Spring resource locations and/or location patterns.
+ *
Default is "classpath*:META-INF/persistence.xml".
+ * @param persistenceXmlLocations an array of Spring resource Strings
+ * identifying the location of the persistence.xml files to read
+ */
+ public void setPersistenceXmlLocations(String[] persistenceXmlLocations) {
+ this.persistenceXmlLocations = persistenceXmlLocations;
+ }
+
+ /**
+ * Set the default persistence unit root location, to be applied
+ * if no unit-specific persistence unit root could be determined.
+ *
Default is "classpath:", that is, the root of the current class path
+ * (nearest root directory). To be overridden if unit-specific resolution
+ * does not work and the class path root is not appropriate either.
+ */
+ public void setDefaultPersistenceUnitRootLocation(String defaultPersistenceUnitRootLocation) {
+ this.defaultPersistenceUnitRootLocation = defaultPersistenceUnitRootLocation;
+ }
+
+ /**
+ * Specify the JDBC DataSources that the JPA persistence provider is supposed
+ * to use for accessing the database, resolving data source names in
+ * persistence.xml against Spring-managed DataSources.
+ *
The specified Map needs to define data source names for specific DataSource
+ * objects, matching the data source names used in persistence.xml.
+ * If not specified, data source names will be resolved as JNDI names instead
+ * (as defined by standard JPA).
+ * @see org.springframework.jdbc.datasource.lookup.MapDataSourceLookup
+ */
+ public void setDataSources(Map dataSources) {
+ this.dataSourceLookup = new MapDataSourceLookup(dataSources);
+ }
+
+ /**
+ * Specify the JDBC DataSourceLookup that provides DataSources for the
+ * persistence provider, resolving data source names in persistence.xml
+ * against Spring-managed DataSource instances.
+ *
Default is JndiDataSourceLookup, which resolves DataSource names as
+ * JNDI names (as defined by standard JPA). Specify a BeanFactoryDataSourceLookup
+ * instance if you want DataSource names to be resolved against Spring bean names.
+ *
Alternatively, consider passing in a map from names to DataSource instances
+ * via the "dataSources" property. If the persistence.xml file
+ * does not define DataSource names at all, specify a default DataSource
+ * via the "defaultDataSource" property.
+ * @see org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup
+ * @see org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup
+ * @see #setDataSources
+ * @see #setDefaultDataSource
+ */
+ public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
+ this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
+ }
+
+ /**
+ * Return the JDBC DataSourceLookup that provides DataSources for the
+ * persistence provider, resolving data source names in persistence.xml
+ * against Spring-managed DataSource instances.
+ */
+ public DataSourceLookup getDataSourceLookup() {
+ return this.dataSourceLookup;
+ }
+
+ /**
+ * Specify the JDBC DataSource that the JPA persistence provider is supposed
+ * to use for accessing the database if none has been specified in
+ * persistence.xml.
+ *
In JPA speak, a DataSource passed in here will be uses as "nonJtaDataSource"
+ * on the PersistenceUnitInfo passed to the PersistenceProvider, provided that
+ * none has been registered before.
+ * @see javax.persistence.spi.PersistenceUnitInfo#getNonJtaDataSource()
+ */
+ public void setDefaultDataSource(DataSource defaultDataSource) {
+ this.defaultDataSource = defaultDataSource;
+ }
+
+ /**
+ * Return the JDBC DataSource that the JPA persistence provider is supposed
+ * to use for accessing the database if none has been specified in
+ * persistence.xml.
+ */
+ public DataSource getDefaultDataSource() {
+ return this.defaultDataSource;
+ }
+
+ /**
+ * Set the PersistenceUnitPostProcessors to be applied to each
+ * PersistenceUnitInfo that has been parsed by this manager.
+ *
Such post-processors can, for example, register further entity
+ * classes and jar files, in addition to the metadata read in from
+ * persistence.xml.
+ */
+ public void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor[] postProcessors) {
+ this.persistenceUnitPostProcessors = postProcessors;
+ }
+
+ /**
+ * Return the PersistenceUnitPostProcessors to be applied to each
+ * PersistenceUnitInfo that has been parsed by this manager.
+ */
+ public PersistenceUnitPostProcessor[] getPersistenceUnitPostProcessors() {
+ return this.persistenceUnitPostProcessors;
+ }
+
+ /**
+ * Specify the Spring LoadTimeWeaver to use for class instrumentation according
+ * to the JPA class transformer contract.
+ *
It is not required to specify a LoadTimeWeaver: Most providers will be
+ * able to provide a subset of their functionality without class instrumentation
+ * as well, or operate with their VM agent specified on JVM startup.
+ *
In terms of Spring-provided weaving options, the most important ones are
+ * InstrumentationLoadTimeWeaver, which requires a Spring-specific (but very general)
+ * VM agent specified on JVM startup, and ReflectiveLoadTimeWeaver, which interacts
+ * with an underlying ClassLoader based on specific extended methods being available
+ * on it (for example, interacting with Spring's TomcatInstrumentableClassLoader).
+ *
NOTE: As of Spring 2.5, the context's default LoadTimeWeaver (defined
+ * as bean with name "loadTimeWeaver") will be picked up automatically, if available,
+ * removing the need for LoadTimeWeaver configuration on each affected target bean.
+ * Consider using the context:load-time-weaver XML tag for creating
+ * such a shared LoadTimeWeaver (autodetecting the environment by default).
+ * @see org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver
+ * @see org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
+ * @see org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader
+ */
+ public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
+ this.loadTimeWeaver = loadTimeWeaver;
+ }
+
+ /**
+ * Return the Spring LoadTimeWeaver to use for class instrumentation according
+ * to the JPA class transformer contract.
+ */
+ public LoadTimeWeaver getLoadTimeWeaver() {
+ return this.loadTimeWeaver;
+ }
+
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourcePatternResolver = (resourceLoader != null ?
+ ResourcePatternUtils.getResourcePatternResolver(resourceLoader) :
+ new PathMatchingResourcePatternResolver());
+ }
+
+
+ public void afterPropertiesSet() {
+ if (this.loadTimeWeaver == null && InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
+ this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(this.resourcePatternResolver.getClassLoader());
+ }
+ preparePersistenceUnitInfos();
+ }
+
+ /**
+ * Prepare the PersistenceUnitInfos according to the configuration
+ * of this manager: scanning for persistence.xml files,
+ * parsing all matching files, configurating and post-processing them.
+ *
PersistenceUnitInfos cannot be obtained before this preparation
+ * method has been invoked.
+ * @see #obtainDefaultPersistenceUnitInfo()
+ * @see #obtainPersistenceUnitInfo(String)
+ */
+ public void preparePersistenceUnitInfos() {
+ this.persistenceUnitInfoNames.clear();
+ this.persistenceUnitInfos.clear();
+ SpringPersistenceUnitInfo[] puis = readPersistenceUnitInfos();
+ for (int i = 0; i < puis.length; i++) {
+ SpringPersistenceUnitInfo pui = puis[i];
+ if (pui.getPersistenceUnitRootUrl() == null) {
+ pui.setPersistenceUnitRootUrl(determineDefaultPersistenceUnitRootUrl());
+ }
+ if (pui.getNonJtaDataSource() == null) {
+ pui.setNonJtaDataSource(this.defaultDataSource);
+ }
+ if (this.loadTimeWeaver != null) {
+ pui.init(this.loadTimeWeaver);
+ }
+ else {
+ pui.init(this.resourcePatternResolver.getClassLoader());
+ }
+ postProcessPersistenceUnitInfo(pui);
+ String name = pui.getPersistenceUnitName();
+ this.persistenceUnitInfoNames.add(name);
+ this.persistenceUnitInfos.put(name, pui);
+ }
+ }
+
+ /**
+ * Read all persistence unit infos from persistence.xml,
+ * as defined in the JPA specification.
+ */
+ private SpringPersistenceUnitInfo[] readPersistenceUnitInfos() {
+ PersistenceUnitReader reader = new PersistenceUnitReader(this.resourcePatternResolver, this.dataSourceLookup);
+ return reader.readPersistenceUnitInfos(this.persistenceXmlLocations);
+ }
+
+ /**
+ * Try to determine the persistence unit root URL based on the given
+ * "defaultPersistenceUnitRootLocation".
+ * @return the persistence unit root URL to pass to the JPA PersistenceProvider
+ * @see #setDefaultPersistenceUnitRootLocation
+ */
+ private URL determineDefaultPersistenceUnitRootUrl() {
+ if (this.defaultPersistenceUnitRootLocation == null) {
+ return null;
+ }
+ try {
+ Resource res = this.resourcePatternResolver.getResource(this.defaultPersistenceUnitRootLocation);
+ return res.getURL();
+ }
+ catch (IOException ex) {
+ throw new PersistenceException("Unable to resolve persistence unit root URL", ex);
+ }
+ }
+
+ /**
+ * Return the specified PersistenceUnitInfo from this manager's cache
+ * of processed persistence units, keeping it in the cache (i.e. not
+ * 'obtaining' it for use but rather just accessing it for post-processing).
+ *
This can be used in {@link #postProcessPersistenceUnitInfo} implementations,
+ * detecting existing persistence units of the same name and potentially merging them.
+ * @param persistenceUnitName the name of the desired persistence unit
+ * @return the PersistenceUnitInfo in mutable form, or null if not available
+ */
+ protected final MutablePersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) {
+ return this.persistenceUnitInfos.get(persistenceUnitName);
+ }
+
+ /**
+ * Hook method allowing subclasses to customize each PersistenceUnitInfo.
+ *
Default implementation delegates to all registered PersistenceUnitPostProcessors.
+ * It is usually preferable to register further entity classes, jar files etc there
+ * rather than in a subclass of this manager, to be able to reuse the post-processors.
+ * @param pui the chosen PersistenceUnitInfo, as read from persistence.xml.
+ * Passed in as MutablePersistenceUnitInfo.
+ * @see #setPersistenceUnitPostProcessors
+ */
+ protected void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
+ PersistenceUnitPostProcessor[] postProcessors = getPersistenceUnitPostProcessors();
+ if (postProcessors != null) {
+ for (PersistenceUnitPostProcessor postProcessor : postProcessors) {
+ postProcessor.postProcessPersistenceUnitInfo(pui);
+ }
+ }
+ }
+
+
+ public PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() {
+ if (this.persistenceUnitInfoNames.isEmpty()) {
+ throw new IllegalStateException("No persistence units parsed from " +
+ ObjectUtils.nullSafeToString(this.persistenceXmlLocations));
+ }
+ if (this.persistenceUnitInfos.isEmpty()) {
+ throw new IllegalStateException("All persistence units from " +
+ ObjectUtils.nullSafeToString(this.persistenceXmlLocations) + " already obtained");
+ }
+ if (this.persistenceUnitInfos.size() > 1) {
+ throw new IllegalStateException("No single default persistence unit defined in " +
+ ObjectUtils.nullSafeToString(this.persistenceXmlLocations));
+ }
+ PersistenceUnitInfo pui = this.persistenceUnitInfos.values().iterator().next();
+ this.persistenceUnitInfos.clear();
+ return pui;
+ }
+
+ public PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName) {
+ PersistenceUnitInfo pui = this.persistenceUnitInfos.remove(persistenceUnitName);
+ if (pui == null) {
+ if (!this.persistenceUnitInfoNames.contains(persistenceUnitName)) {
+ throw new IllegalArgumentException(
+ "No persistence unit with name '" + persistenceUnitName + "' found");
+ }
+ else {
+ throw new IllegalStateException(
+ "Persistence unit with name '" + persistenceUnitName + "' already obtained");
+ }
+ }
+ return pui;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.persistenceunit;
+
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+import org.springframework.util.ClassUtils;
+
+/**
+ * Spring's base implementation of the JPA
+ * {@link javax.persistence.spi.PersistenceUnitInfo} interface,
+ * used to bootstrap an EntityManagerFactory in a container.
+ *
+ *
This implementation is largely a JavaBean, offering mutators
+ * for all standard PersistenceUnitInfo properties.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @author Costin Leau
+ * @since 2.0
+ */
+public class MutablePersistenceUnitInfo implements PersistenceUnitInfo {
+
+ private String persistenceUnitName;
+
+ private String persistenceProviderClassName;
+
+ private PersistenceUnitTransactionType transactionType;
+
+ private DataSource nonJtaDataSource;
+
+ private DataSource jtaDataSource;
+
+ private List mappingFileNames = new LinkedList();
+
+ private List jarFileUrls = new LinkedList();
+
+ private URL persistenceUnitRootUrl;
+
+ private List managedClassNames = new LinkedList();
+
+ private boolean excludeUnlistedClasses = false;
+
+ private Properties properties = new Properties();
+
+ private String persistenceProviderPackageName;
+
+
+ public void setPersistenceUnitName(String persistenceUnitName) {
+ this.persistenceUnitName = persistenceUnitName;
+ }
+
+ public String getPersistenceUnitName() {
+ return this.persistenceUnitName;
+ }
+
+ public void setPersistenceProviderClassName(String persistenceProviderClassName) {
+ this.persistenceProviderClassName = persistenceProviderClassName;
+ }
+
+ public String getPersistenceProviderClassName() {
+ return this.persistenceProviderClassName;
+ }
+
+ public void setTransactionType(PersistenceUnitTransactionType transactionType) {
+ this.transactionType = transactionType;
+ }
+
+ public PersistenceUnitTransactionType getTransactionType() {
+ if (this.transactionType != null) {
+ return this.transactionType;
+ }
+ else {
+ return (this.jtaDataSource != null ?
+ PersistenceUnitTransactionType.JTA : PersistenceUnitTransactionType.RESOURCE_LOCAL);
+ }
+ }
+
+ public void setJtaDataSource(DataSource jtaDataSource) {
+ this.jtaDataSource = jtaDataSource;
+ }
+
+ public DataSource getJtaDataSource() {
+ return this.jtaDataSource;
+ }
+
+ public void setNonJtaDataSource(DataSource nonJtaDataSource) {
+ this.nonJtaDataSource = nonJtaDataSource;
+ }
+
+ public DataSource getNonJtaDataSource() {
+ return this.nonJtaDataSource;
+ }
+
+ public void addMappingFileName(String mappingFileName) {
+ this.mappingFileNames.add(mappingFileName);
+ }
+
+ public List getMappingFileNames() {
+ return this.mappingFileNames;
+ }
+
+ public void addJarFileUrl(URL jarFileUrl) {
+ this.jarFileUrls.add(jarFileUrl);
+ }
+
+ public List getJarFileUrls() {
+ return this.jarFileUrls;
+ }
+
+ public void setPersistenceUnitRootUrl(URL persistenceUnitRootUrl) {
+ this.persistenceUnitRootUrl = persistenceUnitRootUrl;
+ }
+
+ public URL getPersistenceUnitRootUrl() {
+ return this.persistenceUnitRootUrl;
+ }
+
+ public void addManagedClassName(String managedClassName) {
+ this.managedClassNames.add(managedClassName);
+ }
+
+ public List getManagedClassNames() {
+ return this.managedClassNames;
+ }
+
+ public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
+ this.excludeUnlistedClasses = excludeUnlistedClasses;
+ }
+
+ public boolean excludeUnlistedClasses() {
+ return this.excludeUnlistedClasses;
+ }
+
+ public void addProperty(String name, String value) {
+ if (this.properties == null) {
+ this.properties = new Properties();
+ }
+ this.properties.setProperty(name, value);
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ public Properties getProperties() {
+ return this.properties;
+ }
+
+ public void setPersistenceProviderPackageName(String persistenceProviderPackageName) {
+ this.persistenceProviderPackageName = persistenceProviderPackageName;
+ }
+
+ public String getPersistenceProviderPackageName() {
+ return this.persistenceProviderPackageName;
+ }
+
+
+ /**
+ * This implementation returns the default ClassLoader.
+ * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
+ */
+ public ClassLoader getClassLoader() {
+ return ClassUtils.getDefaultClassLoader();
+ }
+
+ /**
+ * This implementation throws an UnsupportedOperationException.
+ */
+ public void addTransformer(ClassTransformer classTransformer) {
+ throw new UnsupportedOperationException("addTransformer not supported");
+ }
+
+ /**
+ * This implementation throws an UnsupportedOperationException.
+ */
+ public ClassLoader getNewTempClassLoader() {
+ throw new UnsupportedOperationException("getNewTempClassLoader not supported");
+ }
+
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PersistenceUnitInfo: name '");
+ builder.append(this.persistenceUnitName);
+ builder.append("', root URL [");
+ builder.append(this.persistenceUnitRootUrl);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitManager.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitManager.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitManager.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2002-2007 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.orm.jpa.persistenceunit;
+
+import javax.persistence.spi.PersistenceUnitInfo;
+
+/**
+ * Interface that defines an abstraction for finding and managing
+ * JPA PersistenceUnitInfos. Used by
+ * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
+ * in order to obtain a {@link javax.persistence.spi.PersistenceUnitInfo}
+ * for building a concrete {@link javax.persistence.EntityManagerFactory}.
+ *
+ *
Obtaining a PersistenceUnitInfo instance is an exclusive process.
+ * A PersistenceUnitInfo instance is not available for further calls
+ * anymore once it has been obtained.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see DefaultPersistenceUnitManager
+ * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPersistenceUnitManager
+ */
+public interface PersistenceUnitManager {
+
+ /**
+ * Obtain the default PersistenceUnitInfo from this manager.
+ * @return the PersistenceUnitInfo (never null)
+ * @throws IllegalStateException if there is no default PersistenceUnitInfo defined
+ * or it has already been obtained
+ */
+ PersistenceUnitInfo obtainDefaultPersistenceUnitInfo() throws IllegalStateException;
+
+ /**
+ * Obtain the specified PersistenceUnitInfo from this manager.
+ * @param persistenceUnitName the name of the desired persistence unit
+ * @return the PersistenceUnitInfo (never null)
+ * @throws IllegalArgumentException if no PersistenceUnitInfo with the given
+ * name is defined
+ * @throws IllegalStateException if the PersistenceUnitInfo with the given
+ * name has already been obtained
+ */
+ PersistenceUnitInfo obtainPersistenceUnitInfo(String persistenceUnitName)
+ throws IllegalArgumentException, IllegalStateException;
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitPostProcessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitPostProcessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitPostProcessor.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2006 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.orm.jpa.persistenceunit;
+
+/**
+ * Callback interface for post-processing a JPA PersistenceUnitInfo.
+ * Implementations can be registered with a DefaultPersistenceUnitManager
+ * or via a LocalContainerEntityManagerFactoryBean.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see DefaultPersistenceUnitManager#setPersistenceUnitPostProcessors
+ * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPersistenceUnitPostProcessors
+ */
+public interface PersistenceUnitPostProcessor {
+
+ /**
+ * Post-process the given PersistenceUnitInfo, for example registering
+ * further entity classes and jar files.
+ * @param pui the chosen PersistenceUnitInfo, as read from persistence.xml.
+ * Passed in as MutablePersistenceUnitInfo.
+ */
+ void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui);
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.persistenceunit;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
+import org.springframework.util.Assert;
+import org.springframework.util.ResourceUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+import org.springframework.util.xml.SimpleSaxErrorHandler;
+
+/**
+ * Internal helper class for reading persistence.xml files.
+ *
+ * @author Costin Leau
+ * @author Juergen Hoeller
+ * @since 2.0
+ */
+class PersistenceUnitReader {
+
+ private static final String MAPPING_FILE_NAME = "mapping-file";
+
+ private static final String JAR_FILE_URL = "jar-file";
+
+ private static final String MANAGED_CLASS_NAME = "class";
+
+ private static final String PROPERTIES = "properties";
+
+ private static final String PROVIDER = "provider";
+
+ private static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes";
+
+ private static final String NON_JTA_DATA_SOURCE = "non-jta-data-source";
+
+ private static final String JTA_DATA_SOURCE = "jta-data-source";
+
+ private static final String TRANSACTION_TYPE = "transaction-type";
+
+ private static final String PERSISTENCE_UNIT = "persistence-unit";
+
+ private static final String UNIT_NAME = "name";
+
+ private static final String META_INF = "META-INF";
+
+ private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+ private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
+
+ private static final String SCHEMA_NAME = "persistence_1_0.xsd";
+
+ private static final String[] SCHEMA_RESOURCE_LOCATIONS = {
+ "classpath:persistence_1_0.xsd",
+ "classpath:org/hibernate/ejb/persistence_1_0.xsd",
+ "classpath:org/jpox/jpa/persistence_1_0.xsd"};
+
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final ResourcePatternResolver resourcePatternResolver;
+
+ private final DataSourceLookup dataSourceLookup;
+
+
+ /**
+ * Create a new PersistenceUnitReader.
+ * @param resourcePatternResolver the ResourcePatternResolver to use for loading resources
+ * @param dataSourceLookup the DataSourceLookup to resolve DataSource names in
+ * persistence.xml files against
+ */
+ public PersistenceUnitReader(ResourcePatternResolver resourcePatternResolver, DataSourceLookup dataSourceLookup) {
+ Assert.notNull(resourcePatternResolver, "ResourceLoader must not be null");
+ Assert.notNull(dataSourceLookup, "DataSourceLookup must not be null");
+ this.resourcePatternResolver = resourcePatternResolver;
+ this.dataSourceLookup = dataSourceLookup;
+ }
+
+
+ /**
+ * Parse and build all persistence unit infos defined in the specified XML file(s).
+ * @param persistenceXmlLocation the resource location (can be a pattern)
+ * @return the resulting PersistenceUnitInfo instances
+ */
+ public SpringPersistenceUnitInfo[] readPersistenceUnitInfos(String persistenceXmlLocation) {
+ return readPersistenceUnitInfos(new String[] {persistenceXmlLocation});
+ }
+
+ /**
+ * Parse and build all persistence unit infos defined in the given XML files.
+ * @param persistenceXmlLocations the resource locations (can be patterns)
+ * @return the resulting PersistenceUnitInfo instances
+ */
+ public SpringPersistenceUnitInfo[] readPersistenceUnitInfos(String[] persistenceXmlLocations) {
+ ErrorHandler handler = new SimpleSaxErrorHandler(logger);
+ List infos = new LinkedList();
+ String resourceLocation = null;
+ try {
+ for (int i = 0; i < persistenceXmlLocations.length; i++) {
+ Resource[] resources = this.resourcePatternResolver.getResources(persistenceXmlLocations[i]);
+ for (Resource resource : resources) {
+ resourceLocation = resource.toString();
+ InputStream stream = resource.getInputStream();
+ try {
+ Document document = validateResource(handler, stream);
+ parseDocument(resource, document, infos);
+ }
+ finally {
+ stream.close();
+ }
+ }
+ }
+ }
+ catch (IOException ex) {
+ throw new IllegalArgumentException("Cannot parse persistence unit from " + resourceLocation, ex);
+ }
+ catch (SAXException ex) {
+ throw new IllegalArgumentException("Invalid XML in persistence unit from " + resourceLocation, ex);
+ }
+ catch (ParserConfigurationException ex) {
+ throw new IllegalArgumentException("Internal error parsing persistence unit from " + resourceLocation);
+ }
+
+ return infos.toArray(new SpringPersistenceUnitInfo[infos.size()]);
+ }
+
+
+ /**
+ * Validate the given stream and return a valid DOM document for parsing.
+ */
+ protected Document validateResource(ErrorHandler handler, InputStream stream)
+ throws ParserConfigurationException, SAXException, IOException {
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+
+ // Set schema location only if we found one inside the classpath.
+ Resource schemaLocation = findSchemaResource();
+ if (schemaLocation != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found schema resource: " + schemaLocation.getURL());
+ }
+ dbf.setValidating(true);
+ dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ dbf.setAttribute(JAXP_SCHEMA_SOURCE, schemaLocation.getURL().toString());
+ }
+ else {
+ logger.debug("Schema resource [" + SCHEMA_NAME +
+ "] not found - falling back to XML parsing without schema validation");
+ }
+
+ DocumentBuilder parser = dbf.newDocumentBuilder();
+ parser.setErrorHandler(handler);
+ return parser.parse(stream);
+ }
+
+ /**
+ * Try to locate the schema first in the class path before using the URL specified inside the XML.
+ * @return an existing resource, or null if none found
+ */
+ protected Resource findSchemaResource() {
+ for (int i = 0; i < SCHEMA_RESOURCE_LOCATIONS.length; i++) {
+ Resource schemaLocation = this.resourcePatternResolver.getResource(SCHEMA_RESOURCE_LOCATIONS[i]);
+ if (schemaLocation.exists()) {
+ return schemaLocation;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Parse the validated document and add entries to the given unit info list.
+ */
+ protected List parseDocument(
+ Resource resource, Document document, List infos) throws IOException {
+
+ Element persistence = document.getDocumentElement();
+ URL unitRootURL = determinePersistenceUnitRootUrl(resource);
+ List units = (List) DomUtils.getChildElementsByTagName(persistence, PERSISTENCE_UNIT);
+ for (Element unit : units) {
+ SpringPersistenceUnitInfo info = parsePersistenceUnitInfo(unit);
+ info.setPersistenceUnitRootUrl(unitRootURL);
+ infos.add(info);
+ }
+
+ return infos;
+ }
+
+ /**
+ * Determine the persistence unit root URL based on the given resource
+ * (which points to the persistence.xml file we're reading).
+ * @param resource the resource to check
+ * @return the corresponding persistence unit root URL
+ * @throws IOException if the checking failed
+ */
+ protected URL determinePersistenceUnitRootUrl(Resource resource) throws IOException {
+ URL originalURL = resource.getURL();
+ String urlToString = originalURL.toExternalForm();
+
+ // If we get an archive, simply return the jar URL (section 6.2 from the JPA spec)
+ if (ResourceUtils.isJarURL(originalURL)) {
+ return ResourceUtils.extractJarFileURL(originalURL);
+ }
+
+ else {
+ // check META-INF folder
+ if (!urlToString.contains(META_INF)) {
+ if (logger.isInfoEnabled()) {
+ logger.info(resource.getFilename() +
+ " should be located inside META-INF directory; cannot determine persistence unit root URL for " +
+ resource);
+ }
+ return null;
+ }
+ if (urlToString.lastIndexOf(META_INF) == urlToString.lastIndexOf('/') - (1 + META_INF.length())) {
+ if (logger.isInfoEnabled()) {
+ logger.info(resource.getFilename() +
+ " is not located in the root of META-INF directory; cannot determine persistence unit root URL for " +
+ resource);
+ }
+ return null;
+ }
+
+ String persistenceUnitRoot = urlToString.substring(0, urlToString.lastIndexOf(META_INF));
+ return new URL(persistenceUnitRoot);
+ }
+ }
+
+ /**
+ * Parse the unit info DOM element.
+ */
+ protected SpringPersistenceUnitInfo parsePersistenceUnitInfo(Element persistenceUnit) throws IOException {
+ SpringPersistenceUnitInfo unitInfo = new SpringPersistenceUnitInfo();
+
+ // set unit name
+ unitInfo.setPersistenceUnitName(persistenceUnit.getAttribute(UNIT_NAME).trim());
+
+ // set transaction type
+ String txType = persistenceUnit.getAttribute(TRANSACTION_TYPE).trim();
+ if (StringUtils.hasText(txType)) {
+ unitInfo.setTransactionType(PersistenceUnitTransactionType.valueOf(txType));
+ }
+
+ // data-source
+ String jtaDataSource = DomUtils.getChildElementValueByTagName(persistenceUnit, JTA_DATA_SOURCE);
+ if (StringUtils.hasText(jtaDataSource)) {
+ unitInfo.setJtaDataSource(this.dataSourceLookup.getDataSource(jtaDataSource.trim()));
+ }
+
+ String nonJtaDataSource = DomUtils.getChildElementValueByTagName(persistenceUnit, NON_JTA_DATA_SOURCE);
+ if (StringUtils.hasText(nonJtaDataSource)) {
+ unitInfo.setNonJtaDataSource(this.dataSourceLookup.getDataSource(nonJtaDataSource.trim()));
+ }
+
+ // provider
+ String provider = DomUtils.getChildElementValueByTagName(persistenceUnit, PROVIDER);
+ if (StringUtils.hasText(provider)) {
+ unitInfo.setPersistenceProviderClassName(provider.trim());
+ }
+
+ // exclude unlisted classes
+ Element excludeUnlistedClasses = DomUtils.getChildElementByTagName(persistenceUnit, EXCLUDE_UNLISTED_CLASSES);
+ if (excludeUnlistedClasses != null) {
+ unitInfo.setExcludeUnlistedClasses(true);
+ }
+
+ parseMappingFiles(persistenceUnit, unitInfo);
+ parseJarFiles(persistenceUnit, unitInfo);
+ parseClass(persistenceUnit, unitInfo);
+ parseProperty(persistenceUnit, unitInfo);
+
+ return unitInfo;
+ }
+
+ /**
+ * Parse the property XML elements.
+ */
+ @SuppressWarnings("unchecked")
+ protected void parseProperty(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) {
+ Element propRoot = DomUtils.getChildElementByTagName(persistenceUnit, PROPERTIES);
+ if (propRoot == null) {
+ return;
+ }
+ List properties = DomUtils.getChildElementsByTagName(propRoot, "property");
+ for (Element property : properties) {
+ String name = property.getAttribute("name");
+ String value = property.getAttribute("value");
+ unitInfo.addProperty(name, value);
+ }
+ }
+
+ /**
+ * Parse the class XML elements.
+ */
+ @SuppressWarnings("unchecked")
+ protected void parseClass(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) {
+ List classes = DomUtils.getChildElementsByTagName(persistenceUnit, MANAGED_CLASS_NAME);
+ for (Element element : classes) {
+ String value = DomUtils.getTextValue(element).trim();
+ if (StringUtils.hasText(value))
+ unitInfo.addManagedClassName(value);
+ }
+ }
+
+ /**
+ * Parse the jar-file XML elements.
+ */
+ @SuppressWarnings("unchecked")
+ protected void parseJarFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) throws IOException {
+ List jars = DomUtils.getChildElementsByTagName(persistenceUnit, JAR_FILE_URL);
+ for (Element element : jars) {
+ String value = DomUtils.getTextValue(element).trim();
+ if (StringUtils.hasText(value)) {
+ Resource[] resources = this.resourcePatternResolver.getResources(value);
+ for (int i = 0; i < resources.length; i++) {
+ unitInfo.addJarFileUrl(resources[i].getURL());
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse the mapping-file XML elements.
+ */
+ @SuppressWarnings("unchecked")
+ protected void parseMappingFiles(Element persistenceUnit, SpringPersistenceUnitInfo unitInfo) {
+ List files = DomUtils.getChildElementsByTagName(persistenceUnit, MAPPING_FILE_NAME);
+ for (Element element : files) {
+ String value = DomUtils.getTextValue(element).trim();
+ if (StringUtils.hasText(value)) {
+ unitInfo.addMappingFileName(value);
+ }
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/SpringPersistenceUnitInfo.java 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.persistenceunit;
+
+import javax.persistence.spi.ClassTransformer;
+
+import org.springframework.core.DecoratingClassLoader;
+import org.springframework.instrument.classloading.LoadTimeWeaver;
+import org.springframework.instrument.classloading.SimpleThrowawayClassLoader;
+import org.springframework.util.Assert;
+
+/**
+ * Subclass of {@link MutablePersistenceUnitInfo} that adds instrumentation hooks based on
+ * Spring's {@link org.springframework.instrument.classloading.LoadTimeWeaver} abstraction.
+ *
+ *
This class is restricted to package visibility, in contrast to its superclass.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @author Costin Leau
+ * @since 2.0
+ * @see PersistenceUnitManager
+ */
+class SpringPersistenceUnitInfo extends MutablePersistenceUnitInfo {
+
+ private LoadTimeWeaver loadTimeWeaver;
+
+ private ClassLoader classLoader;
+
+
+ /**
+ * Initialize this PersistenceUnitInfo with the LoadTimeWeaver SPI interface
+ * used by Spring to add instrumentation to the current class loader.
+ */
+ public void init(LoadTimeWeaver loadTimeWeaver) {
+ Assert.notNull(loadTimeWeaver, "LoadTimeWeaver must not be null");
+ this.loadTimeWeaver = loadTimeWeaver;
+ this.classLoader = loadTimeWeaver.getInstrumentableClassLoader();
+ }
+
+ /**
+ * Initialize this PersistenceUnitInfo with the current class loader
+ * (instead of with a LoadTimeWeaver).
+ */
+ public void init(ClassLoader classLoader) {
+ Assert.notNull(classLoader, "ClassLoader must not be null");
+ this.classLoader = classLoader;
+ }
+
+
+ /**
+ * This implementation returns the LoadTimeWeaver's instrumentable ClassLoader,
+ * if specified.
+ */
+ public ClassLoader getClassLoader() {
+ return this.classLoader;
+ }
+
+ /**
+ * This implementation delegates to the LoadTimeWeaver, if specified.
+ */
+ public void addTransformer(ClassTransformer classTransformer) {
+ if (this.loadTimeWeaver == null) {
+ throw new IllegalStateException("Cannot apply class transformer without LoadTimeWeaver specified");
+ }
+ this.loadTimeWeaver.addTransformer(new ClassFileTransformerAdapter(classTransformer));
+ }
+
+ /**
+ * This implementation delegates to the LoadTimeWeaver, if specified.
+ */
+ public ClassLoader getNewTempClassLoader() {
+ ClassLoader tcl = (this.loadTimeWeaver != null ? this.loadTimeWeaver.getThrowawayClassLoader() :
+ new SimpleThrowawayClassLoader(this.classLoader));
+ String packageToExclude = getPersistenceProviderPackageName();
+ if (packageToExclude != null && tcl instanceof DecoratingClassLoader) {
+ ((DecoratingClassLoader) tcl).excludePackage(packageToExclude);
+ }
+ return tcl;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/package.html
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/package.html,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/persistenceunit/package.html 17 Aug 2012 15:16:08 -0000 1.1
@@ -0,0 +1,7 @@
+
+
+
+Internal support for managing JPA persistence units.
+
+
+
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/JpaDaoSupport.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/JpaDaoSupport.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/JpaDaoSupport.java 17 Aug 2012 15:16:15 -0000 1.1
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.support;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.dao.support.DaoSupport;
+import org.springframework.orm.jpa.JpaTemplate;
+
+/**
+ * Convenient super class for JPA data access objects. Intended for
+ * JpaTemplate usage. Alternatively, JPA-based DAOs can be coded
+ * against the plain JPA EntityManagerFactory/EntityManager API.
+ *
+ *
Requires an EntityManagerFactory or EntityManager to be set,
+ * providing a JpaTemplate based on it to subclasses. Can alternatively
+ * be initialized directly via a JpaTemplate, to reuse the latter's
+ * settings such as the EntityManagerFactory, JpaDialect, flush mode, etc.
+ *
+ *
This class will create its own JpaTemplate if an EntityManagerFactory
+ * or EntityManager reference is passed in. A custom JpaTemplate instance
+ * can be used through overriding createJpaTemplate.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see #setEntityManagerFactory
+ * @see #setEntityManager
+ * @see #createJpaTemplate
+ * @see #setJpaTemplate
+ * @see org.springframework.orm.jpa.JpaTemplate
+ */
+public abstract class JpaDaoSupport extends DaoSupport {
+
+ private JpaTemplate jpaTemplate;
+
+
+ /**
+ * Set the JPA EntityManagerFactory to be used by this DAO.
+ * Will automatically create a JpaTemplate for the given EntityManagerFactory.
+ * @see #createJpaTemplate
+ * @see #setJpaTemplate
+ */
+ public final void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
+ if (this.jpaTemplate == null || entityManagerFactory != this.jpaTemplate.getEntityManagerFactory()) {
+ this.jpaTemplate = createJpaTemplate(entityManagerFactory);
+ }
+ }
+
+ /**
+ * Create a JpaTemplate for the given EntityManagerFactory.
+ * Only invoked if populating the DAO with a EntityManagerFactory reference!
+ *
Can be overridden in subclasses to provide a JpaTemplate instance
+ * with different configuration, or a custom JpaTemplate subclass.
+ * @param entityManagerFactory the JPA EntityManagerFactory to create a JpaTemplate for
+ * @return the new JpaTemplate instance
+ * @see #setEntityManagerFactory
+ */
+ protected JpaTemplate createJpaTemplate(EntityManagerFactory entityManagerFactory) {
+ return new JpaTemplate(entityManagerFactory);
+ }
+
+ /**
+ * Set the JPA EntityManager to be used by this DAO.
+ * Will automatically create a JpaTemplate for the given EntityManager.
+ * @see #createJpaTemplate
+ * @see #setJpaTemplate
+ */
+ public final void setEntityManager(EntityManager entityManager) {
+ this.jpaTemplate = createJpaTemplate(entityManager);
+ }
+
+ /**
+ * Create a JpaTemplate for the given EntityManager.
+ * Only invoked if populating the DAO with a EntityManager reference!
+ *
Can be overridden in subclasses to provide a JpaTemplate instance
+ * with different configuration, or a custom JpaTemplate subclass.
+ * @param entityManager the JPA EntityManager to create a JpaTemplate for
+ * @return the new JpaTemplate instance
+ * @see #setEntityManagerFactory
+ */
+ protected JpaTemplate createJpaTemplate(EntityManager entityManager) {
+ return new JpaTemplate(entityManager);
+ }
+
+ /**
+ * Set the JpaTemplate for this DAO explicitly,
+ * as an alternative to specifying a EntityManagerFactory.
+ * @see #setEntityManagerFactory
+ */
+ public final void setJpaTemplate(JpaTemplate jpaTemplate) {
+ this.jpaTemplate = jpaTemplate;
+ }
+
+ /**
+ * Return the JpaTemplate for this DAO, pre-initialized
+ * with the EntityManagerFactory or set explicitly.
+ */
+ public final JpaTemplate getJpaTemplate() {
+ return jpaTemplate;
+ }
+
+ protected final void checkDaoConfig() {
+ if (this.jpaTemplate == null) {
+ throw new IllegalArgumentException("entityManagerFactory or jpaTemplate is required");
+ }
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java 17 Aug 2012 15:16:16 -0000 1.1
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.support;
+
+import java.io.IOException;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.orm.jpa.EntityManagerHolder;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+/**
+ * Servlet 2.3 Filter that binds a JPA EntityManager to the thread for the
+ * entire processing of the request. Intended for the "Open EntityManager in
+ * View" pattern, i.e. to allow for lazy loading in web views despite the
+ * original transactions already being completed.
+ *
+ *
This filter makes JPA EntityManagers available via the current thread,
+ * which will be autodetected by transaction managers. It is suitable for service
+ * layer transactions via {@link org.springframework.orm.jpa.JpaTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
+ * as for non-transactional read-only execution.
+ *
+ *
Looks up the EntityManagerFactory in Spring's root web application context.
+ * Supports a "entityManagerFactoryBeanName" filter init-param in web.xml;
+ * the default bean name is "entityManagerFactory". Looks up the EntityManagerFactory
+ * on each request, to avoid initialization order issues (when using ContextLoaderServlet,
+ * the root application context will get initialized after this filter).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see OpenEntityManagerInViewInterceptor
+ * @see org.springframework.orm.jpa.JpaInterceptor
+ * @see org.springframework.orm.jpa.JpaTransactionManager
+ * @see org.springframework.orm.jpa.JpaTemplate#execute
+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
+
+ public static final String DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME = "entityManagerFactory";
+
+ private String entityManagerFactoryBeanName = DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME;
+
+
+ /**
+ * Set the bean name of the EntityManagerFactory to fetch from Spring's
+ * root application context. Default is "entityManagerFactory".
+ * @see #DEFAULT_PERSISTENCE_MANAGER_FACTORY_BEAN_NAME
+ */
+ public void setEntityManagerFactoryBeanName(String entityManagerFactoryBeanName) {
+ this.entityManagerFactoryBeanName = entityManagerFactoryBeanName;
+ }
+
+ /**
+ * Return the bean name of the EntityManagerFactory to fetch from Spring's
+ * root application context.
+ */
+ protected String getEntityManagerFactoryBeanName() {
+ return this.entityManagerFactoryBeanName;
+ }
+
+
+ protected void doFilterInternal(
+ HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+
+ EntityManagerFactory emf = lookupEntityManagerFactory(request);
+ boolean participate = false;
+
+ if (TransactionSynchronizationManager.hasResource(emf)) {
+ // Do not modify the EntityManager: just set the participate flag.
+ participate = true;
+ }
+ else {
+ logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter");
+ try {
+ EntityManager em = createEntityManager(emf);
+ TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
+ }
+ catch (PersistenceException ex) {
+ throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
+ }
+ }
+
+ try {
+ filterChain.doFilter(request, response);
+ }
+
+ finally {
+ if (!participate) {
+ EntityManagerHolder emHolder = (EntityManagerHolder)
+ TransactionSynchronizationManager.unbindResource(emf);
+ logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
+ EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
+ }
+ }
+ }
+
+ /**
+ * Look up the EntityManagerFactory that this filter should use,
+ * taking the current HTTP request as argument.
+ *
Default implementation delegates to the lookupEntityManagerFactory
+ * without arguments.
+ * @return the EntityManagerFactory to use
+ * @see #lookupEntityManagerFactory()
+ */
+ protected EntityManagerFactory lookupEntityManagerFactory(HttpServletRequest request) {
+ return lookupEntityManagerFactory();
+ }
+
+ /**
+ * Look up the EntityManagerFactory that this filter should use.
+ * The default implementation looks for a bean with the specified name
+ * in Spring's root application context.
+ * @return the EntityManagerFactory to use
+ * @see #getEntityManagerFactoryBeanName
+ */
+ protected EntityManagerFactory lookupEntityManagerFactory() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using EntityManagerFactory '" + getEntityManagerFactoryBeanName() +
+ "' for OpenEntityManagerInViewFilter");
+ }
+ WebApplicationContext wac =
+ WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
+ return (EntityManagerFactory)
+ wac.getBean(getEntityManagerFactoryBeanName(), EntityManagerFactory.class);
+ }
+
+ /**
+ * Create a JPA EntityManager to be bound to a request.
+ *
Can be overridden in subclasses.
+ * @param emf the EntityManagerFactory to use
+ * @see javax.persistence.EntityManagerFactory#createEntityManager()
+ */
+ protected EntityManager createEntityManager(EntityManagerFactory emf) {
+ return emf.createEntityManager();
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewInterceptor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewInterceptor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/OpenEntityManagerInViewInterceptor.java 17 Aug 2012 15:16:15 -0000 1.1
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.support;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceException;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataAccessResourceFailureException;
+import org.springframework.orm.jpa.EntityManagerFactoryAccessor;
+import org.springframework.orm.jpa.EntityManagerHolder;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+
+/**
+ * Spring web request interceptor that binds a JPA EntityManager to the
+ * thread for the entire processing of the request. Intended for the "Open
+ * EntityManager in View" pattern, i.e. to allow for lazy loading in
+ * web views despite the original transactions already being completed.
+ *
+ *
This interceptor makes JPA EntityManagers available via the current thread,
+ * which will be autodetected by transaction managers. It is suitable for service
+ * layer transactions via {@link org.springframework.orm.jpa.JpaTransactionManager}
+ * or {@link org.springframework.transaction.jta.JtaTransactionManager} as well
+ * as for non-transactional read-only execution.
+ *
+ *
In contrast to {@link OpenEntityManagerInViewFilter}, this interceptor
+ * is set up in a Spring application context and can thus take advantage of
+ * bean wiring. It inherits common JPA configuration properties from
+ * {@link org.springframework.orm.jpa.JpaAccessor}, to be configured in a
+ * bean definition.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see OpenEntityManagerInViewFilter
+ * @see org.springframework.orm.jpa.JpaInterceptor
+ * @see org.springframework.orm.jpa.JpaTransactionManager
+ * @see org.springframework.orm.jpa.JpaTemplate#execute
+ * @see org.springframework.orm.jpa.SharedEntityManagerCreator
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
+ */
+public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAccessor implements WebRequestInterceptor {
+
+ /**
+ * Suffix that gets appended to the EntityManagerFactory toString
+ * representation for the "participate in existing entity manager
+ * handling" request attribute.
+ * @see #getParticipateAttributeName
+ */
+ public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
+
+
+ public void preHandle(WebRequest request) throws DataAccessException {
+ if (TransactionSynchronizationManager.hasResource(getEntityManagerFactory())) {
+ // do not modify the EntityManager: just mark the request accordingly
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ int newCount = (count != null) ? count.intValue() + 1 : 1;
+ request.setAttribute(getParticipateAttributeName(), new Integer(newCount), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewInterceptor");
+ try {
+ EntityManager em = createEntityManager();
+ TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), new EntityManagerHolder(em));
+ }
+ catch (PersistenceException ex) {
+ throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
+ }
+ }
+ }
+
+ public void postHandle(WebRequest request, ModelMap model) {
+ }
+
+ public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
+ String participateAttributeName = getParticipateAttributeName();
+ Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ if (count != null) {
+ // Do not modify the EntityManager: just clear the marker.
+ if (count.intValue() > 1) {
+ request.setAttribute(participateAttributeName, new Integer(count.intValue() - 1), WebRequest.SCOPE_REQUEST);
+ }
+ else {
+ request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
+ }
+ }
+ else {
+ EntityManagerHolder emHolder = (EntityManagerHolder)
+ TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
+ logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewInterceptor");
+ EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
+ }
+ }
+
+ /**
+ * Return the name of the request attribute that identifies that a request is
+ * already filtered. Default implementation takes the toString representation
+ * of the EntityManagerFactory instance and appends ".FILTERED".
+ * @see #PARTICIPATE_SUFFIX
+ */
+ protected String getParticipateAttributeName() {
+ return getEntityManagerFactory().toString() + PARTICIPATE_SUFFIX;
+ }
+
+}
Index: 3rdParty_sources/spring/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java
===================================================================
RCS file: /usr/local/cvsroot/3rdParty_sources/spring/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ 3rdParty_sources/spring/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.java 17 Aug 2012 15:16:15 -0000 1.1
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2002-2008 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.orm.jpa.support;
+
+import java.beans.PropertyDescriptor;
+import java.io.Serializable;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContext;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.PersistenceProperty;
+import javax.persistence.PersistenceUnit;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.annotation.InjectionMetadata;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
+import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.core.Ordered;
+import org.springframework.core.PriorityOrdered;
+import org.springframework.jndi.JndiLocatorSupport;
+import org.springframework.orm.jpa.EntityManagerFactoryInfo;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.orm.jpa.EntityManagerProxy;
+import org.springframework.orm.jpa.ExtendedEntityManagerCreator;
+import org.springframework.orm.jpa.SharedEntityManagerCreator;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * BeanPostProcessor that processes {@link javax.persistence.PersistenceUnit}
+ * and {@link javax.persistence.PersistenceContext} annotations, for injection of
+ * the corresponding JPA resources {@link javax.persistence.EntityManagerFactory}
+ * and {@link javax.persistence.EntityManager}. Any such annotated fields or methods
+ * in any Spring-managed object will automatically be injected.
+ *
+ *
This post-processor will inject sub-interfaces of EntityManagerFactory
+ * and EntityManager if the annotated fields or methods are declared as such.
+ * The actual type will be verified early, with the exception of a shared ("transactional")
+ * EntityManager reference, where type mismatches might be detected as late
+ * as on the first actual invocation.
+ *
+ *
Note: In the present implementation, PersistenceAnnotationBeanPostProcessor
+ * only supports @PersistenceUnit and @PersistenceContext
+ * with the "unitName" attribute, or no attribute at all (for the default unit).
+ * If those annotations are present with the "name" attribute at the class level,
+ * they will simply be ignored, since those only serve as deployment hint
+ * (as per the Java EE 5 specification).
+ *
+ *
This post-processor can either obtain EntityManagerFactory beans defined
+ * in the Spring application context (the default), or obtain EntityManagerFactory
+ * references from JNDI ("persistence unit references"). In the bean case,
+ * the persistence unit name will be matched against the actual deployed unit,
+ * with the bean name used as fallback unit name if no deployed name found.
+ * Typically, Spring's {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
+ * will be used for setting up such EntityManagerFactory beans. Alternatively,
+ * such beans may also be obtained from JNDI, e.g. using the jee:jndi-lookup
+ * XML configuration element (with the bean name matching the requested unit name).
+ * In both cases, the post-processor definition will look as simple as this:
+ *
+ *
+ *
+ * In the JNDI case, specify the corresponding JNDI names in this post-processor's
+ * {@link #setPersistenceUnits "persistenceUnits" map}, typically with matching
+ * persistence-unit-ref entries in the Java EE deployment descriptor.
+ * By default, those names are considered as resource references (according to the
+ * Java EE resource-ref convention), located underneath the "java:comp/env/" namespace.
+ * For example:
+ *
+ *
+ *
+ * In this case, the specified persistence units will always be resolved in JNDI
+ * rather than as Spring-defined beans. The entire persistence unit deployment,
+ * including the weaving of persistent classes, is then up to the Java EE server.
+ * Persistence contexts (i.e. EntityManager references) will be built based on
+ * those server-provided EntityManagerFactory references, using Spring's own
+ * transaction synchronization facilities for transactional EntityManager handling
+ * (typically with Spring's @Transactional annotation for demarcation
+ * and {@link org.springframework.transaction.jta.JtaTransactionManager} as backend).
+ *
+ *
If you prefer the Java EE server's own EntityManager handling, specify entries
+ * in this post-processor's {@link #setPersistenceContexts "persistenceContexts" map}
+ * (or {@link #setExtendedPersistenceContexts "extendedPersistenceContexts" map},
+ * typically with matching persistence-context-ref entries in the
+ * Java EE deployment descriptor. For example:
+ *
+ *
+ *
+ * If the application only obtains EntityManager references in the first place,
+ * this is all you need to specify. If you need EntityManagerFactory references
+ * as well, specify entries for both "persistenceUnits" and "persistenceContexts",
+ * pointing to matching JNDI locations.
+ *
+ *
NOTE: In general, do not inject EXTENDED EntityManagers into STATELESS beans,
+ * i.e. do not use @PersistenceContext with type EXTENDED in
+ * Spring beans defined with scope 'singleton' (Spring's default scope).
+ * Extended EntityManagers are not thread-safe, hence they must not be used
+ * in concurrently accessed beans (which Spring-managed singletons usually are).
+ *
+ *
Note: A default PersistenceAnnotationBeanPostProcessor will be registered
+ * by the "context:annotation-config" and "context:component-scan" XML tags.
+ * Remove or turn off the default annotation configuration there if you intend
+ * to specify a custom PersistenceAnnotationBeanPostProcessor bean definition.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see javax.persistence.PersistenceUnit
+ * @see javax.persistence.PersistenceContext
+ */
+public class PersistenceAnnotationBeanPostProcessor extends JndiLocatorSupport
+ implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor,
+ MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, Serializable {
+
+ private transient Map persistenceUnits;
+
+ private transient Map persistenceContexts;
+
+ private transient Map extendedPersistenceContexts;
+
+ private transient String defaultPersistenceUnitName = "";
+
+ private int order = Ordered.LOWEST_PRECEDENCE - 4;
+
+ private transient ListableBeanFactory beanFactory;
+
+ private transient final Map, InjectionMetadata> injectionMetadataCache =
+ new ConcurrentHashMap, InjectionMetadata>();
+
+ private final Map